]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
This commit was manufactured by cvs2svn to create branch
author(no author) <(no author)@unknown>
Wed, 3 Jul 1996 17:19:50 +0000 (17:19 +0000)
committer(no author) <(no author)@unknown>
Wed, 3 Jul 1996 17:19:50 +0000 (17:19 +0000)
'RELEASE_1_1_X'.

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/1.3@76629 13f79535-47bb-0310-9956-ffa450edef68

175 files changed:
RELEASE_1_1_X/CHANGES [new file with mode: 0644]
RELEASE_1_1_X/LICENSE [new file with mode: 0644]
RELEASE_1_1_X/README [new file with mode: 0644]
RELEASE_1_1_X/RULES.CVS [new file with mode: 0644]
RELEASE_1_1_X/cgi-bin/printenv [new file with mode: 0644]
RELEASE_1_1_X/cgi-bin/test-cgi [new file with mode: 0644]
RELEASE_1_1_X/conf/access.conf-dist [new file with mode: 0644]
RELEASE_1_1_X/conf/httpd.conf-dist [new file with mode: 0644]
RELEASE_1_1_X/conf/mime.types [new file with mode: 0644]
RELEASE_1_1_X/conf/srm.conf-dist [new file with mode: 0644]
RELEASE_1_1_X/htdocs/apache_pb.gif [new file with mode: 0644]
RELEASE_1_1_X/htdocs/index.html [new file with mode: 0644]
RELEASE_1_1_X/icons/README [new file with mode: 0644]
RELEASE_1_1_X/icons/a.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/alert.black.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/alert.red.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/apache_pb.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/back.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/ball.gray.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/ball.red.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/binary.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/binhex.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/blank.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/bomb.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/box1.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/box2.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/broken.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/burst.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/c.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/comp.blue.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/comp.gray.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/compressed.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/continued.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/dir.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/down.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/dvi.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/f.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/folder.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/folder.open.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/folder.sec.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/forward.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/generic.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/generic.red.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/generic.sec.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/hand.right.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/hand.up.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/icon.sheet.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/image1.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/image2.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/image3.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/index.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/layout.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/left.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/link.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/movie.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/p.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/patch.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/pdf.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/pie0.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/pie1.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/pie2.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/pie3.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/pie4.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/pie5.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/pie6.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/pie7.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/pie8.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/portal.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/ps.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/quill.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/right.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/screw1.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/screw2.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/script.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/sound1.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/sound2.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/sphere1.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/sphere2.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/tar.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/tex.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/text.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/transfer.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/unknown.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/up.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/uu.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/uuencoded.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/world1.gif [new file with mode: 0644]
RELEASE_1_1_X/icons/world2.gif [new file with mode: 0644]
RELEASE_1_1_X/src/.cvsignore [new file with mode: 0644]
RELEASE_1_1_X/src/API.html [new file with mode: 0644]
RELEASE_1_1_X/src/CHANGES [new file with mode: 0644]
RELEASE_1_1_X/src/Configuration.tmpl [new file with mode: 0644]
RELEASE_1_1_X/src/Configure [new file with mode: 0755]
RELEASE_1_1_X/src/INSTALL [new file with mode: 0644]
RELEASE_1_1_X/src/Makefile.tmpl [new file with mode: 0644]
RELEASE_1_1_X/src/README [new file with mode: 0644]
RELEASE_1_1_X/src/TODO [new file with mode: 0644]
RELEASE_1_1_X/src/ap/ap_md5c.c [new file with mode: 0644]
RELEASE_1_1_X/src/include/alloc.h [new file with mode: 0644]
RELEASE_1_1_X/src/include/ap_config.h [new file with mode: 0644]
RELEASE_1_1_X/src/include/buff.h [new file with mode: 0644]
RELEASE_1_1_X/src/include/conf.h [new file with mode: 0644]
RELEASE_1_1_X/src/include/explain.h [new file with mode: 0644]
RELEASE_1_1_X/src/include/http_conf_globals.h [new file with mode: 0644]
RELEASE_1_1_X/src/include/http_config.h [new file with mode: 0644]
RELEASE_1_1_X/src/include/http_core.h [new file with mode: 0644]
RELEASE_1_1_X/src/include/http_log.h [new file with mode: 0644]
RELEASE_1_1_X/src/include/http_main.h [new file with mode: 0644]
RELEASE_1_1_X/src/include/http_protocol.h [new file with mode: 0644]
RELEASE_1_1_X/src/include/http_request.h [new file with mode: 0644]
RELEASE_1_1_X/src/include/httpd.h [new file with mode: 0644]
RELEASE_1_1_X/src/include/md5.h [new file with mode: 0644]
RELEASE_1_1_X/src/include/rfc1413.h [new file with mode: 0644]
RELEASE_1_1_X/src/include/scoreboard.h [new file with mode: 0644]
RELEASE_1_1_X/src/include/util_md5.h [new file with mode: 0644]
RELEASE_1_1_X/src/include/util_script.h [new file with mode: 0644]
RELEASE_1_1_X/src/main/alloc.c [new file with mode: 0644]
RELEASE_1_1_X/src/main/buff.c [new file with mode: 0644]
RELEASE_1_1_X/src/main/explain.c [new file with mode: 0644]
RELEASE_1_1_X/src/main/http_bprintf.c [new file with mode: 0644]
RELEASE_1_1_X/src/main/http_config.c [new file with mode: 0644]
RELEASE_1_1_X/src/main/http_core.c [new file with mode: 0644]
RELEASE_1_1_X/src/main/http_log.c [new file with mode: 0644]
RELEASE_1_1_X/src/main/http_main.c [new file with mode: 0644]
RELEASE_1_1_X/src/main/http_protocol.c [new file with mode: 0644]
RELEASE_1_1_X/src/main/http_request.c [new file with mode: 0644]
RELEASE_1_1_X/src/main/md5c.c [new file with mode: 0644]
RELEASE_1_1_X/src/main/rfc1413.c [new file with mode: 0644]
RELEASE_1_1_X/src/main/util.c [new file with mode: 0644]
RELEASE_1_1_X/src/main/util_md5.c [new file with mode: 0644]
RELEASE_1_1_X/src/main/util_script.c [new file with mode: 0644]
RELEASE_1_1_X/src/mod_ai_backcompat.c [new file with mode: 0644]
RELEASE_1_1_X/src/mod_cookies.c [new file with mode: 0644]
RELEASE_1_1_X/src/mod_log_common.c [new file with mode: 0644]
RELEASE_1_1_X/src/mod_proxy.c [new file with mode: 0644]
RELEASE_1_1_X/src/modules/standard/mod_access.c [new file with mode: 0644]
RELEASE_1_1_X/src/modules/standard/mod_actions.c [new file with mode: 0644]
RELEASE_1_1_X/src/modules/standard/mod_alias.c [new file with mode: 0644]
RELEASE_1_1_X/src/modules/standard/mod_asis.c [new file with mode: 0644]
RELEASE_1_1_X/src/modules/standard/mod_auth.c [new file with mode: 0644]
RELEASE_1_1_X/src/modules/standard/mod_auth_anon.c [new file with mode: 0644]
RELEASE_1_1_X/src/modules/standard/mod_auth_db.c [new file with mode: 0644]
RELEASE_1_1_X/src/modules/standard/mod_auth_dbm.c [new file with mode: 0644]
RELEASE_1_1_X/src/modules/standard/mod_auth_msql.c [new file with mode: 0644]
RELEASE_1_1_X/src/modules/standard/mod_autoindex.c [new file with mode: 0644]
RELEASE_1_1_X/src/modules/standard/mod_cern_meta.c [new file with mode: 0644]
RELEASE_1_1_X/src/modules/standard/mod_cgi.c [new file with mode: 0644]
RELEASE_1_1_X/src/modules/standard/mod_digest.c [new file with mode: 0644]
RELEASE_1_1_X/src/modules/standard/mod_dir.c [new file with mode: 0644]
RELEASE_1_1_X/src/modules/standard/mod_dld.c [new file with mode: 0644]
RELEASE_1_1_X/src/modules/standard/mod_env.c [new file with mode: 0644]
RELEASE_1_1_X/src/modules/standard/mod_imap.c [new file with mode: 0644]
RELEASE_1_1_X/src/modules/standard/mod_include.c [new file with mode: 0644]
RELEASE_1_1_X/src/modules/standard/mod_info.c [new file with mode: 0644]
RELEASE_1_1_X/src/modules/standard/mod_log_agent.c [new file with mode: 0644]
RELEASE_1_1_X/src/modules/standard/mod_log_config.c [new file with mode: 0644]
RELEASE_1_1_X/src/modules/standard/mod_log_referer.c [new file with mode: 0644]
RELEASE_1_1_X/src/modules/standard/mod_mime.c [new file with mode: 0644]
RELEASE_1_1_X/src/modules/standard/mod_negotiation.c [new file with mode: 0644]
RELEASE_1_1_X/src/modules/standard/mod_status.c [new file with mode: 0644]
RELEASE_1_1_X/src/modules/standard/mod_userdir.c [new file with mode: 0644]
RELEASE_1_1_X/src/support/.cvsignore [new file with mode: 0644]
RELEASE_1_1_X/src/support/Makefile [new file with mode: 0755]
RELEASE_1_1_X/src/support/cls.c [new file with mode: 0644]
RELEASE_1_1_X/src/support/dbmmanage [new file with mode: 0644]
RELEASE_1_1_X/src/support/dbmmanage.new [new file with mode: 0644]
RELEASE_1_1_X/src/support/dbmmanage.readme [new file with mode: 0644]
RELEASE_1_1_X/src/support/htdigest.c [new file with mode: 0644]
RELEASE_1_1_X/src/support/htpasswd.c [new file with mode: 0644]
RELEASE_1_1_X/src/support/httpd.1m [new file with mode: 0644]
RELEASE_1_1_X/src/support/httpd_monitor.c [new file with mode: 0644]
RELEASE_1_1_X/src/support/log_server_status [new file with mode: 0755]
RELEASE_1_1_X/src/support/logresolve.c [new file with mode: 0644]
RELEASE_1_1_X/src/support/rotatelogs.c [new file with mode: 0644]
RELEASE_1_1_X/src/test/cls.c [new file with mode: 0644]

diff --git a/RELEASE_1_1_X/CHANGES b/RELEASE_1_1_X/CHANGES
new file mode 100644 (file)
index 0000000..a9d5649
--- /dev/null
@@ -0,0 +1,85 @@
+New features with this release, as extensions of the Apache functionality
+(see also more detailed CHANGES file) in the source directory. For more
+information, see http://www.apache.org/docs/1.1/
+
+In addition to a number of bug fixes and internal performance
+enhancements, Apache 1.1 has the following specific new user
+features:
+
+  *) Caching Proxy Server
+       Apache can now act as an HTTP proxy server, allowing clients
+       behind firewalls to use the server to access the outside world. In
+       addition, it can cache documents it proxies, speeding up access to
+       frequently requested documents.
+
+  *) Filetype-based Script "Actions"
+       You can now run CGI scripts whenever a file of a certion type is
+       requested. Makes it much easier to execute scripts that process
+       files.
+
+  *) Support for Keep-Alive Persistent Connections
+       Apache now has (optional) support for persistent connections, as
+       defined by the HTTP/1.1 draft. This protocol, supported by a
+       number of current HTTP servers and browsers (including Netscape
+       Navigator 2.0) has been shown to increase speed of document
+       transfer by up to 50% in certain cases.
+
+  *) Customizable CGI Environment Variables (not in this release)
+       New PassEnv and SetEnv directives allow you to modify the
+       environment variables passed to CGI scripts
+
+  *) CERN Metafile Support
+       Now emulates the CERN httpd's support for metafiles containing
+       additional HTTP headers to be supplied with a document.
+
+  *) Redirect Now Usable in .htaccess Files
+       The Redirect directive can now be used in .htaccess files when the
+       FileInfo directive has been set on. This allows users to redirect
+       parts of their directories without requiring CGI scripts
+
+  *) Improved UserDir Directive (not in this release)
+       Now supports the ability to point user's files (as specificed by
+       URLs beginning with the "~" character) at directories other than
+       those specified by the Unix password file.
+
+  *) Minimal DNS Now Runtime Option
+       New HostnameLookups server configuration directive can be used to
+       turn On or  Off DNS lookups. This supercedes the -DMINIMAL_DNS
+       compile-time configuration option.
+
+  *) Listen to Multiple Addresses and Ports
+       Using the new Listen directive, Apache can listen to more than one
+       port and IP address, using the same configuration set.
+
+  *) Anonymous HTTP Logins
+       New options allow you to allow, using Basic HTTP Authentication,
+       anonymous logins, like those of FTP. This allows you to collect
+       email addresses of people accessing your site.
+
+  *) File Owner Avialable to Included CGI Scripts
+       Server-side includes that call CGI scripts will now set a
+       USER_NAME environment variable that contains the owner of the file
+       which included it.
+
+  *) Improved Icons
+       Thanks to Kevin Hughes, Apache's nifty color GIF icons for
+       directory listings have been updated. In addition, the Powered by
+       Apache (apache_pb.gif) logo has been included.
+
+  *) Log Rotation
+       New support utility to allow log rotation without shutting down the
+       server. See support/rotatelogs.c.
+
+NEW AUTHENTICATION MODULES:
+
+Note: These modules are not compiled into the server by default, as
+they require special support on the host system. They must be enabled
+specifically in the Configuration file.
+
+  *) Support for Unix DB Authentication - mod_db.c
+       In addition to DBM support, Apache now contains optional support
+       for Berkeley DB databases.
+
+  *) mSQL Database Authentication - mod_auth_msql.html
+       Support for the use of mSQL databases for user authentication via
+       HTTP is now supported.
diff --git a/RELEASE_1_1_X/LICENSE b/RELEASE_1_1_X/LICENSE
new file mode 100644 (file)
index 0000000..825e5c1
--- /dev/null
@@ -0,0 +1,56 @@
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+
+
diff --git a/RELEASE_1_1_X/README b/RELEASE_1_1_X/README
new file mode 100644 (file)
index 0000000..2eb4025
--- /dev/null
@@ -0,0 +1,76 @@
+                                 Apache
+                             Version 1.1 (and up)
+
+What is it?
+-----------
+
+Apache is an HTTP server designed as a plug-in replacement for the NCSA
+server version 1.3 (or 1.4). It fixes numerous bugs in the NCSA server and
+includes many frequently requested new features, and has an API which
+allows it to be extended to meet users' needs more easily.
+
+Documentation
+-------------
+
+All the documentation is on-line on the WWW, via <URL:http://www.apache.org/>.
+
+Installation
+------------
+
+Unless you grabbed a binary distribution of Apache, you must compile
+it for your specific platform.  In order to compile it, you must set
+compile-time options (in particular, system type) for your system by
+editing a Configuration file, run a script which generates a Makefile
+and a small piece of C code, and then compile it.
+
+For instructions on compilation, see the file 'INSTALL' in the src/ directory.
+
+After compilation, you will have a binary called "httpd" in the src/
+directory.  If you received a binary distribution of apache, you
+should have this file already.
+
+The next step is to edit the configuration files for the server.  In
+the subdirectory called "conf" you should find distribution versions
+of the three configuration files: srm.conf-dist, access.conf-dist, and
+httpd.conf-dist.  Copy them to srm.conf, access.conf, httpd.conf
+respectively.
+
+First edit httpd.conf.  This sets up general attributes about the
+server - the port number, the user it runs as, etc.  Next edit the
+srm.conf file - this sets up the root of the document tree, special
+functions like server-parsed HTML or internal imagemap parsing, etc.
+Finally, edit the access.conf file to at least set the base cases of
+access. Documentation for all of these is located at
+<URL:http://www.apache.org/docs/>.
+
+Finally, make a call to httpd, with a -f to the full path to the
+httpd.conf file.  I.e., the common case:
+
+  /usr/local/etc/apache/src/httpd -f /usr/local/etc/apache/conf/httpd.conf
+
+And voila!  The server should be running.
+
+By default the srm.conf and access.conf files are located by name - to
+specifically call them by other names, use the AccessConfig and
+ResourceConfig directives in httpd.conf.
+
+The Latest Version
+------------------
+
+Details of the latest version are in the apache project page (above).
+
+NOTE: At the time of release of Apache 1.1, two modules had updated
+versions which were not sufficiently tested for inclusion into the 1.1
+distribution: mod_auth_msql and mod_cern_meta.  The newer versions are
+available from http://www.apache.org/dist/contrib/modules/ - if you
+plan on using this functionality we encourage you to give the newer
+modules a test drive, and let us know of any problems.  In particular,
+mod_cern_meta is now configurable per-directory, and the configuration
+directives have changed.  We can not promise that the existing
+configuration directives provided by the mod_cern_meta included in the
+distribution will be supported in the future.
+
+Licencing
+---------
+
+Please see the file called LICENSE.
diff --git a/RELEASE_1_1_X/RULES.CVS b/RELEASE_1_1_X/RULES.CVS
new file mode 100644 (file)
index 0000000..7ecbbff
--- /dev/null
@@ -0,0 +1,13 @@
+1. Don't commit several unrelated changes in one go. Each change should be
+committed separately (that is, it can affect multiple files, but it should all
+be part of a single change).
+
+2. When committing, make sure that the CVS log message explains what the
+patches do and why.
+
+3. Don't edit CHANGES files unless there is a change which is visible to a user
+of Apache. CVS logs provide a detailed history of all changes (if people follow
+rule 2), so there is no need to duplicate it in CHANGES.
+
+4. Don't change src/Configuration.tmpl to your local configuration. Copy it to
+Configuration (which is _not_ version controlled) and change that.
diff --git a/RELEASE_1_1_X/cgi-bin/printenv b/RELEASE_1_1_X/cgi-bin/printenv
new file mode 100644 (file)
index 0000000..7d389e0
--- /dev/null
@@ -0,0 +1,7 @@
+#!/usr/local/bin/perl
+
+print "Content-type: text/html\n\n";
+while (($key, $val) = each %ENV) {
+       print "$key = $val<BR>\n";
+}
+
diff --git a/RELEASE_1_1_X/cgi-bin/test-cgi b/RELEASE_1_1_X/cgi-bin/test-cgi
new file mode 100644 (file)
index 0000000..9748971
--- /dev/null
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+echo Content-type: text/plain
+echo
+
+echo CGI/1.0 test script report:
+echo
+
+echo argc is $#. argv is "$*".
+echo
+
+echo SERVER_SOFTWARE = $SERVER_SOFTWARE
+echo SERVER_NAME = $SERVER_NAME
+echo GATEWAY_INTERFACE = $GATEWAY_INTERFACE
+echo SERVER_PROTOCOL = $SERVER_PROTOCOL
+echo SERVER_PORT = $SERVER_PORT
+echo REQUEST_METHOD = $REQUEST_METHOD
+echo HTTP_ACCEPT = "$HTTP_ACCEPT"
+echo PATH_INFO = "$PATH_INFO"
+echo PATH_TRANSLATED = "$PATH_TRANSLATED"
+echo SCRIPT_NAME = "$SCRIPT_NAME"
+echo QUERY_STRING = "$QUERY_STRING"
+echo REMOTE_HOST = $REMOTE_HOST
+echo REMOTE_ADDR = $REMOTE_ADDR
+echo REMOTE_USER = $REMOTE_USER
+echo AUTH_TYPE = $AUTH_TYPE
+echo CONTENT_TYPE = $CONTENT_TYPE
+echo CONTENT_LENGTH = $CONTENT_LENGTH
diff --git a/RELEASE_1_1_X/conf/access.conf-dist b/RELEASE_1_1_X/conf/access.conf-dist
new file mode 100644 (file)
index 0000000..3947bc1
--- /dev/null
@@ -0,0 +1,59 @@
+# access.conf: Global access configuration
+# Online docs at http://www.apache.org/
+
+# This file defines server settings which affect which types of services
+# are allowed, and in what circumstances. 
+
+# Each directory to which Apache has access, can be configured with respect
+# to which services and features are allowed and/or disabled in that
+# directory (and its subdirectories). 
+
+# Originally by Rob McCool
+
+# This should be changed to whatever you set DocumentRoot to.
+
+<Directory /usr/local/etc/httpd/htdocs>
+
+# This may also be "None", "All", or any combination of "Indexes",
+# "Includes", "FollowSymLinks", "ExecCGI", or "MultiViews".
+
+# Note that "MultiViews" must be named *explicitly* --- "Options All"
+# doesn't give it to you (or at least, not yet).
+
+Options Indexes FollowSymLinks
+
+# This controls which options the .htaccess files in directories can
+# override. Can also be "All", or any combination of "Options", "FileInfo", 
+# "AuthConfig", and "Limit"
+
+AllowOverride None
+
+# Controls who can get stuff from this server.
+
+order allow,deny
+allow from all
+
+</Directory>
+
+# /usr/local/etc/httpd/cgi-bin should be changed to whatever your ScriptAliased
+# CGI directory exists, if you have that configured.
+
+<Directory /usr/local/etc/httpd/cgi-bin>
+AllowOverride None
+Options None
+</Directory>
+
+# Allow server status reports, with the URL of http://servername/status
+# Change the ".nowhere.com" to match your domain to enable.
+
+#<Location /status>
+#SetHandler server-status
+
+#order deny,allow
+#deny from all
+#allow from .nowhere.com
+#</Location>
+
+# You may place any other directories or locations you wish to have
+# access information for after this one.
+
diff --git a/RELEASE_1_1_X/conf/httpd.conf-dist b/RELEASE_1_1_X/conf/httpd.conf-dist
new file mode 100644 (file)
index 0000000..7fd7de9
--- /dev/null
@@ -0,0 +1,168 @@
+# This is the main server configuration file. See URL http://www.apache.org/
+# for instructions.
+
+# Do NOT simply read the instructions in here without understanding
+# what they do, if you are unsure consult the online docs. You have been
+# warned.  
+
+# Originally by Rob McCool
+
+# ServerType is either inetd, or standalone.
+
+ServerType standalone
+
+# If you are running from inetd, go to "ServerAdmin".
+
+# Port: The port the standalone listens to. For ports < 1023, you will
+# need httpd to be run as root initially.
+
+Port 80
+
+# HostnameLookups: Log the names of clients or just their IP numbers
+#   e.g.   www.apache.org (on) or 204.62.129.132 (off)
+HostnameLookups on
+
+# If you wish httpd to run as a different user or group, you must run
+# httpd as root initially and it will switch.  
+
+# User/Group: The name (or #number) of the user/group to run httpd as.
+#  On SCO (ODT 3) use User nouser and Group nogroup
+User nobody
+Group #-1
+
+# ServerAdmin: Your address, where problems with the server should be
+# e-mailed.
+
+ServerAdmin you@your.address
+
+# ServerRoot: The directory the server's config, error, and log files
+# are kept in
+
+ServerRoot /usr/local/etc/httpd
+
+# BindAddress: You can support virtual hosts with this option. This option
+# is used to tell the server which IP address to listen to. It can either
+# contain "*", an IP address, or a fully qualified Internet domain name.
+# See also the VirtualHost directive.
+
+#BindAddress *
+
+# ErrorLog: The location of the error log file. If this does not start
+# with /, ServerRoot is prepended to it.
+
+ErrorLog logs/error_log
+
+# TransferLog: The location of the transfer log file. If this does not
+# start with /, ServerRoot is prepended to it.
+
+TransferLog logs/access_log
+
+# PidFile: The file the server should log its pid to
+PidFile logs/httpd.pid
+
+# ScoreBoardFile: File used to store internal server process information
+ScoreBoardFile logs/apache_status
+
+# ServerName allows you to set a host name which is sent back to clients for
+# your server if it's different than the one the program would get (i.e. use
+# "www" instead of the host's real name).
+#
+# Note: You cannot just invent host names and hope they work. The name you 
+# define here must be a valid DNS name for your host. If you don't understand
+# this, ask your network administrator.
+
+#ServerName new.host.name
+
+# CacheNegotiatedDocs: By default, Apache sends Pragma: no-cache with each
+# document that was negotiated on the basis of content. This asks proxy
+# servers not to cache the document. Uncommenting the following line disables
+# this behavior, and proxies will be allowed to cache the documents.
+
+#CacheNegotiatedDocs
+
+# Timeout: The number of seconds before receives and sends time out
+#  n.b. the compiled default is 1200 (20 minutes !)
+
+Timeout 400
+
+# KeepAlive: The number of Keep-Alive persistent requests to accept
+# per connection. Set to 0 to deactivate Keep-Alive support
+
+KeepAlive 5
+
+# KeepAliveTimeout: Number of seconds to wait for the next request
+
+KeepAliveTimeout 15
+
+# Server-pool size regulation.  Rather than making you guess how many
+# server processes you need, Apache dynamically adapts to the load it
+# sees --- that is, it tries to maintain enough server processes to
+# handle the current load, plus a few spare servers to handle transient
+# load spikes (e.g., multiple simultaneous requests from a single
+# Netscape browser).
+
+# It does this by periodically checking how many servers are waiting
+# for a request.  If there are fewer than MinSpareServers, it creates
+# a new spare.  If there are more than MaxSpareServers, some of the
+# spares die off.  These values are probably OK for most sites ---
+
+MinSpareServers 5
+MaxSpareServers 10
+
+# Number of servers to start --- should be a reasonable ballpark figure.
+
+StartServers 5
+
+# Limit on total number of servers running, i.e., limit on the number
+# of clients who can simultaneously connect --- if this limit is ever
+# reached, clients will be LOCKED OUT, so it should NOT BE SET TOO LOW.
+# It is intended mainly as a brake to keep a runaway server from taking
+# Unix with it as it spirals down...
+
+MaxClients 150
+
+# MaxRequestsPerChild: the number of requests each child process is
+#  allowed to process before the child dies.
+#  The child will exit so as to avoid problems after prolonged use when
+#  Apache (and maybe the libraries it uses) leak.  On most systems, this
+#  isn't really needed, but a few (such as Solaris) do have notable leaks
+#  in the libraries.
+
+MaxRequestsPerChild 30
+
+# Proxy Server directives. Uncomment the following line to
+# enable the proxy server:
+
+#ProxyRequests On
+
+# To enable the cache as well, edit and uncomment the following lines:
+
+#CacheRoot /usr/local/etc/httpd/proxy
+#CacheSize 5
+#CacheGcInterval 4
+#CacheMaxExpire 24
+#CacheLastModifiedFactor 0.1
+#CacheDefaultExpire 1
+#NoCache adomain.com anotherdomain.edu joes.garage.com
+
+# Listen: Allows you to bind Apache to specific IP addresses and/or
+# ports, in addition to the default. See also the VirtualHost command
+
+#Listen 3000
+#Listen 12.34.56.78:80
+
+# VirtualHost: Allows the daemon to respond to requests for more than one
+# server address, if your server machine is configured to accept IP packets
+# for multiple addresses. This can be accomplished with the ifconfig 
+# alias flag, or through kernel patches like VIF.
+
+# Any httpd.conf or srm.conf directive may go into a VirtualHost command.
+# See alto the BindAddress entry.
+#<VirtualHost host.foo.com>
+#ServerAdmin webmaster@host.foo.com
+#DocumentRoot /www/docs/host.foo.com
+#ServerName host.foo.com
+#ErrorLog logs/host.foo.com-error_log
+#TransferLog logs/host.foo.com-access_log
+#</VirtualHost>
diff --git a/RELEASE_1_1_X/conf/mime.types b/RELEASE_1_1_X/conf/mime.types
new file mode 100644 (file)
index 0000000..8853c1f
--- /dev/null
@@ -0,0 +1,99 @@
+# This is a comment. I love comments.
+
+
+application/activemessage
+application/andrew-inset
+application/applefile
+application/atomicmail
+application/dca-rft
+application/dec-dx
+application/mac-binhex40       hqx
+application/mac-compactpro     cpt
+application/macwriteii
+application/msword             doc
+application/news-message-id
+application/news-transmission
+application/octet-stream       bin dms lha lzh exe class
+application/oda                        oda
+application/pdf                        pdf
+application/postscript         ai eps ps
+application/powerpoint         ppt
+application/remote-printing
+application/rtf                        rtf
+application/slate
+application/wita
+application/wordperfect5.1
+application/x-bcpio            bcpio
+application/x-cdlink           vcd
+application/x-compress         Z
+application/x-cpio             cpio
+application/x-csh              csh
+application/x-director         dcr dir dxr
+application/x-dvi              dvi
+application/x-gtar             gtar
+application/x-gzip             gz
+application/x-hdf              hdf
+application/x-httpd-cgi                cgi
+application/x-koan             skp skd skt skm
+application/x-latex            latex
+application/x-mif              mif
+application/x-netcdf           nc cdf
+application/x-sh               sh
+application/x-shar             shar
+application/x-stuffit          sit
+application/x-sv4cpio          sv4cpio
+application/x-sv4crc           sv4crc
+application/x-tar              tar
+application/x-tcl              tcl
+application/x-tex              tex
+application/x-texinfo          texinfo texi
+application/x-troff            t tr roff
+application/x-troff-man                man
+application/x-troff-me         me
+application/x-troff-ms         ms
+application/x-ustar            ustar
+application/x-wais-source      src
+application/zip                        zip
+audio/basic                    au snd
+audio/mpeg                     mpga mp2
+audio/x-aiff                   aif aiff aifc
+audio/x-pn-realaudio           ram
+audio/x-pn-realaudio-plugin    rpm
+audio/x-realaudio              ra
+audio/x-wav                    wav
+chemical/x-pdb                 pdb xyz
+image/gif                      gif
+image/ief                      ief
+image/jpeg                     jpeg jpg jpe
+image/png                      png
+image/tiff                     tiff tif
+image/x-cmu-raster             ras
+image/x-portable-anymap                pnm
+image/x-portable-bitmap                pbm
+image/x-portable-graymap       pgm
+image/x-portable-pixmap                ppm
+image/x-rgb                    rgb
+image/x-xbitmap                        xbm
+image/x-xpixmap                        xpm
+image/x-xwindowdump            xwd
+message/external-body
+message/news
+message/partial
+message/rfc822
+multipart/alternative
+multipart/appledouble
+multipart/digest
+multipart/mixed
+multipart/parallel
+text/html                      html htm
+text/plain                     txt
+text/richtext                  rtx
+text/tab-separated-values      tsv
+text/x-setext                  etx
+text/x-sgml                    sgml sgm
+video/mpeg                     mpeg mpg mpe
+video/quicktime                        qt mov
+video/x-msvideo                        avi
+video/x-sgi-movie              movie
+x-conference/x-cooltalk                ice
+x-world/x-vrml                 wrl vrml
diff --git a/RELEASE_1_1_X/conf/srm.conf-dist b/RELEASE_1_1_X/conf/srm.conf-dist
new file mode 100644 (file)
index 0000000..668e513
--- /dev/null
@@ -0,0 +1,210 @@
+# With this document, you define the name space that users see of your http
+# server.  This file also defines server settings which affect how requests are
+# serviced, and how results should be formatted. 
+  
+# See the tutorials at http://www.apache.org/ for
+# more information.
+
+# Originally by Rob McCool; Adapted for Apache
+
+
+# DocumentRoot: The directory out of which you will serve your
+# documents. By default, all requests are taken from this directory, but
+# symbolic links and aliases may be used to point to other locations.
+
+DocumentRoot /usr/local/etc/httpd/htdocs
+
+# UserDir: The name of the directory which is appended onto a user's home
+# directory if a ~user request is recieved.
+
+UserDir public_html
+
+# DirectoryIndex: Name of the file or files to use as a pre-written HTML
+# directory index.  Separate multiple entries with spaces.
+
+DirectoryIndex index.html
+
+# FancyIndexing is whether you want fancy directory indexing or standard
+
+FancyIndexing on
+
+# AddIcon tells the server which icon to show for different files or filename
+# extensions
+
+AddIconByEncoding (CMP,/icons/compressed.gif) x-compress x-gzip
+
+AddIconByType (TXT,/icons/text.gif) text/*
+AddIconByType (IMG,/icons/image2.gif) image/*
+AddIconByType (SND,/icons/sound2.gif) audio/*
+AddIconByType (VID,/icons/movie.gif) video/*
+
+AddIcon /icons/binary.gif .bin .exe
+AddIcon /icons/binhex.gif .hqx
+AddIcon /icons/tar.gif .tar
+AddIcon /icons/world2.gif .wrl .wrl.gz .vrml .vrm .iv
+AddIcon /icons/compressed.gif .Z .z .tgz .gz .zip
+AddIcon /icons/a.gif .ps .ai .eps
+AddIcon /icons/layout.gif .html .shtml .htm .pdf
+AddIcon /icons/text.gif .txt
+AddIcon /icons/c.gif .c
+AddIcon /icons/p.gif .pl .py
+AddIcon /icons/f.gif .for
+AddIcon /icons/dvi.gif .dvi
+AddIcon /icons/uuencoded.gif .uu
+AddIcon /icons/script.gif .conf .sh .shar .csh .ksh .tcl
+AddIcon /icons/tex.gif .tex
+AddIcon /icons/bomb.gif core
+
+AddIcon /icons/back.gif ..
+AddIcon /icons/hand.right.gif README
+AddIcon /icons/folder.gif ^^DIRECTORY^^
+AddIcon /icons/blank.gif ^^BLANKICON^^
+
+# DefaultIcon is which icon to show for files which do not have an icon
+# explicitly set.
+
+DefaultIcon /icons/unknown.gif
+
+# AddDescription allows you to place a short description after a file in
+# server-generated indexes.
+# Format: AddDescription "description" filename
+
+# ReadmeName is the name of the README file the server will look for by
+# default. Format: ReadmeName name
+#
+# The server will first look for name.html, include it if found, and it will
+# then look for name and include it as plaintext if found.
+#
+# HeaderName is the name of a file which should be prepended to
+# directory indexes. 
+
+ReadmeName README
+HeaderName HEADER
+
+# IndexIgnore is a set of filenames which directory indexing should ignore
+# Format: IndexIgnore name1 name2...
+
+IndexIgnore */.??* *~ *# */HEADER* */README* */RCS
+
+# AccessFileName: The name of the file to look for in each directory
+# for access control information.
+
+AccessFileName .htaccess
+
+# DefaultType is the default MIME type for documents which the server
+# cannot find the type of from filename extensions.
+
+DefaultType text/plain
+
+# AddEncoding allows you to have certain browsers (Mosaic/X 2.1+) uncompress
+# information on the fly. Note: Not all browsers support this.
+
+AddEncoding x-compress Z
+AddEncoding x-gzip gz
+
+# AddLanguage allows you to specify the language of a document. You can
+# then use content negotiation to give a browser a file in a language
+# it can understand.  Note that the suffix does not have to be the same
+# as the language keyword --- those with documents in Polish (whose
+# net-standard language code is pl) may wish to use "AddLanguage pl .po" 
+# to avoid the ambiguity with the common suffix for perl scripts.
+
+AddLanguage en .en
+AddLanguage fr .fr
+AddLanguage de .de
+AddLanguage da .da
+AddLanguage el .el
+AddLanguage it .it
+
+# LanguagePriority allows you to give precedence to some languages
+# in case of a tie during content negotiation.
+# Just list the languages in decreasing order of preference.
+
+LanguagePriority en fr de
+
+# Redirect allows you to tell clients about documents which used to exist in
+# your server's namespace, but do not anymore. This allows you to tell the
+# clients where to look for the relocated document.
+# Format: Redirect fakename url
+
+
+# Aliases: Add here as many aliases as you need (with no limit). The format is 
+# Alias fakename realname
+
+#Alias /icons/ /usr/local/etc/httpd/icons/
+
+# ScriptAlias: This controls which directories contain server scripts.
+# Format: ScriptAlias fakename realname
+
+#ScriptAlias /cgi-bin/ /usr/local/etc/httpd/cgi-bin/
+
+# If you want to use server side includes, or CGI outside
+# ScriptAliased directories, uncomment the following lines.
+
+# AddType allows you to tweak mime.types without actually editing it, or to
+# make certain files to be certain types.
+# Format: AddType type/subtype ext1
+
+# AddHandler allows you to map certain file extensions to "handlers",
+# actions unrelated to filetype. These can be either built into the server
+# or added with the Action command (see below)
+# Format: AddHandler action-name ext1
+
+# To use CGI scripts:
+#AddHandler cgi-script .cgi
+
+# To use server-parsed HTML files
+#AddType text/html .shtml
+#AddHandler server-parsed .shtml
+
+# Uncomment the following line to enable Apache's send-asis HTTP file
+# feature
+#AddHandler send-as-is asis
+
+# If you wish to use server-parsed imagemap files, use
+#AddHandler imap-file map
+
+# To enable type maps, you might want to use
+#AddHandler type-map var
+
+# Action lets you define media types that will execute a script whenever
+# a matching file is called. This eliminates the need for repeated URL
+# pathnames for oft-used CGI file processors.
+# Format: Action media/type /cgi-script/location
+# Format: Action handler-name /cgi-script/location
+
+# For example to add a footer (footer.html in your document root) to
+# files with extension .foot (e.g. foo.html.foot), you could use:
+#AddHandler foot-action foot
+#Action foot-action /cgi-bin/footer
+
+# Or to do this for all HTML files, for example, use:
+#Action text/html /cgi-bin/footer
+
+# MetaDir: specifies the name of the directory in which Apache can find
+# meta information files. These files contain additional HTTP headers
+# to include when sending the document
+
+#MetaDir .web
+
+# MetaSuffix: specifies the file name suffix for the file containing the
+# meta information.
+
+#MetaSuffix .meta
+
+# Customizable error response (Apache style)
+#  these come in three flavors
+#
+#    1) plain text
+#ErrorDocument 500 "The server made a boo boo.
+#  n.b.  the (") marks it as text, it does not get output
+#
+#    2) local redirects
+#ErrorDocument 404 /missing.html
+#  to redirect to local url /missing.html
+#ErrorDocument 404 /cgi-bin/missing_handler.pl
+#  n.b. can redirect to a script or a document using server-side-includes.
+#
+#    3) external redirects
+#ErrorDocument 402 http://other.server.com/subscription_info.html
+#
diff --git a/RELEASE_1_1_X/htdocs/apache_pb.gif b/RELEASE_1_1_X/htdocs/apache_pb.gif
new file mode 100644 (file)
index 0000000..3a1c139
Binary files /dev/null and b/RELEASE_1_1_X/htdocs/apache_pb.gif differ
diff --git a/RELEASE_1_1_X/htdocs/index.html b/RELEASE_1_1_X/htdocs/index.html
new file mode 100644 (file)
index 0000000..576fcf3
--- /dev/null
@@ -0,0 +1,30 @@
+<HTML>
+
+<HEAD>
+
+<TITLE>Test Page for Apache</TITLE>
+
+</HEAD>
+
+<BODY>
+
+<H1>It Worked!</H1>
+
+If you can see this, then your 
+<A HREF="http://www.apache.org/">Apache</A> installation was 
+successful.  You may now add content to this directory and 
+replace this page.
+
+<P>
+
+You are free to use the image below on an Apache-powered web
+server.  Thanks for using Apache!
+
+<P>
+
+<img src="apache_pb.gif">
+
+</BODY>
+
+</HTML>
+
diff --git a/RELEASE_1_1_X/icons/README b/RELEASE_1_1_X/icons/README
new file mode 100644 (file)
index 0000000..a1fc5a5
--- /dev/null
@@ -0,0 +1,161 @@
+Public Domain Icons
+
+     These icons were originally made for Mosaic for X and have been
+     included in the NCSA httpd and Apache server distributions in the
+     past. They are in the public domain and may be freely included in any
+     application. The originals were done by Kevin Hughes (kevinh@eit.com).
+
+     Many thanks to Andy Polyakov for tuning the icon colors and adding a
+     few new images. If you'd like to contribute additions or ideas to
+     this set, please let me know.
+
+     The distribution site for these icons is at:
+
+          http://www.eit.com/goodies/www.icons/
+
+     Kevin Hughes
+     September 11, 1995
+
+
+Suggested Uses
+
+The following are a few suggestions, to serve as a starting point for ideas.
+Please feel free to tweak and rename the icons as you like.
+
+     a.gif
+          This might be used to represent PostScript or text layout
+          languages.
+
+     alert.black.gif, alert.red.gif
+          These can be used to highlight any important items, such as a
+          README file in a directory.
+
+     back.gif, forward.gif
+          These can be used as links to go to previous and next areas.
+
+     ball.gray.gif, ball.red.gif
+          These might be used as bullets.
+
+     binary.gif
+          This can be used to represent binary files.
+
+     binhex.gif
+          This can represent BinHex-encoded data.
+
+     blank.gif
+          This can be used as a placeholder or a spacing element.
+
+     bomb.gif
+          This can be used to repreesnt core files.
+
+     box1.gif, box2.gif
+          These icons can be used to represent generic 3D applications and
+          related files.
+
+     broken.gif
+          This can represent corrupted data.
+
+     burst.gif
+          This can call attention to new and important items.
+
+     c.gif
+          This might represent C source code.
+
+     comp.blue.gif, comp.red.gif
+          These little computer icons can stand for telnet or FTP
+          sessions.
+
+     compressed.gif
+          This may represent compressed data.
+
+     continued.gif
+          This can be a link to a continued listing of a directory.
+
+     down.gif, up.gif, left.gif, right.gif
+          These can be used to scroll up, down, left and right in a
+          listing or may be used to denote items in an outline.
+
+     dvi.gif
+          This can represent DVI files.
+
+     f.gif
+          This might represent FORTRAN or Forth source code.
+
+     folder.gif, folder.open.gif, folder.sec.gif
+          The folder can represent directories. There is also a version
+          that can represent secure directories or directories that cannot
+          be viewed.
+
+     generic.gif, generic.sec.gif, generic.red.gif
+          These can represent generic files, secure files, and important
+          files, respectively.
+
+     hand.right.gif, hand.up.gif
+          These can point out important items (pun intended).
+
+     image1.gif, image2.gif, image3.gif
+          These can represent image formats of various types.
+
+     index.gif
+          This might represent a WAIS index or search facility.
+
+     layout.gif
+          This might represent files and formats that contain graphics as
+          well as text layout, such as HTML and PDF files.
+
+     link.gif
+          This might represent files that are symbolic links.
+
+     movie.gif
+          This can represent various movie formats.
+
+     p.gif
+          This may stand for Perl or Python source code.
+
+     pie0.gif ... pie8.gif
+          These icons can be used in applications where a list of
+          documents is returned from a search. The little pie chart images
+          can denote how relevant the documents may be to your search
+          query.
+
+     patch.gif
+          This may stand for patches and diff files.
+
+     portal.gif
+          This might be a link to an online service or a 3D world.
+
+     ps.gif, quill.gif
+          These may represent PostScript files.
+
+     screw1.gif, screw2.gif
+          These may represent CAD or engineering data and formats.
+
+     script.gif
+          This can represent any of various interpreted languages, such as
+          Perl, python, TCL, and shell scripts, as well as server
+          configuration files.
+
+     sound1.gif, sound2.gif
+          These can represent sound files.
+
+     sphere1.gif, sphere2.gif
+          These can represent 3D worlds or rendering applications and
+          formats.
+
+     tex.gif
+          This can represent TeX files.
+
+     text.gif
+          This can represent generic (plain) text files.
+
+     transfer.gif
+          This can represent FTP transfers or uploads/downloads.
+
+     unknown.gif
+          This may represent a file of an unknown type.
+
+     uuencoded.gif
+          This can stand for uuencoded data.
+
+     world1.gif, world2.gif
+          These can represent 3D worlds or other 3D formats.
diff --git a/RELEASE_1_1_X/icons/a.gif b/RELEASE_1_1_X/icons/a.gif
new file mode 100644 (file)
index 0000000..bb23d97
Binary files /dev/null and b/RELEASE_1_1_X/icons/a.gif differ
diff --git a/RELEASE_1_1_X/icons/alert.black.gif b/RELEASE_1_1_X/icons/alert.black.gif
new file mode 100644 (file)
index 0000000..eaecd21
Binary files /dev/null and b/RELEASE_1_1_X/icons/alert.black.gif differ
diff --git a/RELEASE_1_1_X/icons/alert.red.gif b/RELEASE_1_1_X/icons/alert.red.gif
new file mode 100644 (file)
index 0000000..a423894
Binary files /dev/null and b/RELEASE_1_1_X/icons/alert.red.gif differ
diff --git a/RELEASE_1_1_X/icons/apache_pb.gif b/RELEASE_1_1_X/icons/apache_pb.gif
new file mode 100644 (file)
index 0000000..3a1c139
Binary files /dev/null and b/RELEASE_1_1_X/icons/apache_pb.gif differ
diff --git a/RELEASE_1_1_X/icons/back.gif b/RELEASE_1_1_X/icons/back.gif
new file mode 100644 (file)
index 0000000..a694ae1
Binary files /dev/null and b/RELEASE_1_1_X/icons/back.gif differ
diff --git a/RELEASE_1_1_X/icons/ball.gray.gif b/RELEASE_1_1_X/icons/ball.gray.gif
new file mode 100644 (file)
index 0000000..eb84268
Binary files /dev/null and b/RELEASE_1_1_X/icons/ball.gray.gif differ
diff --git a/RELEASE_1_1_X/icons/ball.red.gif b/RELEASE_1_1_X/icons/ball.red.gif
new file mode 100644 (file)
index 0000000..a8425cb
Binary files /dev/null and b/RELEASE_1_1_X/icons/ball.red.gif differ
diff --git a/RELEASE_1_1_X/icons/binary.gif b/RELEASE_1_1_X/icons/binary.gif
new file mode 100644 (file)
index 0000000..9a15cba
Binary files /dev/null and b/RELEASE_1_1_X/icons/binary.gif differ
diff --git a/RELEASE_1_1_X/icons/binhex.gif b/RELEASE_1_1_X/icons/binhex.gif
new file mode 100644 (file)
index 0000000..62d0363
Binary files /dev/null and b/RELEASE_1_1_X/icons/binhex.gif differ
diff --git a/RELEASE_1_1_X/icons/blank.gif b/RELEASE_1_1_X/icons/blank.gif
new file mode 100644 (file)
index 0000000..0ccf01e
Binary files /dev/null and b/RELEASE_1_1_X/icons/blank.gif differ
diff --git a/RELEASE_1_1_X/icons/bomb.gif b/RELEASE_1_1_X/icons/bomb.gif
new file mode 100644 (file)
index 0000000..270fdb1
Binary files /dev/null and b/RELEASE_1_1_X/icons/bomb.gif differ
diff --git a/RELEASE_1_1_X/icons/box1.gif b/RELEASE_1_1_X/icons/box1.gif
new file mode 100644 (file)
index 0000000..65dcd00
Binary files /dev/null and b/RELEASE_1_1_X/icons/box1.gif differ
diff --git a/RELEASE_1_1_X/icons/box2.gif b/RELEASE_1_1_X/icons/box2.gif
new file mode 100644 (file)
index 0000000..c43bc4f
Binary files /dev/null and b/RELEASE_1_1_X/icons/box2.gif differ
diff --git a/RELEASE_1_1_X/icons/broken.gif b/RELEASE_1_1_X/icons/broken.gif
new file mode 100644 (file)
index 0000000..9f8cbe9
Binary files /dev/null and b/RELEASE_1_1_X/icons/broken.gif differ
diff --git a/RELEASE_1_1_X/icons/burst.gif b/RELEASE_1_1_X/icons/burst.gif
new file mode 100644 (file)
index 0000000..fbdcf57
Binary files /dev/null and b/RELEASE_1_1_X/icons/burst.gif differ
diff --git a/RELEASE_1_1_X/icons/c.gif b/RELEASE_1_1_X/icons/c.gif
new file mode 100644 (file)
index 0000000..7555b6c
Binary files /dev/null and b/RELEASE_1_1_X/icons/c.gif differ
diff --git a/RELEASE_1_1_X/icons/comp.blue.gif b/RELEASE_1_1_X/icons/comp.blue.gif
new file mode 100644 (file)
index 0000000..f8d76a8
Binary files /dev/null and b/RELEASE_1_1_X/icons/comp.blue.gif differ
diff --git a/RELEASE_1_1_X/icons/comp.gray.gif b/RELEASE_1_1_X/icons/comp.gray.gif
new file mode 100644 (file)
index 0000000..7664cd0
Binary files /dev/null and b/RELEASE_1_1_X/icons/comp.gray.gif differ
diff --git a/RELEASE_1_1_X/icons/compressed.gif b/RELEASE_1_1_X/icons/compressed.gif
new file mode 100644 (file)
index 0000000..39e7327
Binary files /dev/null and b/RELEASE_1_1_X/icons/compressed.gif differ
diff --git a/RELEASE_1_1_X/icons/continued.gif b/RELEASE_1_1_X/icons/continued.gif
new file mode 100644 (file)
index 0000000..b0ffb7e
Binary files /dev/null and b/RELEASE_1_1_X/icons/continued.gif differ
diff --git a/RELEASE_1_1_X/icons/dir.gif b/RELEASE_1_1_X/icons/dir.gif
new file mode 100644 (file)
index 0000000..4826460
Binary files /dev/null and b/RELEASE_1_1_X/icons/dir.gif differ
diff --git a/RELEASE_1_1_X/icons/down.gif b/RELEASE_1_1_X/icons/down.gif
new file mode 100644 (file)
index 0000000..a354c87
Binary files /dev/null and b/RELEASE_1_1_X/icons/down.gif differ
diff --git a/RELEASE_1_1_X/icons/dvi.gif b/RELEASE_1_1_X/icons/dvi.gif
new file mode 100644 (file)
index 0000000..791be33
Binary files /dev/null and b/RELEASE_1_1_X/icons/dvi.gif differ
diff --git a/RELEASE_1_1_X/icons/f.gif b/RELEASE_1_1_X/icons/f.gif
new file mode 100644 (file)
index 0000000..fbe353c
Binary files /dev/null and b/RELEASE_1_1_X/icons/f.gif differ
diff --git a/RELEASE_1_1_X/icons/folder.gif b/RELEASE_1_1_X/icons/folder.gif
new file mode 100644 (file)
index 0000000..4826460
Binary files /dev/null and b/RELEASE_1_1_X/icons/folder.gif differ
diff --git a/RELEASE_1_1_X/icons/folder.open.gif b/RELEASE_1_1_X/icons/folder.open.gif
new file mode 100644 (file)
index 0000000..30979cb
Binary files /dev/null and b/RELEASE_1_1_X/icons/folder.open.gif differ
diff --git a/RELEASE_1_1_X/icons/folder.sec.gif b/RELEASE_1_1_X/icons/folder.sec.gif
new file mode 100644 (file)
index 0000000..75332d9
Binary files /dev/null and b/RELEASE_1_1_X/icons/folder.sec.gif differ
diff --git a/RELEASE_1_1_X/icons/forward.gif b/RELEASE_1_1_X/icons/forward.gif
new file mode 100644 (file)
index 0000000..b2959b4
Binary files /dev/null and b/RELEASE_1_1_X/icons/forward.gif differ
diff --git a/RELEASE_1_1_X/icons/generic.gif b/RELEASE_1_1_X/icons/generic.gif
new file mode 100644 (file)
index 0000000..de60b29
Binary files /dev/null and b/RELEASE_1_1_X/icons/generic.gif differ
diff --git a/RELEASE_1_1_X/icons/generic.red.gif b/RELEASE_1_1_X/icons/generic.red.gif
new file mode 100644 (file)
index 0000000..9474398
Binary files /dev/null and b/RELEASE_1_1_X/icons/generic.red.gif differ
diff --git a/RELEASE_1_1_X/icons/generic.sec.gif b/RELEASE_1_1_X/icons/generic.sec.gif
new file mode 100644 (file)
index 0000000..88d5240
Binary files /dev/null and b/RELEASE_1_1_X/icons/generic.sec.gif differ
diff --git a/RELEASE_1_1_X/icons/hand.right.gif b/RELEASE_1_1_X/icons/hand.right.gif
new file mode 100644 (file)
index 0000000..5cdbc72
Binary files /dev/null and b/RELEASE_1_1_X/icons/hand.right.gif differ
diff --git a/RELEASE_1_1_X/icons/hand.up.gif b/RELEASE_1_1_X/icons/hand.up.gif
new file mode 100644 (file)
index 0000000..85a5d68
Binary files /dev/null and b/RELEASE_1_1_X/icons/hand.up.gif differ
diff --git a/RELEASE_1_1_X/icons/icon.sheet.gif b/RELEASE_1_1_X/icons/icon.sheet.gif
new file mode 100644 (file)
index 0000000..ad1686e
Binary files /dev/null and b/RELEASE_1_1_X/icons/icon.sheet.gif differ
diff --git a/RELEASE_1_1_X/icons/image1.gif b/RELEASE_1_1_X/icons/image1.gif
new file mode 100644 (file)
index 0000000..01e442b
Binary files /dev/null and b/RELEASE_1_1_X/icons/image1.gif differ
diff --git a/RELEASE_1_1_X/icons/image2.gif b/RELEASE_1_1_X/icons/image2.gif
new file mode 100644 (file)
index 0000000..751faee
Binary files /dev/null and b/RELEASE_1_1_X/icons/image2.gif differ
diff --git a/RELEASE_1_1_X/icons/image3.gif b/RELEASE_1_1_X/icons/image3.gif
new file mode 100644 (file)
index 0000000..4f30484
Binary files /dev/null and b/RELEASE_1_1_X/icons/image3.gif differ
diff --git a/RELEASE_1_1_X/icons/index.gif b/RELEASE_1_1_X/icons/index.gif
new file mode 100644 (file)
index 0000000..162478f
Binary files /dev/null and b/RELEASE_1_1_X/icons/index.gif differ
diff --git a/RELEASE_1_1_X/icons/layout.gif b/RELEASE_1_1_X/icons/layout.gif
new file mode 100644 (file)
index 0000000..c96338a
Binary files /dev/null and b/RELEASE_1_1_X/icons/layout.gif differ
diff --git a/RELEASE_1_1_X/icons/left.gif b/RELEASE_1_1_X/icons/left.gif
new file mode 100644 (file)
index 0000000..279e671
Binary files /dev/null and b/RELEASE_1_1_X/icons/left.gif differ
diff --git a/RELEASE_1_1_X/icons/link.gif b/RELEASE_1_1_X/icons/link.gif
new file mode 100644 (file)
index 0000000..c5b6889
Binary files /dev/null and b/RELEASE_1_1_X/icons/link.gif differ
diff --git a/RELEASE_1_1_X/icons/movie.gif b/RELEASE_1_1_X/icons/movie.gif
new file mode 100644 (file)
index 0000000..0035183
Binary files /dev/null and b/RELEASE_1_1_X/icons/movie.gif differ
diff --git a/RELEASE_1_1_X/icons/p.gif b/RELEASE_1_1_X/icons/p.gif
new file mode 100644 (file)
index 0000000..7b917b4
Binary files /dev/null and b/RELEASE_1_1_X/icons/p.gif differ
diff --git a/RELEASE_1_1_X/icons/patch.gif b/RELEASE_1_1_X/icons/patch.gif
new file mode 100644 (file)
index 0000000..39bc90e
Binary files /dev/null and b/RELEASE_1_1_X/icons/patch.gif differ
diff --git a/RELEASE_1_1_X/icons/pdf.gif b/RELEASE_1_1_X/icons/pdf.gif
new file mode 100644 (file)
index 0000000..c88fd77
Binary files /dev/null and b/RELEASE_1_1_X/icons/pdf.gif differ
diff --git a/RELEASE_1_1_X/icons/pie0.gif b/RELEASE_1_1_X/icons/pie0.gif
new file mode 100644 (file)
index 0000000..6f7a0ae
Binary files /dev/null and b/RELEASE_1_1_X/icons/pie0.gif differ
diff --git a/RELEASE_1_1_X/icons/pie1.gif b/RELEASE_1_1_X/icons/pie1.gif
new file mode 100644 (file)
index 0000000..03aa6be
Binary files /dev/null and b/RELEASE_1_1_X/icons/pie1.gif differ
diff --git a/RELEASE_1_1_X/icons/pie2.gif b/RELEASE_1_1_X/icons/pie2.gif
new file mode 100644 (file)
index 0000000..b04c5e0
Binary files /dev/null and b/RELEASE_1_1_X/icons/pie2.gif differ
diff --git a/RELEASE_1_1_X/icons/pie3.gif b/RELEASE_1_1_X/icons/pie3.gif
new file mode 100644 (file)
index 0000000..4db9d02
Binary files /dev/null and b/RELEASE_1_1_X/icons/pie3.gif differ
diff --git a/RELEASE_1_1_X/icons/pie4.gif b/RELEASE_1_1_X/icons/pie4.gif
new file mode 100644 (file)
index 0000000..93471fd
Binary files /dev/null and b/RELEASE_1_1_X/icons/pie4.gif differ
diff --git a/RELEASE_1_1_X/icons/pie5.gif b/RELEASE_1_1_X/icons/pie5.gif
new file mode 100644 (file)
index 0000000..57aee93
Binary files /dev/null and b/RELEASE_1_1_X/icons/pie5.gif differ
diff --git a/RELEASE_1_1_X/icons/pie6.gif b/RELEASE_1_1_X/icons/pie6.gif
new file mode 100644 (file)
index 0000000..0dc327b
Binary files /dev/null and b/RELEASE_1_1_X/icons/pie6.gif differ
diff --git a/RELEASE_1_1_X/icons/pie7.gif b/RELEASE_1_1_X/icons/pie7.gif
new file mode 100644 (file)
index 0000000..8661337
Binary files /dev/null and b/RELEASE_1_1_X/icons/pie7.gif differ
diff --git a/RELEASE_1_1_X/icons/pie8.gif b/RELEASE_1_1_X/icons/pie8.gif
new file mode 100644 (file)
index 0000000..59ddb34
Binary files /dev/null and b/RELEASE_1_1_X/icons/pie8.gif differ
diff --git a/RELEASE_1_1_X/icons/portal.gif b/RELEASE_1_1_X/icons/portal.gif
new file mode 100644 (file)
index 0000000..0e6e506
Binary files /dev/null and b/RELEASE_1_1_X/icons/portal.gif differ
diff --git a/RELEASE_1_1_X/icons/ps.gif b/RELEASE_1_1_X/icons/ps.gif
new file mode 100644 (file)
index 0000000..0f565bc
Binary files /dev/null and b/RELEASE_1_1_X/icons/ps.gif differ
diff --git a/RELEASE_1_1_X/icons/quill.gif b/RELEASE_1_1_X/icons/quill.gif
new file mode 100644 (file)
index 0000000..818a5cd
Binary files /dev/null and b/RELEASE_1_1_X/icons/quill.gif differ
diff --git a/RELEASE_1_1_X/icons/right.gif b/RELEASE_1_1_X/icons/right.gif
new file mode 100644 (file)
index 0000000..b256e5f
Binary files /dev/null and b/RELEASE_1_1_X/icons/right.gif differ
diff --git a/RELEASE_1_1_X/icons/screw1.gif b/RELEASE_1_1_X/icons/screw1.gif
new file mode 100644 (file)
index 0000000..af6ba2b
Binary files /dev/null and b/RELEASE_1_1_X/icons/screw1.gif differ
diff --git a/RELEASE_1_1_X/icons/screw2.gif b/RELEASE_1_1_X/icons/screw2.gif
new file mode 100644 (file)
index 0000000..06dccb3
Binary files /dev/null and b/RELEASE_1_1_X/icons/screw2.gif differ
diff --git a/RELEASE_1_1_X/icons/script.gif b/RELEASE_1_1_X/icons/script.gif
new file mode 100644 (file)
index 0000000..d8a853b
Binary files /dev/null and b/RELEASE_1_1_X/icons/script.gif differ
diff --git a/RELEASE_1_1_X/icons/sound1.gif b/RELEASE_1_1_X/icons/sound1.gif
new file mode 100644 (file)
index 0000000..8efb49f
Binary files /dev/null and b/RELEASE_1_1_X/icons/sound1.gif differ
diff --git a/RELEASE_1_1_X/icons/sound2.gif b/RELEASE_1_1_X/icons/sound2.gif
new file mode 100644 (file)
index 0000000..48e6a7f
Binary files /dev/null and b/RELEASE_1_1_X/icons/sound2.gif differ
diff --git a/RELEASE_1_1_X/icons/sphere1.gif b/RELEASE_1_1_X/icons/sphere1.gif
new file mode 100644 (file)
index 0000000..7067070
Binary files /dev/null and b/RELEASE_1_1_X/icons/sphere1.gif differ
diff --git a/RELEASE_1_1_X/icons/sphere2.gif b/RELEASE_1_1_X/icons/sphere2.gif
new file mode 100644 (file)
index 0000000..a9e462a
Binary files /dev/null and b/RELEASE_1_1_X/icons/sphere2.gif differ
diff --git a/RELEASE_1_1_X/icons/tar.gif b/RELEASE_1_1_X/icons/tar.gif
new file mode 100644 (file)
index 0000000..617e779
Binary files /dev/null and b/RELEASE_1_1_X/icons/tar.gif differ
diff --git a/RELEASE_1_1_X/icons/tex.gif b/RELEASE_1_1_X/icons/tex.gif
new file mode 100644 (file)
index 0000000..45e4323
Binary files /dev/null and b/RELEASE_1_1_X/icons/tex.gif differ
diff --git a/RELEASE_1_1_X/icons/text.gif b/RELEASE_1_1_X/icons/text.gif
new file mode 100644 (file)
index 0000000..4c62390
Binary files /dev/null and b/RELEASE_1_1_X/icons/text.gif differ
diff --git a/RELEASE_1_1_X/icons/transfer.gif b/RELEASE_1_1_X/icons/transfer.gif
new file mode 100644 (file)
index 0000000..33697db
Binary files /dev/null and b/RELEASE_1_1_X/icons/transfer.gif differ
diff --git a/RELEASE_1_1_X/icons/unknown.gif b/RELEASE_1_1_X/icons/unknown.gif
new file mode 100644 (file)
index 0000000..32b1ea2
Binary files /dev/null and b/RELEASE_1_1_X/icons/unknown.gif differ
diff --git a/RELEASE_1_1_X/icons/up.gif b/RELEASE_1_1_X/icons/up.gif
new file mode 100644 (file)
index 0000000..6d6d6d1
Binary files /dev/null and b/RELEASE_1_1_X/icons/up.gif differ
diff --git a/RELEASE_1_1_X/icons/uu.gif b/RELEASE_1_1_X/icons/uu.gif
new file mode 100644 (file)
index 0000000..4387d52
Binary files /dev/null and b/RELEASE_1_1_X/icons/uu.gif differ
diff --git a/RELEASE_1_1_X/icons/uuencoded.gif b/RELEASE_1_1_X/icons/uuencoded.gif
new file mode 100644 (file)
index 0000000..4387d52
Binary files /dev/null and b/RELEASE_1_1_X/icons/uuencoded.gif differ
diff --git a/RELEASE_1_1_X/icons/world1.gif b/RELEASE_1_1_X/icons/world1.gif
new file mode 100644 (file)
index 0000000..05b4ec2
Binary files /dev/null and b/RELEASE_1_1_X/icons/world1.gif differ
diff --git a/RELEASE_1_1_X/icons/world2.gif b/RELEASE_1_1_X/icons/world2.gif
new file mode 100644 (file)
index 0000000..e3203f7
Binary files /dev/null and b/RELEASE_1_1_X/icons/world2.gif differ
diff --git a/RELEASE_1_1_X/src/.cvsignore b/RELEASE_1_1_X/src/.cvsignore
new file mode 100644 (file)
index 0000000..c383b46
--- /dev/null
@@ -0,0 +1,4 @@
+Configuration
+Makefile
+modules.c
+httpd
diff --git a/RELEASE_1_1_X/src/API.html b/RELEASE_1_1_X/src/API.html
new file mode 100644 (file)
index 0000000..87fc4a0
--- /dev/null
@@ -0,0 +1,980 @@
+<title>Apache API notes</title>
+<h1>Apache API notes</h1>
+
+<h3>Robert S. Thau</h3>
+
+These are some notes on the Apache API and the data structures you
+have to deal with, etc.  They are not yet nearly complete, but
+hopefully, they will help you get your bearings.  Keep in mind that
+the API is still subject to change as we gain experience with it.
+(See the TODO file for what <em>might</em> be coming).  However,
+it will be easy to adapt modules to any changes that are made.
+(We have more modules to adapt than you do).
+<p>
+
+A few notes on general pedagogical style here.  In the interest of
+conciseness, all structure declarations here are incomplete --- the
+real ones have more slots, that I'm not telling you about.  For the
+most part, these are reserved to one component of the server core or
+another, and should be altered by modules with caution.  However, in
+some cases, they really are things I just haven't gotten around to
+yet.  Welcome to the bleeding edge.<p>
+
+Finally, here's an outline, to give you some bare idea of what's
+coming up, and in what order:
+
+<ul>
+  <li> <a href="#basics">Basic concepts.</a>
+       <ul>
+        <li> <a href="#HMR">Handlers, Modules, and Requests</a>
+        <li> <a href="#moduletour">A brief tour of a module</a>
+       </ul>
+  <li> <a href="#handlers">How handlers work</a>
+       <ul>
+        <li> <a href="#req_tour">A brief tour of the <code>request_rec</code></a>
+        <li> <a href="#req_orig">Where request_rec structures come from</a>
+        <li> <a href="#req_return">Handling requests, declining, and returning error codes</a>
+        <li> <a href="#resp_handlers">Special considerations for response handlers</a>
+        <li> <a href="#auth_handlers">Special considerations for authentication handlers</a>
+        <li> <a href="#log_handlers">Special considerations for logging handlers</a>
+       </ul>
+  <li> <a href="#pools">Resource allocation and resource pools</a>
+  <li> <a href="#config">Configuration, commands and the like</a>
+       <ul>
+        <li> <a href="#per-dir">Per-directory configuration structures</a>
+        <li> <a href="#commands">Command handling</a>
+        <li> <a href="#servconf">Side notes --- per-server configuration, virtual servers, etc.</a>
+       </ul>
+</ul>
+
+<h2><a name="basics">Basic concepts.</a></h2>
+
+We begin with an overview of the basic concepts behind the 
+API, and how they are manifested in the code.
+
+<h3><a name="HMR">Handlers, Modules, and Requests</a></h3>
+
+Apache breaks down request handling into a series of steps, more or
+less the same way the Netscape Server API does (although this API has
+a few more stages than NetSite does, as hooks for stuff I thought
+might be useful in the future).  These are:
+
+<ul>
+  <li> URI -&gt; Filename translation
+  <li> Auth ID checking [is the user who they say they are?]
+  <li> Auth access checking [is the user authorized <em>here</em>?]
+  <li> Access checking other than auth
+  <li> Determining MIME type of the object requested
+  <li> "Fixups" --- there aren't any of these yet, but the phase is
+       intended as a hook for possible extensions like
+       <code>SetEnv</code>, which don't really fit well elsewhere.
+  <li> Actually sending a response back to the client.  
+  <li> Logging the request
+</ul>
+
+These phases are handled by looking at each of a succession of
+<em>modules</em>, looking to see if each of them has a handler for the
+phase, and attempting invoking it if so.  The handler can typically do
+one of three things:
+
+<ul>
+  <li> <em>Handle</em> the request, and indicate that it has done so
+       by returning the magic constant <code>OK</code>.  
+  <li> <em>Decline</em> to handle the request, by returning the magic
+       integer constant <code>DECLINED</code>.  In this case, the
+       server behaves in all respects as if the handler simply hadn't
+       been there.
+  <li> Signal an error, by returning one of the HTTP error codes.
+       This terminates normal handling of the request, although an
+       ErrorDocument may be invoked to try to mop up, and it will be
+       logged in any case.
+</ul>
+
+Most phases are terminated by the first module that handles them;
+however, for logging, "fixups", and non-access authentication
+checking, all handlers always run (barring an error).  Also, the
+response phase is unique in that modules may declare multiple handlers
+for it, via a dispatch table keyed on the MIME type of the requested
+object.  Modules may declare a response-phase handler which can handle
+<em>any</em> request, by giving it the key <code>*/*</code> (i.e., a
+wildcard MIME type specification).  However, wildcard handlers are
+only invoked if the server has already tried and failed to find a more
+specific response handler for the MIME type of the requested object
+(either none existed, or they all declined).<p>
+
+The handlers themselves are functions of one argument (a
+<code>request_rec</code> structure. vide infra), which returns an
+integer, as above.<p>
+
+<h3><a name="moduletour">A brief tour of a module</a></h3>
+
+At this point, we need to explain the structure of a module.  Our
+candidate will be one of the messier ones, the CGI module --- this
+handles both CGI scripts and the <code>ScriptAlias</code> config file
+command.  It's actually a great deal more complicated than most
+modules, but if we're going to have only one example, it might as well
+be the one with its fingers in everyplace.<p>
+
+Let's begin with handlers.  In order to handle the CGI scripts, the
+module declares a response handler for them. Because of
+<code>ScriptAlias</code>, it also has handlers for the name
+translation phase (to recognise <code>ScriptAlias</code>ed URI's), the
+type-checking phase (any <code>ScriptAlias</code>ed request is typed
+as a CGI script).<p>
+
+The module needs to maintain some per (virtual)
+server information, namely, the <code>ScriptAlias</code>es in effect;
+the module structure therefore contains pointers to a functions which
+builds these structures, and to another which combines two of them (in
+case the main server and a virtual server both have
+<code>ScriptAlias</code>es declared).<p>
+
+Finally, this module contains code to handle the
+<code>ScriptAlias</code> command itself.  This particular module only
+declares one command, but there could be more, so modules have
+<em>command tables</em> which declare their commands, and describe
+where they are permitted, and how they are to be invoked.  <p>
+
+A final note on the declared types of the arguments of some of these
+commands: a <code>pool</code> is a pointer to a <em>resource pool</em>
+structure; these are used by the server to keep track of the memory
+which has been allocated, files opened, etc., either to service a
+particular request, or to handle the process of configuring itself.
+That way, when the request is over (or, for the configuration pool,
+when the server is restarting), the memory can be freed, and the files
+closed, en masse, without anyone having to write explicit code to
+track them all down and dispose of them.  Also, a
+<code>cmd_parms</code> structure contains various information about
+the config file being read, and other status information, which is
+sometimes of use to the function which processes a config-file command
+(such as <code>ScriptAlias</code>).
+
+With no further ado, the module itself:
+<pre>
+/* Declarations of handlers. */
+
+int translate_scriptalias (request_rec *);
+int type_scriptalias (request_rec *);
+int cgi_handler (request_rec *);
+
+/* Subsdiary dispatch table for response-phase handlers, by MIME type */
+
+handler_rec cgi_handlers[] = {
+{ "application/x-httpd-cgi", cgi_handler },
+{ NULL }
+};
+
+/* Declarations of routines to manipulate the module's configuration
+ * info.  Note that these are returned, and passed in, as void *'s;
+ * the server core keeps track of them, but it doesn't, and can't,
+ * know their internal structure.
+ */
+
+void *make_cgi_server_config (pool *);
+void *merge_cgi_server_config (pool *, void *, void *);
+
+/* Declarations of routines to handle config-file commands */
+
+char *script_alias (cmd_parms *, void *per_dir_config, char *fake, char *real);
+
+command_rec cgi_cmds[] = {
+{ "ScriptAlias", script_alias, NULL, RSRC_CONF, TAKE2,
+    "a fakename and a realname"},
+{ NULL }
+};
+
+module cgi_module = {
+   STANDARD_MODULE_STUFF,
+   NULL,                       /* initializer */
+   NULL,                       /* dir config creater */
+   NULL,                       /* dir merger --- default is to override */
+   make_cgi_server_config,      /* server config */
+   merge_cgi_server_config,    /* merge server config */
+   cgi_cmds,                   /* command table */
+   cgi_handlers,               /* handlers */
+   translate_scriptalias,      /* filename translation */
+   NULL,                       /* check_user_id */
+   NULL,                       /* check auth */
+   NULL,                       /* check access */
+   type_scriptalias,           /* type_checker */
+   NULL,                       /* fixups */
+   NULL                                /* logger */
+};
+</pre>
+
+<h2><a name="handlers">How handlers work</a></h2>
+
+The sole argument to handlers is a <code>request_rec</code> structure.
+This structure describes a particular request which has been made to
+the server, on behalf of a client.  In most cases, each connection to
+the client generates only one <code>request_rec</code> structure.<p>
+
+<h3><a name="req_tour">A brief tour of the <code>request_rec</code></a></h3>
+
+The <code>request_rec</code> contains pointers to a resource pool
+which will be cleared when the server is finished handling the
+request; to structures containing per-server and per-connection
+information, and most importantly, information on the request itself.<p>
+
+The most important such information is a small set of character
+strings describing attributes of the object being requested, including
+its URI, filename, content-type and content-encoding (these being filled
+in by the translation and type-check handlers which handle the
+request, respectively). <p>
+
+Other commonly used data items are tables giving the MIME headers on
+the client's original request, MIME headers to be sent back with the
+ppppresponse (which modules can add to at will), and environment variables
+for any subprocesses which are spawned off in the course of servicing
+the request.  These tables are manipulated using the
+<code>table_get</code> and <code>table_set</code> routines. <p>
+
+Finally, there are pointers to two data structures which, in turn,
+point to per-module configuration structures.  Specifically, these
+hold pointers to the data structures which the module has built to
+describe the way it has been configured to operate in a given
+directory (via <code>.htaccess</code> files or
+<code>&lt;Directory&gt;</code> sections), for private data it has
+built in the course of servicing the request (so modules' handlers for
+one phase can pass "notes" to their handlers for other phases).  There
+is another such configuration vector in the <code>server_rec</code>
+data structure pointed to by the <code>request_rec</code>, which
+contains per (virtual) server configuration data.<p>
+
+Here is an abridged declaration, giving the fields most commonly used:<p>
+
+<pre>
+struct request_rec {
+
+  pool *pool;
+  conn_rec *connection;
+  server_rec *server;
+
+  /* What object is being requested */
+  
+  char *uri;
+  char *filename;
+  char *path_info;
+  char *args;                  /* QUERY_ARGS, if any */
+  struct stat finfo;           /* Set by server core;
+                                 * st_mode set to zero if no such file */
+  
+  char *content_type;
+  char *content_encoding;
+  
+  /* MIME header environments, in and out.  Also, an array containing
+   * environment variables to be passed to subprocesses, so people can
+   * write modules to add to that environment.
+   *
+   * The difference between headers_out and err_headers_out is that the
+   * latter are printed even on error, and persist across internal redirects
+   * (so the headers printed for ErrorDocument handlers will have them).
+   */
+  
+  table *headers_in;
+  table *headers_out;
+  table *err_headers_out;
+  table *subprocess_env;
+
+  /* Info about the request itself... */
+  
+  int header_only;             /* HEAD request, as opposed to GET */
+  char *protocol;              /* Protocol, as given to us, or HTTP/0.9 */
+  char *method;                        /* GET, HEAD, POST, etc. */
+  int method_number;           /* M_GET, M_POST, etc. */
+
+  /* Info for logging */
+
+  char *the_request;
+  int bytes_sent;
+
+  /* A flag which modules can set, to indicate that the data being
+   * returned is volatile, and clients should be told not to cache it.
+   */
+
+  int no_cache;
+
+  /* Various other config info which may change with .htaccess files
+   * These are config vectors, with one void* pointer for each module
+   * (the thing pointed to being the module's business).
+   */
+  
+  void *per_dir_config;                /* Options set in config files, etc. */
+  void *request_config;                /* Notes on *this* request */
+  
+};
+
+</pre>
+
+<h3><a name="req_orig">Where request_rec structures come from</a></h3>
+
+Most <code>request_rec</code> structures are built by reading an HTTP
+request from a client, and filling in the fields.  However, there are
+a few exceptions:
+
+<ul>
+  <li> If the request is to an imagemap, a type map (i.e., a
+       <code>*.var</code> file), or a CGI script which returned a
+       local "Location:", then the resource which the user requested
+       is going to be ultimately located by some URI other than what
+       the client originally supplied.  In this case, the server does
+       an <em>internal redirect</em>, constructing a new
+       <code>request_rec</code> for the new URI, and processing it
+       almost exactly as if the client had requested the new URI
+       directly. <p>
+
+  <li> If some handler signaled an error, and an
+       <code>ErrorDocument</code> is in scope, the same internal
+       redirect machinery comes into play.<p>
+
+  <li> Finally, a handler occasionally needs to investigate "what
+       would happen if" some other request were run.  For instance,
+       the directory indexing module needs to know what MIME type
+       would be assigned to a request for each directory entry, in
+       order to figure out what icon to use.<p>
+
+       Such handlers can construct a <em>sub-request</em>, using the
+       functions <code>sub_req_lookup_file</code> and
+       <code>sub_req_lookup_uri</code>; this constructs a new
+       <code>request_rec</code> structure and processes it as you
+       would expect, up to but not including the point of actually
+       sending a response.  (These functions skip over the access
+       checks if the sub-request is for a file in the same directory
+       as the original request).<p>
+
+       (Server-side includes work by building sub-requests and then
+       actually invoking the response handler for them, via the
+       function <code>run_sub_request</code>).
+</ul>
+
+<h3><a name="req_return">Handling requests, declining, and returning error codes</a></h3>
+
+As discussed above, each handler, when invoked to handle a particular
+<code>request_rec</code>, has to return an <code>int</code> to
+indicate what happened.  That can either be
+
+<ul>
+  <li> OK --- the request was handled successfully.  This may or may
+       not terminate the phase.
+  <li> DECLINED --- no erroneous condition exists, but the module
+       declines to handle the phase; the server tries to find another.
+  <li> an HTTP error code, which aborts handling of the request.
+</ul>
+
+Note that if the error code returned is <code>REDIRECT</code>, then
+the module should put a <code>Location</code> in the request's
+<code>headers_out</code>, to indicate where the client should be
+redirected <em>to</em>. <p>
+
+<h3><a name="resp_handlers">Special considerations for response handlers</a></h3>
+
+Handlers for most phases do their work by simply setting a few fields
+in the <code>request_rec</code> structure (or, in the case of access
+checkers, simply by returning the correct error code).  However,
+response handlers have to actually send a request back to the client. <p>
+
+They should begin by sending an HTTP response header, using the
+function <code>send_http_header</code>.  (You don't have to do
+anything special to skip sending the header for HTTP/0.9 requests; the
+function figures out on its own that it shouldn't do anything).  If
+the request is marked <code>header_only</code>, that's all they should
+do; they should return after that, without attempting any further
+output.  <p>
+
+Otherwise, they should produce a request body which responds to the
+client as appropriate.  The primitives for this are <code>rputc</code>
+and <code>rprintf</code>, for internally generated output, and
+<code>send_fd</code>, to copy the contents of some <code>FILE *</code>
+straight to the client.  <p>
+
+At this point, you should more or less understand the following piece
+of code, which is the handler which handles <code>GET</code> requests
+which have no more specific handler; it also shows how conditional
+<code>GET</code>s can be handled, if it's desirable to do so in a
+particular response handler --- <code>set_last_modified</code> checks
+agaisnt the <code>If-modified-since</code> value supplied by the
+client, if annny, and returns an appropriate code (which will, if
+nonzero, be USE_LOCAL_COPY).   No similar considerations apply for
+<code>set_content_length</code>, but it returns an error code for
+symmetry.<p>
+
+<pre>
+int default_handler (request_rec *r)
+{
+    int errstatus;
+    FILE *f;
+    
+    if (r-&gt;method_number != M_GET) return DECLINED;
+    if (r-&gt;finfo.st_mode == 0) return NOT_FOUND;
+       
+    if ((errstatus = set_content_length (r, r-&gt;finfo.st_size))
+       || (errstatus = set_last_modified (r, r-&gt;finfo.st_mtime)))
+        return errstatus;
+    
+    f = fopen (r-&gt;filename, "r");
+
+    if (f == NULL) {
+        log_reason("file permissions deny server access", r-&gt;filename, r);
+        return FORBIDDEN;
+    }
+      
+    register_timeout ("send", r);
+    send_http_header (r);
+
+    if (!r-&gt;header_only) send_fd (f, r);
+    pfclose (r-&gt;pool, f);
+    return OK;
+}
+</pre>
+
+Finally, if all of this is too much of a challenge, there are a few
+ways out of it.  First off, as shown above, a response handler which
+has not yet produced any output can simply return an error code, in
+which case the server will automatically produce an error response.
+Secondly, it can punt to some other handler by invoking
+<code>internal_redirect</code>, which is how the internal redirection
+machinery discussed above is invoked.  A response handler which has
+internally redirected should always return <code>OK</code>. <p>
+
+(Invoking <code>internal_redirect</code> from handlers which are
+<em>not</em> response handlers will lead to serious confusion).
+
+<h3><a name="auth_handlers">Special considerations for authentication handlers</a></h3>
+
+Stuff that should be discussed here in detail:
+
+<ul>
+  <li> Authentication-phase handlers not invoked unless auth is
+       configured for the directory.
+  <li> Common auth configuration stored in the core per-dir
+       configuration; it has accessors <code>auth_type</code>,
+       <code>auth_name</code>, and <code>requires</code>.
+  <li> Common routines, to handle the protocol end of things, at least
+       for HTTP basic authentication (<code>get_basic_auth_pw</code>,
+       which sets the <code>connection-&gt;user</code> structure field
+       automatically, and <code>note_basic_auth_failure</code>, which
+       arranges for the proper <code>WWW-Authenticate:</code> header
+       to be sent back).
+</ul>
+
+<h3><a name="log_handlers">Special considerations for logging handlers</a></h3>
+
+When a request has internally redirected, there is the question of
+what to log.  Apache handles this by bundling the entire chain of
+redirects into a list of <code>request_rec</code> structures which are
+threaded through the <code>r-&gt;prev</code> and <code>r-&gt;next</code>
+pointers.  The <code>request_rec</code> which is passed to the logging
+handlers in such cases is the one which was originally built for the
+intial request from the client; note that the bytes_sent field will
+only be correct in the last request in the chain (the one for which a
+response was actually sent). 
+
+<h2><a name="pools">Resource allocation and resource pools</a></h2>
+
+One of the problems of writing and designing a server-pool server is
+that of preventing leakage, that is, allocating resources (memory,
+open files, etc.), without subsequently releasing them.  The resource
+pool machinery is designed to make it easy to prevent this from
+happening, by allowing resource to be allocated in such a way that
+they are <em>automatically</em> released when the server is done with
+them. <p>
+
+The way this works is as follows:  the memory which is allocated, file
+opened, etc., to deal with a particular request are tied to a
+<em>resource pool</em> which is allocated for the request.  The pool
+is a data structure which itself tracks the resources in question. <p>
+
+When the request has been processed, the pool is <em>cleared</em>.  At
+that point, all the memory associated with it is released for reuse,
+all files associated with it are closed, and any other clean-up
+functions which are associated with the pool are run.  When this is
+over, we can be confident that all the resource tied to the pool have
+been released, and that none of them have leaked. <p>
+
+Server restarts, and allocation of memory and resources for per-server
+configuration, are handled in a similar way.  There is a
+<em>configuration pool</em>, which keeps track of resources which were
+allocated while reading the server configuration files, and handling
+the commands therein (for instance, the memory that was allocated for
+per-server module configuration, log files and other files that were
+opened, and so forth).  When the server restarts, and has to reread
+the configuration files, the configuration pool is cleared, and so the
+memory and file descriptors which were taken up by reading them the
+last time are made available for reuse. <p>
+
+It should be noted that use of the pool machinery isn't generally
+obligatory, except for situations like logging handlers, where you
+really need to register cleanups to make sure that the log file gets
+closed when the server restarts (this is most easily done by using the
+function <code><a href="#pool-files">pfopen</a></code>, which also
+arranges for the underlying file descriptor to be closed before any
+child processes, such as for CGI scripts, are <code>exec</code>ed), or
+in case you are using the timeout machinery (which isn't yet even
+documented here).  However, there are two benefits to using it:
+resources allocated to a pool never leak (even if you allocate a
+scratch string, and just forget about it); also, for memory
+allocation, <code>palloc</code> is generally faster than
+<code>malloc</code>.<p>
+
+We begin here by describing how memory is allocated to pools, and then
+discuss how other resources are tracked by the resource pool
+machinery.
+
+<h3>Allocation of memory in pools</h3>
+
+Memory is allocated to pools by calling the function
+<code>palloc</code>, which takes two arguments, one being a pointer to
+a resource pool structure, and the other being the amount of memory to
+allocate (in <code>char</code>s).  Within handlers for handling
+requests, the most common way of getting a resource pool structure is
+by looking at the <code>pool</code> slot of the relevant
+<code>request_rec</code>; hence the repeated appearance of the
+following idiom in module code:
+
+<pre>
+int my_handler(request_rec *r)
+{
+    struct my_structure *foo;
+    ...
+
+    foo = (foo *)palloc (r->pool, sizeof(my_structure));
+}
+</pre>
+
+Note that <em>there is no <code>pfree</code></em> ---
+<code>palloc</code>ed memory is freed only when the associated
+resource pool is cleared.  This means that <code>palloc</code> doesn't
+have to do as much accounting as <code>malloc()</code>; all it does in
+the typical case is to round up the size, bump a pointer, and do a
+range check.<p>
+
+(It also raises the possibility that heavy use of <code>palloc</code>
+could cause a server process to grow excessively large.  There are
+two ways to deal with this, which are dealt with below; briefly, you
+can use <code>malloc</code>, and try to be sure that all of the memory
+gets explicitly <code>free</code>d, or you can allocate a sub-pool of
+the main pool, allocate your memory in the sub-pool, and clear it out
+periodically.  The latter technique is discussed in the section on
+sub-pools below, and is used in the directory-indexing code, in order
+to avoid excessive storage allocation when listing directories with
+thousands of files).
+
+<h3>Allocating initialized memory</h3>
+
+There are functions which allocate initialized memory, and are
+frequently useful.  The function <code>pcalloc</code> has the same
+interface as <code>palloc</code>, but clears out the memory it
+allocates before it returns it.  The function <code>pstrdup</code>
+takes a resource pool and a <code>char *</code> as arguments, and
+allocates memory for a copy of the string the pointer points to,
+returning a pointer to the copy.  Finally <code>pstrcat</code> is a
+varargs-style function, which takes a pointer to a resource pool, and
+at least two <code>char *</code> arguments, the last of which must be
+<code>NULL</code>.  It allocates enough memory to fit copies of each
+of the strings, as a unit; for instance:
+
+<pre>
+     pstrcat (r->pool, "foo", "/", "bar", NULL);
+</pre>
+
+returns a pointer to 8 bytes worth of memory, initialized to
+<code>"foo/bar"</code>.
+
+<h3>Tracking open files, etc.</h3>
+
+As indicated above, resource pools are also used to track other sorts
+of resources besides memory.  The most common are open files.  The
+routine which is typically used for this is <code>pfopen</code>, which
+takes a resource pool and two strings as arguments; the strings are
+the same as the typical arguments to <code>fopen</code>, e.g.,
+
+<pre>
+     ...
+     FILE *f = pfopen (r->pool, r->filename, "r");
+
+     if (f == NULL) { ... } else { ... }
+</pre>
+
+There is also a <code>popenf</code> routine, which parallels the
+lower-level <code>open</code> system call.  Both of these routines
+arrange for the file to be closed when the resource pool in question
+is cleared.  <p>
+
+Unlike the case for memory, there <em>are</em> functions to close
+files allocated with <code>pfopen</code>, and <code>popenf</code>,
+namely <code>pfclose</code> and <code>pclosef</code>.  (This is
+because, on many systems, the number of files which a single process
+can have open is quite limited).  It is important to use these
+functions to close files allocated with <code>pfopen</code> and
+<code>popenf</code>, since to do otherwise could cause fatal errors on
+systems such as Linux, which react badly if the same
+<code>FILE*</code> is closed more than once. <p>
+
+(Using the <code>close</code> functions is not mandatory, since the
+file will eventually be closed regardless, but you should consider it
+in cases where your module is opening, or could open, a lot of files).
+
+<h3>Other sorts of resources --- cleanup functions</h3>
+
+More text goes here.  Describe the the cleanup primitives in terms of
+which the file stuff is implemented; also, <code>spawn_process</code>. 
+
+<h3>Fine control --- creating and dealing with sub-pools, with a note
+on sub-requests</h3>
+
+On rare occasions, too-free use of <code>palloc()</code> and the
+associated primitives may result in undesirably profligate resource
+allocation.  You can deal with such a case by creating a
+<em>sub-pool</em>, allocating within the sub-pool rather than the main
+pool, and clearing or destroying the sub-pool, which releases the
+resources which were associated with it.  (This really <em>is</em> a
+rare situation; the only case in which it comes up in the standard
+module set is in case of listing directories, and then only with
+<em>very</em> large directories.  Unnecessary use of the primitives
+dicussed here can hair up your code quite a bit, with very little
+gain). <p>
+
+The primitive for creating a sub-pool is <code>make_sub_pool</code>,
+which takes another pool (the parent pool) as an argument.  When the
+main pool is cleared, the sub-pool will be destroyed.  The sub-pool
+may also be cleared or destroyed at any time, by calling the functions
+<code>clear_pool</code> and <code>destroy_pool</code>, respectively.
+(The difference is that <code>clear_pool</code> frees resources
+associated with the pool, while <code>destroy_pool</code> also
+deallocates the pool itself.  In the former case, you can allocate new
+resources within the pool, and clear it again, and so forth; in the
+latter case, it is simply gone). <p>
+
+One final note --- sub-requests have their own resource pools, which
+are sub-pools of the resource pool for the main request.  The polite
+way to reclaim the resources associated with a sub request which you
+have allocated (using the <code>sub_req_lookup_...</code> functions)
+is <code>destroy_sub_request</code>, which frees the resource pool.
+Before calling this function, be sure to copy anything that you care
+about which might be allocated in the sub-request's resource pool into
+someplace a little less volatile (for instance, the filename in its
+<code>request_rec</code> structure). <p>
+
+(Again, under most circumstances, you shouldn't feel obliged to call
+this function; only 2K of memory or so are allocated for a typical sub
+request, and it will be freed anyway when the main request pool is
+cleared.  It is only when you are allocating many, many sub-requests
+for a single main request that you should seriously consider the
+<code>destroy...</code> functions).
+
+<h2><a name="config">Configuration, commands and the like</a></h2>
+
+One of the design goals for this server was to maintain external
+compatibility with the NCSA 1.3 server --- that is, to read the same
+configuration files, to process all the directives therein correctly,
+and in general to be a drop-in replacement for NCSA.  On the other
+hand, another design goal was to move as much of the server's
+functionality into modules which have as little as possible to do with
+the monolithic server core.  The only way to reconcile these goals is
+to move the handling of most commands from the central server into the
+modules.  <p>
+
+However, just giving the modules command tables is not enough to
+divorce them completely from the server core.  The server has to
+remember the commands in order to act on them later.  That involves
+maintaining data which is private to the modules, and which can be
+either per-server, or per-directory.  Most things are per-directory,
+including in particular access control and authorization information,
+but also information on how to determine file types from suffixes,
+which can be modified by <code>AddType</code> and
+<code>DefaultType</code> directives, and so forth.  In general, the
+governing philosophy is that anything which <em>can</em> be made
+configurable by directory should be; per-server information is
+generally used in the standard set of modules for information like
+<code>Alias</code>es and <code>Redirect</code>s which come into play
+before the request is tied to a particular place in the underlying
+file system. <p>
+
+Another requirement for emulating the NCSA server is being able to
+handle the per-directory configuration files, generally called
+<code>.htaccess</code> files, though even in the NCSA server they can
+contain directives which have nothing at all to do with access
+control.  Accordingly, after URI -&gt; filename translation, but before
+performing any other phase, the server walks down the directory
+hierarchy of the underlying filesystem, following the translated
+pathname, to read any <code>.htaccess</code> files which might be
+present.  The information which is read in then has to be
+<em>merged</em> with the applicable information from the server's own
+config files (either from the <code>&lt;Directory&gt;</code> sections
+in <code>access.conf</code>, or from defaults in
+<code>srm.conf</code>, which actually behaves for most purposes almost
+exactly like <code>&lt;Directory /&gt;</code>).<p>
+
+Finally, after having served a request which involved reading
+<code>.htaccess</code> files, we need to discard the storage allocated
+for handling them.  That is solved the same way it is solved wherever
+else similar problems come up, by tying those structures to the
+per-transaction resource pool.  <p>
+
+<h3><a name="per-dir">Per-directory configuration structures</a></h3>
+
+Let's look out how all of this plays out in <code>mod_mime.c</code>,
+which defines the file typing handler which emulates the NCSA server's
+behavior of determining file types from suffixes.  What we'll be
+looking at, here, is the code which implements the
+<code>AddType</code> and <code>AddEncoding</code> commands.  These
+commands can appear in <code>.htaccess</code> files, so they must be
+handled in the module's private per-directory data, which in fact,
+consists of two separate <code>table</code>s for MIME types and
+encoding information, and is declared as follows:
+
+<pre>
+typedef struct {
+    table *forced_types;       /* Additional AddTyped stuff */
+    table *encoding_types;     /* Added with AddEncoding... */
+} mime_dir_config;
+</pre>
+
+When the server is reading a configuration file, or
+<code>&lt;Directory&gt;</code> section, which includes one of the MIME
+module's commands, it needs to create a <code>mime_dir_config</code>
+structure, so those commands have something to act on.  It does this
+by invoking the function it finds in the module's "create per-dir
+config slot", with two arguments: the name of the directory to which
+this configuration information applies (or <code>NULL</code> for
+<code>srm.conf</code>), and a pointer to a resource pool in which the
+allocation should happen. <p>
+
+(If we are reading a <code>.htaccess</code> file, that resource pool
+is the per-request resource pool for the request; otherwise it is a
+resource pool which is used for configuration data, and cleared on
+restarts.  Either way, it is important for the structure being created
+to vanish when the pool is cleared, by registering a cleanup on the
+pool if necessary). <p>
+
+For the MIME module, the per-dir config creation function just
+<code>palloc</code>s the structure above, and a creates a couple of
+<code>table</code>s to fill it.  That looks like this:
+
+<pre>
+void *create_mime_dir_config (pool *p, char *dummy)
+{
+    mime_dir_config *new =
+      (mime_dir_config *) palloc (p, sizeof(mime_dir_config));
+
+    new-&gt;forced_types = make_table (p, 4);
+    new-&gt;encoding_types = make_table (p, 4);
+    
+    return new;
+}
+</pre>
+
+Now, suppose we've just read in a <code>.htaccess</code> file.  We
+already have the per-directory configuration structure for the next
+directory up in the hierarchy.  If the <code>.htaccess</code> file we
+just read in didn't have any <code>AddType</code> or
+<code>AddEncoding</code> commands, its per-directory config structure
+for the MIME module is still valid, and we can just use it.
+Otherwise, we need to merge the two structures somehow. <p>
+
+To do that, the server invokes the module's per-directory config merge
+function, if one is present.  That function takes three arguments:
+the two structures being merged, and a resource pool in which to
+allocate the result.  For the MIME module, all that needs to be done
+is overlay the tables from the new per-directory config structure with
+those from the parent:
+
+<pre>
+void *merge_mime_dir_configs (pool *p, void *parent_dirv, void *subdirv)
+{
+    mime_dir_config *parent_dir = (mime_dir_config *)parent_dirv;
+    mime_dir_config *subdir = (mime_dir_config *)subdirv;
+    mime_dir_config *new =
+      (mime_dir_config *)palloc (p, sizeof(mime_dir_config));
+
+    new-&gt;forced_types = overlay_tables (p, subdir-&gt;forced_types,
+                                       parent_dir-&gt;forced_types);
+    new-&gt;encoding_types = overlay_tables (p, subdir-&gt;encoding_types,
+                                         parent_dir-&gt;encoding_types);
+
+    return new;
+}
+</pre>
+
+As a note --- if there is no per-directory merge function present, the
+server will just use the subdirectory's configuration info, and ignore
+the parent's.  For some modules, that works just fine (e.g., for the
+includes module, whose per-directory configuration information
+consists solely of the state of the <code>XBITHACK</code>), and for
+those modules, you can just not declare one, and leave the
+corresponding structure slot in the module itself <code>NULL</code>.<p>
+
+<h3><a name="commands">Command handling</a></h3>
+
+Now that we have these structures, we need to be able to figure out
+how to fill them.  That involves processing the actual
+<code>AddType</code> and <code>AddEncoding</code> commands.  To find
+commands, the server looks in the module's <code>command table</code>.
+That table contains information on how many arguments the commands
+take, and in what formats, where it is permitted, and so forth.  That
+information is sufficient to allow the server to invoke most
+command-handling functions with preparsed arguments.  Without further
+ado, let's look at the <code>AddType</code> command handler, which
+looks like this (the <code>AddEncoding</code> command looks basically
+the same, and won't be shown here):
+
+<pre>
+char *add_type(cmd_parms *cmd, mime_dir_config *m, char *ct, char *ext)
+{
+    if (*ext == '.') ++ext;
+    table_set (m-&gt;forced_types, ext, ct);
+    return NULL;
+}
+</pre>
+
+This command handler is unusually simple.  As you can see, it takes
+four arguments, two of which are preparsed arguments, the third being
+the per-directory configuration structure for the module in question,
+and the fourth being a pointer to a <code>cmd_parms</code> structure.
+That structure contains a bunch of arguments which are frequently of
+use to some, but not all, commands, including a resource pool (from
+which memory can be allocated, and to which cleanups should be tied),
+and the (virtual) server being configured, from which the module's
+per-server configuration data can be obtained if required.<p>
+
+Another way in which this particular command handler is unusually
+simple is that there are no error conditions which it can encounter.
+If there were, it could return an error message instead of
+<code>NULL</code>; this causes an error to be printed out on the
+server's <code>stderr</code>, followed by a quick exit, if it is in
+the main config files; for a <code>.htaccess</code> file, the syntax
+error is logged in the server error log (along with an indication of
+where it came from), and the request is bounced with a server error
+response (HTTP error status, code 500). <p>
+
+The MIME module's command table has entries for these commands, which
+look like this:
+
+<pre>
+command_rec mime_cmds[] = {
+{ "AddType", add_type, NULL, OR_FILEINFO, TAKE2, 
+    "a mime type followed by a file extension" },
+{ "AddEncoding", add_encoding, NULL, OR_FILEINFO, TAKE2, 
+    "an encoding (e.g., gzip), followed by a file extension" },
+{ NULL }
+};
+</pre>
+
+The entries in these tables are:
+
+<ul>
+  <li> The name of the command
+  <li> The function which handles it
+  <li> a <code>(void *)</code> pointer, which is passed in the
+       <code>cmd_parms</code> structure to the command handler ---
+       this is useful in case many similar commands are handled by the
+       same function.
+  <li> A bit mask indicating where the command may appear.  There are
+       mask bits corresponding to each <code>AllowOverride</code>
+       option, and an additional mask bit, <code>RSRC_CONF</code>,
+       indicating that the command may appear in the server's own
+       config files, but <em>not</em> in any <code>.htaccess</code>
+       file.
+  <li> A flag indicating how many arguments the command handler wants
+       preparsed, and how they should be passed in.
+       <code>TAKE2</code> indicates two preparsed arguments.  Other
+       options are <code>TAKE1</code>, which indicates one preparsed
+       argument, <code>FLAG</code>, which indicates that the argument
+       should be <code>On</code> or <code>Off</code>, and is passed in
+       as a boolean flag, <code>RAW_ARGS</code>, which causes the
+       server to give the command the raw, unparsed arguments
+       (everything but the command name itself).  There is also
+       <code>ITERATE</code>, which means that the handler looks the
+       same as <code>TAKE1</code>, but that if multiple arguments are
+       present, it should be called multiple times, and finally
+       <code>ITERATE2</code>, which indicates that the command handler
+       looks like a <code>TAKE2</code>, but if more arguments are
+       present, then it should be called multiple times, holding the
+       first argument constant.
+  <li> Finally, we have a string which describes the arguments that
+       should be present.  If the arguments in the actual config file
+       are not as required, this string will be used to help give a
+       more specific error message.  (You can safely leave this
+       <code>NULL</code>). 
+</ul>
+
+Finally, having set this all up, we have to use it.  This is
+ultimately done in the module's handlers, specifically for its
+file-typing handler, which looks more or less like this; note that the
+per-directory configuration structure is extracted from the
+<code>request_rec</code>'s per-directory configuration vector by using
+the <code>get_module_config</code> function.
+
+<pre>
+int find_ct(request_rec *r)
+{
+    int i;
+    char *fn = pstrdup (r->pool, r->filename);
+    mime_dir_config *conf =
+      (mime_dir_config *)get_module_config(r->per_dir_config, &mime_module);
+    char *type;
+
+    if (S_ISDIR(r->finfo.st_mode)) {
+        r->content_type = DIR_MAGIC_TYPE;
+       return OK;
+    }
+    
+    if((i=rind(fn,'.')) < 0) return DECLINED;
+    ++i;
+
+    if ((type = table_get (conf->encoding_types, &fn[i])))
+    {
+        r->content_encoding = type;
+
+       /* go back to previous extension to try to use it as a type */
+       
+        fn[i-1] = '\0';
+       if((i=rind(fn,'.')) < 0) return OK;
+       ++i;
+    }
+
+    if ((type = table_get (conf->forced_types, &fn[i])))
+    {
+        r->content_type = type;
+    }
+    
+    return OK;
+}
+
+</pre>
+
+<h3><a name="servconf">Side notes --- per-server configuration, virtual servers, etc.</a></h3>
+
+The basic ideas behind per-server module configuration are basically
+the same as those for per-directory configuration; there is a creation
+function and a merge function, the latter being invoked where a
+virtual server has partially overriden the base server configuration,
+and a combined structure must be computed.  (As with per-directory
+configuration, the default if no merge function is specified, and a
+module is configured in some virtual server, is that the base
+configuration is simply ignored). <p>
+
+The only substantial difference is that when a command needs to
+configure the per-server private module data, it needs to go to the
+<code>cmd_parms</code> data to get at it.  Here's an example, from the
+alias module, which also indicates how a syntax error can be returned
+(note that the per-directory configuration argument to the command
+handler is declared as a dummy, since the module doesn't actually have
+per-directory config data):
+
+<pre>
+char *add_redirect(cmd_parms *cmd, void *dummy, char *f, char *url)
+{
+    server_rec *s = cmd->server;
+    alias_server_conf *conf =
+        (alias_server_conf *)get_module_config(s-&gt;module_config,&amp;alias_module);
+    alias_entry *new = push_array (conf-&gt;redirects);
+
+    if (!is_url (url)) return "Redirect to non-URL";
+    
+    new-&gt;fake = f; new-&gt;real = url;
+    return NULL;
+}
+</pre>
+
diff --git a/RELEASE_1_1_X/src/CHANGES b/RELEASE_1_1_X/src/CHANGES
new file mode 100644 (file)
index 0000000..ced9c51
--- /dev/null
@@ -0,0 +1,1093 @@
+  *) Bring NeXT support up to date. [Takaaki Matsumoto]
+
+  *) Bring QNX support up to date. [Ben Laurie]
+
+  *) Make virtual hosts default to main server keepalive parameters.
+     [Alexei Kosut, Ben Laurie]
+
+  *) Allow ScanHTMLTitles to work with lowercase <title> tags. [Alexei Kosut]
+
+  *) Fix missing address family for connect, also remove unreachable statement
+     in mod_proxy. [Ben Laurie]
+
+  *) mod_env now turned on by default in Configuration.tmpl.
+
+  *) Bugs which were fixed:
+        a) yet more mod_proxy bugs [Ben Laurie]
+        b) CGI works again with inetd [Alexei Kosut]
+       c) Leading colons were stripped from passwords [osm@interguide.com] 
+       d) Another fix to multi-method Limit problem [jk@tools.de]
+
+Changes with Apache 1.1b4:
+
+  *) r->bytes_sent variable restored. [Robert Thau]
+
+  *) Previously broken multi-method <Limit> parsing fixed. [Robert Thau]
+
+  *) More possibly unsecure programs removed from the support directory.
+
+  *) More mod_auth_msql authentication improvements.
+
+  *) VirtualHosts based on Host: headers no longer conflict with the
+     Listen directive.
+
+  *) OS/2 compatibility enhancements. [Gary Smiley]
+
+  *) POST now allowed to directory index CGI scripts.
+
+  *) Actions now work with files of the default type.
+
+  *) Bugs which were fixed:
+        a) more mod_proxy bugs
+        b) early termination of inetd requests
+        c) compile warnings on several systems
+        d) problems when scripts stop reading output early
+
+Changes with Apache 1.1b3:
+
+  *) Much of cgi-bin and all of cgi-src has been removed, due to
+     various security holes found and that we could no longer support
+     them.  
+
+  *) The "Set-Cookie" header is now special-special-cased to not 
+     merge multiple instances, since certain popular browsers can not 
+     handle multiple Set-Cookie instructions in a single header.
+
+  *) rprintf() added to buffer code, occurrences of sprintf removed.
+     [Ben Laurie]
+
+  *) CONNECT method for proxy module, which means tunneling SSL should work.
+     (No crypto needed)  Also a NoCache config directive.
+
+  *) Several API additions: pstrndup(), table_unset() and get_token()
+     functions now available to modules.
+
+  *) mod_imap fixups, in particular Location: headers are now complete
+     URL's.
+
+  *) New "info" module which reports on installed module set through a 
+     special URL, a la mod_status.
+
+  *) "ServerPath" directive added - allows for graceful transition
+     for Host:-header-based virtual hosts.
+
+  *) Anonymous authentication module improvements.
+
+  *) MSQL authentication module improvements.
+
+  *) Status module design improved - output now table-based. [Ben Laurie]
+
+  *) htdigest utility included for use with digest authentication
+     module.
+  *) mod_negotiation: Accept values with wildcards to be treated with
+     less priority than those without wildcards at the same quality
+     value. [Alexei Kosut]
+
+  *) Bugs which were fixed:
+       a) numerous mod_proxy bugs
+       b) CGI early-termination bug [Ben Laurie]
+       c) Keepalives not working with virtual hosts
+       d) RefererIgnore problems
+       e) closing fd's twice in mod_include (causing core dumps on
+          Linux and elsewhere).
+
+Changes with Apache 1.1b2.
+
+  *) Bugfixes:
+        a) core dumps in mod_digest
+        b) truncated hostnames/ip address in the logs
+        c) relative URL's in mod_imap map files
+
+Changes with Apache 1.1b1. Also see http://www.apache.org/docs/1.1/
+
+  *) Add new <Location> directive, similar to <Directory>, but protects
+     URLs instead of directories. [Alexei Kosut]
+
+  *) Allow ErrorDocument directive to also be used from .htaccess files.
+     This is enabled/disabled by using the FileInfo flag with 
+     AllowOverrides [Mark Cox]
+     
+  *) Add AddHandler command, which allows content-type-independent 
+     "handlers" to be defined for file extensions. These can be either
+     built into Apache (such as CGI scripts or server-side includes, or
+     added with the Action command). [Alexei Kosut]
+
+  *) Added new Explain() function, intended to help trace execution. Currently
+     only used in mod_proxy.c (and there not yet complete). Switch it on with
+     -DEXPLAIN. See explain.h. [Ben Laurie]
+
+  *) Added two new directives to proxy module, CacheDirLevels and
+     CacheDirLength. Values of 3 and 2 respectively will result in files like
+     aa/bb/cc/dddddd in the cache. [Ben Laurie]
+
+  *) Modify <VirtualHost> directive to work without the system supporting
+     multiple IP addresses. It can now take advantage of the Host: header
+     sent by some (but not all) new web browsers (e.g. Netscape 2.0). Those
+     that do not support it will get the default documents. More names or
+     name patters can be added using the ScriptAlias directive, e.g.
+     "ScriptAlias foo.bar.net *.foo.com foo.com" [Alexei Kosut]
+
+  *) Added Status module with preliminary documentation available
+     http://www.apache.org/docs/1.1/mod_status.html [Mark Cox]
+
+  *) Added simple and complex instrumentation to Apache to allow a
+     instantaneous status screen to be displayed.  Since the complex
+     instrumentation makes the scoreboard file bigger it has been 
+     made a compile-time define (add "-DSTATUS" to 
+     CFLAGS in the Configuration file) [Mark Cox]
+
+  *) Made it so XBITHACK behavior only occurs for files of type text/html, as
+     any other file type doesn't really make sense. [Alexei Kosut]
+
+  *) Slightly modified the API to allow handlers by things other than
+     content type. Setting r->handler will override r->content_type in
+     invoke_handler(). [Alexei Kosut]
+
+  *) Added FLOCK_SERIALIZED_ACCEPT for those systems, like A/UX,
+     that need mutex-capability but using fcntl-locking is
+     expensive. [Jim Jagielski]
+
+  *) Added in Cliff Skolnick's read_client_block patch (check for
+     no reads and break) [Jim Jagielski]
+
+  *) If there was no default MIME type defined, Apache sent Content-type:
+     without a newline, thus swallowing the next header. Changed to send no
+     Content-type: at all. [Ben Laurie]
+
+  *) Long overdue revamp of the Cookies module to stop Apache cookies
+     colliding with other cookies a site may be using.  Cookies are now
+     always generated for every browser, not just Netscape (and clones)
+     and the cookie log can be a pipe just like the other logs [Mark Cox]
+
+  *) Add HAVE_MMAP to SCO 5. [Ben Laurie]
+
+  *) SCO 5 reportedly (by Jay Thorne <jay@result.com>) requires
+     FCNTL_SERIALIZED_ACCEPT. Added to conf.h. [Ben Laurie]
+
+  *) Clear up some nasty (int)NULLs. [Ben Laurie]
+
+  *) Clean code to warning level 3 under SCO 5. [Ben Laurie]
+
+  *) Fix potential buffer overrun in mod_proxy.c. [Ben Laurie]
+
+  *) Internal redirects now preserve HTTP headers [Rob Hartil]
+
+  *) Adds SysV-based Shared Memory support for Apache [Jim Jagielski]
+
+  *) Use bread() etc instead of fread() for reading/writing to client.
+     Move the count of bytes sent into the buffering routines.
+     Rewrite the buffering routines to provide bputc(), bgetc() macros.
+     [David Robinson]
+
+  *) Make hostname_lookups a per-directory core configuration variable.
+     Replace all accesses to the connection.remote_host and remote_name
+     variables to calls to get_remote_host(), which is now in http_core.c.
+     [David Robinson]
+
+  *) Make do_rfc1413 a per-directory core configuration variable.
+     Replace all accesses to the connection.remote_logname
+     variables to calls to get_remote_logname(). Rewrite rfc931.c as
+     rfc1413.c to conform to new standard, avoid stdio and avoid syslog.
+     [David Robinson]
+
+  *) CGI variables are now available to server side include directives
+     as well as the QUERY_STRING_UNESCAPED variable, as required by
+     the NCSA server side include documentation. [Nathan Schrenk]
+
+  *) Better diagnostic info to enhance "malformed header from script"
+     [Rob Hartill]
+
+  *) Improvements and new features added to the UserDir directive:
+     Additional forms of specifiying user directories, and the ability to
+     specify multiple user directories, much like the DirectoryIndex
+     command. [Alexei Kosut]
+
+  *) Internal redirects no longer force the GET method, except when desired
+     (CGI scripts and error documents). [Adam Sussman and Rasmus Lerdorf]
+
+  *) Rewrite/reorganization of mod_imap.c.  New handling of default, base
+     and relative URLs. New Configuration directives. Support for creating
+     non-graphical menu added.  (backwards compatible). [Nathan Kurz]
+
+  *) New module which allows Apache's CGI and SSI environment to inherit
+     environment variables from the shell which invoked the httpd
+     process. CERN webservers are able to do this, so this module is
+     especially useful to webadmins who wish to migrate from CERN to Apache
+     without rewriting all their scripts [Andrew Wilson]
+
+  *) Updated /cgi-src to the latest NCSA version, including the IBM-ERS patch
+     to close a security hole, as well as other changes to the distribution
+     since it was last updated (Apache 0.8.5) [Alexei Kosut]
+
+  *) Move Configuration to Configuration.tmpl for CVS development. Make CVS
+     ignore Configuration, Makefile and modules.c. [Ben Laurie]
+
+Changes with Apache 1.1b0
+
+  *) Use shmget() (and family) for shared memory for the scoreboard
+     for SysV-based systems; basically A/UX and IRIX. Allow for
+     memory break-point (brk(0)) to be moved if need be before
+     attaching the mem segment. [Jim Jagielski]
+
+  *) Use mmap() to allocated shared memory for the scoreboard on
+     Solaris, SunOS, Digital UNIX, BSDI and HP/UX. It should work on
+     most of the other architectures. [David Robinson]
+
+  *) Cache the contents of .htaccess file for the duration of a request.
+     [David Robinson]
+
+  *) Avoid use of strftime() whilst processing request. [David Robinson]
+
+  *) Add the ability to have media type-based CGI script actions,
+     as well as an example and relevent srm.conf entries. [Alexei Kosut]
+
+  *) Update to the icon set, and apache_pb (Powered by Apache!) logo
+     added [Alexei Kosut]
+
+  *) Added an extra variable for use in mod_include: FILE_OWNER
+     which contains the owner of the file.  [Nick Williams]
+
+  *)  Adds support for Keep-Alive persistent connections, as defined
+      in the HTTP/1.1 draft and implemented by several existing browsers
+      and servers. [Alexei Kosut and Rob Hartill]
+
+  *) "HostnameLookups" is a new httpd.conf setting (on/off) to make obsolete
+     -DMINIMAL_DNS and enable name lookups to be switched
+     on/off without recompiling Apache. [Rob Hartill]
+
+  *) Allows Redirect entries in .htaccess files, allowing users to
+     add their own redirects without using CGI scripts, asis files, or
+     access to the main server conf file. [Alexei Kosut]
+
+  *) Scoreboard monitor program (C version) in support/ directory
+     [Jim Jagielski]
+
+  *) A module to implement a caching HTTP and FTP proxy server
+     [David Robinson]
+
+  *) Adds OS/2 support [Garey Smiley]
+
+  *) Add Listen directive, causing Apache to bind to the address and
+     port specified. Allow <VirtualHost *>, <VirtualHost *:port>,
+     VirtualHost addr:*> syntaxes [David Robinson]
+
+  *) Allow anonymous HTTP logins [Dirk van Gulik]
+
+  *) Authentication using Berkeley DB [Andrew Cohen]
+
+  *) Authentication using mSQL [Dirk van Gulik]
+
+  *) Emulate the CERN HTTPD metafile semantics, allowing the ability
+     to manipulate HTTP headers for individual files. [Andrew Wilson[
+
+Changes with Apache 1.0.3
+
+  *) Internal redirects which occur in mod_dir.c now preserve the
+     query portion of a request (the bit after the question mark).
+     [Adam Sussman]
+
+  *) Escape active characters '<', '>' and '&' in html output in
+     directory listings, error messages and redirection links.
+     [David Robinson]
+
+  *) Apache will now work with LynxOS 2.3 and later [Steven Watt]
+
+  *) Fix for POSIX compliance in waiting for processes in alloc.c.
+     [Nick Williams]
+
+  *) setsockopt no longer takes a const declared argument [Martijn Koster]
+
+  *) Reset timeout timer after each successful fwrite() to the network.
+     This patch adds a reset_timeout() procedure that is called by
+     send_fd() to reset the timeout ever time data is written to the net.
+     [Nathan Schrenk]
+
+  *) timeout() signal handler now checks for SIGPIPE and reports
+     lost connections in a more user friendly way. [Rob Hartill]
+
+  *) Location of the "scoreboard" file which used to live in /tmp is
+     now configurable (for OSes that can't use mmap) via ScoreBoardFile
+     which works similar to PidFile (in httpd.conf) [Rob Hartill]
+
+  *) Include sys/resource.h in the correct place for SunOS4 [Samerr Parekh]
+
+  *) the pstrcat call in mod_cookies.c didn't have an ending NULL,
+     which caused a SEGV with cookies enabled
+
+  *) Output warning when MinSpareServers is set to <= 0 and change it to 1
+     [Rob Hartill]
+
+  *) Log the UNIX textual error returned by some system calls, in
+     particular errors from accept() [David Robinson]
+
+  *) Add strerror function to util.c for SunOS4 [Randy Terbush]
+
+Changes with Apache 1.0.2
+
+  *) patch to get Apache compiled on UnixWare 2.x, recommended as 
+     a temporary measure, pending rewrite of rfc931.c. [Chuck Murcko]
+
+  *) Fix get_basic_auth_pw() to set the auth_type of the request.
+     [David Robinson]
+
+  *) past changes to http_config.c to only use the 
+     setrlimit function on systems defining RLIMIT_NOFILE
+     broke the feature on SUNOS4. Now defines HAVE_RESOURCE
+     for SUNOS and prototypes the needed functions.
+
+  *) Remove uses of MAX_STRING_LEN/HUGE_STRING_LEN from several routines.
+     [David Robinson]
+
+  *) Fix use of pointer to scratch memory. [Cliff Skolnick]
+
+  *) Merge multiple headers from CGI scripts instead of taking last
+     one. [David Robinson]
+
+  *) Add support for SCO 5. [Ben Laurie]
+
+Changes with Apache 1.0.1
+
+  *) Silence mod_log_referer and mod_log_agent if not configured
+     [Randy Terbush]
+
+  *) Recursive includes can occur if the client supplies PATH_INFO data
+     and the server provider uses relative links; as file.html
+     relative to /doc.shtml/pathinfo is /doc.shtml/file.html. [David Robinson]
+
+  *) The replacement for initgroups() did not call {set,end}grent(). This
+     had two implications: if anything else used getgrent(), then
+     initgroups() would fail, and it was consuming a file descriptor.
+     [Ben Laurie]
+
+  *) On heavily loaded servers it was possible for the scoreboard to get 
+     out of sync with reality, as a result of a race condition.
+     The observed symptoms are far more Apaches running than should
+     be, and heavy system loads, generally followed by catastrophic
+     system failure. [Ben Laurie]
+
+  *) Fix typo in licence. [David Robinson]
+
+Changes with Apache 1.0.0
+
+  *) 'dbmmanage' script now takes fourth command-line argument, which is
+     group(s) of the user, if given.  [Rob Hartill]
+
+  *) httpd_monitor Perl utility script added to "support" directory;
+     lets you know what your active server processes are up to.  [Known
+     to work on SunOS and HP-UX at least].  [Rob Hartill]
+
+  *) Passes TZ environment variable to child processes if set on startup
+     [ David Robinson ]
+
+  *) Attempting to retrieve the URI /foo/bar/zot.map (an imagemap request
+     with *no* QUERY_STRING) returns the default URL, rather than a core
+     dump.  [Mark Cox]
+
+  *) Attempting to configure auth without any "requires" lines should now
+     be equivalent to "require valid-user", rather than a core dump.
+     [Patch supplied by J. Katzman]
+
+  *) Getparents() routine fixed to handle some awkward corner cases better;
+     in particular, '/./' is eliminated from incoming URIs.  Also fixed the
+     no2slash() utility routine to reduce any number of consecutive slashes
+     to one.  These changes keep "trick" URIs from avoiding <Directory>
+     checks.  [David Robinson]
+
+  *) Allowed any number of '/' characters to match a single '/' when
+     checking for Aliases; this keeps certain ScriptAlias directives
+     from getting bypassed.  [Robert Thau]
+
+  *) DBM group code now checks all groups, not just the first [Rob Hartill]
+
+  *) "allow from good.com" no longer allows clients from nogood.com to
+     connect; formerly this was allowed because the terminal substrings
+     do match.  [Robert Thau]
+
+  *) Transactions interrupted in the middle of processing some include
+     directive are now logged correctly [Robert Thau]
+
+  *) Cleaned up Configure script so it doesn't abuse EXTRA_LIBS to specify
+     host-specific default libraries.  [Ben Laurie]
+
+  *) Cleaned up http_main code a bit; IdentityCheck may now work better on 
+     systems with virtual hosts.  [David Robinson]
+
+  *) Improved installation instructions in top-level README [Brian Behlendorf]
+
+Changes with Apache 0.8.16
+
+  *) New man page for 'httpd' added to support directory [David Robinson]
+
+  *) .htgroup files can have more than one line giving members for a
+     given group (each must have the group name in front), for NCSA
+     back-compatibility [Robert Thau]
+
+  *) Mutual exclusion around accept() is on by default for SVR4 systems
+     generally, since they generally can't handle multiple processes in
+     accept() on the same socket.  This should cure flaky behavior on
+     a lot of those systems.  [David Robinson]
+
+  *) AddType, AddEncoding, and AddLanguage directives take multiple
+     extensions on a single command line [David Robinson]
+
+  *) UserDir can be disabled for a given virtual host by saying
+     "UserDir disabled" in the <VirtualHost> section --- it was a bug
+     that this didn't work.  [David Robinson]
+
+  *) Compiles on QNX [Ben Laurie]
+
+  *) Corrected parsing of ctime time format [David Robinson]
+
+  *) httpd does a perror() before exiting if it can't log its pid
+     to the PidFile, to make diagnosing the error a bit easier.
+     [David Robinson]
+
+  *) <!--#include file="..."--> can no longer include files in the
+     parent directory, for NCSA back-compatibility.  [David Robinson]
+
+  *) '~' is *not* escaped in URIs generated for directory listings
+     [Roy Fielding]
+
+  *) Eliminated compiler warning in the imagemap module [Randy Terbush]
+
+  *) Fixed bug involving handling URIs with escaped %-characters
+     in redirects [David Robinson]
+
+Changes with Apache 0.8.15
+
+  *) Switched to new, simpler license
+
+  *) Eliminated core dumps with improperly formatted DBM group files [Mark Cox]
+
+  *) Don't allow requests for ordinary files to have PATH_INFO [Ben Laurie]
+
+  *) Reject paths containing %-escaped '%' or null characters [David Robinson]
+
+  *) Correctly handles internal redirects to files with names containing '%'
+     [David Robinson]
+
+  *) Repunctuated some error messages [Aram Mirzadeh, Andrew Wilson]
+
+  *) Use geteuid() rather than getuid() to see if we have root privilege,
+     so that server correctly resets privilege if run setuid root.  [Andrew
+     Wilson]
+
+  *) Handle ftp: and telnet: URLs correctly in imagemaps (built-in module)
+     [Randy Terbush]
+
+  *) Fix relative URLs in imagemap files [Randy Terbush]
+
+  *) Somewhat better fix for the old "Alias /foo/ /bar/" business
+     [David Robinson]
+
+  *) Don't repeatedly open the ErrorLog if a bunch of <VirtualHost>
+     entries all name the same one. [David Robinson]
+
+  *) Fix directory listings with filenames containing unusual characters
+     [David Robinson]
+
+  *) Better URI-escaping for generated URIs in directories with filenames
+     containing unusual characters [Ben Laurie]
+
+  *) Fixed potential FILE* leak in http_main.c [Ben Laurie]
+
+  *) Unblock alarms on error return from spawn_child() [David Robinson]  
+
+  *) Sample Config files have extra note for SCO users [Ben Laurie]
+
+  *) Configuration has note for HP-UX users [Rob Hartill]
+
+  *) Eliminated some bogus Linux-only #defines in conf.h [Aram Mirzadeh]
+
+  *) Nuked bogus #define in httpd.h [David Robinson]
+
+  *) Better test for whether a system has setrlimit() [David Robinson]
+
+  *) Calls update_child_status() after reopen_scoreboard() [David Robinson]
+
+  *) Doesn't send itself SIGHUP on startup when run in the -X debug-only mode
+     [Ben Laurie]
+
+Changes with Apache 0.8.14
+
+  *) Compiles on SCO ODT 3.0 [Ben Laurie]
+
+  *) AddDescription works (better) [Ben Laurie]
+
+  *) Leaves an intelligible error diagnostic when it can't set group
+     privileges on standalone startup [Andrew Wilson]
+
+  *) Compiles on NeXT again --- the 0.8.13 RLIMIT patch was failing on
+     that machine, which claims to be BSD but does not support RLIMIT.
+     [Randy Terbush]
+
+  *) gcc -Wall no longer complains about an unused variable when util.c
+     is compiled with -DMINIMAL_DNS [Andrew Wilson]
+
+  *) Nuked another compiler warning for -Wall on Linux [Aram Mirzadeh]
+
+Changes with Apache 0.8.13
+
+  *) Make IndexIgnore *work* (ooops) [Jarkko Torppa]
+
+  *) Have built-in imagemap code recognize & honor Point directive [James
+     Cloos]
+
+  *) Generate cleaner directory listings in directories with a mix of
+     long and short filenames [Rob Hartill]
+
+  *) Properly initialize dynamically loaded modules [Royston Shufflebotham]
+
+  *) Properly default ServerName for virtual servers [Robert Thau]
+
+  *) Rationalize handling of BSD in conf.h and elsewhere [Randy Terbush,
+     Paul Richards and a cast of thousands...]
+
+  *) On self-identified BSD systems (we don't try to guess any more),
+     allocate a few extra file descriptors per virtual host with setrlimit,
+     if we can, to avoid running out. [Randy Terbush]
+
+  *) Write 22-character lock file name into buffer with enough space
+     on startup [Konstantin Olchanski]
+
+  *) Use archaic setpgrp() interface on NeXT, which requires it [Brian
+     Pinkerton]
+
+  *) Suppress -Wall warning by casting const away in util.c [Aram Mirzadeh]
+
+  *) Suppress -Wall warning by initializing variable in negotation code
+     [Tobias Weingartner]
+
+Changes with Apache 0.8.12
+
+  *) Doesn't pause three seconds after including a CGI script which is
+     too slow to die off (this is done by not even trying to kill off
+     subprocesses, including the SIGTERM/pause/SIGKILL routine, until
+     after the entire document has been processed).  [Robert Thau]
+
+  *) Doesn't do SSI if Options Includes is off.  (Ooops).  [David Robinson]
+
+  *) Options IncludesNoExec allows inclusion of at least text/* [Roy Fielding]
+
+  *) Allows .htaccess files to override <Directory> sections naming the
+     same directory [David Robinson]
+
+  *) Removed an efficiency hack in sub_req_lookup_uri which was
+     causing certain extremely marginal cases (e.g., ScriptAlias of a
+     *particular* index.html file) to fail.  [David Robinson]
+
+  *) Doesn't log an error when the requested URI requires
+     authentication, but no auth header line was supplied by the
+     client; this is a normal condition (the client doesn't no auth is
+     needed here yet).  [Robert Thau]
+
+  *) Behaves more sanely when the name server loses its mind [Sean Welch]
+
+  *) RFC931 code compiles cleanly on old BSDI releases [Randy Terbush]
+
+  *) RFC931 code no longer passes out name of prior clients on current
+     requests if the current request came from a server that doesn't
+     do RFC931.  [David Robinson]
+
+  *) Configuration script accepts "Module" lines with trailing whitespace.
+     [Robert Thau]
+
+  *) Cleaned up compiler warning from mod_access.c [Robert Thau]
+
+  *) Cleaned up comments in mod_cgi.c [Robert Thau]
+
+Changes with Apache 0.8.11
+
+  *) Wildcard <Directory> specifications work.  [Robert Thau]
+
+  *) Doesn't loop for buggy CGI on Solaris [Cliff Skolnick]
+  
+  *) Symlink checks (FollowSymLinks off, or SymLinkIfOwnerMatch) always check
+     the file being requested itself, in addition to the directories leading
+     up to it. [Robert Thau]
+  
+  *) Logs access failures due to symlink checks or invalid client address
+     in the error log [Roy Fielding, Robert Thau]
+  
+  *) Symlink checks deal correctly with systems where lstat of
+     "/path/to/some/link/" follows the link.  [Thau, Fielding]
+
+  *) Doesn't reset DirectoryIndex to 'index.html' when
+     other directory options are set in a .htaccess file.  [Robert Thau]
+  
+  *) Clarifed init code and nuked bogus warning in mod_access.c
+     [Florent Guillaume]
+  
+  *) Corrected several directives in sample srm.conf
+     --- includes corrections to directory indexing icon-related directives
+     (using unknown.gif rather than unknown.xbm as the DefaultIcon, doing
+     icons for encodings right, and turning on AddEncoding by default).
+     [Roy Fielding]
+  
+  *) Corrected descriptions of args to AddIcon and AddAlt in command table
+     [James Cloos]
+  
+  *) INSTALL & README mention "contributed modules" directory [Brian
+     Behlendorf]
+  
+  *) Fixed English in the license language...  "for for" --> "for".
+     [Roy Fielding]
+  
+  *) Fixed ScriptAlias/Alias interaction by moving ScriptAlias handling to
+     mod_alias.c, merging it almost completely with handling of Alias, and
+     adding a 'notes' field to the request_rec which allows the CGI module
+     to discover whether the Alias module has put this request through
+     ScriptAlias (which it needs to know for back-combatibility, as the old
+     NCSA code did not check Options ExecCGI in ScriptAliased directories).
+     [Robert Thau]
+  
+
+Changes with Apache 0.8.10
+
+  *) AllowOverride applies to the named directory, and not just
+     subdirectories.  [David Robinson]
+
+  *) Do locking for accept() exclusion (on systems that need it)
+     using a special file created for the purpose in /usr/tmp, and
+     not the error log; using the error log causes real problems
+     if it's NFS-mounted; this is known to be the cause of a whole
+     lot of "server hang" problems with Solaris.  [David Robinson;
+     thanks to Merten Schumann for help diagnosing the problem].
+
+Changes with Apache 0.8.9
+
+  *) Compiles with -DMAXIMUM_DNS ---- ooops! [Henrik Mortensen]
+
+  *) Nested includes see environment variables of the including document,
+     for NCSA bug-compatibility (some sites have standard footer includes
+     which try to print out the last-modified date).  [Eric Hagberg/Robert
+     Thau]
+
+  *) <!--exec cgi="/some/uri/here"--> always treats the item named by the
+     URI as a CGI script, even if it would have been treated as something
+     else if requested directly, for NCSA back-combatibility.  (Note that
+     this means that people who know the name of the script can see the
+     code just by asking for it).  [Robert Thau]
+
+  *) New version of dbmmanage script included in support directory as
+     dbmmanage.new.
+
+  *) Check if scoreboard file couldn't be opened, and say so, rather
+     then going insane [David Robinson]
+
+  *) POST to CGI works on A/UX [Jim Jaglieski]
+
+  *) AddIcon and AddAlt commands work properly [Rob Hartill]
+
+  *) NCSA server push works properly --- the Arena bug compatibility
+     workaround, which broke it, is gone (use -DARENA_BUG_WORKAROUND
+     if you still want the workaround).  [Rob Hartill]
+
+  *) If client didn't submit any Accept-encodings, ignore encodings in
+     content negotiation.  (NB this will all have to be reworked anyway
+     for the new HTTP draft).  [Florent Guillaume]
+     
+  *) Don't dump core when trying to log timed-out requests [Jim Jaglieski]
+
+  *) Really honor CacheNegotiatedDocs [Florent Guillaume]
+
+  *) Give Redirect priority over Alias, for NCSA bug compatibility
+     [David Robinson]
+
+  *) Correctly set PATH_TRANSLATED in all cases from <!--#exec cmd=""-->,
+     paralleling earlier bug fix for CGI [David Robinson]
+
+  *) If DBM auth is improperly configured, report a server error and don't
+     dump core.
+
+  *) Deleted FCNTL_SERIALIZED_ACCEPTS from conf.h entry for A/UX;
+     it seems to work well enough without it (even in a 10 hits/sec
+     workout), and the overhead for the locking under A/UX is
+     alarmingly high (though it is very low on other systems).
+     [Eric Hagberg]
+
+  *) Fixed portability problems with mod_cookies.c [Cliff Skolnick]
+
+  *) Further de-Berklize mod_cookies.c; change the bogus #include.  [Brian
+     Behlendorf/Eric Hagberg]
+
+  *) More improvements to default Configuration for A/UX [Jim Jaglieski]
+
+  *) Compiles clean on NEXT [Rob Hartill]
+
+  *) Compiles clean on SGI [Robert Thau]
+
+Changes with Apache 0.8.8
+
+  *) SunOS library prototypes now never included unless explicitly
+     requested in the configuration (via -DSUNOS_LIB_PROTOTYPES);
+     people using GNU libc on SunOS are screwed by prototypes for the
+     standard library.
+
+     (Those who wish to compile clean with gcc -Wall on a standard
+     SunOS setup need the prototypes, and may obtain them using
+     -DSUNOS_LIB_PROTOTYPES.  Those wishing to use -Wall on a system
+     with nonstandard libraries are presumably competent to make their
+     own arrangements).
+
+  *) Strips trailing '/' characters off both args to the Alias command,
+     to make 'Alias /foo/ /bar/' work.
+
+Changes with Apache 0.8.7
+
+  *) Don't hang when restarting with a child from 'TransferLog "|..."' running
+     [reported by David Robinson]
+
+  *) Compiles clean on OSF/1 [David Robinson]
+
+  *) Added some of the more recent significant changes (AddLanguage stuff,
+     experimental LogFormat support) to CHANGES file in distribution root
+     directory
+
+Changes with Apache 0.8.6
+
+  *) Deleted Netscape reload workaround --- it's in violation of HTTP specs.
+     (If you actually wanted a conditional GET which bypassed the cache, you
+     couldn't get it). [Reported by Roy Fielding]
+
+  *) Properly terminate headers on '304 Not Modified' replies to conditional
+     GETs --- no browser we can find cares much, but the CERN proxy chokes.
+     [Reported by Cliff Skolnick; fix discovered independently by Rob Hartill]
+
+  *) httpd -v doesn't call itself "Shambhala".  [Reported by Chuck Murcko]
+
+  *) SunOS lib-function prototypes in conf.h conditionalized on __GNUC__,
+     not __SUNPRO_C (they're needed to quiet gcc -Wall, but acc chokes on 'em,
+     and older versions don't set the __SUNPRO_C preprocessor variable).  On
+     all other systems, these are never used anyway.  [Reported by Mark Cox].
+
+  *) Scoreboard file (/tmp/htstatus.*) no longer publically writable.
+
+Changes with Apache 0.8.5
+
+  *) Added last-minute configurable log experiment, as optional module
+
+  *) Correctly set r->bytes_sent for HTTP/0.9 requests, so they get logged
+     properly.  (One-line fix to http_protocol.c).
+
+  *) Work around bogus behavior when reloading from Netscape.
+     It's Netscape's bug --- for some reason they expect a request with
+     If-modified-since: to not function as a conditional GET if it also
+     comes with Pragma: no-cache, which is way out of line with the HTTP
+     spec (according to Roy Fielding, the redactor).  
+
+  *) Added parameter to set maximum number of server processes.  
+
+  *) Added patches to make it work on A/UX.  A/UX is *weird*.  [Eric Hagberg]
+
+  *) IdentityCheck bugfix [Chuck Murcko].
+
+  *) Corrected cgi-src/Makefile entry for new imagemap script.  [Alexei Kosut]
+
+  *) More sample config file corrections; add extension to AddType for
+     *.asis, move AddType generic description to its proper place, and
+     fix miscellaneous typos. [ Alexei Kosut ]
+
+  *) Deleted the *other* reference to the regents from the Berkeley
+     legal disclaimer (everyplace).
+
+  *) Nuked Shambhala name from src/README; had already cleaned it out
+     of everywhere else.
+
+Changes with Apache 0.8.4
+
+  *) Changes to server-pool management parms --- renamed current
+     StartServers to MinSpareServers, created separate StartServers
+     parameter which means what it says, and renamed MaxServers to
+     MaxSpareServers (though the old name still works, for NCSA 1.4
+     back-combatibility).  The old names were generally regarded as
+     too confusing.  Also altered "docs" in sample config files.
+
+  *) More improvements to default config files ---
+     sample directives (commented out) for XBitHack, BindAddress,
+     CacheNegotiatedDocs, VirtualHost; decent set of AddLanguage
+     defaults, AddTypes for send-as-is and imagemap magic types, and
+     improvements to samples for DirectoryIndex [Alexei Kosut]
+
+  *) Yet more improvements to default config files --- changes to
+     Alexei's sample AddLanguage directives, and sample LanguagePriority
+     [ Florent Guillaume ]
+
+  *) Set config file locations properly if not set in httpd.conf
+     [ David Robinson ]
+
+  *) Don't escape URIs in internal redirects multiple times; don't
+     do that when translating PATH_INFO to PATH_TRANSLATED either.
+     [ David Robinson ]
+
+  *) Corrected spelling of "Required" in 401 error reports [Andrew Wilson]
+
+Changes with Apache 0.8.3
+
+  *) Edited distribution README to *briefly* summarize installation
+     procedures, and give a pointer to the INSTALL file in the src/
+     directory.
+
+  *) Upgraded imagemap script in cgi-bin to 1.8 version from more
+     recent NCSA distributions.
+
+  *) Bug fix to previous bug fix --- if .htaccess file and <Directory>
+     exist for the same directory, use both and don't segfault.  [Reported
+     by David Robinson]
+
+  *) Proper makefile dependencies [David Robinson]
+
+  *) Note (re)starts in error log --- reported by Rob Hartill.
+
+  *) Only call no2slash() after get_path_info() has been done, to
+     preserve multiple slashes in the PATH_INFO [NCSA compatibility,
+     reported by Andrew Wilson, though this one is probably a real bug]
+
+  *) Fixed mod_imap.c --- relative paths with base_uri referer don't
+     dump core when Referer is not supplied. [Randy Terbush]
+
+  *) Lightly edited sample config files to refer people to our documentation
+     instead of NCSA's, and to list Rob McCool as *original* author (also
+     deleted his old, and no doubt non-functional email address).  Would be
+     nice to have examples of new features...
+
+Changes with Apache 0.8.2
+
+  *) Added AddLanuage code [Florent Guillaume]
+
+  *) Don't say "access forbidden" when a CGI script is not found.  [Mark Cox] 
+
+  *) All sorts of problems when MultiViews finds a directory.  It would
+     be nice if mod_dir.c was robust enough to handle that, but for now,
+     just punt.  [reported by Brian Behlendorf]
+
+  *) Wait for all children on restart, to make sure that the old socket
+     is gone and we can reopen it.  [reported by Randy Terbush]
+
+  *) Imagemap module is enabled in default Configuration 
+
+  *) RefererLog and UserAgentLog modules properly default the logfile
+     [Randy Terbush]
+
+  *) Mark Cox's mod_cookies added to the distribution as an optional
+     module (commented out in the default Configuration, and noted as
+     an experiment, along with mod_dld). [Mark Cox]
+
+  *) Compiles on Ultrix (a continuing battle...). [Robert Thau]
+
+  *) Fixed nasty bug in SIGTERM handling [reported by Randy Terbush]
+
+  *) Changed "Shambhala" to "Apache" in API docs. [Robert Thau]
+
+  *) Added new, toothier legal disclaimer. [Robert Thau; copied from BSD
+     license]
+
+Changes with Apache 0.8.1
+
+  *) New imagemap module [Randy Terbush]
+
+  *) Replacement referer log module with NCSA-compatible RefererIgnore
+     [Matthew Gray again]
+
+  *) Don't mung directory listings with very long filenames.
+     [Florent Guillaume]
+
+Changes with Apache 0.8.0 (nee Shambhala 0.6.2):
+
+  *) New config script.  See INSTALL for info.  [Robert Thau]
+
+  *) Scoreboard mechanism for regulating the number of extant server
+     processes.  MaxServers and StartServers defaults are the same as
+     for NCSA, but the meanings are slightly different.  (Actually,
+     I should probably lower the MaxServers default to 10).
+
+     Before asking for a new connection, each server process checks
+     the number of other servers which are also waiting for a
+     connection.  If there are more than MaxServers, it quietly dies
+     off.  Conversely, every second, the root, or caretaker, process
+     looks to see how many servers are waiting for a new connection;
+     if there are fewer than StartServers, it starts a new one.  This
+     does not depend on the number of server processes already extant.
+     The accounting is arranged through a "scoreboard" file, named
+     /tmp/htstatus.*, on which each process has an independant file
+     descriptor (they need to seek without interference).
+
+     The end effect is that MaxServers is the maximum number of
+     servers on an *inactive* server machine, but more will be forked
+     off to handle unusually heavy loads (or unusually slow clients);
+     these will die off when they are no longer needed --- without
+     reverting to the overhead of full forking operation.  There is a
+     hard maximum of 150 server processes compiled in, largely to
+     avoid forking out of control and dragging the machine down.
+     (This is arguably too high).
+
+     In my server endurance tests, this mechanism did not appear to
+     impose any significant overhead, even after I forced it to put the
+     scoreboard file on a normal filesystem (which might have more
+     overhead than tmpfs).  [Robert Thau]
+   
+  *) Set HTTP_FOO variables for SSI <!--#exec cmd-->s, not just CGI scripts.
+     [Cliff Skolnick]
+
+  *) Read .htaccess files even in directory with <Directory> section.
+     (Former incompatibility noted on mailing list, now fixed). [Robert
+     Thau]
+
+  *) "HEAD /" gives the client a "Bad Request" error message, rather
+     than trying to send no body *and* no headers.  [Cliff Skolnick].
+
+  *) Don't produce double error reports for some very obscure cases
+     mainly involving auth configuration (the "all modules decline to
+     handle" case which is a sure sign of a server bug in most cases,
+     but also happens when authentication is badly misconfigured).
+     [Robert Thau]
+
+  *) Moved FCNTL_SERIALIZED_ACCEPT defines into conf.h (that's what
+     it's *for*, and this sort of thing really shouldn't be cluttering
+     up the Makefile). [Robert Thau]
+
+  *) Incidental code cleanups in http_main.c --- stop dragging
+     sa_client around; just declare it where used.  [Robert Thau]
+  
+  *) Another acc-related fix.  (It doesn't like const char
+     in some places...). [Mark Cox]
+
+Changes with 0.6.1
+
+  *) Fixed auth_name-related typos in http_core.c [Brian Behlendorf]
+     Also, fixed auth typo in http_protocol.c unmasked by this fix.
+
+  *) Compiles clean with acc on SunOS [Paul Sutton]
+
+  *) Reordered modules in modules.c so that Redirect takes priority
+     over ScriptAlias, for NCSA bug-compatibility [Rob Hartill] ---
+     believe it or not, he has an actual site with a ScriptAlias and
+     a Redirect declared for the *exact same directory*.  Even *my*
+     compatibility fetish wouldn't motivate me to fix this if the fix
+     required any effort, but it doesn't, so what the hey. 
+
+  *) Fixed to properly default several server_rec fields for virtual
+     servers from the corresponding fields in the main server_rec.
+     [Cliff Skolnick --- 'port' was a particular irritant].
+
+  *) No longer kills off nph- child processes before they are
+     finished sending output. [Matthew Gray]
+
+Changes with 0.6.0
+
+  *) Two styles of timeout --- hard and soft.  soft_timeout()s just put
+     the connection to the client in an "aborted" state, but otherwise
+     allow whatever handlers are running to clean up.  hard_timeout()s
+     abort the request in progress completely; anything not tied to some
+     resource pool cleanup will leak.  They're still around because I
+     haven't yet come up with a more elegant way of handling
+     timeouts when talking to something that isn't the client.  The
+     default_handler and the dir_handler now use soft timeouts, largely
+     so I can test the feature.  [Robert Thau]
+
+  *) TransferLog "| my_postprocessor ..." seems to be there.  Note that
+     the case of log handlers dying prematurely is probably handled VERY
+     gracelessly at this point, and if the logger stops reading input,
+     the server will hang.  (It is known to correctly restart the
+     logging process on server restart; this is (should be!) going through
+     the same SIGTERM/pause/SIGKILL routine used to ding an errant CGI
+     script).  [Robert Thau]
+
+  *) asis files supported (new module).  [Robert Thau]
+
+  *) IdentityCheck code is compiled in, but has not been tested.  (I
+     don't know anyone who runs identd). [Robert Thau]
+
+  *) PATH_INFO and PATH_TRANSLATED are not set unless some real PATH_INFO
+     came in with the request, for NCSA bug-compatibility. [Robert Thau]
+
+  *) Don't leak the DIR * on HEAD request for a directory. [Robert Thau]
+
+  *) Deleted the block_alarms() stuff from dbm_auth; no longer necessary,
+     as timeouts are not in scope. [Robert Thau]
+
+  *) quoted-string args in config files now handled correctly (doesn't drop
+     the last character). [Robert Thau; reported by Randy Terbush]
+
+  *) Fixed silly typo in http_main.c which was suddenly fatal in HP-UX.
+     How the hell did it ever work? [Robert Thau; reported by Rob Hartill]
+
+  *) mod_core.c --- default_type returns DEFAULT_TYPE (the compile-time
+     default default type); the former default default behavior when all
+     type-checkers defaulted had been a core dump.  [Paul Sutton]
+
+  *) Copy filenames out of the struct dirent when indexing
+     directories.  (On Linux, readdir() returns a pointer to the same
+     memory area every time).  Fix is in mod_dir.c.  [Paul Sutton]
+
+Changes with 0.5.3 [not released]
+
+  *) Default response handler notes "file not found" in the error log,
+     if the file was not found.  [Cliff Skolnick].
+
+  *) Another Cliff bug --- "GET /~user" now properly redirects (the userdir
+     code no longer sets up bogus PATH_INFO which fakes out the directory
+     handler). [Cliff Skolnick]
+
+Changes with 0.5.2
+
+  *) Changes to http_main.c --- root server no longer plays silly
+     games with SIGCHLD, and so now detects and replaces dying
+     children.  Child processes just die on SIGTERM, without taking
+     the whole process group with them.  Potential problem --- if any
+     child process refuses to die, we hang in restart.
+     MaxRequestsPerChild may still not work, but it certainly works
+     better than it did before this!  [Robert Thau]
+
+  *) mod_dir.c bug fixes: ReadmeName and HeaderName
+     work (or work better, at least); over-long description lines
+     properly terminated. [Mark Cox]
+
+  *) http_request.c now calls unescape_url() more places where it
+     should [Paul Sutton].
+
+  *) More directory handling bugs (reported by Cox)
+     Parent Directory link is now set correctly. [Robert Thau]
+
+Changes with 0.5.1: [Hopefully complete]
+
+  *) Generalized cleanup interface in alloc.c --- any function can be
+     registered with alloc.c as a cleanup for a resource pool;
+     tracking of files and file descriptors has been reimplemented in
+     terms of this interface, so I can give it some sort of a test.
+     [Robert Thau]
+
+  *) More changes in alloc.c --- new cleanup_for_exec() function,
+     which tracks down and closes all file descriptors which have been
+     registered with the alloc.c machinery before the server exec()s a
+     child process for CGI or <!--#exec-->.  CGI children now get
+     started with exactly three file descriptors open.  Hopefully,
+     this cures the problem Rob H. was having with overly persistent
+     CGI connections. [Robert Thau]
+
+  *) Mutual exclusion around the accept() in child_main() --- this is
+     required on at least SGI, Solaris and Linux, and is #ifdef'ed in
+     by default on those systems only (-DFCNTL_SERIALIZED_ACCEPT).
+     This uses fcntl(F_SETLK,...) on the error log descriptor because
+     flock() on that descriptor won't work on systems which have BSD
+     flock() semantics, including (I think) Linux 1.3 and Solaris.
+
+     This does work on SunOS (when the server is idle, only one
+     process in the pool is waiting on accept()); it *ought* to work
+     on the other systems. [Robert Thau]
+
+  *) FreeBSD and BSDI portability tweaks [Chuck Murcko]
+
+  *) sizeof(*sa_client) bugfix from [Rob Hartill]
+
+  *) pstrdup(..., NULL) returns NULL, [Randy Terbush]
+
+  *) block_alarms() to avoid leaking the DBM* in dbm auth (this should
+     be unnecessary if I go to the revised timeout-handling scheme).
+     [Robert Thau]
+
+  *) For NCSA bug-compatibility, set QUERY_STRING env var (to a null
+     string) even if none came in with the request.  [Robert Thau]
+
+  *) CHANGES file added to distribution ;-).
diff --git a/RELEASE_1_1_X/src/Configuration.tmpl b/RELEASE_1_1_X/src/Configuration.tmpl
new file mode 100644 (file)
index 0000000..bd29647
--- /dev/null
@@ -0,0 +1,272 @@
+# Config file for the Apache httpd.
+
+# Configuration.tmpl is the template for Configuration. Configuration should
+# be edited to select system type. Configuration.tmpl should only be changed
+# when a new system or module is added, or an existing one modified.
+
+# There are three types of lines here:
+
+# '#' comments, distinguished by having a '#' as the first non-blank character
+#
+# Lines which set a Make option --- these are simply copied into the Makefile
+#
+# Module selection lines, distinguished by having 'Module' at the front.
+# These list the configured modules, in priority order (highest priority
+# first).  They're down at the bottom.
+
+# First, ordinary compile-time configuration.
+
+# What to call the compiler:  For normal machines with ANSI compilers
+# CC= cc
+# For Suns or other non-ANSI platforms. Please make sure your gcc is
+# 2.0 or later, as 1.40 seems to create bad code for the Sun 4.
+CC= gcc
+
+# CFLAGS, compile flags.
+
+# -DMINIMAL_DNS is now obsolete. Use httpd.conf settings of
+# HostnameLookups on
+# or
+# HostnameLookups off
+#
+# If you want to have more secure hostname resolution at the cost of some 
+# performance, use -DMAXIMUM_DNS.
+# If you want setting the xbit of a file to cause it to be treated as
+# server-included HTML (unless it is a CGI script), say -DXBITHACK.  Note
+# that this is a run-time option, per-directory, either way (via the XBITHACK
+# command); this option only sets the default.
+
+# If you find that your OS can't cope with mmap (compiles OKAY but refuses
+# to run and moans "httpd: Could not mmap memory" .. or similar) try
+# disabling use of shared memory for process management (scoreboard with
+# -DNO_MMAP
+
+# Status Instrumentation
+# In order for the status module to obtain full statistics Apache must
+# be modified to keep track of various information.  This is not
+# turned on by default. In order to enable full status details add -DSTATUS 
+# to the end of the CFLAGS line below.
+
+# Using SOCKS
+# Apache can be compiled to work over a SOCKS firewall by 
+# adding the following string to your CFLAGS define:
+#
+#  -Dconnect=Rconnect -Dselect=Rselect -Dgethostbyname=Rgethostbyname
+#
+# and by adding the following to the EXTRA_LIBS define:
+#
+#  -L/usr/local/lib -lsocks
+#
+# making sure that -L points to wherever you've put libsocks.a.
+
+# [Some other former Apache compile-time options are now treated differently;
+#  the virtual host code is always present; DBM auth is an optional module, and
+#  may be configured out by changing the module config below, though it still
+#  defaults in.  Note that this config file does not include DBM auth by
+#  default --- configure it in below if you need it].
+
+CFLAGS= -O2
+
+# Place here any flags you may need upon linking, such as a flag to
+# prevent dynamic linking (if desired)
+LFLAGS= 
+
+# Place here any extra libraries you may need to link to. 
+# -lndbm is commonly required for DBM auth, if that is configured in.
+EXTRA_LIBS=
+
+# AUX_CFLAGS are system-specific control flags.
+# NOTE: IF YOU DO NOT CHOOSE ONE OF THESE, EDIT httpd.h AND CHOOSE
+# SETTINGS FOR THE SYSTEM FLAGS. IF YOU DON'T, BAD THINGS WILL HAPPEN.
+
+# For SunOS 4
+#AUX_CFLAGS= -DSUNOS4
+# For Solaris 2.
+#AUX_CFLAGS= -DSOLARIS2
+#AUX_LIBS= -lsocket -lnsl
+# For SGI IRIX. Use the AUX_LIBS line if you're using NIS and want
+# user-supported directories
+#AUX_CFLAGS= -DIRIX
+#AUX_LIBS= -lsun
+# For HP-UX       n.b. if you use the paid-for HP CC compiler, use flag -Ae
+#AUX_CFLAGS= -DHPUX
+# For AIX
+#AUX_CFLAGS= -DAIX -U__STR__
+# For Ultrix
+#AUX_CFLAGS= -DULTRIX
+# For DEC OSF/1
+#AUX_CFLAGS= -DOSF1
+# For NeXT
+#AUX_CFLAGS= -DNEXT
+# For Sequent
+#AUX_CFLAGS= -DSEQUENT
+# For Linux -m486 ONLY IF YOU HAVE 486 BINARY SUPPORT IN KERNEL
+#AUX_CFLAGS= -DLINUX
+# For A/UX
+#AUX_CFLAGS= -DAUX -D_POSIX_SOURCE
+#AUX_LIBS= -lposix -lbsd -s
+# For SCO ODT 3
+# libcrypt_i available from sosco.sco.com, files /SLS/lng225b.Z and
+# /SLS/lng225b.ltr.Z
+# the -Oe option causes cc to die compiling mod_imap (using 3.0.0a of the dev sys)
+#CFLAGS= -Oacgiltz
+#AUX_CFLAGS= -DSCO
+#AUX_LIBS= -lPW -lsocket -lmalloc -lcrypt_i
+# For SCO OpenServer Release 5
+# -K noinline is needed to work around an optimiser bug which appears in
+# http_bprintf.c
+#AUX_CFLAGS= -DSCO5
+#AUX_LIBS=-lsocket -lmalloc -lprot
+#BROKEN_BPRINTF_FLAGS=-K noinline
+# For SVR4
+# Some SVR4 implementations will require SO_LINGER option to be set in order
+# to guarantee buffer flushes. Dell, Esix, and UnixWare are a few of these.
+# Use -DNEED_LINGER in addition to other AUX_CFLAGS for these.
+#AUX_CFLAGS= -DSVR4
+#AUX_LIBS= -lsocket -lnsl -lc
+# For UnixWare 2.x, no longer just SVR4 (sigh) - use cc, not gcc
+# AUX_LIBS= -lsocket -lnsl -lcrypt
+# For Amdahl UTS 2.1
+# -Xa enables ANSI mode, -eft is expanded types
+#AUX_CFLAGS= -Xa -eft -DUTS21
+#AUX_LIBS= -lsocket -lbsd -la
+# For HP/Apollo Domain/OS
+#AUX_CFLAGS= -DAPOLLO
+# For NetBSD/FreeBSD/BSDI 2.x
+# -m486 only if you are running on Intel 486/586
+#AUX_CFLAGS= -m486
+# BSDI doesn't need -lcrypt
+#AUX_LIBS= -lcrypt
+# For QNX
+#AUX_CFLAGS= -DQNX
+#AUX_LFLAGS= -N 0x20000
+# For LynxOS
+#AUX_CFLAGS= -DLYNXOS
+#EXTRA_LIBS=-lbsd -ldes -lc_p
+# For DG/UX 5.4
+#AUX_CFLAGS= -DDGUX
+#AUX_LIBS=
+
+# For EMX OS/2 port
+#AUX_CFLAGS= -Zbsd-signals -Zbin-files
+#-DNO_KILLPG -DNEED_STRCASECMP -DNO_SETSID
+#-g
+#AUX_LIBS= -lsocket -llibufc -lgdbm -lbsd
+
+################################################################
+# Module configuration
+#
+# Modules are listed in reverse priority order --- the ones that come
+# later can override the behavior of those that come earlier.  This
+# can have visible effects; for instance, if UserDir followed Alias,
+# you couldn't alias out a particular user's home directory.
+
+# The configuration below is what we consider a decent default 
+# configuration.  If you want the functionality provided by a particular
+# module, remove the "#" sign at the beginning of the line. But remember, 
+# the more modules you compile into the server, the larger the executable
+# is and the more memory it will take, so if you are unlikely to use the
+# functionality of a particular module you might wish to leave it out.
+
+## Basic modules (i.e., generally useful stuff that works everyplace):
+## You should probably not comment out any of these unless you know what it
+## does and you know you won't need it.
+
+Module mime_module         mod_mime.o
+Module access_module       mod_access.o
+Module auth_module         mod_auth.o
+Module negotiation_module  mod_negotiation.o
+Module includes_module     mod_include.o
+Module dir_module          mod_dir.o
+Module cgi_module          mod_cgi.o
+Module userdir_module      mod_userdir.o
+Module alias_module        mod_alias.o
+Module env_module          mod_env.o
+Module common_log_module   mod_log_common.o
+
+## The asis module implemented ".asis" file types, which allow the embedding
+## of HTTP headers at the beginning of the document.  mod_imap handles internal 
+## imagemaps (no more cgi-bin/imagemap/!).  mod_actions is used to specify 
+## CGI scripts which act as "handlers" for particular files, for example to
+## automatically convert every GIF to another file type.
+
+Module asis_module         mod_asis.o
+Module imap_module         mod_imap.o
+Module action_module       mod_actions.o
+
+## Optional modules for NCSA user-agent/referer logging compatibility
+## We recommend, however, that you migrate to the configurable logging
+## module, below.
+
+# Module agent_log_module    mod_log_agent.o
+# Module referer_log_module  mod_log_referer.o
+
+## This is a *replacement* for mod_log_common which supports a
+## LogFormat directive which allows you to specify what goes into 
+## the TransferLog (if you want Referer, etc.)  source code for docs.
+##
+## If you play with this, remember to drop the standard
+## mod_log_common --- a server with both will work, but you'll get
+## very confused trying to figure out what's going on...
+
+# Module config_log_module   mod_log_config.o
+
+## cern_meta mimicks the behavior of the CERN web server with regards to 
+## metainformation files.  
+
+# Module cern_meta_module    mod_cern_meta.o
+
+## The status module allows the server to display current details about 
+## how well it is performing and what it is doing.  Consider also enabling 
+## -DSTATUS (see the CFLAGS section near the start of the file) to allow
+## full status information.  Check conf/access.conf on how to enable this.
+
+# Module status_module      mod_status.o
+
+## The Info module displays configuration information for the server and 
+## all included modules. It's very useful for debugging.
+
+# Module info_module         mod_info.o
+
+## Optional authentication modules. 
+##
+## The anon_auth module allows for anonymous-FTP-style username/ 
+## password authentication.
+
+# Module anon_auth_module    mod_auth_anon.o
+
+## db_auth and dbm_auth work with Berkeley DB files - make sure there
+## is support for DBM files on your system.  You may need to grab the GNU
+## "gdbm" package if not.
+
+# Module db_auth_module      mod_auth_db.o
+# Module dbm_auth_module     mod_auth_dbm.o
+
+## msql_auth checks against an MSQL database.  You must have MSQL installed
+## and an "msql.h" available for this to even compile.  Additionally,
+## you may need to add a couple entries to the CFLAGS line, like
+##
+##  -lmsql -L/usr/local/lib -L/usr/local/Minerva/lib
+##
+## This depends on your installation of MSQL.
+
+# Module msql_auth_module    mod_auth_msql.o
+
+## "digest" implements HTTP Digest Authentication rather than the less 
+## secure Basic Auth used by the other modules.
+
+# Module digest_module       mod_digest.o
+
+## Outright experiments --- mod_dld defines commands which
+## allows other modules to be loaded in at runtime, and mod_cookies
+## uses Netscape cookies to automatically construct and log accurate
+## click-trails from Netscape cookies, for Netscape-using clients who
+## aren't coming in via proxy.   
+
+# Module dld_module         mod_dld.o
+# Module cookies_module      mod_cookies.o
+
+## Finally, the proxy module.  It's not as complete as it could
+## be yet, so use at your own risk.
+
+# Module proxy_module        mod_proxy.o
diff --git a/RELEASE_1_1_X/src/Configure b/RELEASE_1_1_X/src/Configure
new file mode 100755 (executable)
index 0000000..d27cf4b
--- /dev/null
@@ -0,0 +1,85 @@
+#! /bin/sh
+
+# Apache configuration script, first cut --- rst.
+# Dont like it?  Inspired to do something better?  Go for it.
+
+file=Configuration
+tmpfile=htconf.$$
+
+if [ "x$1" = "x-file" ] ; then
+  echo "Using alternate config file $2"
+  file=$2 
+else
+  echo "Using '$file' as config file"
+fi
+
+# First, strip comments and blank lines...
+
+sed 's/#.*//' $file | sed '/^[         ]*$/d' | sed 's/[       ]*$//' > $tmpfile
+
+# Check for syntax errors...
+
+if grep -v = $tmpfile | \
+   egrep -v '^Module[  ]+[A-Za-z0-9_]+[        ]+[^    ]+$' > /dev/null
+then
+   echo "Syntax error --- each config file command must either"
+   echo "set a Makefile option, or configure a module (giving a"
+   echo "module name and a filename).  This doesn't appear to be"
+   echo "doing either:"
+   grep -v = $tmpfile | \
+      egrep -v '^Module[       ]+[A-Za-z0-9_]+[        ]+[^    ]+$'
+   rm $tmpfile
+   exit 1
+fi
+
+# File is OK --- make backup copies of things and then get the new ones:
+
+if [ -f Makefile ] ; then mv Makefile Makefile.bak; fi
+if [ -f modules.c ] ; then mv modules.c modules.c.bak; fi
+
+awk >modules.c <$tmpfile '\
+   BEGIN { modules[n++] = "core_module" } \
+   /^Module/ { modules[n++] = $2 } \
+   END { print "/* modules.c --- automatically generated by Apache"; \
+         print " * configuration script.  DO NOT HAND EDIT!!!!!"; \
+         print " */"; \
+         print ""; \
+        print "#include \"httpd.h\""; \
+        print "#include \"http_config.h\""; \
+         print ""; \
+         for (i = 0; i < n; ++i) { \
+             printf ("extern module %s;\n", modules[i]); \
+         } \
+         print ""; \
+         print "module *prelinked_modules[] = {"; \
+         for (i = 0; i < n; ++i) { \
+             printf "  &%s,\n", modules[i]; \
+         } \
+        print "  NULL"; \
+         print "};"; \
+         print "char *module_names[] = {"; \
+         for (i = n-1; i > -1; --i) { \
+             printf "  \"%s\",\n", modules[i]; \
+         } \
+       print "  NULL"; \
+         print "};"; \
+   }'
+
+awk >Makefile <$tmpfile '\
+   BEGIN { print "# Makefile automatically generated from Makefile.tmpl"; \
+          print "# and configuration file by Apache config script. "; \
+          print "# Hand-edited changes will be lost if the config script"; \
+          print "# is re-run."; \
+         } \
+   /^Module/ { modules[n++] = $3 } \
+   /\=/ { print } \
+   END { print "MODULES=\\"; \
+         for (i = 0; i < n; ++i) { \
+             if (i < n-1) printf ("  %s \\\n", modules[i]); \
+             else printf ("  %s\n", modules[i]); \
+         } \
+         print "" \
+       }'
+
+cat Makefile.tmpl >> Makefile
+rm $tmpfile
diff --git a/RELEASE_1_1_X/src/INSTALL b/RELEASE_1_1_X/src/INSTALL
new file mode 100644 (file)
index 0000000..ced55b8
--- /dev/null
@@ -0,0 +1,51 @@
+This release of Apache supports the notion of "optional modules".
+However, the server has to know which modules are compiled into it, in
+order for those modules to be effective; this requires generation of a
+short bit of code ("modules.c") which simply has a list of them.
+
+It is also necessary to choose the correct options for your platform.
+
+To do this:
+
+1) Copy the file "Configuration.tmpl" to "Configuration" and then edit
+   "Configuration".  This contains the per-machine config settings of
+   the Makefile, and also an additional section at the bottom which
+   lists the modules which have been compiled in, and also names the
+   files containing them.  You will need to:
+
+   a) Select a compiler, and compilation options as appropriate to
+      your machine.
+
+   b) Uncomment lines corresponding to those optional modules you wish
+      to include (among the Module lines at the bottom of the file),
+      or add new lines corresponding to custom modules you have written.
+      (See API.html for preliminary docs on how to do that).   
+
+      Note that DBM auth has to be explicitly configured in, if you want
+      it --- just uncomment the corresponding line.
+
+2) Run the "Configure" script:
+
+      % Configure
+      Using 'Configuration' as config file
+      %
+
+   This generates new versions of the Makefile and of modules.c.  (If
+   you want to maintain multiple configurations, you can say, e.g.,
+
+      % Configure -file Configuration.ai
+      Using alternate config file Configuration.ai
+      % 
+
+3) Type "make".
+
+The modules we place in the Apache distribution are the ones we have
+tested and are used regularly by various members of the Apache
+development group.  Additional modules contributed by members or third
+parties with specific needs or functions are available at
+<URL:http://www.apache.org/dist/contrib/modules/>.  There are
+instructions on that page for linking these modules into the
+core Apache code.
+
+
diff --git a/RELEASE_1_1_X/src/Makefile.tmpl b/RELEASE_1_1_X/src/Makefile.tmpl
new file mode 100644 (file)
index 0000000..3b57a2b
--- /dev/null
@@ -0,0 +1,80 @@
+# Apache makefile template (well, suffix).
+
+# This is combined with the information in the "Configuration" file
+# by the configure script to make the actual Makefile.
+
+OBJS= alloc.o http_main.o http_core.o http_config.o http_request.o \
+  http_log.o http_protocol.o rfc1413.o util.o util_script.o modules.o buff.o\
+  md5c.o util_md5.o explain.o http_bprintf.o $(MODULES)
+
+.c.o:
+       $(CC) -c $(CFLAGS) $(AUX_CFLAGS) $<
+
+all: Configuration httpd
+
+Configuration: Configuration.tmpl
+       @echo "Configuration older than Configuration.tmpl, or doesn't exist."
+       @echo "Consider copying Configuration.tmpl to Configuration, editing and rerunning"
+       @echo "Configure."
+       @echo "If not, you will at least have to touch Configuration."
+       @false
+
+httpd: $(OBJS)
+       $(CC) $(LFLAGS) $(AUX_LFLAGS) -o httpd $(OBJS) $(EXTRA_LIBS) $(AUX_LIBS)
+
+clean:
+       rm -f httpd $(OBJS) *pure*
+
+dist.tar: 
+       # Assure a semi-sensible configuration going out...
+       cp Makefile.orig Makefile
+       cp modules.c.orig modules.c
+       tar cvf dist.tar README INSTALL CHANGES TODO API.html \
+               Configuration Configure Makefile.tmpl Makefile *.h *.c
+
+# Work around broken compilers
+http_bprintf.o: http_bprintf.c
+       $(CC) -c $(CFLAGS) $(AUX_CFLAGS) $(BROKEN_BPRINTF_FLAGS) http_bprintf.c
+
+#Dependencies
+#Core code
+$(OBJS): Makefile httpd.h alloc.h buff.h conf.h
+
+http_config.o http_core.o http_main.o util.o: http_conf_globals.h
+http_config.o http_core.o http_main.o: http_config.h http_log.h
+http_log.o http_protocol.o http_request.o modules.o: http_config.h
+http_config.o http_core.o http_log.o http_main.o http_protocol.o: http_core.h
+http_request.o: http_core.h
+http_protocol.o http_request.o util_script.o rfc1413.o: http_log.h
+http_core.o http_main.o http_protocol.o http_request.o: http_main.h
+http_core.o http_main.o http_protocol.o http_request.o: http_protocol.h
+http_config.o http_main.o http_request.o: http_request.h
+http_main.o: scoreboard.h
+http_core.o rfc1413.o: rfc1413.h
+
+#Modules
+$(MODULES): http_config.h httpd.h
+mod_dld.o: http_conf_globals.h
+mod_ai_backcompat.o mod_auth.o mod_auth_dbm.o mod_cgi.o mod_dir.o: http_core.h
+mod_access.o mod_imap.o mod_include.o mod_negotiation.o: http_core.h
+mod_asis.o mod_auth.o mod_auth_dbm.o mod_cgi.o mod_dir.o: http_core.h
+mod_status.o mod_cookies.o mod_log_common.o: http_core.h
+mod_access.o mod_proxy.o mod_imap.o mod_include.o mod_negotiation.o: http_log.h
+mod_proxy.o mod_asis.o mod_cgi.o mod_dir.o mod_imap.o: http_main.h
+mod_status.o mod_include.o: http_main.h
+mod_proxy.o mod_asis.o mod_auth.o mod_auth_dbm.o mod_cgi.o: http_protocol.h
+mod_status.o mod_dir.o: http_protocol.h
+mod_imap.o mod_include.o: http_protocol.h
+mod_cgi.o mod_dir.o mod_imap.o mod_include.o mod_negotiation.o: http_request.h
+mod_proxy.o: md5.h
+mod_status.o: util_script.h
+mod_asis.o mod_cgi.o mod_dir.o mod_imap.o mod_include.o: util_script.h
+mod_digest.o: util_md5.h
+mod_status.o: scoreboard.h
+
+#Utils
+md5c.o: md5.h
+util.o: http_conf_globals.h
+util_script.o: http_core.h http_main.h http_protocol.h util_script.h
+util_md5.o: md5.h
+
diff --git a/RELEASE_1_1_X/src/README b/RELEASE_1_1_X/src/README
new file mode 100644 (file)
index 0000000..d1e6c1a
--- /dev/null
@@ -0,0 +1,219 @@
+The basic idea of the new Apache release is to make a modular
+"tinkertoy" server, to which people can easily add code which is
+valuable to them (even if it isn't universally useful) without hairing
+up a monolithic server.  Applications for this idea include database
+integration, support for experimental search and scripting extensions,
+new authentication modes (digest authentication, for instance, could
+be done entirely as a module), and so forth.  All modules have the
+same interface to the server core, and through it, to each other.
+
+In particular, the following are modules in the current code base:
+common log format (other loggers can easily coexist with it), auth and
+dbm auth (although both use common code in http_protocol.c to parse
+the Authorization: line), directory handling (which can be added or
+replaced), handling of aliases and access control, content
+negotiation, CGI, includes, aliases, and so forth.  (What's left in
+the basic server?  Not a whole lot).  The configuration file commands
+which configure these things are defined, for the most part, by the
+modules themselves, and not by the server core (each module has, or
+can have, a command dispatch table).
+
+Besides carving up the base code into modules, this release makes a
+few other fairly pervasive changes.  Most of the global variables are
+gone; most of the MAX_STRING_LENGTH char arrays are gone (the few that
+are left being sprintf() targets, or I/O buffers of various sorts),
+and unmunge_name has vanished.  The most drastic change is the use of
+a "compool" strategy to manage resources allocated for a request ---
+the code in alloc.c keeps track of it all and allows it to be freed en
+bloc at the end of the request.  This strategy seems to be effective
+in stanching memory and descriptor leaks.
+
+Additional third-party modules can be found at
+<URL:http://www.apache.org/dist/contrib/modules/>.
+
+
+A brief code review:
+
+The code here can be divided into the server core (the http_* files,
+along with alloc.c and the various utility files), and several modules
+(the mod_* files).
+
+The core interfaces to modules through the "module" structure which
+describes each one.  There's a linked list of these things rooted at
+top_module, through which http_config.c dispatches when necessary.  The
+module structures themselves are defined at the bottom of the mod_foo
+files.  (Loading new modules dynamically at runtime should be simple;
+just push them onto the linked list.  The only complication is what to
+do with AddModule commands when the config files are reread,
+particularly if you find a module has been taken out).
+
+In addition to the core itself (which does have a module structure to
+hold its command tables, and the handlers for various phases of
+request handling which make it *barely* a web server on its own),
+the modules included here are the following:
+
+mod_mime.c --- deduction of MIME types and content-encodings from
+  filename extensions.  This module defines the AddType, AddEncoding,
+  and TypesConfig config-file directives.  This code is off in a
+  module by itself so that people who want to experiment with other
+  meta-information schemes can replace it, and still have content
+  negotiation work.
+
+mod_common_log.c --- logging in common log format.
+
+mod_auth.c --- HTTP authentication.  Defines the AuthUserFile and
+  AuthGroupFile directives (other auth-related commands are handled by
+  the core itself, so it knows which requests require it to poll the
+  modules for authentication handlers).
+
+mod_auth_dbm.c --- DBM auth.  Untested, and left out of the modules
+  list in modules.c because of that, but it does at least compile.
+  Grump. 
+
+mod_access.c --- access checking by DNS name or IP address; defines
+  the "order", "allow" and "deny" config-file commands.  (If this
+  module is compiled out, the server fails safe --- any attempt to
+  configure access control will die on a config file syntax error when
+  the relevant commands go unrecognized).
+
+mod_negotiation.c --- Content negotiation.  Defines the
+  CacheNegotiatedDocs config-file command.  Making this a module is
+  perhaps going overboard, but I wanted to see how far I could push
+  it. 
+
+mod_alias.c --- Alias command and file translation.
+
+mod_userdir.c --- ditto for Userdir.
+
+mod_cgi.c --- Common Gateway Interface.  Also defines ScriptAlias,
+  because scripts are treated slightly differently depending on
+  whether they are ScriptAliased or not (in particular, ExecCGI is not
+  required in the former case).
+
+mod_includes.c --- server-side includes.
+
+mod_dir.c --- defines a whole *raft* of commands; handles directories.
+
+mod_asis.c --- ASIS file handling.
+
+mod_dld.c --- the experimental runtime-code-loader described above.
+  You'll have to alter the makefile and modules.c to make this active
+  if you want it.
+
+
+
+As to the core, here's a brief review of what's where:
+
+http_protocol.c --- functions for dealing directly with the client.
+  Reading requests, writing replies of various sorts.  I've tried to
+  route all data transfer between server and client through here, so
+  there's a single piece of code to change if we want to add, say,
+  HTTP-NG packetization.  The major glaring exception is NPH- CGI
+  scripts; what *will* we do with those for HTTP-NG?
+
+http_request.c --- functions which direct the processing of requests,
+  including error handling.  Generally responsible for making sure
+  that the right module handlers get invoked, in the right order.
+  (This includes the "sub-request" mechanism, which is used by
+  includes and other stuff to ask about the status of particular
+  subfiles).
+
+http_core.c --- 
+  Contains the core module structure, its command table, and the
+  command handlers, also the filename translation routine, and the
+  like for the core.  (Basically, this is all of the core module stuff
+  which looks more or less like the boilerplate from the other modules).
+
+http_config.c --- Functions to read config files and dispatch to the
+  command handlers; also, routines to manage configuration vectors,
+  and to dispatch to modules' handlers for the various phases of
+  handling a request.  
+
+http_log.c --- just the error log.  Error handling is split between
+  http_protocol.c (for generating the default error responses) and
+  http_request.c (for executive handling, including ErrorDocument
+  invocation); transaction logging is in the modules.
+
+http_main.c --- System startup, restart, and accepting connections;
+  also timeout handling (which is pretty grotesque right now; ideas?)
+
+alloc.c --- allocation of all resources which might have to be reclaimed
+  eventually, including memory, files, and child processes.
+
+ =================================================
+List of various #defines used in the code:
+The Apache code, specifically in conf.h, uses a variety of #defines to
+control how the code is compiled and what options are available for each
+support OS. The following list provides a short list and description
+of these #defines.
+
+--
+
+ NEED_*:
+  If the particular OS doesn't supply the specified function, we use the
+  Apache-supplied version (in util.c). 
+
+    NEED_STRERROR:
+    NEED_STRDUP:
+    NEED_STRCASECMP:
+    NEED_STRNCASECMP:
+    NEED_INITGROUPS:
+    NEED_WAITPID:
+    NEED_STRERROR:
+    NEED_SELECT_H:
+      Define if the OS needs the <sys/select.h> header file.
+
+--
+
+ HAVE_*:
+  Does this OS have/support this capablity?
+
+    HAS_GMTOFF:
+      Define if the OS's tm struct has the tm_gmtoff element
+
+    HAVE_RESOURCE:
+      Define as 1 if the OS supports the getrlimit()/setrlimit() functions
+
+    HAVE_MMAP:
+      Define if the OS supports the BSD mmap() call. This is used by various
+      OSs to allow the scoreboard file to be held in shared mmapped-memory
+      instead of a real file.
+
+    HAVE_SHMGET:
+      Define if the OS has the SysV-based shmget() family of shared-memory
+      functions. Used to allow the scoreboard to live in a shared-memory
+      slot instead of a real file.
+
+    HAVE_CRYPT_H:
+      Define if the OS has the <crypt.h> header file.
+
+--
+
+  NO_*:
+   These are defined if the OS does NOT have the specified function or if
+   we should not use it.
+
+      NO_KILLPG:
+      NO_SETSID:
+      NO_USE_SIGACTION:
+       Do not use the sigaction() call, even if we have it.
+--
+
+  MISC #DEFINES:
+   Various other #defines used in the code.
+
+     FCNTL_SERIALIZED_ACCEPT:
+      Define if the OS requires a mutex "lock" around the socket accept()
+      call. Use fcntl() locking.
+
+     FLOCK_SERIALIZED_ACCEPT:
+      Define if the OS requires a mutex "lock" around the socket accept()
+      call. Use flock() locking (fcntl() is expensive on some OSs, esp.
+      when using NFS).
+
+     JMP_BUF:
+      The variable-type for siglongjmp() or longjmp() call.
+
+     MOVEBREAK:
+      Amount to move sbrk() breakpoint, if required, before attaching
+      shared-memory segment.
diff --git a/RELEASE_1_1_X/src/TODO b/RELEASE_1_1_X/src/TODO
new file mode 100644 (file)
index 0000000..af09059
--- /dev/null
@@ -0,0 +1,45 @@
+*) Random stray failures to get_local_addr --- it's returning EINVAL, of all
+   things.  Are these clients aborting really, really early or what?
+
+*) Clean up inclusion stuff --- PATH_INFO in <!--#exec cgi-->, also
+   make sure that if the response handler sets an error code, then an
+   error report winds up on the output...
+
+*) More complete scoreboard for child processes.  For each process, at least:
+   number of requests handled, start time, current request (first line and
+   client and server addresses).  Also an httpstat program to print this all
+   out readably (thereby giving you your first real shot at figuring out what
+   that CGI script which has been chewing up all your CPU for the past few
+   minutes thinks it's actually doing...).
+
+*) Assess efficiency cost of rputc() in includes.
+
+*) Varargs printf-like log_reason (would allow me to ditch most of the
+   remaining instances of MAX_STRING_LENGTH).
+
+*) Byte ranges, as per recent Netscape/Franks I-D.
+
+*) Allow modules to request their own AllowOverrides and Options bits.
+   (If nothing else, will get rid of the last bit of directory-handling
+   lint in the core --- likewise for CGI and includes lint).
+
+*) -c command line option; processed as commands, *after* config files
+   (so -c "Port ..." can override).
+
+*) multiple util_files:  util_time, util_string, util_sys, util_misc (?).
+
+*) Look at multithreading... known problem areas:
+   need to throw a mutex around free-block management in alloc.c; need to
+   adjust timeout and SIGPIPE handling (who got the SIGPIPE?); need to
+   create new per-connection pools in main.c (as subpools of pconf,
+   presumably), rather than just using one global ptrans pool, and need
+   to triple-check that no thread will want to allocate in the same pool
+   as another that is simultaneously running.  Then we get to worry about
+   all the obscure C library functions that return pointers to static
+   data (the time stuff is particularly bad about this).
+
+   Oh yeah, the rfc931 code is nowhere near thread-safe (is it leak-safe?);
+   it has a single static jmp_buf, and returns a pointer to static data.
+
+*) Possible cleanup --- feed module functions their per-directory configuration
+   as a second argument, rather than making them fish it out of r->per_dir_....
diff --git a/RELEASE_1_1_X/src/ap/ap_md5c.c b/RELEASE_1_1_X/src/ap/ap_md5c.c
new file mode 100644 (file)
index 0000000..4ec60cb
--- /dev/null
@@ -0,0 +1,354 @@
+/*
+ * This is work is derived from material Copyright RSA Data Security, Inc.
+ *
+ * The RSA copyright statement and Licence for that original material is
+ * included below. This is followed by the Apache copyright statement and
+ * licence for the modifications made to that material.
+ */
+
+/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
+ */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+ */
+
+/* ====================================================================
+ * Copyright (c) 1996 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+#include <string.h>
+
+#include "md5.h"
+
+/* Constants for MD5Transform routine.
+ */
+
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+static void MD5Transform(UINT4 state[4], const unsigned char block[64]);
+static void Encode(unsigned char *output, const UINT4 *input,
+                  unsigned int len);
+static void Decode(UINT4 *output, const unsigned char *input,
+                  unsigned int len);
+
+static unsigned char PADDING[64] =
+{
+    0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* F, G, H and I are basic MD5 functions.
+ */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits.
+ */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+Rotation is separate from addition to prevent recomputation.
+ */
+#define FF(a, b, c, d, x, s, ac) { \
+ (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+  }
+#define GG(a, b, c, d, x, s, ac) { \
+ (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+  }
+#define HH(a, b, c, d, x, s, ac) { \
+ (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+  }
+#define II(a, b, c, d, x, s, ac) { \
+ (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+  }
+
+/* MD5 initialization. Begins an MD5 operation, writing a new context.
+ */
+void
+MD5Init(MD5_CTX *context)
+{
+    context->count[0] = context->count[1] = 0;
+  /* Load magic initialization constants. */
+    context->state[0] = 0x67452301;
+    context->state[1] = 0xefcdab89;
+    context->state[2] = 0x98badcfe;
+    context->state[3] = 0x10325476;
+}
+
+/* MD5 block update operation. Continues an MD5 message-digest
+  operation, processing another message block, and updating the
+  context.
+ */
+void
+MD5Update(MD5_CTX *context, const unsigned char *input, unsigned int inputLen)
+{
+    unsigned int i, index, partLen;
+
+  /* Compute number of bytes mod 64 */
+    index = (unsigned int)((context->count[0] >> 3) & 0x3F);
+
+  /* Update number of bits */
+    if ((context->count[0] += ((UINT4)inputLen << 3)) < ((UINT4)inputLen << 3))
+       context->count[1]++;
+    context->count[1] += (UINT4)inputLen >> 29;
+
+    partLen = 64 - index;
+
+  /* Transform as many times as possible. */
+    if (inputLen >= partLen)
+    {
+       memcpy(&context->buffer[index], input, partLen);
+       MD5Transform(context->state, context->buffer);
+
+       for (i = partLen; i + 63 < inputLen; i += 64)
+           MD5Transform(context->state, &input[i]);
+
+       index = 0;
+    }
+    else
+       i = 0;
+
+  /* Buffer remaining input */
+    memcpy(&context->buffer[index], &input[i], inputLen-i);
+}
+
+/* MD5 finalization. Ends an MD5 message-digest operation, writing the
+  the message digest and zeroizing the context.
+ */
+void
+MD5Final(unsigned char digest[16], MD5_CTX *context)
+{
+    unsigned char bits[8];
+    unsigned int index, padLen;
+
+  /* Save number of bits */
+    Encode (bits, context->count, 8);
+
+  /* Pad out to 56 mod 64. */
+    index = (unsigned int)((context->count[0] >> 3) & 0x3f);
+    padLen = (index < 56) ? (56 - index) : (120 - index);
+    MD5Update(context, PADDING, padLen);
+
+  /* Append length (before padding) */
+    MD5Update(context, bits, 8);
+
+  /* Store state in digest */
+    Encode(digest, context->state, 16);
+
+  /* Zeroize sensitive information. */
+    memset(context, 0, sizeof (*context));
+}
+
+/* MD5 basic transformation. Transforms state based on block. */
+static void
+MD5Transform(UINT4 state[4], const unsigned char block[64])
+{
+    UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+
+    Decode (x, block, 64);
+
+  /* Round 1 */
+    FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
+    FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
+    FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
+    FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
+    FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
+    FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
+    FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
+    FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
+    FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
+    FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
+    FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+    FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+    FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+    FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+    FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+    FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+    
+ /* Round 2 */
+    GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
+    GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
+    GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+    GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
+    GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
+    GG (d, a, b, c, x[10], S22,  0x2441453); /* 22 */
+    GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+    GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
+    GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
+    GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+    GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
+    GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
+    GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+    GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
+    GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
+    GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+    
+  /* Round 3 */
+    HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
+    HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
+    HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+    HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+    HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
+    HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
+    HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
+    HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+    HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+    HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
+    HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
+    HH (b, c, d, a, x[ 6], S34,  0x4881d05); /* 44 */
+    HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
+    HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+    HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+    HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
+
+  /* Round 4 */
+    II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
+    II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
+    II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+    II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
+    II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+    II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
+    II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+    II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
+    II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
+    II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+    II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
+    II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+    II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
+    II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+    II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
+    II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
+
+    state[0] += a;
+    state[1] += b;
+    state[2] += c;
+    state[3] += d;
+
+  /* Zeroize sensitive information. */
+    memset(x, 0, sizeof (x));
+}
+
+/* Encodes input (UINT4) into output (unsigned char). Assumes len is
+  a multiple of 4.
+ */
+static void
+Encode(unsigned char *output, const UINT4 *input, unsigned int len)
+{
+    unsigned int i, j;
+    UINT4 k;
+
+    for (i = 0, j = 0; j < len; i++, j += 4)
+    {
+       k = input[i];
+       output[j] = (unsigned char)(k & 0xff);
+       output[j+1] = (unsigned char)((k >> 8) & 0xff);
+       output[j+2] = (unsigned char)((k >> 16) & 0xff);
+       output[j+3] = (unsigned char)((k >> 24) & 0xff);
+    }
+}
+
+/* Decodes input (unsigned char) into output (UINT4). Assumes len is
+  a multiple of 4.
+ */
+static void
+Decode(UINT4 *output, const unsigned char *input, unsigned int len)
+{
+    unsigned int i, j;
+
+    for (i = 0, j = 0; j < len; i++, j += 4)
+       output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
+           (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
+}
diff --git a/RELEASE_1_1_X/src/include/alloc.h b/RELEASE_1_1_X/src/include/alloc.h
new file mode 100644 (file)
index 0000000..c65b3af
--- /dev/null
@@ -0,0 +1,242 @@
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * Resource allocation routines...
+ *
+ * designed so that we don't have to keep track of EVERYTHING so that
+ * it can be explicitly freed later (a fundamentally unsound strategy ---
+ * particularly in the presence of die()).
+ *
+ * Instead, we maintain pools, and allocate items (both memory and I/O
+ * handlers) from the pools --- currently there are two, one for per
+ * transaction info, and one for config info.  When a transaction is over,
+ * we can delete everything in the per-transaction pool without fear, and
+ * without thinking too hard about it either.
+ *
+ * rst
+ */
+
+/* Arenas for configuration info and transaction info
+ * --- actual layout of the pool structure is private to 
+ * alloc.c.  
+ */
+
+typedef struct pool pool;
+
+extern pool *permanent_pool;
+void init_alloc();             /* Set up everything */
+pool *make_sub_pool (pool *);  /* All pools are subpools of permanent_pool */
+void destroy_pool (pool *);
+
+/* Clearing out EVERYTHING in an pool... destroys any sub-pools */
+
+void clear_pool (struct pool *);
+
+/* Preparing for exec() --- close files, etc., but *don't* flush I/O
+ * buffers, *don't* wait for subprocesses, and *don't* free any memory.
+ */
+
+void cleanup_for_exec ();
+
+/* routines to allocate memory from an pool... */
+
+void *palloc(struct pool *, int nbytes);
+void *pcalloc(struct pool *, int nbytes);
+extern char *pstrdup(struct pool *, const char *s);
+extern char *pstrndup(struct pool *, const char *s, int n);
+char *pstrcat(struct pool *, ...); /* all '...' must be char* */
+
+/* array and alist management... keeping lists of things.
+ * Common enough to want common support code ...
+ */
+
+typedef struct {
+    pool *pool;
+    int elt_size;
+    int nelts;
+    int nalloc;
+    char *elts;
+} array_header;
+
+array_header *make_array (pool *p, int nelts, int elt_size);
+void *push_array (array_header *);
+void array_cat (array_header *dst, array_header *src);
+array_header *append_arrays (pool *, array_header *, array_header *);
+
+/* copy_array copies the *entire* array.  copy_array_hdr just copies
+ * the header, and arranges for the elements to be copied if (and only
+ * if) the code subsequently does a push or arraycat.
+ */
+     
+array_header *copy_array (pool *p, array_header *src);
+array_header *copy_array_hdr (pool *p, array_header *src);
+                          
+
+/* Tables.  Implemented alist style, for now, though we try to keep
+ * it so that imposing a hash table structure on top in the future
+ * wouldn't be *too* hard...
+ *
+ * Note that key comparisons for these are case-insensitive, largely
+ * because that's what's appropriate and convenient everywhere they're
+ * currently being used...
+ */
+
+typedef array_header table;     
+     
+typedef struct {
+    char *key;                 /* maybe NULL in future;
+                                * check when iterating thru table_elts
+                                */
+    char *val;
+} table_entry;
+
+table *make_table (pool *p, int nelts);
+table *copy_table (pool *p, table *);     
+char *table_get (table *, char *);
+void table_set (table *, const char *name, const char *val);
+void table_merge (table *, char *name, char *more_val);
+void table_unset (table *, char *key);
+void table_add (table *, char *name, char *val);
+
+table *overlay_tables (pool *p, table *overlay, table *base);     
+
+array_header *table_elts (table *);     
+
+/* routines to remember allocation of other sorts of things...
+ * generic interface first.  Note that we want to have two separate
+ * cleanup functions in the general case, one for exec() preparation,
+ * to keep CGI scripts and the like from inheriting access to things
+ * they shouldn't be able to touch, and one for actually cleaning up,
+ * when the actual server process wants to get rid of the thing,
+ * whatever it is.  
+ *
+ * kill_cleanup disarms a cleanup, presumably because the resource in
+ * question has been closed, freed, or whatever, and it's scarce
+ * enough to want to reclaim (e.g., descriptors).  It arranges for the
+ * resource not to be cleaned up a second time (it might have been
+ * reallocated).  run_cleanup does the same, but runs it first.
+ *
+ * Cleanups are identified for purposes of finding & running them off by the
+ * plain_cleanup and data, which should presumably be unique.
+ *
+ * NB any code which invokes register_cleanup or kill_cleanup directly
+ * is a critical section which should be guarded by block_alarms() and
+ * unblock_alarms() below...
+ */
+
+void register_cleanup (pool *p, void *data,
+                      void (*plain_cleanup)(void *),
+                      void (*child_cleanup)(void *));
+
+void kill_cleanup (pool *p, void *data, void (*plain_cleanup)(void *));
+
+/* The time between when a resource is actually allocated, and when it
+ * its cleanup is registered is a critical section, during which the
+ * resource could leak if we got interrupted or timed out.  So, anything
+ * which registers cleanups should bracket resource allocation and the
+ * cleanup registry with these.  (This is done internally by run_cleanup).
+ *
+ * NB they are actually implemented in http_main.c, since they are bound
+ * up with timeout handling in general...
+ */
+
+extern void block_alarms();
+extern void unblock_alarms();
+
+/* Common cases which want utility support..
+ * the note_cleanups_for_foo routines are for 
+ */
+
+FILE *pfopen(struct pool *, char *name, char *fmode);
+FILE *pfdopen(struct pool *, int fd, char *fmode);
+int popenf(struct pool *, char *name, int flg, int mode); 
+
+void note_cleanups_for_file (pool *, FILE *);
+void note_cleanups_for_fd (pool *, int);
+
+/* routines to note closes... file descriptors are constrained enough
+ * on some systems that we want to support this.
+ */
+
+int pfclose(struct pool *, FILE *);
+int pclosef(struct pool *, int fd);
+
+/* ... even child processes (which we may want to wait for,
+ * or to kill outright, on unexpected termination).
+ *
+ * spawn_child is a utility routine which handles an awful lot of
+ * the rigamarole associated with spawning a child --- it arranges
+ * for pipes to the child's stdin and stdout, if desired (if not,
+ * set the associated args to NULL).  It takes as args a function
+ * to call in the child, and an argument to be passed to the function.
+ */
+     
+enum kill_conditions { kill_never, kill_always, kill_after_timeout, just_wait};
+
+int spawn_child (pool *, void (*)(void *), void *,
+                enum kill_conditions, FILE **pipe_in, FILE **pipe_out);
+#ifdef __EMX__
+int spawn_child_os2 (pool *, void (*)(void *), void *,
+         enum kill_conditions, FILE **pipe_in, FILE **pipe_out, char *buffer, int lenp);
+#endif
+
+/* magic numbers --- only one so far, min free bytes in a new pool block */
+
+#define BLOCK_MINFREE 8192     
+
+/* Finally, some accounting */
+
+long bytes_in_pool(pool *p);
+long bytes_in_free_blocks();
diff --git a/RELEASE_1_1_X/src/include/ap_config.h b/RELEASE_1_1_X/src/include/ap_config.h
new file mode 100644 (file)
index 0000000..fef4055
--- /dev/null
@@ -0,0 +1,511 @@
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * conf.h: system-dependant #defines and includes...
+ * See README for a listing of what they mean
+ */
+
+#ifndef QNX
+#include <sys/param.h>
+#endif
+
+/* Define one of these according to your system. */
+#if defined(SUNOS4)
+#define HAS_GMTOFF
+#define HAVE_RESOURCE 1
+#undef NO_KILLPG
+#undef NO_SETSID
+char *crypt(char *pw, char *salt);
+#define JMP_BUF sigjmp_buf
+#define HAVE_MMAP
+#include <sys/time.h>     
+#define NEED_STRERROR
+
+#elif defined(SOLARIS2)
+#undef HAS_GMTOFF
+#define NO_KILLPG
+#undef NO_SETSID
+#define HAVE_RESOURCE 1
+#define bzero(a,b) memset(a,0,b)
+#define getwd(d) getcwd(d,MAX_STRING_LEN)
+#define JMP_BUF sigjmp_buf
+#define FCNTL_SERIALIZED_ACCEPT
+#define HAVE_MMAP
+#define HAVE_CRYPT_H
+
+#elif defined(IRIX)
+#undef HAS_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+#define JMP_BUF sigjmp_buf
+#define FCNTL_SERIALIZED_ACCEPT
+#define HAVE_SHMGET
+#define HAVE_CRYPT_H
+#elif defined(HPUX)
+#define HAVE_RESOURCE 1
+#undef HAS_GMTOFF
+#define NO_KILLPG
+#undef NO_SETSID
+#ifndef _HPUX_SOURCE
+#define _HPUX_SOURCE
+#endif
+#define getwd(d) getcwd(d,MAX_STRING_LEN)
+#define JMP_BUF sigjmp_buf
+#define HAVE_MMAP
+
+#elif defined(AIX)
+#undef HAS_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+#define NEED_SELECT_H
+#define JMP_BUF sigjmp_buf
+
+#elif defined(ULTRIX)
+#define HAS_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+#define ULTRIX_BRAIN_DEATH
+#define NEED_STRDUP
+/* If you have Ultrix 4.3, and are using cc, const is broken */
+#ifndef __ultrix__ /* Hack to check for pre-Ultrix 4.4 cc */
+#define const /* Not implemented */
+#endif
+#define JMP_BUF sigjmp_buf
+
+#elif defined(OSF1)
+#define HAS_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+#define JMP_BUF sigjmp_buf
+#define HAVE_MMAP
+#define HAVE_CRYPT_H
+
+#elif defined(SEQUENT)
+#define HAS_GMTOFF
+#undef NO_KILLPG
+#define NO_SETSID
+#define NEED_STRDUP
+#define tolower(c) (isupper(c) ? tolower(c) : c)
+
+#elif defined(NEXT)
+#include <libc.h>
+typedef unsigned short mode_t;
+#define HAS_GMTOFF
+#undef NO_KILLPG
+#define NO_SETSID
+#define NEED_STRDUP
+#undef _POSIX_SOURCE
+#ifndef FD_CLOEXEC
+#define FD_CLOEXEC 1
+#endif
+#ifndef S_ISDIR
+#define S_ISDIR(m)      (((m)&(S_IFMT)) == (S_IFDIR))
+#endif
+#ifndef S_ISREG
+#define S_ISREG(m)      (((m)&(S_IFMT)) == (S_IFREG))
+#endif
+#ifndef S_IXUSR
+#define S_IXUSR 00100
+#endif
+#ifndef S_IRGRP
+#define S_IRGRP 00040
+#endif
+#ifndef S_IXGRP
+#define S_IXGRP 00010
+#endif
+#ifndef S_IROTH
+#define S_IROTH 00004
+#endif
+#ifndef S_IXOTH
+#define S_IXOTH 00001
+#endif
+#ifndef S_IRUSR
+#define S_IRUSR S_IREAD
+#endif
+#ifndef S_IWUSR
+#define S_IWUSR S_IWRITE
+#endif
+#define STDIN_FILENO  0
+#define STDOUT_FILENO 1
+#define STDERR_FILENO 2
+#define waitpid(a,b,c) wait4(a,(union wait *)b,c,NULL)
+typedef int pid_t;
+#define JMP_BUF jmp_buf
+#define NO_USE_SIGACTION
+
+#elif defined(LINUX)
+#undef HAS_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+#undef NEED_STRDUP
+#define JMP_BUF sigjmp_buf
+#define FCNTL_SERIALIZED_ACCEPT
+#include <sys/time.h>     
+
+#elif defined(SCO)
+#undef HAS_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+#define NEED_INITGROUPS
+#define JMP_BUF sigjmp_buf
+#define SIGURG SIGUSR1 /* but note, this signal will be sent to a process group if enabled (for OOB data). It is not currently enabled. */
+#define getwd(d) getcwd(d,MAX_STRING_LEN)
+
+#elif defined(SCO5)
+
+#define JMP_BUF sigjmp_buf
+#define SIGURG SIGUSR1
+#define NEED_SELECT_H
+#define FCNTL_SERIALIZED_ACCEPT
+#define HAVE_MMAP
+#define SecureWare
+
+/* Although SCO 5 defines these in <strings.h> (note the "s") they don't have
+consts. Sigh. */
+extern int strcasecmp(const char *,const char *);
+extern int strncasecmp(const char *,const char *,unsigned);
+
+#elif defined(CONVEXOS)
+#define HAS_GMTOFF
+#define NEED_STRDUP
+#define getwd(d) getcwd(d,MAX_STRING_LEN)
+
+#elif defined(AUX)
+#undef HAS_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+#define NEED_STRDUP
+#define JMP_BUF sigjmp_buf
+/* fcntl() locking is expensive with NFS */
+#undef FLOCK_SERIALIZED_ACCEPT
+#define HAVE_SHMGET
+#define MOVEBREAK              0x4000000
+/* These are to let -Wall compile more cleanly */
+extern int strcasecmp(const char *, const char *);
+extern int strncasecmp(const char *,const char *,unsigned);
+
+#elif defined(SVR4)
+#define NO_KILLPG
+#undef  NO_SETSID
+#undef NEED_STRDUP
+#define NEED_STRCASECMP
+#define NEED_STRNCASECMP
+#define bzero(a,b) memset(a,0,b)
+#define JMP_BUF sigjmp_buf
+#define getwd(d) getcwd(d,MAX_STRING_LEN)
+/* A lot of SVR4 systems need this */
+#define FCNTL_SERIALIZED_ACCEPT
+
+#elif defined(DGUX)
+#define NO_KILLPG
+#undef  NO_SETSID
+#undef NEED_STRDUP
+#define NEED_STRCASECMP
+#define NEED_STRNCASECMP
+#define bzero(a,b) memset(a,0,b)
+#define JMP_BUF sigjmp_buf
+#define getwd(d) getcwd(d,MAX_STRING_LEN)
+/* A lot of SVR4 systems need this */
+#define FCNTL_SERIALIZED_ACCEPT
+
+#elif defined(__NetBSD__)
+#define HAS_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+#define JMP_BUF sigjmp_buf
+
+#elif defined(UTS21)
+#undef HAS_GMTOFF
+#undef NO_KILLPG
+#define NO_SETSID
+#define NEED_WAITPID
+#define STDIN_FILENO 0
+#define STDOUT_FILENO 1
+#define STDERR_FILENO 2
+#define strftime(buf,bufsize,fmt,tm)    ascftime(buf,fmt,tm)
+#include <sys/types.h>
+
+#elif defined(APOLLO)
+#undef HAS_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+#define timezone       _bky_timezone
+
+#elif defined(__FreeBSD__) || defined(__bsdi__)
+#define HAS_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+#define JMP_BUF sigjmp_buf
+#define HAVE_MMAP
+
+#elif defined(QNX)
+#undef NO_KILLPG
+#undef NO_SETSID
+#define NEED_INITGROUPS
+#define NEED_SELECT_H
+#define JMP_BUF sigjmp_buf
+
+#elif defined(LYNXOS)
+#undef NO_KILLPG
+#undef NO_SETSID
+#define NO_TIMEZONE
+#define NEED_STRCASECMP
+#define NEED_STRNCASECMP
+#define NEED_INITGROUPS
+#define JMP_BUF jmp_buf
+
+#elif defined(__EMX__)
+/* Defines required for EMX OS/2 port. */
+#define JMP_BUF sigjmp_buf
+#define NO_KILLPG
+#define NEED_STRCASECMP
+#define NEED_STRNCASECMP
+#define NO_SETSID
+/* Add some drive name support */
+#define chdir _chdir2
+
+/* Unknown system - Edit these to match */
+#else
+#ifdef BSD
+#define HAS_GMTOFF
+#else
+#undef HAS_GMTOFF
+#endif
+/* NO_KILLPG is set on systems that don't have killpg */
+#undef NO_KILLPG
+/* NO_SETSID is set on systems that don't have setsid */
+#undef NO_SETSID
+/* NEED_STRDUP is set on stupid systems that don't have strdup. */
+#undef NEED_STRDUP
+#endif
+
+/* Do we have sys/resource.h; assume that BSD does. */
+#ifndef HAVE_RESOURCE
+#ifdef BSD
+#define HAVE_RESOURCE 1
+#else
+#define HAVE_RESOURCE 0
+#endif
+#endif /* HAVE_RESOURCE */
+
+/*
+ * The particular directory style your system supports. If you have dirent.h
+ * in /usr/include (POSIX) or /usr/include/sys (SYSV), #include 
+ * that file and define DIR_TYPE to be dirent. Otherwise, if you have 
+ * /usr/include/sys/dir.h, define DIR_TYPE to be direct and include that
+ * file. If you have neither, I'm confused.
+ */
+
+#include <sys/types.h>
+
+#if !defined(NEXT) && !defined(CONVEXOS)
+#include <dirent.h>
+#define DIR_TYPE dirent
+#else
+#include <sys/dir.h>
+#define DIR_TYPE direct
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <sys/socket.h>
+#ifdef NEED_SELECT_H
+#include <sys/select.h>
+#endif
+#include <ctype.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <sys/ioctl.h>
+#include <arpa/inet.h>  /* for inet_ntoa */
+#include <time.h>  /* for ctime */
+#include <signal.h>
+#include <errno.h>
+#include <sys/wait.h>
+#include <pwd.h>
+#include <grp.h>
+#include <fcntl.h>
+#include <limits.h>
+#ifndef QNX
+#include <memory.h>
+#endif
+
+#if HAVE_RESOURCE
+#include <sys/resource.h>
+#ifdef SUNOS4
+int getrlimit( int, struct rlimit *);
+int setrlimit( int, struct rlimit *);
+#endif
+#endif
+#ifdef HAVE_MMAP
+#include <sys/mman.h>
+#endif
+#if !defined(MAP_ANON) && defined(MAP_ANONYMOUS)
+#define MAP_ANON MAP_ANONYMOUS
+#endif
+
+#if defined(HAVE_MMAP) && defined(NO_MMAP)
+#undef HAVE_MMAP
+#endif
+
+#ifndef LOGNAME_MAX
+#define LOGNAME_MAX 25
+#endif
+
+#ifndef NEXT
+#include <unistd.h>
+#endif
+
+#ifdef ultrix
+#define ULTRIX_BRAIN_DEATH
+#endif
+
+#ifndef S_ISLNK
+#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
+#endif
+
+/* Finding offsets of elements within structures.
+ * Taken from the X code... they've sweated portability of this stuff
+ * so we don't have to.  Sigh...
+ */
+
+#if defined(CRAY) || defined(__arm)
+#if __STDC__
+#define XtOffset(p_type,field) _Offsetof(p_type,field)
+#else
+#ifdef CRAY2
+#define XtOffset(p_type,field) \
+       (sizeof(int)*((unsigned int)&(((p_type)NULL)->field)))
+
+#else  /* !CRAY2 */
+
+#define XtOffset(p_type,field) ((unsigned int)&(((p_type)NULL)->field))
+
+#endif /* !CRAY2 */
+#endif  /* __STDC__ */
+#else  /* ! (CRAY || __arm) */
+
+#define XtOffset(p_type,field) \
+       ((long) (((char *) (&(((p_type)NULL)->field))) - ((char *) NULL)))
+
+#endif /* !CRAY */
+
+#ifdef offsetof
+#define XtOffsetOf(s_type,field) offsetof(s_type,field)
+#else
+#define XtOffsetOf(s_type,field) XtOffset(s_type*,field)
+#endif
+
+#ifdef SUNOS_LIB_PROTOTYPES
+/* Prototypes needed to get a clean compile with gcc -Wall.
+ * Believe it or not, these do have to be declared, at least on SunOS,
+ * because they aren't mentioned in the relevant system headers.
+ * Sun Quality Software.  Gotta love it.
+ */
+
+int getopt (int, char **, char *);
+
+int strcasecmp (char *, char *);
+int strncasecmp (char *, char *, int);
+int toupper(int);
+int tolower(int);     
+     
+int printf (char *, ...);     
+int fprintf (FILE *, char *, ...);
+int fputs (char *, FILE *);
+int fread (char *, int, int, FILE *);     
+int fwrite (char *, int, int, FILE *);     
+int fflush (FILE *);
+int fclose (FILE *);
+int ungetc (int, FILE *);
+int _filbuf (FILE *);          /* !!! */
+int _flsbuf (unsigned char, FILE *); /* !!! */
+int sscanf (char *, char *, ...);
+void setbuf (FILE *, char *);
+void perror (char *);
+     
+time_t time (time_t *);
+int strftime (char *, int, char *, struct tm *);
+     
+int initgroups (char *, int);     
+int wait3 (int *, int, void*); /* Close enough for us... */
+int lstat (const char *, struct stat *);
+int stat (const char *, struct stat *);     
+int flock (int, int);
+int getwd (char *);
+#ifndef NO_KILLPG
+int killpg(int, int);
+#endif
+int socket (int, int, int);     
+int setsockopt (int, int, int, const char*, int);
+int listen (int, int);     
+int bind (int, struct sockaddr *, int);     
+int connect (int, struct sockaddr *, int);
+int accept (int, struct sockaddr *, int *);
+int shutdown (int, int);     
+
+int getsockname (int s, struct sockaddr *name, int *namelen);
+int getpeername (int s, struct sockaddr *name, int *namelen);
+int gethostname (char *name, int namelen);     
+void syslog (int, char *, ...);
+char *mktemp (char *);
+     
+#include <stdarg.h>
+long vfprintf (FILE *, char *, va_list);
+     
+#endif
diff --git a/RELEASE_1_1_X/src/include/buff.h b/RELEASE_1_1_X/src/include/buff.h
new file mode 100644 (file)
index 0000000..bb432ee
--- /dev/null
@@ -0,0 +1,127 @@
+/* ====================================================================
+ * Copyright (c) 1996 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+#include <stdarg.h>
+
+/* Reading is buffered */
+#define B_RD     (1)
+/* Writing is buffered */
+#define B_WR     (2)
+#define B_RDWR   (3)
+/* At end of file, or closed stream; no further input allowed */
+#define B_EOF    (4)
+/* No further output possible */
+#define B_EOUT   (8)
+/* A read error has occurred */
+#define B_RDERR (16)
+/* A write error has occurred */
+#define B_WRERR (32)
+#define B_ERROR (48)
+
+typedef struct buff_struct BUFF;
+
+struct buff_struct
+{
+    int flags;             /* flags */
+    unsigned char *inptr;  /* pointer to next location to read */
+    int incnt;             /* number of bytes left to read from input buffer;
+                           * always 0 if had a read error  */
+    int outcnt;            /* number of byte put in output buffer */
+    unsigned char *inbase;
+    unsigned char *outbase;
+    int bufsiz;
+    void (*error)(BUFF *fb, int op, void *data);
+    void *error_data;
+    long int bytes_sent;   /* number of bytes actually written */
+
+    pool *pool;
+
+/* could also put pointers to the basic I/O routines here */
+    int fd;                /* the file descriptor */
+    int fd_in;             /* input file descriptor, if different */
+};
+
+/* Options to bset/getopt */
+#define BO_BYTECT (1)
+
+/* Stream creation and modification */
+extern BUFF *bcreate(pool *p, int flags);
+extern void bpushfd(BUFF *fb, int fd_in, int fd_out);
+extern int bsetopt(BUFF *fb, int optname, const void *optval);
+extern int bgetopt(BUFF *fb, int optname, void *optval);
+extern int bclose(BUFF *fb);
+
+/* Error handling */
+extern void bonerror(BUFF *fb, void (*error)(BUFF *, int, void *),
+                    void *data);
+
+/* I/O */
+extern int bread(BUFF *fb, void *buf, int nbyte);
+extern int bgets(char *s, int n, BUFF *fb);
+extern int bskiplf(BUFF *fb);
+extern int bwrite(BUFF *fb, const void *buf, int nbyte);
+extern int bflush(BUFF *fb);
+extern int bputs(const char *x, BUFF *fb);
+extern int bvputs(BUFF *fb, ...);
+extern int bprintf(BUFF *fb,const char *fmt,...);
+extern int vbprintf(BUFF *fb,const char *fmt,va_list vlist);
+
+/* Internal routines */
+extern int bflsbuf(int c, BUFF *fb);
+extern int bfilbuf(BUFF *fb);
+
+#define bgetc(fb)   ( ((fb)->incnt == 0) ? bfilbuf(fb) : \
+                   ((fb)->incnt--, *((fb)->inptr++)) )
+
+#define bputc(c, fb) ((((fb)->flags & (B_EOUT|B_WRERR|B_WR)) != B_WR || \
+                    (fb)->outcnt == (fb)->bufsiz) ? bflsbuf(c, (fb)) : \
+                    ((fb)->outbase[(fb)->outcnt++] = (c), 0))
diff --git a/RELEASE_1_1_X/src/include/conf.h b/RELEASE_1_1_X/src/include/conf.h
new file mode 100644 (file)
index 0000000..fef4055
--- /dev/null
@@ -0,0 +1,511 @@
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * conf.h: system-dependant #defines and includes...
+ * See README for a listing of what they mean
+ */
+
+#ifndef QNX
+#include <sys/param.h>
+#endif
+
+/* Define one of these according to your system. */
+#if defined(SUNOS4)
+#define HAS_GMTOFF
+#define HAVE_RESOURCE 1
+#undef NO_KILLPG
+#undef NO_SETSID
+char *crypt(char *pw, char *salt);
+#define JMP_BUF sigjmp_buf
+#define HAVE_MMAP
+#include <sys/time.h>     
+#define NEED_STRERROR
+
+#elif defined(SOLARIS2)
+#undef HAS_GMTOFF
+#define NO_KILLPG
+#undef NO_SETSID
+#define HAVE_RESOURCE 1
+#define bzero(a,b) memset(a,0,b)
+#define getwd(d) getcwd(d,MAX_STRING_LEN)
+#define JMP_BUF sigjmp_buf
+#define FCNTL_SERIALIZED_ACCEPT
+#define HAVE_MMAP
+#define HAVE_CRYPT_H
+
+#elif defined(IRIX)
+#undef HAS_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+#define JMP_BUF sigjmp_buf
+#define FCNTL_SERIALIZED_ACCEPT
+#define HAVE_SHMGET
+#define HAVE_CRYPT_H
+#elif defined(HPUX)
+#define HAVE_RESOURCE 1
+#undef HAS_GMTOFF
+#define NO_KILLPG
+#undef NO_SETSID
+#ifndef _HPUX_SOURCE
+#define _HPUX_SOURCE
+#endif
+#define getwd(d) getcwd(d,MAX_STRING_LEN)
+#define JMP_BUF sigjmp_buf
+#define HAVE_MMAP
+
+#elif defined(AIX)
+#undef HAS_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+#define NEED_SELECT_H
+#define JMP_BUF sigjmp_buf
+
+#elif defined(ULTRIX)
+#define HAS_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+#define ULTRIX_BRAIN_DEATH
+#define NEED_STRDUP
+/* If you have Ultrix 4.3, and are using cc, const is broken */
+#ifndef __ultrix__ /* Hack to check for pre-Ultrix 4.4 cc */
+#define const /* Not implemented */
+#endif
+#define JMP_BUF sigjmp_buf
+
+#elif defined(OSF1)
+#define HAS_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+#define JMP_BUF sigjmp_buf
+#define HAVE_MMAP
+#define HAVE_CRYPT_H
+
+#elif defined(SEQUENT)
+#define HAS_GMTOFF
+#undef NO_KILLPG
+#define NO_SETSID
+#define NEED_STRDUP
+#define tolower(c) (isupper(c) ? tolower(c) : c)
+
+#elif defined(NEXT)
+#include <libc.h>
+typedef unsigned short mode_t;
+#define HAS_GMTOFF
+#undef NO_KILLPG
+#define NO_SETSID
+#define NEED_STRDUP
+#undef _POSIX_SOURCE
+#ifndef FD_CLOEXEC
+#define FD_CLOEXEC 1
+#endif
+#ifndef S_ISDIR
+#define S_ISDIR(m)      (((m)&(S_IFMT)) == (S_IFDIR))
+#endif
+#ifndef S_ISREG
+#define S_ISREG(m)      (((m)&(S_IFMT)) == (S_IFREG))
+#endif
+#ifndef S_IXUSR
+#define S_IXUSR 00100
+#endif
+#ifndef S_IRGRP
+#define S_IRGRP 00040
+#endif
+#ifndef S_IXGRP
+#define S_IXGRP 00010
+#endif
+#ifndef S_IROTH
+#define S_IROTH 00004
+#endif
+#ifndef S_IXOTH
+#define S_IXOTH 00001
+#endif
+#ifndef S_IRUSR
+#define S_IRUSR S_IREAD
+#endif
+#ifndef S_IWUSR
+#define S_IWUSR S_IWRITE
+#endif
+#define STDIN_FILENO  0
+#define STDOUT_FILENO 1
+#define STDERR_FILENO 2
+#define waitpid(a,b,c) wait4(a,(union wait *)b,c,NULL)
+typedef int pid_t;
+#define JMP_BUF jmp_buf
+#define NO_USE_SIGACTION
+
+#elif defined(LINUX)
+#undef HAS_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+#undef NEED_STRDUP
+#define JMP_BUF sigjmp_buf
+#define FCNTL_SERIALIZED_ACCEPT
+#include <sys/time.h>     
+
+#elif defined(SCO)
+#undef HAS_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+#define NEED_INITGROUPS
+#define JMP_BUF sigjmp_buf
+#define SIGURG SIGUSR1 /* but note, this signal will be sent to a process group if enabled (for OOB data). It is not currently enabled. */
+#define getwd(d) getcwd(d,MAX_STRING_LEN)
+
+#elif defined(SCO5)
+
+#define JMP_BUF sigjmp_buf
+#define SIGURG SIGUSR1
+#define NEED_SELECT_H
+#define FCNTL_SERIALIZED_ACCEPT
+#define HAVE_MMAP
+#define SecureWare
+
+/* Although SCO 5 defines these in <strings.h> (note the "s") they don't have
+consts. Sigh. */
+extern int strcasecmp(const char *,const char *);
+extern int strncasecmp(const char *,const char *,unsigned);
+
+#elif defined(CONVEXOS)
+#define HAS_GMTOFF
+#define NEED_STRDUP
+#define getwd(d) getcwd(d,MAX_STRING_LEN)
+
+#elif defined(AUX)
+#undef HAS_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+#define NEED_STRDUP
+#define JMP_BUF sigjmp_buf
+/* fcntl() locking is expensive with NFS */
+#undef FLOCK_SERIALIZED_ACCEPT
+#define HAVE_SHMGET
+#define MOVEBREAK              0x4000000
+/* These are to let -Wall compile more cleanly */
+extern int strcasecmp(const char *, const char *);
+extern int strncasecmp(const char *,const char *,unsigned);
+
+#elif defined(SVR4)
+#define NO_KILLPG
+#undef  NO_SETSID
+#undef NEED_STRDUP
+#define NEED_STRCASECMP
+#define NEED_STRNCASECMP
+#define bzero(a,b) memset(a,0,b)
+#define JMP_BUF sigjmp_buf
+#define getwd(d) getcwd(d,MAX_STRING_LEN)
+/* A lot of SVR4 systems need this */
+#define FCNTL_SERIALIZED_ACCEPT
+
+#elif defined(DGUX)
+#define NO_KILLPG
+#undef  NO_SETSID
+#undef NEED_STRDUP
+#define NEED_STRCASECMP
+#define NEED_STRNCASECMP
+#define bzero(a,b) memset(a,0,b)
+#define JMP_BUF sigjmp_buf
+#define getwd(d) getcwd(d,MAX_STRING_LEN)
+/* A lot of SVR4 systems need this */
+#define FCNTL_SERIALIZED_ACCEPT
+
+#elif defined(__NetBSD__)
+#define HAS_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+#define JMP_BUF sigjmp_buf
+
+#elif defined(UTS21)
+#undef HAS_GMTOFF
+#undef NO_KILLPG
+#define NO_SETSID
+#define NEED_WAITPID
+#define STDIN_FILENO 0
+#define STDOUT_FILENO 1
+#define STDERR_FILENO 2
+#define strftime(buf,bufsize,fmt,tm)    ascftime(buf,fmt,tm)
+#include <sys/types.h>
+
+#elif defined(APOLLO)
+#undef HAS_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+#define timezone       _bky_timezone
+
+#elif defined(__FreeBSD__) || defined(__bsdi__)
+#define HAS_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+#define JMP_BUF sigjmp_buf
+#define HAVE_MMAP
+
+#elif defined(QNX)
+#undef NO_KILLPG
+#undef NO_SETSID
+#define NEED_INITGROUPS
+#define NEED_SELECT_H
+#define JMP_BUF sigjmp_buf
+
+#elif defined(LYNXOS)
+#undef NO_KILLPG
+#undef NO_SETSID
+#define NO_TIMEZONE
+#define NEED_STRCASECMP
+#define NEED_STRNCASECMP
+#define NEED_INITGROUPS
+#define JMP_BUF jmp_buf
+
+#elif defined(__EMX__)
+/* Defines required for EMX OS/2 port. */
+#define JMP_BUF sigjmp_buf
+#define NO_KILLPG
+#define NEED_STRCASECMP
+#define NEED_STRNCASECMP
+#define NO_SETSID
+/* Add some drive name support */
+#define chdir _chdir2
+
+/* Unknown system - Edit these to match */
+#else
+#ifdef BSD
+#define HAS_GMTOFF
+#else
+#undef HAS_GMTOFF
+#endif
+/* NO_KILLPG is set on systems that don't have killpg */
+#undef NO_KILLPG
+/* NO_SETSID is set on systems that don't have setsid */
+#undef NO_SETSID
+/* NEED_STRDUP is set on stupid systems that don't have strdup. */
+#undef NEED_STRDUP
+#endif
+
+/* Do we have sys/resource.h; assume that BSD does. */
+#ifndef HAVE_RESOURCE
+#ifdef BSD
+#define HAVE_RESOURCE 1
+#else
+#define HAVE_RESOURCE 0
+#endif
+#endif /* HAVE_RESOURCE */
+
+/*
+ * The particular directory style your system supports. If you have dirent.h
+ * in /usr/include (POSIX) or /usr/include/sys (SYSV), #include 
+ * that file and define DIR_TYPE to be dirent. Otherwise, if you have 
+ * /usr/include/sys/dir.h, define DIR_TYPE to be direct and include that
+ * file. If you have neither, I'm confused.
+ */
+
+#include <sys/types.h>
+
+#if !defined(NEXT) && !defined(CONVEXOS)
+#include <dirent.h>
+#define DIR_TYPE dirent
+#else
+#include <sys/dir.h>
+#define DIR_TYPE direct
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <sys/socket.h>
+#ifdef NEED_SELECT_H
+#include <sys/select.h>
+#endif
+#include <ctype.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <sys/ioctl.h>
+#include <arpa/inet.h>  /* for inet_ntoa */
+#include <time.h>  /* for ctime */
+#include <signal.h>
+#include <errno.h>
+#include <sys/wait.h>
+#include <pwd.h>
+#include <grp.h>
+#include <fcntl.h>
+#include <limits.h>
+#ifndef QNX
+#include <memory.h>
+#endif
+
+#if HAVE_RESOURCE
+#include <sys/resource.h>
+#ifdef SUNOS4
+int getrlimit( int, struct rlimit *);
+int setrlimit( int, struct rlimit *);
+#endif
+#endif
+#ifdef HAVE_MMAP
+#include <sys/mman.h>
+#endif
+#if !defined(MAP_ANON) && defined(MAP_ANONYMOUS)
+#define MAP_ANON MAP_ANONYMOUS
+#endif
+
+#if defined(HAVE_MMAP) && defined(NO_MMAP)
+#undef HAVE_MMAP
+#endif
+
+#ifndef LOGNAME_MAX
+#define LOGNAME_MAX 25
+#endif
+
+#ifndef NEXT
+#include <unistd.h>
+#endif
+
+#ifdef ultrix
+#define ULTRIX_BRAIN_DEATH
+#endif
+
+#ifndef S_ISLNK
+#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
+#endif
+
+/* Finding offsets of elements within structures.
+ * Taken from the X code... they've sweated portability of this stuff
+ * so we don't have to.  Sigh...
+ */
+
+#if defined(CRAY) || defined(__arm)
+#if __STDC__
+#define XtOffset(p_type,field) _Offsetof(p_type,field)
+#else
+#ifdef CRAY2
+#define XtOffset(p_type,field) \
+       (sizeof(int)*((unsigned int)&(((p_type)NULL)->field)))
+
+#else  /* !CRAY2 */
+
+#define XtOffset(p_type,field) ((unsigned int)&(((p_type)NULL)->field))
+
+#endif /* !CRAY2 */
+#endif  /* __STDC__ */
+#else  /* ! (CRAY || __arm) */
+
+#define XtOffset(p_type,field) \
+       ((long) (((char *) (&(((p_type)NULL)->field))) - ((char *) NULL)))
+
+#endif /* !CRAY */
+
+#ifdef offsetof
+#define XtOffsetOf(s_type,field) offsetof(s_type,field)
+#else
+#define XtOffsetOf(s_type,field) XtOffset(s_type*,field)
+#endif
+
+#ifdef SUNOS_LIB_PROTOTYPES
+/* Prototypes needed to get a clean compile with gcc -Wall.
+ * Believe it or not, these do have to be declared, at least on SunOS,
+ * because they aren't mentioned in the relevant system headers.
+ * Sun Quality Software.  Gotta love it.
+ */
+
+int getopt (int, char **, char *);
+
+int strcasecmp (char *, char *);
+int strncasecmp (char *, char *, int);
+int toupper(int);
+int tolower(int);     
+     
+int printf (char *, ...);     
+int fprintf (FILE *, char *, ...);
+int fputs (char *, FILE *);
+int fread (char *, int, int, FILE *);     
+int fwrite (char *, int, int, FILE *);     
+int fflush (FILE *);
+int fclose (FILE *);
+int ungetc (int, FILE *);
+int _filbuf (FILE *);          /* !!! */
+int _flsbuf (unsigned char, FILE *); /* !!! */
+int sscanf (char *, char *, ...);
+void setbuf (FILE *, char *);
+void perror (char *);
+     
+time_t time (time_t *);
+int strftime (char *, int, char *, struct tm *);
+     
+int initgroups (char *, int);     
+int wait3 (int *, int, void*); /* Close enough for us... */
+int lstat (const char *, struct stat *);
+int stat (const char *, struct stat *);     
+int flock (int, int);
+int getwd (char *);
+#ifndef NO_KILLPG
+int killpg(int, int);
+#endif
+int socket (int, int, int);     
+int setsockopt (int, int, int, const char*, int);
+int listen (int, int);     
+int bind (int, struct sockaddr *, int);     
+int connect (int, struct sockaddr *, int);
+int accept (int, struct sockaddr *, int *);
+int shutdown (int, int);     
+
+int getsockname (int s, struct sockaddr *name, int *namelen);
+int getpeername (int s, struct sockaddr *name, int *namelen);
+int gethostname (char *name, int namelen);     
+void syslog (int, char *, ...);
+char *mktemp (char *);
+     
+#include <stdarg.h>
+long vfprintf (FILE *, char *, va_list);
+     
+#endif
diff --git a/RELEASE_1_1_X/src/include/explain.h b/RELEASE_1_1_X/src/include/explain.h
new file mode 100644 (file)
index 0000000..5912502
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef EXPLAIN
+#define DEF_Explain
+#define Explain0(f)
+#define Explain1(f,a1)
+#define Explain2(f,a1,a2)
+#define Explain3(f,a1,a2,a3)
+#define Explain4(f,a1,a2,a3,a4)
+#define Explain5(f,a1,a2,a3,a4,a5)
+#define Explain6(f,a1,a2,a3,a4,a5,a6)
+#else
+#define DEF_Explain    static const char *__ExplainFile=__FILE__;
+void _Explain(const char *szFile,int nLine,const char *szFmt,...);
+#define Explain0(f)    _Explain(__ExplainFile,__LINE__,f)
+#define Explain1(f,a1) _Explain(__ExplainFile,__LINE__,f,a1)
+#define Explain2(f,a1,a2)      _Explain(__ExplainFile,__LINE__,f,a1,a2)
+#define Explain3(f,a1,a2,a3)   _Explain(__ExplainFile,__LINE__,f,a1,a2,a3)
+#define Explain4(f,a1,a2,a3,a4)        _Explain(__ExplainFile,__LINE__,f,a1,a2,a3,a4)
+#define Explain5(f,a1,a2,a3,a4,a5)     \
+                       _Explain(__ExplainFile,__LINE__,f,a1,a2,a3,a4,a5)
+#define Explain6(f,a1,a2,a3,a4,a5,a6)  \
+                       _Explain(__ExplainFile,__LINE__,f,a1,a2,a3,a4,a5,a6)
+
+#endif
diff --git a/RELEASE_1_1_X/src/include/http_conf_globals.h b/RELEASE_1_1_X/src/include/http_conf_globals.h
new file mode 100644 (file)
index 0000000..6bdcac5
--- /dev/null
@@ -0,0 +1,83 @@
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/* 
+ * Process config --- what the process ITSELF is doing
+ */
+
+extern int standalone;
+extern uid_t user_id;
+extern char *user_name;
+extern gid_t group_id;
+extern int max_requests_per_child;
+extern struct in_addr bind_address;
+extern listen_rec *listeners;
+extern int daemons_to_start;
+extern int daemons_min_free;
+extern int daemons_max_free;
+extern int daemons_limit;
+
+extern char *pid_fname;
+extern char *scoreboard_fname;
+extern char *server_argv0;
+
+/* Trying to allocate these in the config pool gets us into some *nasty*
+ * chicken-and-egg problems in http_main.c --- where do you stick them
+ * when pconf gets cleared?  Better to just allocate a little space
+ * statically...
+ */
+
+extern char server_root[MAX_STRING_LEN];
+extern char server_confname[MAX_STRING_LEN];
+
diff --git a/RELEASE_1_1_X/src/include/http_config.h b/RELEASE_1_1_X/src/include/http_config.h
new file mode 100644 (file)
index 0000000..7228e4b
--- /dev/null
@@ -0,0 +1,260 @@
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * The central data structures around here...
+ */
+
+/* Command dispatch structures... */
+
+enum cmd_how {
+  RAW_ARGS,                    /* cmd_func parses command line itself */
+  TAKE1,                       /* one argument only */
+  TAKE2,                       /* two arguments only */
+  ITERATE,                     /* one argument, occuring multiple times
+                                * (e.g., IndexIgnore)
+                                */
+  ITERATE2,                    /* two arguments, 2nd occurs multiple times
+                                * (e.g., AddIcon)
+                                */
+  FLAG,                                /* One of 'On' or 'Off' */
+  NO_ARGS                      /* No args at all, e.g. </Directory> */
+};
+
+typedef struct command_struct {
+  char *name;                  /* Name of this command */
+  char *(*func)();             /* Function invoked */
+  void *cmd_data;              /* Extra data, for functions which
+                                * implement multiple commands...
+                                */
+  int req_override;            /* What overrides need to be allowed to
+                                * enable this command.
+                                */
+  enum cmd_how args_how;       /* What the command expects as arguments */
+  
+  char *errmsg;                        /* 'usage' message, in case of syntax errors */
+} command_rec;
+
+/* Values for the req_override slot */
+
+#define OR_NONE 0
+#define OR_LIMIT 1
+#define OR_OPTIONS 2
+#define OR_FILEINFO 4
+#define OR_AUTHCFG 8
+#define OR_INDEXES 16
+#define OR_UNSET 32
+#define ACCESS_CONF 64         /* command valid in access.conf */
+#define RSRC_CONF 128          /* command valid in srm.conf */
+#define OR_ALL (OR_LIMIT|OR_OPTIONS|OR_FILEINFO|OR_AUTHCFG|OR_INDEXES)
+
+/*
+ * This structure is passed to a command which is being invoked,
+ * to carry a large variety of miscellaneous data which is all of
+ * use to *somebody*...
+ */
+
+typedef struct {
+    void *info;                        /* Argument to command from cmd_table */
+    int override;              /* Which allow-override bits are set */
+    int limited;               /* Which methods are <Limit>ed */
+    
+    char *config_file;         /* Filename cmd read from */
+    int config_line;           /* Line cmd read from */
+    FILE *infile;              /* fd for more lines (not currently used) */
+    
+    pool *pool;                        /* Pool to allocate new storage in */
+    pool *temp_pool;           /* Pool for scratch memory; persists during
+                                * configuration, but wiped before the first
+                                * request is served...
+                                */
+    server_rec *server;                /* Server_rec being configured for */
+    char *path;                        /* If configuring for a directory,
+                                * pathname of that directory.
+                                */
+} cmd_parms;
+
+/* This structure records the existence of handlers in a module... */
+
+typedef struct {
+    char *content_type;
+    int (*handler) ();
+} handler_rec;
+
+/*
+ * Module structures.  Just about everything is dispatched through
+ * these, directly or indirectly (through the command and handler
+ * tables).
+ */
+
+typedef struct module_struct {
+    int version;               /* API version, *not* module version;
+                                * check that module is compatible with this
+                                * version of the server.
+                                */
+    int module_index;          /* Index to this modules structures in
+                                * config vectors.
+                                */
+    struct module_struct *next;
+
+#ifdef ULTRIX_BRAIN_DEATH
+    void (*init)();
+    void *(*create_dir_config)();
+    void *(*merge_dir_config)();
+    void *(*create_server_config)();
+    void *(*merge_server_config)();
+#else
+    void (*init)(server_rec *, pool *);
+    void *(*create_dir_config)(pool *p, char *dir);
+    void *(*merge_dir_config)(pool *p, void *base_conf, void *new_conf);
+    void *(*create_server_config)(pool *p, server_rec *s);
+    void *(*merge_server_config)(pool *p, void *base_conf, void *new_conf);
+#endif
+
+    command_rec *cmds;
+    handler_rec *handlers;
+
+    /* Hooks for getting into the middle of server ops...
+     *
+     * translate_handler --- translate URI to filename
+     * access_checker --- check access by host address, etc.   All of these
+     *                    run; if all decline, that's still OK.
+     * check_user_id --- get and validate user id from the HTTP request
+     * auth_checker --- see if the user (from check_user_id) is OK *here*.
+     *                  If all of *these* decline, the request is rejected
+     *                  (as a SERVER_ERROR, since the module which was
+     *                  supposed to handle this was configured wrong).
+     * type_checker --- Determine MIME type of the requested entity;
+     *                  sets content_type, _encoding and _language fields.
+     * logger --- log a transaction.  Not supported yet out of sheer
+     *            laziness on my part.
+     */
+    
+    int (*translate_handler)(request_rec *);
+    int (*check_user_id)(request_rec *);
+    int (*auth_checker)(request_rec *);
+    int (*access_checker)(request_rec *);
+    int (*type_checker)(request_rec *);
+    int (*fixer_upper)(request_rec *);
+    int (*logger)(request_rec *);
+} module;
+
+/* Initializer for the first few module slots, which are only
+ * really set up once we start running.  Note that the first word
+ * is a version check; this should allow us to deal with changes to
+ * the API (the server can detect an old-format module, and either
+ * handle it back-compatibly, or at least signal an error).
+ */
+
+#define MODULE_MAGIC_NUMBER 19960526
+#define STANDARD_MODULE_STUFF MODULE_MAGIC_NUMBER, 0, NULL
+
+/* Generic accessors for other modules to get at their own module-specific
+ * data
+ */
+
+void *get_module_config (void *conf_vector, module *m);
+void set_module_config (void *conf_vector, module *m, void *val);     
+     
+/* Generic command handling function... */
+
+char *set_string_slot (cmd_parms *, char *, char *);
+
+/* For modules which need to read config files, open logs, etc. ...
+ * this returns the fname argument if it begins with '/'; otherwise
+ * it relativizes it wrt server_root.
+ */
+
+char *server_root_relative (pool *p, char *fname);
+     
+/* Finally, the hook for dynamically loading modules in... */
+
+void add_module (module *m);
+
+#ifdef CORE_PRIVATE
+
+/* For http_main.c... */
+
+server_rec *read_config (pool *conf_pool, pool *temp_pool, char *config_name);
+void setup_prelinked_modules();
+
+/* For http_request.c... */
+
+void *create_request_config (pool *p);
+void *create_per_dir_config (pool *p);
+void *merge_per_dir_configs (pool *p, void *base, void *new);
+
+/* For http_core.c... (<Directory> command and virtual hosts) */
+
+int parse_htaccess(void **result, request_rec *r, int override,
+                  char *path, char *file);
+char *srm_command_loop (cmd_parms *parms, void *config);
+
+server_rec *init_virtual_host (pool *p, char *hostname);
+int is_virtual_server (server_rec *);
+void process_resource_config(server_rec *s, char *fname, pool *p, pool *ptemp);
+
+/* Module-method dispatchers, also for http_request.c */
+
+int translate_name (request_rec *);
+int directory_walk (request_rec *); /* check symlinks, get per-dir config */
+int check_access (request_rec *); /* check access on non-auth basis */
+int check_user_id (request_rec *); /* obtain valid username from client auth */
+int check_auth (request_rec *); /* check (validated) user is authorized here */
+int find_types (request_rec *);        /* identify MIME type */
+int run_fixups (request_rec *);        /* poke around for other metainfo, etc.... */
+int invoke_handler (request_rec *);     
+int log_transaction (request_rec *r);
+     
+#endif
diff --git a/RELEASE_1_1_X/src/include/http_core.h b/RELEASE_1_1_X/src/include/http_core.h
new file mode 100644 (file)
index 0000000..2af40db
--- /dev/null
@@ -0,0 +1,174 @@
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*****************************************************************
+ *
+ * The most basic server code is encapsulated in a single module
+ * known as the core, which is just *barely* functional enough to
+ * serve documents, though not terribly well.
+ *
+ * Largely for NCSA back-compatibility reasons, the core needs to
+ * make pieces of its config structures available to other modules.
+ * The accessors are declared here, along with the interpretation
+ * of one of them (allow_options).
+ */
+
+#define OPT_NONE 0
+#define OPT_INDEXES 1
+#define OPT_INCLUDES 2
+#define OPT_SYM_LINKS 4
+#define OPT_EXECCGI 8
+#define OPT_UNSET 16
+#define OPT_INCNOEXEC 32
+#define OPT_SYM_OWNER 64
+#define OPT_MULTI 128
+#define OPT_ALL (OPT_INDEXES|OPT_INCLUDES|OPT_SYM_LINKS|OPT_EXECCGI)
+
+/* options for get_remote_host() */
+#define REMOTE_HOST (0)
+#define REMOTE_NAME (1)
+
+int allow_options (request_rec *);
+int allow_overrides (request_rec *);
+char *default_type (request_rec *);     
+char *document_root (request_rec *); /* Don't use this!  If your request went
+                                     * through a Userdir, or something like
+                                     * that, it'll screw you.  But it's
+                                     * back-compatible...
+                                     */
+extern const char *get_remote_host(conn_rec *conn, void *dir_config, int type);
+extern const char *get_remote_logname(request_rec *r);
+     
+/* Authentication stuff.  This is one of the places where compatibility
+ * with the old config files *really* hurts; they don't discriminate at
+ * all between different authentication schemes, meaning that we need
+ * to maintain common state for all of them in the core, and make it
+ * available to the other modules through interfaces.
+ */
+    
+typedef struct {
+    int method_mask;
+    char *requirement;
+} require_line;
+     
+char *auth_type (request_rec *);
+char *auth_name (request_rec *);     
+array_header *requires (request_rec *);    
+
+#ifdef CORE_PRIVATE
+
+/*
+ * Core is also unlike other modules in being implemented in more than
+ * one file... so, data structures are declared here, even though most of
+ * the code that cares really is in http_core.c.  Also, anothre accessor.
+ */
+
+char *response_code_string (request_rec *r, int error_index);
+
+extern module core_module;
+
+/* Per-directory configuration */
+
+typedef char allow_options_t;
+typedef char overrides_t;
+
+typedef struct {
+    char *d;
+    allow_options_t opts;
+    overrides_t override;
+    
+    /* MIME typing --- the core doesn't do anything at all with this,
+     * but it does know what to slap on a request for a document which
+     * goes untyped by other mechanisms before it slips out the door...
+     */
+    
+    char *default_type;
+  
+    /* Authentication stuff.  Groan... */
+    
+    char *auth_type;
+    char *auth_name;
+    array_header *requires;
+
+    int content_md5;
+    
+    /* Custom response config. These can contain text or a URL to redirect to.
+     */
+  
+    char *response_code_strings[RESPONSE_CODES+1];
+
+    /* Hostname resolution etc */
+    int hostname_lookups;
+    int do_rfc1413;   /* See if client is advertising a username? */
+
+} core_dir_config;
+
+/* Per-server core configuration */
+
+typedef struct {
+  
+    /* Name translations --- we want the core to be able to do *something*
+     * so it's at least a minimally functional web server on its own (and
+     * can be tested that way).  But let's keep it to the bare minimum:
+     */
+    char *document_root;
+  
+    /* Access control */
+  
+    char *access_name;
+    array_header *sec;
+    array_header *sec_url;
+} core_server_config;
+
+#endif
diff --git a/RELEASE_1_1_X/src/include/http_log.h b/RELEASE_1_1_X/src/include/http_log.h
new file mode 100644 (file)
index 0000000..32fd4c4
--- /dev/null
@@ -0,0 +1,64 @@
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+void open_logs (server_rec *, pool *p);
+void error_log2stderr (server_rec *);     
+
+void log_pid (pool *p, char *pid_fname);
+void log_error(char *err, server_rec *s);
+extern void log_unixerr(const char *routine, const char *file,
+                       const char *msg, server_rec *s);
+void log_printf(const server_rec *s, const char *fmt, ...);
+void log_reason(char *reason, char *fname, request_rec *r);
+
diff --git a/RELEASE_1_1_X/src/include/http_main.h b/RELEASE_1_1_X/src/include/http_main.h
new file mode 100644 (file)
index 0000000..30aea73
--- /dev/null
@@ -0,0 +1,99 @@
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * Routines in http_main.c which other code --- in particular modules ---
+ * may want to call.  Right now, that's limited to timeout handling.
+ * There are two functions which modules can call to trigger a timeout
+ * (with the per-virtual-server timeout duration); these are hard_timeout
+ * and soft_timeout.
+ *
+ * The difference between the two is what happens when the timeout
+ * expires (or earlier than that, if the client connection aborts) ---
+ * a soft_timeout just puts the connection to the client in an
+ * "aborted" state, which will cause http_protocol.c to stop trying to
+ * talk to the client, but otherwise allows the code to continue normally.
+ * hard_timeout(), by contrast, logs the request, and then aborts it
+ * completely --- longjmp()ing out to the accept() loop in http_main.
+ * Any resources tied into the request's resource pool will be cleaned up;
+ * everything that isn't will leak.
+ *
+ * soft_timeout() is recommended as a general rule, because it gives your
+ * code a chance to clean up.  However, hard_timeout() may be the most
+ * convenient way of dealing with timeouts waiting for some external
+ * resource other than the client, if you can live with the restrictions.
+ *
+ * (When a hard timeout is in scope, critical sections can be guarded
+ * with block_alarms() and unblock_alarms() --- these are declared in
+ * alloc.c because they are most often used in conjunction with
+ * routines to allocate something or other, to make sure that the
+ * cleanup does get registered before any alarm is allowed to happen
+ * which might require it to be cleaned up; they * are, however,
+ * implemented in http_main.c).
+ *
+ * kill_timeout() will disarm either variety of timeout.
+ *
+ * reset_timeout() resets the timeout in progress.
+ */
+
+void hard_timeout (char *, request_rec *);
+void soft_timeout (char *, request_rec *);
+void kill_timeout (request_rec *);     
+void reset_timeout (request_rec *);
+
+void sync_scoreboard_image ();
+int update_child_status (int child_num, int status, request_rec *r);
+int get_child_status (int child_num);
+int count_busy_servers ();
+int count_idle_servers ();
diff --git a/RELEASE_1_1_X/src/include/http_protocol.h b/RELEASE_1_1_X/src/include/http_protocol.h
new file mode 100644 (file)
index 0000000..c468739
--- /dev/null
@@ -0,0 +1,173 @@
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * Prototypes for routines which either talk directly back to the user,
+ * or control the ones that eventually do.
+ */
+
+/* Read a request and fill in the fields. */
+
+request_rec *read_request (conn_rec *c);
+
+/* Send header for http response */
+
+void send_http_header (request_rec *l);     
+     
+/* Send error back to client... last arg indicates error status in case
+ * we get an error in the process of trying to deal with an ErrorDocument
+ * to handle some other error.  In that case, we print the default report
+ * for the first thing that went wrong, and more briefly report on the
+ * problem with the ErrorDocument.
+ */
+
+void send_error_response (request_rec *r, int recursive_error);
+     
+/* Set last modified header line from the lastmod date of the associated file.
+ * Also, set content length.
+ *
+ * May return an error status, typically USE_LOCAL_COPY (that when the
+ * permit_cache argument is set to one).
+ */
+
+int set_content_length (request_rec *r, long length);
+int set_keepalive (request_rec *r);
+int set_last_modified (request_rec *r, time_t mtime);
+
+void add_env_var (array_header *env, char *header_name, char *val);
+
+/* Other ways to send stuff at the client.  All of these keep track
+ * of bytes_sent automatically.  This indirection is intended to make
+ * it a little more painless to slide things like HTTP-NG packetization
+ * underneath the main body of the code later.  In the meantime, it lets
+ * us centralize a bit of accounting (bytes_sent).
+ *
+ * These also return the number of bytes written by the call.
+ * They should only be called with a timeout registered, for obvious reaasons.
+ * (Ditto the send_header stuff).
+ */
+
+long send_fd(FILE *f, request_rec *r);
+     
+/* Hmmm... could macrofy these for now, and maybe forever, though the
+ * definitions of the macros would get a whole lot hairier.
+ */
+     
+#if 0
+long rprintf (request_rec *r, char *s, ...);     
+#endif
+int rputc (int c, request_rec *r);     
+int rputs(const char *str, request_rec *r);
+int rvputs(request_rec *r, ...);
+int rprintf(request_rec *r,const char *fmt,...);
+     
+/*
+ * Index used in custom_responses array for a specific error code
+ * (only use outside protocol.c is in getting them configured).
+ */
+
+int index_of_response (int status);
+
+/* Reading a block of data from the client connection (e.g., POST arg) */
+     
+long read_client_block (request_rec *r, char *buffer, int bufsiz);
+     
+/* Finally, this charming little number is here to encapsulate the
+ * degree to which nph- scripts completely escape from any discipline
+ * the protocol code might care to impose (this as opposed to other
+ * scripts, which *partially* escape to the extent that they may try
+ * to explicitly set the status line).
+ */
+
+void client_to_stdout (conn_rec *c); 
+
+
+/* Support for the Basic authentication protocol.  Note that there's
+ * nothing that prevents these from being in mod_auth.c, except that other
+ * modules which wanted to provide their own variants on finding users and
+ * passwords for Basic auth (a fairly common request) would then require
+ * mod_auth to be loaded or they wouldn't work.
+ *
+ * get_basic_auth_pw returns 0 (OK) if it set the 'pw' argument (and assured
+ * a correct value in r->connection->user); otherwise it returns an error
+ * code, either SERVER_ERROR if things are really confused, AUTH_REQUIRED
+ * if no authentication at all seemed to be in use, or DECLINED if there
+ * was authentication but it wasn't Basic (in which case, the caller should
+ * presumably decline as well).
+ *
+ * note_basic_auth_failure arranges for the right stuff to be scribbled on
+ * the HTTP return so that the client knows how to authenticate itself the
+ * next time. As does note_digest_auth_failure for Digest auth.
+ *
+ * note_auth_failure does the same thing, but will call the correct one
+ * based on the authentication type in use.
+ *
+ */
+
+void note_auth_failure(request_rec *r);
+void note_basic_auth_failure(request_rec *r);
+void note_digest_auth_failure(request_rec *r);
+int get_basic_auth_pw (request_rec *r, char **pw);
+
+/*
+ * Setting up the protocol fields for subsidiary requests...
+ * Also, a wrapup function to keep the internal accounting straight.
+ */
+
+void set_sub_req_protocol (request_rec *rnew, request_rec *r);
+void finalize_sub_req_protocol (request_rec *sub_r);
+
+/* This is also useful for putting sub_reqs and internal_redirects together */
+
+void parse_uri (request_rec *r, char *uri);     
diff --git a/RELEASE_1_1_X/src/include/http_request.h b/RELEASE_1_1_X/src/include/http_request.h
new file mode 100644 (file)
index 0000000..b433457
--- /dev/null
@@ -0,0 +1,93 @@
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/* http_request.c is the code which handles the main line of request
+ * processing, once a request has been read in (finding the right per-
+ * directory configuration, building it if necessary, and calling all
+ * the module dispatch functions in the right order).
+ *
+ * The pieces here which are public to the modules, allow them to learn
+ * how the server would handle some other file or URI, or perhaps even
+ * direct the server to serve that other file instead of the one the
+ * client requested directly.
+ *
+ * There are two ways to do that.  The first is the sub_request mechanism,
+ * which handles looking up files and URIs as adjuncts to some other
+ * request (e.g., directory entries for multiviews and directory listings);
+ * the lookup functions stop short of actually running the request, but
+ * (e.g., for includes), a module may call for the request to be run
+ * by calling run_sub_req.  The space allocated to create sub_reqs can be
+ * reclaimed by calling destroy_sub_req --- be sure to copy anything you care
+ * about which was allocated in its pool elsewhere before doing this.
+ */
+
+request_rec *sub_req_lookup_uri (char *new_file, request_rec *r);
+request_rec *sub_req_lookup_file (char *new_file, request_rec *r);
+int run_sub_req (request_rec *r);
+void destroy_sub_req (request_rec *r);
+     
+/*
+ * Then there's the case that you want some other request to be served
+ * as the top-level request INSTEAD of what the client requested directly.
+ * If so, call this from a handler, and then immediately return OK.
+ */
+
+void internal_redirect (char *new_uri, request_rec *);     
+void internal_redirect_handler (char *new_uri, request_rec *);
+
+#ifdef CORE_PRIVATE
+/* Function called by main.c to handle first-level request */
+void process_request (request_rec *);     
+int default_handler (request_rec *);
+#endif
diff --git a/RELEASE_1_1_X/src/include/httpd.h b/RELEASE_1_1_X/src/include/httpd.h
new file mode 100644 (file)
index 0000000..4e4ab53
--- /dev/null
@@ -0,0 +1,560 @@
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * httpd.h: header for simple (ha! not anymore) http daemon
+ */
+
+/* Headers in which EVERYONE has an interest... */
+
+#include "conf.h"
+#include "alloc.h"
+#include "buff.h"
+
+/* ----------------------------- config dir ------------------------------ */
+
+/* Define this to be the default server home dir. Anything later in this
+ * file with a relative pathname will have this added.
+ */
+#ifdef __EMX__
+/* Set default for OS/2 file system */ 
+#define HTTPD_ROOT "/os2httpd"
+#else
+#define HTTPD_ROOT "/usr/local/etc/httpd"
+#endif
+
+/* Root of server */
+#ifdef __EMX__
+/* Set default for OS/2 file system */ 
+#define DOCUMENT_LOCATION "/os2httpd/docs"
+#else
+#define DOCUMENT_LOCATION "/usr/local/etc/httpd/htdocs"
+#endif
+
+/* Max. number of dynamically loaded modules */
+#define DYNAMIC_MODULE_LIMIT 64
+
+/* Default administrator's address */
+#define DEFAULT_ADMIN "[no address given]"
+
+/* 
+ * --------- You shouldn't have to edit anything below this line ----------
+ *
+ * Any modifications to any defaults not defined above should be done in the 
+ * respective config. file. 
+ *
+ */
+
+
+/* -------------- Port number for server running standalone --------------- */
+
+#define DEFAULT_PORT 80
+
+/* --------- Default user name and group name running standalone ---------- */
+/* --- These may be specified as numbers by placing a # before a number --- */
+
+#define DEFAULT_USER "#-1"
+#define DEFAULT_GROUP "#-1"
+
+/* The name of the log files */
+#ifdef __EMX__
+/* Set default for OS/2 file system */ 
+#define DEFAULT_XFERLOG "logs/access.log"
+#else
+#define DEFAULT_XFERLOG "logs/access_log"
+#endif
+#ifdef __EMX__
+/* Set default for OS/2 file system */ 
+#define DEFAULT_ERRORLOG "logs/error.log"
+#else
+#define DEFAULT_ERRORLOG "logs/error_log"
+#endif
+#define DEFAULT_PIDLOG "logs/httpd.pid"
+#define DEFAULT_SCOREBOARD "logs/apache_runtime_status"
+
+/* Define this to be what your HTML directory content files are called */
+#define DEFAULT_INDEX "index.html"
+
+/* Define this to 1 if you want fancy indexing, 0 otherwise */
+#define DEFAULT_INDEXING 0
+
+/* Define this to be what type you'd like returned for files with unknown */
+/* suffixes */
+#define DEFAULT_TYPE "text/html"
+
+/* Define this to be what your per-directory security files are called */
+#ifdef __EMX__
+/* Set default for OS/2 file system */ 
+#define DEFAULT_ACCESS_FNAME "htaccess"
+#else
+#define DEFAULT_ACCESS_FNAME ".htaccess"
+#endif
+
+/* The name of the server config file */
+#define SERVER_CONFIG_FILE "conf/httpd.conf"
+
+/* The name of the document config file */
+#define RESOURCE_CONFIG_FILE "conf/srm.conf"
+
+/* The name of the MIME types file */
+#define TYPES_CONFIG_FILE "conf/mime.types"
+
+/* The name of the access file */
+#define ACCESS_CONFIG_FILE "conf/access.conf"
+
+/* Whether we should enable rfc1413 identity checking */
+#define DEFAULT_RFC1413 0
+/* The default directory in user's home dir */
+#define DEFAULT_USER_DIR "public_html"
+
+/* The default path for CGI scripts if none is currently set */
+#define DEFAULT_PATH "/bin:/usr/bin:/usr/ucb:/usr/bsd:/usr/local/bin"
+
+/* The path to the Bourne shell, for parsed docs */
+#ifdef __EMX__
+/* Set default for OS/2 file system */ 
+#define SHELL_PATH "CMD.EXE"
+#else
+#define SHELL_PATH "/bin/sh"
+#endif
+
+/* The default string lengths */
+#define MAX_STRING_LEN HUGE_STRING_LEN
+#define HUGE_STRING_LEN 8192
+
+/* The timeout for waiting for messages */
+#define DEFAULT_TIMEOUT 1200
+
+/* The timeout for waiting for keepalive timeout until next request */
+#define DEFAULT_KEEPALIVE_TIMEOUT 15
+
+/* The number of requests to entertain per connection */
+#define DEFAULT_KEEPALIVE 5
+
+/* The size of the server's internal read-write buffers */
+#define IOBUFSIZE 8192
+
+/* The number of header lines we will accept from a client */
+#define MAX_HEADERS 200
+
+/* Number of servers to spawn off by default --- also, if fewer than
+ * this free when the caretaker checks, it will spawn more.
+ */
+#define DEFAULT_START_DAEMON 5
+
+/* Maximum number of *free* server processes --- more than this, and
+ * they will die off.
+ */
+
+#define DEFAULT_MAX_FREE_DAEMON 10
+
+/* Minimum --- fewer than this, and more will be created */
+
+#define DEFAULT_MIN_FREE_DAEMON 5
+
+/* 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 (I was originally going to make this 256, but it turns out
+ * that that would actually fill the process table on reasonably configured
+ * machines).  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.
+ */
+#define HARD_SERVER_LIMIT 150
+
+/* Number of requests to try to handle in a single process.  If <= 0,
+ * the children don't die off.  That's the default here, since I'm still
+ * interested in finding and stanching leaks.
+ */
+
+#define DEFAULT_MAX_REQUESTS_PER_CHILD 0
+
+/* If you have altered Apache and wish to change the SERVER_VERSION define
+ * below, please keep to the HTTP/1.0 specification.  This states that
+ * the identification string should consist of product tokens with an optional
+ * slash and version designator.  Sub-products which form a significant part 
+ * of the application can be listed, separated by whitespace.  The tokens
+ * are listed in order of their significance for identifying the application.
+ *
+ * "Product tokens should be short and to the point -- use of them for 
+ * advertizing or other non-essential information is explicitly forbidden."
+ *
+ * Example: "Apache/1.1b3 MrWidget/0.1-alpha" 
+ */
+
+#define SERVER_VERSION "Apache/1.1.0" /* SEE COMMENTS ABOVE */
+
+#define SERVER_PROTOCOL "HTTP/1.0"
+#define SERVER_SUPPORT "http://www.apache.org/"
+
+#define DECLINED -1            /* Module declines to handle */
+#define OK 0                   /* Module has handled this stage. */
+
+/* ------------------------------ error types ------------------------------ */
+
+#define DOCUMENT_FOLLOWS 200
+#define REDIRECT 302
+#define USE_LOCAL_COPY 304
+#define BAD_REQUEST 400
+#define AUTH_REQUIRED 401
+#define FORBIDDEN 403
+#define NOT_FOUND 404
+#define SERVER_ERROR 500
+#define NOT_IMPLEMENTED 501
+#define BAD_GATEWAY 502
+#define SERVICE_UNAVAILABLE 503
+#define RESPONSE_CODES 10
+
+#define METHODS 6
+#define M_GET 0
+#define M_PUT 1
+#define M_POST 2
+#define M_DELETE 3
+#define M_CONNECT 4
+#define M_INVALID 5
+
+#define CGI_MAGIC_TYPE "application/x-httpd-cgi"
+#define INCLUDES_MAGIC_TYPE "text/x-server-parsed-html"
+#define INCLUDES_MAGIC_TYPE3 "text/x-server-parsed-html3"
+#define MAP_FILE_MAGIC_TYPE "application/x-type-map"
+#define ASIS_MAGIC_TYPE "httpd/send-as-is"
+#define DIR_MAGIC_TYPE "httpd/unix-directory"
+#define STATUS_MAGIC_TYPE "application/x-httpd-status"
+
+/* Just in case your linefeed isn't the one the other end is expecting. */
+#define LF 10
+#define CR 13
+
+/* Things which may vary per file-lookup WITHIN a request ---
+ * e.g., state of MIME config.  Basically, the name of an object, info
+ * about the object, and any other info we may ahve which may need to
+ * change as we go poking around looking for it (e.g., overridden by
+ * .htaccess files).
+ *
+ * Note how the default state of almost all these things is properly
+ * zero, so that allocating it with pcalloc does the right thing without
+ * a whole lot of hairy initialization... so long as we are willing to
+ * make the (fairly) portable assumption that the bit pattern of a NULL
+ * pointer is, in fact, zero.
+ */
+
+/* This represents the result of calling htaccess; these are cached for
+ * each request.
+ */
+struct htaccess_result
+{
+    char *dir;              /* the directory to which this applies */
+    int override;           /* the overrides allowed for the .htaccess file */
+    void *htaccess;         /* the configuration directives */
+/* the next one, or NULL if no more; N.B. never change this */
+    const struct htaccess_result *next;
+};
+
+
+typedef struct conn_rec conn_rec;
+typedef struct server_rec server_rec;
+typedef struct request_rec request_rec;
+typedef struct listen_rec listen_rec;
+
+struct request_rec {
+
+  pool *pool;
+  conn_rec *connection;
+  server_rec *server;
+
+  request_rec *next;           /* If we wind up getting redirected,
+                                * pointer to the request we redirected to.
+                                */
+  request_rec *prev;           /* If this is an internal redirect,
+                                * pointer to where we redirected *from*.
+                                */
+  
+  request_rec *main;           /* If this is a sub_request (see request.h) 
+                                * pointer back to the main request.
+                                */
+
+  /* Info about the request itself... we begin with stuff that only
+   * protocol.c should ever touch...
+   */
+  
+  char *the_request;           /* First line of request, so we can log it */
+  int assbackwards;            /* HTTP/0.9, "simple" request */
+  int proxyreq;                 /* A proxy request */
+  int header_only;             /* HEAD request, as opposed to GET */
+  char *protocol;              /* Protocol, as given to us, or HTTP/0.9 */
+  int proto_num;               /* Number version of protocol; 1.1 = 1001 */
+  char *hostname;              /* Host, as set by full URI or Host: */
+  int hostlen;                 /* Length of http://host:port in full URI */
+
+  char *status_line;           /* Status line, if set by script */
+  int status;                  /* In any case */
+  
+  /* Request method, two ways; also, protocol, etc..  Outside of protocol.c,
+   * look, but don't touch.
+   */
+  
+  char *method;                        /* GET, HEAD, POST, etc. */
+  int method_number;           /* M_GET, M_POST, etc. */
+
+  int sent_bodyct;             /* byte count in stream is for body */
+  long bytes_sent;             /* body byte count, for easy access */
+  
+  /* MIME header environments, in and out.  Also, an array containing
+   * environment variables to be passed to subprocesses, so people can
+   * write modules to add to that environment.
+   *
+   * The difference between headers_out and err_headers_out is that the
+   * latter are printed even on error, and persist across internal redirects
+   * (so the headers printed for ErrorDocument handlers will have them).
+   *
+   * The 'notes' table is for notes from one module to another, with no
+   * other set purpose in mind...
+   */
+  
+  table *headers_in;
+  table *headers_out;
+  table *err_headers_out;
+  table *subprocess_env;
+  table *notes;
+
+  char *content_type;          /* Break these out --- we dispatch on 'em */
+  char *handler;               /* What we *really* dispatch on           */
+
+  char *content_encoding;
+  char *content_language;
+  
+  int no_cache;
+  
+  /* What object is being requested (either directly, or via include
+   * or content-negotiation mapping).
+   */
+
+  char *uri;                    /* complete URI for a proxy req, or
+                                   URL path for a non-proxy req */
+  char *filename;
+  char *path_info;
+  char *args;                  /* QUERY_ARGS, if any */
+  struct stat finfo;           /* ST_MODE set to zero if no such file */
+  
+  /* Various other config info which may change with .htaccess files
+   * These are config vectors, with one void* pointer for each module
+   * (the thing pointed to being the module's business).
+   */
+  
+  void *per_dir_config;                /* Options set in config files, etc. */
+  void *request_config;                /* Notes on *this* request */
+
+/*
+ * a linked list of the configuration directives in the .htaccess files
+ * accessed by this request.
+ * N.B. always add to the head of the list, _never_ to the end.
+ * that way, a sub request's list can (temporarily) point to a parent's list
+ */
+  const struct htaccess_result *htaccess;
+};
+
+
+/* Things which are per connection
+ */
+
+struct conn_rec {
+  
+  pool *pool;
+  server_rec *server;
+  
+  /* Information about the connection itself */
+
+  int child_num;                /* The number of the child handling conn_rec */
+  BUFF *client;                        /* Connetion to the guy */
+  int aborted;                 /* Are we still talking? */
+  
+  /* Who is the client? */
+  
+  struct sockaddr_in local_addr; /* local address */
+  struct sockaddr_in remote_addr;/* remote address */
+  char *remote_ip;             /* Client's IP address */
+  char *remote_host;           /* Client's DNS name, if known.
+                                 * NULL if DNS hasn't been checked,
+                                 * "" if it has and no address was found.
+                                 * N.B. Only access this though
+                                * get_remote_host() */
+  char *remote_logname;                /* Only ever set if doing_rfc931
+                                 * N.B. Only access this through
+                                * get_remote_logname() */
+    char *user;                        /* If an authentication check was made,
+                                * this gets set to the user name.  We assume
+                                * that there's only one user per connection(!)
+                                */
+  char *auth_type;             /* Ditto. */
+
+  int keepalive;               /* Are we using HTTP Keep-Alive? */
+  int keptalive;               /* Did we use HTTP Keep-Alive? */
+  int keepalives;              /* How many times have we used it? */
+};
+
+/* Per-vhost config... */
+
+struct server_rec {
+
+  server_rec *next;
+  
+  /* Full locations of server config info */
+  
+  char *srm_confname;
+  char *access_confname;
+  
+  /* Contact information */
+  
+  char *server_admin;
+  char *server_hostname;
+  short port;                    /* for redirects, etc. */
+  
+  /* Log files --- note that transfer log is now in the modules... */
+  
+  char *error_fname;
+  FILE *error_log;
+  
+  /* Module-specific configuration for server, and defaults... */
+
+  int is_virtual;               /* true if this is the virtual server */
+  void *module_config;         /* Config vector containing pointers to
+                                * modules' per-server config structures.
+                                */
+  void *lookup_defaults;       /* MIME type info, etc., before we start
+                                * checking per-directory info.
+                                */
+  /* Transaction handling */
+
+  struct in_addr host_addr;    /* The bound address, for this server */
+  short host_port;              /* The bound port, for this server */
+  int timeout;                 /* Timeout, in seconds, before we give up */
+  int keep_alive_timeout;      /* Seconds we'll wait for another request */
+  int keep_alive;              /* Maximum requests per connection */
+
+  char *path;                  /* Pathname for ServerPath */
+  int pathlen;                 /* Length of path */
+
+  char *names;                 /* Wildcarded names for HostAlias servers */
+  char *virthost;              /* The name given in <VirtualHost> */
+};
+
+/* These are more like real hosts than virtual hosts */
+struct listen_rec {
+    listen_rec *next;
+    struct sockaddr_in local_addr; /* local IP address and port */
+/* more stuff here, like which protocol is bound to the port */
+};
+
+/* Prototypes for utilities... util.c.
+ */
+
+/* Time */
+extern const char month_snames[12][4];
+
+struct tm *get_gmtoff(long *tz);
+char *get_time();
+char *ht_time (pool *p, time_t t, char *fmt, int gmt);     
+char *gm_timestr_822(pool *p, time_t t);
+     
+/* String handling */     
+     
+char *getword(pool *p, char **line, char stop);
+char *getword_nulls (pool *p, char **line, char stop);
+char *getword_conf (pool *p, char **line);      
+
+char *get_token (pool *p, char **accept_line, int accept_white);
+     
+int is_url(char *u);
+extern int unescape_url(char *url);
+void no2slash(char *name);
+void getparents(char *name);
+char *escape_path_segment(pool *p, const char *s);
+char *os_escape_path(pool *p,const char *path,int partial);
+char *escape_uri (pool *p, char *s);
+extern char *escape_html(pool *p, const char *s);
+char *construct_url (pool *p, char *path, server_rec *s);     
+char *escape_shell_cmd (pool *p, char *s);
+     
+int count_dirs(char *path);
+char *make_dirstr(pool *a, char *s, int n);
+char *make_full_path(pool *a, char *dir, char *f);
+     
+int is_matchexp(char *str);
+int strcmp_match(char *str, char *exp);
+int strcasecmp_match(char *str, char *exp);
+char *uudecode (pool *, char *);
+
+void str_tolower (char *);
+int ind (const char *, char);  /* Sigh... */
+int rind (const char *, char);     
+
+int cfg_getline(char *s, int n, FILE *f);
+     
+/* Misc system hackery */
+     
+uid_t uname2id(char *name);
+gid_t gname2id(char *name);
+int is_directory(char *name);
+int can_exec(struct stat *);     
+void chdir_file(char *file);
+     
+char *get_local_host(pool *);
+unsigned long get_virthost_addr (char *hostname, short int *port);
+
+extern time_t restart_time;
diff --git a/RELEASE_1_1_X/src/include/md5.h b/RELEASE_1_1_X/src/include/md5.h
new file mode 100644 (file)
index 0000000..786b010
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * This is work is derived from material Copyright RSA Data Security, Inc.
+ *
+ * The RSA copyright statement and Licence for that original material is
+ * included below. This is followed by the Apache copyright statement and
+ * licence for the modifications made to that material.
+ */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+ */
+
+/* ====================================================================
+ * Copyright (c) 1996 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/* MD5.H - header file for MD5C.C */
+
+/* UINT4 defines a four byte word */
+typedef unsigned int UINT4;
+
+/* MD5 context. */
+typedef struct {
+  UINT4 state[4];                                   /* state (ABCD) */
+  UINT4 count[2];        /* number of bits, modulo 2^64 (lsb first) */
+  unsigned char buffer[64];                         /* input buffer */
+} MD5_CTX;
+
+extern void MD5Init(MD5_CTX *context);
+extern void MD5Update(MD5_CTX *context, const unsigned char *input,
+                     unsigned int inputLen);
+extern void MD5Final(unsigned char digest[16], MD5_CTX *context);
diff --git a/RELEASE_1_1_X/src/include/rfc1413.h b/RELEASE_1_1_X/src/include/rfc1413.h
new file mode 100644 (file)
index 0000000..a15df86
--- /dev/null
@@ -0,0 +1,53 @@
+/* ====================================================================
+ * Copyright (c) 1996 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+extern char *rfc1413(conn_rec *conn, server_rec *srv);
diff --git a/RELEASE_1_1_X/src/include/scoreboard.h b/RELEASE_1_1_X/src/include/scoreboard.h
new file mode 100644 (file)
index 0000000..fe482b8
--- /dev/null
@@ -0,0 +1,94 @@
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+#include <sys/times.h>
+
+/* Scoreboard info on a process is, for now, kept very brief --- 
+ * just status value and pid (the latter so that the caretaker process
+ * can properly update the scoreboard when a process dies).  We may want
+ * to eventually add a separate set of long_score structures which would
+ * give, for each process, the number of requests serviced, and info on
+ * the current, or most recent, request.
+ *
+ * Status values:
+ */
+
+#define SERVER_UNKNOWN (-1)    /* should never be in this state */
+#define SERVER_DEAD 0
+#define SERVER_READY 1          /* Waiting for connection (or accept() lock) */
+#define SERVER_STARTING 3       /* Server Starting up */
+#define SERVER_BUSY_READ 2      /* Reading a client request */
+#define SERVER_BUSY_WRITE 4     /* Processing a client request */
+#define SERVER_BUSY_KEEPALIVE 5 /* Waiting for more requests via keepalive */
+#define SERVER_BUSY_LOG 6       /* Logging the request */
+#define SERVER_BUSY_DNS 7       /* Looking up a hostname */
+
+typedef struct {
+    pid_t pid;
+    char status;
+#if defined(STATUS)
+    unsigned long access_count;
+    unsigned long bytes_served;
+    unsigned long my_access_count;
+    unsigned long my_bytes_served;
+    unsigned long conn_bytes;
+    unsigned short conn_count;
+    struct tms times;
+    time_t last_used;
+    char client[32];   /* Keep 'em small... */
+    char request[64];  /* We just want an idea... */
+#endif
+} short_score;
+
+extern void sync_scoreboard_image(void);
+short_score get_scoreboard_info(int x);
diff --git a/RELEASE_1_1_X/src/include/util_md5.h b/RELEASE_1_1_X/src/include/util_md5.h
new file mode 100644 (file)
index 0000000..121dfec
--- /dev/null
@@ -0,0 +1,59 @@
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+#include "md5.h"
+
+char *md5(pool *a, unsigned char *string);
+char *md5contextTo64(pool *p, MD5_CTX *context);
+char *md5digest(pool *p, FILE *infile);
+
diff --git a/RELEASE_1_1_X/src/include/util_script.h b/RELEASE_1_1_X/src/include/util_script.h
new file mode 100644 (file)
index 0000000..056f614
--- /dev/null
@@ -0,0 +1,64 @@
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+char **create_argv(pool *p, char *av0, char *args);
+#ifdef __EMX__
+char **create_argv_cmd(pool *p, char *av0, char *args, char *path);
+#endif
+char **create_environment(pool *p, table *t);
+void add_cgi_vars(request_rec *r);
+void add_common_vars(request_rec *r);
+int scan_script_header(request_rec *r, FILE *f);
+void send_size(size_t size, request_rec *r);
+
diff --git a/RELEASE_1_1_X/src/main/alloc.c b/RELEASE_1_1_X/src/main/alloc.c
new file mode 100644 (file)
index 0000000..9afaa9a
--- /dev/null
@@ -0,0 +1,1070 @@
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * Resource allocation code... the code here is responsible for making
+ * sure that nothing leaks.
+ *
+ * rst --- 4/95 --- 6/95
+ */
+
+#include "conf.h"
+#include "alloc.h"
+
+#include <stdarg.h>
+
+/*****************************************************************
+ *
+ * Managing free storage blocks...
+ */
+
+union align
+{
+  /* Types which are likely to have the longest RELEVANT alignment
+   * restrictions...
+   */
+  
+  char *cp;
+  void (*f)();
+  long l;
+  FILE *fp;
+  double d;
+};
+
+#define CLICK_SZ (sizeof(union align))
+
+union block_hdr
+{
+  union align a;
+  
+  /* Actual header... */
+  
+  struct {
+    char *endp;
+    union block_hdr *next;
+    char *first_avail;
+  } h;
+};
+
+union block_hdr *block_freelist = NULL;
+
+
+
+/* Get a completely new block from the system pool */
+
+union block_hdr *malloc_block (int size)
+{
+  union block_hdr *blok =
+    (union block_hdr *)malloc(size + sizeof(union block_hdr));
+
+  if (blok == NULL) return NULL;
+  
+  blok->h.next = NULL;
+  blok->h.first_avail = (char *)(blok + 1);
+  blok->h.endp = size + blok->h.first_avail;
+  
+  return blok;
+}
+
+
+
+void chk_on_blk_list (union block_hdr *blok, union block_hdr *free_blk)
+{
+  /* Debugging code.  Left in for the moment. */
+    
+  while (free_blk) {
+    if (free_blk == blok) {
+      fprintf (stderr, "Ouch!  Freeing free block\n");
+      exit (1);
+    }
+    free_blk = free_blk->h.next;
+  }
+}
+
+/* Free a chain of blocks --- must be called with alarms blocked. */
+
+void free_blocks (union block_hdr *blok)
+{
+  /* First, put new blocks at the head of the free list ---
+   * we'll eventually bash the 'next' pointer of the last block
+   * in the chain to point to the free blocks we already had.
+   */
+  
+  union block_hdr *old_free_list = block_freelist;
+
+  if (blok == NULL) return;    /* Sanity check --- freeing empty pool? */
+  
+  block_freelist = blok;
+  
+  /*
+   * Next, adjust first_avail pointers of each block --- have to do it
+   * sooner or later, and it simplifies the search in new_block to do it
+   * now.
+   */
+
+  while (blok->h.next != NULL) {
+    chk_on_blk_list (blok, old_free_list);
+    blok->h.first_avail = (char *)(blok + 1);
+    blok = blok->h.next;
+  }
+
+  chk_on_blk_list (blok, old_free_list);
+  blok->h.first_avail = (char *)(blok + 1);
+
+  /* Finally, reset next pointer to get the old free blocks back */
+
+  blok->h.next = old_free_list;
+}
+
+
+
+
+/* Get a new block, from our own free list if possible, from the system
+ * if necessary.  Must be called with alarms blocked.
+ */
+
+union block_hdr *new_block (int min_size)
+{
+  union block_hdr **lastptr = &block_freelist;
+  union block_hdr *blok = block_freelist;
+  
+  /* First, see if we have anything of the required size
+   * on the free list...
+   */
+
+  min_size += BLOCK_MINFREE;
+
+  while (blok != NULL) {
+    if (min_size <= blok->h.endp - blok->h.first_avail) {
+      
+      *lastptr = blok->h.next;
+      blok->h.next = NULL;
+      return blok;
+    }
+    else {
+      lastptr = &blok->h.next;
+      blok = blok->h.next;
+    }
+  }
+
+  /* Nope. */
+
+  return malloc_block (min_size);
+}
+
+
+
+/* Accounting */
+
+long bytes_in_block_list (union block_hdr *blok)
+{
+  long size = 0;
+
+  while (blok) {
+    size += blok->h.endp - (char *)(blok + 1);
+    blok = blok->h.next;
+  }
+
+  return size;
+}
+
+
+/*****************************************************************
+ *
+ * Pool internals and management...
+ * NB that subprocesses are not handled by the generic cleanup code,
+ * basically because we don't want cleanups for multiple subprocesses
+ * to result in multiple three-second pauses.
+ */
+
+struct process_chain;
+struct cleanup;
+
+static void run_cleanups (struct cleanup *);
+static void free_proc_chain (struct process_chain *);
+
+struct pool {
+  union block_hdr *first;
+  union block_hdr *last;
+  struct cleanup *cleanups;
+  struct process_chain *subprocesses;
+  struct pool *sub_pools;
+  struct pool *sub_next;
+  struct pool *sub_prev;
+  struct pool *parent;
+  char *free_first_avail;
+};
+
+pool *permanent_pool;
+
+/* Each pool structure is allocated in the start of its own first block,
+ * so we need to know how many bytes that is (once properly aligned...).
+ * This also means that when a pool's sub-pool is destroyed, the storage
+ * associated with it is *completely* gone, so we have to make sure it
+ * gets taken off the parent's sub-pool list...
+ */
+
+#define POOL_HDR_CLICKS (1 + ((sizeof(struct pool) - 1) / CLICK_SZ))
+#define POOL_HDR_BYTES (POOL_HDR_CLICKS * CLICK_SZ)                     
+
+struct pool *make_sub_pool (struct pool *p)
+{
+  union block_hdr *blok;
+  pool *new_pool;
+
+  block_alarms();
+  
+  blok = new_block (0);
+  new_pool = (pool *)blok->h.first_avail;
+  blok->h.first_avail += POOL_HDR_BYTES;
+
+  memset ((char *)new_pool, '\0', sizeof (struct pool));
+  new_pool->free_first_avail = blok->h.first_avail;
+  new_pool->first = new_pool->last = blok;
+    
+  if (p) {
+    new_pool->parent = p;
+    new_pool->sub_next = p->sub_pools;
+    if (new_pool->sub_next) new_pool->sub_next->sub_prev = new_pool;
+    p->sub_pools = new_pool;
+  }
+  
+  unblock_alarms();
+  
+  return new_pool;
+}
+
+void init_alloc() { permanent_pool = make_sub_pool (NULL); }
+
+void clear_pool (struct pool *a)
+{
+  block_alarms();
+  
+  while (a->sub_pools)
+    destroy_pool (a->sub_pools);
+    
+  a->sub_pools = NULL;
+  
+  run_cleanups (a->cleanups);        a->cleanups = NULL;
+  free_proc_chain (a->subprocesses); a->subprocesses = NULL;
+  free_blocks (a->first->h.next);    a->first->h.next = NULL;
+
+  a->last = a->first;
+  a->first->h.first_avail = a->free_first_avail;
+
+  unblock_alarms();
+}
+
+void destroy_pool (pool *a)
+{
+  block_alarms();
+  clear_pool (a);
+
+  if (a->parent) {
+    if (a->parent->sub_pools == a) a->parent->sub_pools = a->sub_next;
+    if (a->sub_prev) a->sub_prev->sub_next = a->sub_next;
+    if (a->sub_next) a->sub_next->sub_prev = a->sub_prev;
+  }
+  
+  free_blocks (a->first);
+  unblock_alarms();
+}
+
+long bytes_in_pool (pool *p) { return bytes_in_block_list (p->first); }
+long bytes_in_free_blocks () { return bytes_in_block_list (block_freelist); }
+
+/*****************************************************************
+ *
+ * Allocating stuff...
+ */
+
+
+void *palloc (struct pool *a, int reqsize)
+{
+  /* Round up requested size to an even number of alignment units (core clicks)
+   */
+  
+  int nclicks = 1 + ((reqsize - 1) / CLICK_SZ);
+  int size = nclicks * CLICK_SZ;
+  
+  /* First, see if we have space in the block most recently
+   * allocated to this pool
+   */
+  
+  union block_hdr *blok = a->last; 
+  char *first_avail = blok->h.first_avail;
+  char *new_first_avail;
+
+  if (size <= 0) size = 1;
+  new_first_avail = first_avail + size;
+  
+  if (new_first_avail <= blok->h.endp) {
+    blok->h.first_avail = new_first_avail;
+    return (void *)first_avail;
+  }
+
+  /* Nope --- get a new one that's guaranteed to be big enough */
+  
+  block_alarms();
+  blok = new_block (size);
+  a->last->h.next = blok;
+  a->last = blok;
+  unblock_alarms();
+
+  first_avail = blok->h.first_avail;
+  blok->h.first_avail += size;
+
+  return (void *)first_avail;
+}
+
+void *pcalloc(struct pool *a, int size)
+{
+  void *res = palloc (a, size);
+  memset (res, '\0', size);
+  return res;
+}
+
+char *pstrdup(struct pool *a, const char *s)
+{
+  char *res;
+  if (s == NULL) return NULL;
+  res = palloc (a, strlen(s) + 1);
+  strcpy (res, s);
+  return res;
+}
+
+char *pstrndup(struct pool *a, const char *s, int n)
+{
+  char *res;
+  if (s == NULL) return NULL;
+  res = palloc (a, n + 1);
+  strncpy (res, s, n);
+  res[n] = '\0';
+  return res;
+}
+
+char *pstrcat(pool *a, ...)
+{
+  char *cp, *argp, *res;
+  
+  /* Pass one --- find length of required string */
+  
+  int len = 0;
+  va_list adummy;
+  
+  va_start (adummy, a);
+
+  while ((cp = va_arg (adummy, char *)) != NULL) 
+    len += strlen(cp);
+
+  va_end (adummy);
+
+  /* Allocate the required string */
+
+  res = (char *)palloc(a, len + 1);
+  cp = res;
+
+  /* Pass two --- copy the argument strings into the result space */
+
+  va_start (adummy, a);
+  
+  while ((argp = va_arg (adummy, char *)) != NULL) {
+    strcpy (cp, argp);
+    cp += strlen(argp);
+  }
+
+  va_end (adummy);
+
+  /* Return the result string */
+
+  return res;
+}
+
+
+/*****************************************************************
+ *
+ * The 'array' functions...
+ */
+
+array_header *make_array (pool *p, int nelts, int elt_size)
+{
+  array_header *res = (array_header *)palloc(p, sizeof(array_header));
+
+  if (nelts < 1) nelts = 1;    /* Assure sanity if someone asks for
+                                * array of zero elts.
+                                */
+  
+  res->elts = pcalloc (p, nelts * elt_size);
+  
+  res->pool = p;
+  res->elt_size = elt_size;
+  res->nelts = 0;              /* No active elements yet... */
+  res->nalloc = nelts;         /* ...but this many allocated */
+
+  return res;
+}
+
+void *push_array (array_header *arr)
+{
+  if (arr->nelts == arr->nalloc) {
+    char *new_data = pcalloc (arr->pool, arr->nalloc * arr->elt_size * 2);
+
+    memcpy (new_data, arr->elts, arr->nalloc * arr->elt_size);
+    arr->elts = new_data;
+    arr->nalloc *= 2;
+  }
+
+  ++arr->nelts;
+  return arr->elts + (arr->elt_size * (arr->nelts - 1));
+}
+
+void array_cat (array_header *dst, array_header *src)
+{
+  int elt_size = dst->elt_size;
+  
+  if (dst->nelts + src->nelts > dst->nalloc) {
+    int new_size = dst->nalloc * 2;
+    char *new_data;
+
+    if (new_size == 0) ++new_size;
+    
+    while (dst->nelts + src->nelts > new_size)
+      new_size *= 2;
+
+    new_data = pcalloc (dst->pool, elt_size * new_size);
+    memcpy (new_data, dst->elts, dst->nalloc * elt_size);
+    
+    dst->elts = new_data;
+    dst->nalloc = new_size;
+  }
+
+  memcpy (dst->elts + dst->nelts * elt_size, src->elts, elt_size * src->nelts);
+  dst->nelts += src->nelts;
+}
+
+array_header *copy_array (pool *p, array_header *arr)
+{
+  array_header *res = make_array (p, arr->nalloc, arr->elt_size);
+
+  memcpy (res->elts, arr->elts, arr->elt_size * arr->nelts);
+  res->nelts = arr->nelts;
+  return res;
+}
+
+/* This cute function copies the array header *only*, but arranges
+ * for the data section to be copied on the first push or arraycat.
+ * It's useful when the elements of the array being copied are
+ * read only, but new stuff *might* get added on the end; we have the
+ * overhead of the full copy only where it is really needed.
+ */
+
+array_header *copy_array_hdr (pool *p, array_header *arr)
+{
+  array_header *res = (array_header *)palloc(p, sizeof(array_header));
+
+  res->elts = arr->elts;
+  
+  res->pool = p;
+  res->elt_size = arr->elt_size;
+  res->nelts = arr->nelts;
+  res->nalloc = arr->nelts;    /* Force overflow on push */
+
+  return res;
+}
+
+/* The above is used here to avoid consing multiple new array bodies... */
+
+array_header *append_arrays (pool *p,
+                            array_header *first, array_header *second)
+{
+  array_header *res = copy_array_hdr (p, first);
+
+  array_cat (res, second);
+  return res;
+}
+
+
+/*****************************************************************
+ *
+ * The "table" functions.
+ */
+
+table *make_table (pool *p, int nelts) {
+    return make_array (p, nelts, sizeof (table_entry));
+}
+
+table *copy_table (pool *p, table *t) {
+    return copy_array (p, t);
+}
+
+array_header *table_elts (table *t) { return t; }
+
+char *table_get (table *t, char *key)
+{
+    table_entry *elts = (table_entry *)t->elts;
+    int i;
+
+    if (key == NULL) return NULL;
+    
+    for (i = 0; i < t->nelts; ++i)
+        if (!strcasecmp (elts[i].key, key))
+           return elts[i].val;
+
+    return NULL;
+}
+
+void table_set (table *t, const char *key, const char *val)
+{
+    table_entry *elts = (table_entry *)t->elts;
+    int i;
+
+    for (i = 0; i < t->nelts; ++i)
+        if (!strcasecmp (elts[i].key, key)) {
+           elts[i].val = pstrdup (t->pool, val);
+           return;
+       }
+
+    elts = (table_entry *)push_array(t);
+    elts->key = pstrdup (t->pool, key);
+    elts->val = pstrdup (t->pool, val);
+}
+
+void table_unset( table *t, char *key ) 
+{
+    table_entry *elts = (table_entry *)t->elts;
+    int i;   
+    int j;   
+    for (i = 0; i < t->nelts; ++i)
+        if (!strcasecmp (elts[i].key, key)) {
+            /* found the element to skip over
+             * there are any number of ways to remove an element from
+             * a contiguous block of memory.  I've chosen one that
+             * doesn't do a memcpy/bcopy/array_delete, *shrug*...
+             */
+            j = i;
+            ++i;
+            for ( ; i < t->nelts; ) {
+                elts[j].key = elts[i].key;
+                elts[j].val = elts[i].val;
+                ++i;
+                ++j;
+            };
+            --t->nelts;
+
+            return;
+        }
+}     
+
+void table_merge (table *t, char *key, char *val)
+{
+    table_entry *elts = (table_entry *)t->elts;
+    int i;
+
+    for (i = 0; i < t->nelts; ++i)
+        if (!strcasecmp (elts[i].key, key)) {
+           elts[i].val = pstrcat (t->pool, elts[i].val, ", ", val, NULL);
+           return;
+       }
+
+    elts = (table_entry *)push_array(t);
+    elts->key = pstrdup (t->pool, key);
+    elts->val = pstrdup (t->pool, val);
+}
+
+void table_add (table *t, char *key, char *val)
+{
+    table_entry *elts = (table_entry *)t->elts;
+
+    elts = (table_entry *)push_array(t);
+    elts->key = pstrdup (t->pool, key);
+    elts->val = pstrdup (t->pool, val);
+}
+
+table* overlay_tables (pool *p, table *overlay, table *base)
+{
+    return append_arrays (p, overlay, base);
+}
+
+/*****************************************************************
+ *
+ * Managing generic cleanups.  
+ */
+
+struct cleanup {
+  void *data;
+  void (*plain_cleanup)(void *);
+  void (*child_cleanup)(void *);
+  struct cleanup *next;
+};
+
+void register_cleanup (pool *p, void *data, void (*plain_cleanup)(void *),
+                      void (*child_cleanup)(void *))
+{
+  struct cleanup *c = (struct cleanup *)palloc(p, sizeof (struct cleanup));
+  c->data = data;
+  c->plain_cleanup = plain_cleanup;
+  c->child_cleanup = child_cleanup;
+  c->next = p->cleanups;
+  p->cleanups = c;
+}
+
+void kill_cleanup (pool *p, void *data, void (*cleanup)(void *))
+{
+  struct cleanup *c = p->cleanups;
+  struct cleanup **lastp = &p->cleanups;
+    
+  while (c) {
+    if (c->data == data && c->plain_cleanup == cleanup) {
+      *lastp = c->next;
+      break;
+    }
+
+    lastp = &c->next;
+    c = c->next;
+  }
+}
+
+void run_cleanup (pool *p, void *data, void (*cleanup)(void *))
+{
+  block_alarms();              /* Run cleanup only once! */
+  (*cleanup)(data);
+  kill_cleanup (p, data, cleanup);
+  unblock_alarms();
+}
+
+static void run_cleanups (struct cleanup *c)
+{
+  while (c) {
+    (*c->plain_cleanup)(c->data);
+    c = c->next;
+  }
+}
+
+static void run_child_cleanups (struct cleanup *c)
+{
+  while (c) {
+    (*c->child_cleanup)(c->data);
+    c = c->next;
+  }
+}
+
+static void cleanup_pool_for_exec (pool *p)
+{
+  run_child_cleanups (p->cleanups);
+  p->cleanups = NULL;
+
+  for (p = p->sub_pools; p; p = p->sub_next)
+    cleanup_pool_for_exec (p);
+}
+
+void cleanup_for_exec()
+{
+  block_alarms();
+  cleanup_pool_for_exec (permanent_pool);
+  unblock_alarms();
+}
+
+/*****************************************************************
+ *
+ * Files and file descriptors; these are just an application of the
+ * generic cleanup interface.
+ */
+
+static void fd_cleanup (void *fdv) { close ((int)fdv); }
+
+void note_cleanups_for_fd (pool *p, int fd) {
+  register_cleanup (p, (void *)fd, fd_cleanup, fd_cleanup);
+}
+
+int popenf(struct pool *a, char *name, int flg, int mode)
+{
+  int fd;
+
+  block_alarms();
+  fd = open(name, flg, mode);
+  if (fd >= 0) note_cleanups_for_fd (a, fd);
+  unblock_alarms();
+  return fd;
+}
+
+int pclosef(struct pool *a, int fd)
+{
+  int res;
+  
+  block_alarms();
+  res = close(fd);
+  kill_cleanup(a, (void *)fd, fd_cleanup);
+  unblock_alarms();
+  return res;
+}
+
+/* Note that we have separate plain_ and child_ cleanups for FILE *s,
+ * since fclose() would flush I/O buffers, which is extremely undesirable;
+ * we just close the descriptor.
+ */
+
+static void file_cleanup (void *fpv) { fclose ((FILE *)fpv); }
+static void file_child_cleanup (void *fpv) { close (fileno ((FILE *)fpv)); }
+
+void note_cleanups_for_file (struct pool *p, FILE *fp) {
+  register_cleanup (p, (void *)fp, file_cleanup, file_child_cleanup);
+}
+
+FILE *pfopen(struct pool *a, char *name, char *mode)
+{
+  FILE *fd;
+
+  block_alarms();
+  fd = fopen(name, mode);
+  if (fd != NULL) note_cleanups_for_file (a, fd);
+  unblock_alarms();
+  return fd;
+}
+
+FILE *pfdopen(struct pool *a,int fd,char *mode)
+{
+  FILE *f;
+
+  block_alarms();
+  f=fdopen(fd,mode);
+  if(f != NULL)
+    note_cleanups_for_file(a,f);
+  unblock_alarms();
+  return f;
+}
+
+
+int pfclose(struct pool *a, FILE *fd)
+{
+  int res;
+  
+  block_alarms();
+  res = fclose(fd);
+  kill_cleanup(a, (void *)fd, file_cleanup);
+  unblock_alarms();
+  return res;
+}
+
+/*****************************************************************
+ *
+ * More grotty system stuff... subprocesses.  Frump.  These don't use
+ * the generic cleanup interface because I don't want multiple
+ * subprocesses to result in multiple three-second pauses; the
+ * subprocesses have to be "freed" all at once.  If someone comes
+ * along with another resource they want to allocate which has the
+ * same property, we might want to fold support for that into the
+ * generic interface, but for now, it's a special case
+ */
+
+struct process_chain {
+  pid_t pid;
+  enum kill_conditions kill_how;
+  struct process_chain *next;
+};
+
+void note_subprocess (pool *a, int pid, enum kill_conditions how)
+{
+  struct process_chain *new =
+    (struct process_chain *)palloc(a, sizeof(struct process_chain));
+
+  new->pid = pid;
+  new->kill_how = how;
+  new->next = a->subprocesses;
+  a->subprocesses = new;
+}
+
+int spawn_child (pool *p, void (*func)(void *), void *data,
+                enum kill_conditions kill_how,
+                FILE **pipe_in, FILE **pipe_out)
+{
+  int pid;
+  int in_fds[2];
+  int out_fds[2];
+
+  block_alarms();
+  
+  if (pipe_in && pipe (in_fds) < 0)
+  {
+      unblock_alarms();
+      return 0;
+  }
+  
+  if (pipe_out && pipe (out_fds) < 0) {
+    if (pipe_in) {
+      close (in_fds[0]); close (in_fds[1]);
+    }
+    unblock_alarms();
+    return 0;
+  }
+
+  if ((pid = fork()) < 0) {
+    if (pipe_in) {
+      close (in_fds[0]); close (in_fds[1]);
+    }
+    if (pipe_out) {
+      close (out_fds[0]); close (out_fds[1]);
+    }
+    unblock_alarms();
+    return 0;
+  }
+
+  if (!pid) {
+    /* Child process */
+    
+    if (pipe_out) {
+      close (out_fds[0]);
+      dup2 (out_fds[1], STDOUT_FILENO);
+      close (out_fds[1]);
+    }
+
+    if (pipe_in) {
+      close (in_fds[1]);
+      dup2 (in_fds[0], STDIN_FILENO);
+      close (in_fds[0]);
+    }
+
+    /* HP-UX SIGCHLD fix goes here, if someone will remind me what it is... */
+    signal (SIGCHLD, SIG_DFL); /* Was that it? */
+    
+    func (data);
+    exit (0);                  /* Should never get here... */
+  }
+
+  /* Parent process */
+
+  note_subprocess (p, pid, kill_how);
+  
+  if (pipe_out) {
+    close (out_fds[1]);
+#ifdef __EMX__
+    /* Need binary mode set for OS/2. */
+    *pipe_out = fdopen (out_fds[0], "rb");
+#else
+    *pipe_out = fdopen (out_fds[0], "r");
+#endif  
+  
+    if (*pipe_out) note_cleanups_for_file (p, *pipe_out);
+  }
+
+  if (pipe_in) {
+    close (in_fds[0]);
+#ifdef __EMX__
+    /* Need binary mode set for OS/2 */
+    *pipe_in = fdopen (in_fds[1], "wb");
+#else
+    *pipe_in = fdopen (in_fds[1], "w");
+#endif
+    
+    if (*pipe_in) note_cleanups_for_file (p, *pipe_in);
+  }
+
+  unblock_alarms();
+  return pid;
+}
+
+static void free_proc_chain (struct process_chain *procs)
+{
+  /* Dispose of the subprocesses we've spawned off in the course of
+   * whatever it was we're cleaning up now.  This may involve killing
+   * some of them off...
+   */
+
+  struct process_chain *p;
+  int need_timeout = 0;
+  int status;
+
+  if (procs == NULL) return;   /* No work.  Whew! */
+
+  /* First, check to see if we need to do the SIGTERM, sleep, SIGKILL
+   * dance with any of the processes we're cleaning up.  If we've got
+   * any kill-on-sight subprocesses, ditch them now as well, so they
+   * don't waste any more cycles doing whatever it is that they shouldn't
+   * be doing anymore.
+   */
+
+#ifndef NEED_WAITPID
+  /* Pick up all defunct processes */
+  for (p = procs; p; p = p->next) {
+    if (waitpid (p->pid, (int *) 0, WNOHANG) > 0) {
+      p->kill_how = kill_never;
+    }
+  }
+#endif
+
+  for (p = procs; p; p = p->next) {
+    if (p->kill_how == kill_after_timeout) {
+      /* Subprocess may be dead already.  Only need the timeout if not. */
+      if (kill (p->pid, SIGTERM) != -1)
+       need_timeout = 1;
+    } else if (p->kill_how == kill_always) {
+      kill (p->pid, SIGKILL);
+    }
+  }
+
+  /* Sleep only if we have to... */
+
+  if (need_timeout) sleep (3);
+
+  /* OK, the scripts we just timed out for have had a chance to clean up
+   * --- now, just get rid of them, and also clean up the system accounting
+   * goop...
+   */
+
+  for (p = procs; p; p = p->next){
+    
+    if (p->kill_how == kill_after_timeout) 
+      kill (p->pid, SIGKILL);
+
+    if (p->kill_how != kill_never)
+      waitpid (p->pid, &status, 0);
+  }
+}
+
+#ifdef __EMX__
+int spawn_child_os2 (pool *p, void (*func)(void *), void *data,
+         enum kill_conditions kill_how,
+         FILE **pipe_in, FILE **pipe_out, char *buffer, int lenp)
+{
+  int pid;
+  int in_fds[2];
+  int out_fds[2];
+
+  block_alarms();
+  
+  if (pipe_in && pipe (in_fds) < 0)
+  {
+      unblock_alarms();
+      return 0;
+  }
+  
+  if (pipe_out && pipe (out_fds) < 0) {
+    if (pipe_in) {
+      close (in_fds[0]); close (in_fds[1]);
+    }
+    unblock_alarms();
+    return 0;
+  }
+
+  if ((pid = fork()) < 0) {
+    if (pipe_in) {
+      close (in_fds[0]); close (in_fds[1]);
+    }
+    if (pipe_out) {
+      close (out_fds[0]); close (out_fds[1]);
+    }
+    unblock_alarms();
+    return 0;
+  }
+
+  if (!pid) {
+    int stdinpipe[2];
+    /* Due to a limitation of EMX, inheriting socket handles is not
+    allowed so we need to read the input and place it in a pipe and 
+    then pass that handle instead of the socket. */
+    
+    if (lenp > 0) {
+        pipe(stdinpipe);
+        write(stdinpipe[1], buffer, lenp);
+        close(stdinpipe[1]);
+        in_fds[0] = dup(stdinpipe[0]);
+        close(stdinpipe[0]);
+    }
+                                
+    /* Child process */
+    
+    if (pipe_out) {
+      close (out_fds[0]);
+      dup2 (out_fds[1], STDOUT_FILENO);
+      close (out_fds[1]);
+    }
+
+    if (pipe_in) {
+      close (in_fds[1]);
+      dup2 (in_fds[0], STDIN_FILENO);
+      close (in_fds[0]);
+    }
+
+    /* HP-UX SIGCHLD fix goes here, if someone will remind me what it is... */
+    signal (SIGCHLD, SIG_DFL);    /* Was that it? */
+    
+    func (data);
+    exit (0);            /* Should never get here... */
+  }
+
+  /* Parent process */
+
+  note_subprocess (p, pid, kill_how);
+  
+  if (pipe_out) {
+    close (out_fds[1]);
+    /* Need binary mode set for OS/2. */
+    *pipe_out = fdopen (out_fds[0], "rb");
+    
+    if (*pipe_out) note_cleanups_for_file (p, *pipe_out);
+  }
+
+  if (pipe_in) {
+    close (in_fds[0]);
+    /* Need binary mode set for OS/2. */
+    *pipe_in = fdopen (in_fds[1], "wb");
+    
+    if (*pipe_in) note_cleanups_for_file (p, *pipe_in);
+  }
+
+  unblock_alarms();
+  return pid;
+}
+#endif
diff --git a/RELEASE_1_1_X/src/main/buff.c b/RELEASE_1_1_X/src/main/buff.c
new file mode 100644 (file)
index 0000000..2636889
--- /dev/null
@@ -0,0 +1,648 @@
+/* ====================================================================
+ * Copyright (c) 1996 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "alloc.h"
+#include "buff.h"
+
+#define DEFAULT_BUFSIZE (4096)
+
+/*
+ * Buffered I/O routines.
+ * These are a replacement for the stdio routines.
+ * Advantages:
+ *  Known semantics for handling of file-descriptors (on close etc.)
+ *  No problems reading and writing simultanously to the same descriptor
+ *  No limits on the number of open file handles.
+ *  Only uses memory resources; no need to ensure the close routine
+ *  is called.
+ *  Extra code could be inserted between the buffered and un-buffered routines.
+ *  Timeouts could be handled by using select or poll before read or write.
+ *  Extra error handling could be introduced; e.g.
+ *   keep an address to which we should longjump(), or
+ *   keep a stack of routines to call on error.
+ */
+
+/* Notes:
+ *  On reading EOF, EOF will set in the flags and no further Input will
+ * be done.
+ *
+ * On an error except for EAGAIN, ERROR will be set in the flags and no
+ * futher I/O will be done
+ */
+
+static void
+doerror(BUFF *fb, int err)
+{
+    if (err == B_RD)
+       fb->flags |= B_RDERR;
+    else
+       fb->flags |= B_WRERR;
+    if (fb->error != NULL) (*fb->error)(fb, err, fb->error_data);
+}
+
+/* Buffering routines */
+/*
+ * Create a new buffered stream
+ */
+BUFF *
+bcreate(pool *p, int flags)
+{
+    BUFF *fb;
+
+    fb = palloc(p, sizeof(BUFF));
+    fb->pool=p;
+    fb->bufsiz = DEFAULT_BUFSIZE;
+    fb->flags = flags & B_RDWR;
+
+    if (flags & B_RD) fb->inbase = palloc(p, fb->bufsiz);
+    else fb->inbase = NULL;
+
+    if (flags & B_WR) fb->outbase = palloc(p, fb->bufsiz);
+    else fb->inbase = NULL;
+
+    fb->inptr = fb->inbase;
+
+    fb->incnt = 0;
+    fb->outcnt = 0;
+    fb->error = NULL;
+    fb->bytes_sent = 0L;
+
+    fb->fd = -1;
+    fb->fd_in = -1;
+
+    return fb;
+}
+
+/*
+ * Push some I/O file descriptors onto the stream
+ */
+void
+bpushfd(BUFF *fb, int fd_in, int fd_out)
+{
+    fb->fd = fd_out;
+    fb->fd_in = fd_in;
+    note_cleanups_for_fd(fb->pool,fb->fd);
+    if(fb->fd != fb->fd_in)
+       note_cleanups_for_fd(fb->pool,fb->fd_in);
+}
+
+int
+bsetopt(BUFF *fb, int optname, const void *optval)
+{
+    if (optname == BO_BYTECT)
+    {
+       fb->bytes_sent = *(const long int *)optval - (long int)fb->outcnt;;
+       return 0;
+    } else
+    {
+       errno = EINVAL;
+       return -1;
+    }
+}
+
+int
+bgetopt(BUFF *fb, int optname, void *optval)
+{
+    if (optname == BO_BYTECT)
+    {
+       long int bs=fb->bytes_sent + fb->outcnt;
+       if (bs < 0L) bs = 0L;
+       *(long int *)optval = bs;
+       return 0;
+    } else
+    {
+       errno = EINVAL;
+       return -1;
+    }
+}
+
+/*
+ * Read up to nbyte bytes into buf.
+ * If fewer than byte bytes are currently available, then return those.
+ * Returns 0 for EOF, -1 for error.
+ */
+int
+bread(BUFF *fb, void *buf, int nbyte)
+{
+    int i, nrd;
+
+    if (fb->flags & B_RDERR) return -1;
+    if (nbyte == 0) return 0;
+
+    if (!(fb->flags & B_RD))
+    {
+/* Unbuffered reading */
+       do i = read(fb->fd_in, buf, nbyte);
+       while (i == -1 && errno == EINTR);
+       if (i == -1 && errno != EAGAIN) doerror(fb, B_RD);
+       return i;
+    }
+
+    nrd = fb->incnt;
+/* can we fill the buffer */
+    if (nrd >= nbyte)
+    {
+       memcpy(buf, fb->inptr, nbyte);
+       fb->incnt = nrd - nbyte;
+       fb->inptr += nbyte;
+       return nbyte;
+    }
+       
+    if (nrd > 0)
+    {
+       memcpy(buf, fb->inptr, nrd);
+       nbyte -= nrd;
+       buf = nrd + (char *)buf;
+       fb->incnt = 0;
+    }
+    if (fb->flags & B_EOF) return nrd;
+
+/* do a single read */
+    if (nbyte >= fb->bufsiz)
+    {
+/* read directly into buffer */
+       do i = read(fb->fd_in, buf, nbyte);
+       while (i == -1 && errno == EINTR);
+       if (i == -1)
+       {
+           if (nrd == 0)
+           {
+               if (errno != EAGAIN) doerror(fb, B_RD);
+               return -1;
+           }
+           else return nrd;
+       } else if (i == 0) fb->flags |= B_EOF;
+    } else
+    {
+/* read into hold buffer, then memcpy */
+       fb->inptr = fb->inbase;
+       do i = read(fb->fd_in, fb->inptr, fb->bufsiz);
+       while (i == -1 && errno == EINTR);
+       if (i == -1)
+       {
+           if (nrd == 0)
+           {
+               if (errno != EAGAIN) doerror(fb, B_RD);
+               return -1;
+           }
+           else return nrd;
+       } else if (i == 0) fb->flags |= B_EOF;
+       fb->incnt = i;
+       if (i > nbyte) i = nbyte;
+       memcpy(buf, fb->inptr, i);
+       fb->incnt -= i;
+       fb->inptr += i;
+    }
+    return nrd + i;
+}
+
+
+/*
+ * Reads from the stream into the array pointed to by buff, until
+ * a (CR)LF sequence is read, or end-of-file condition is encountered
+ * or until n-1 bytes have been stored in buff. If a CRLF sequence is
+ * read, it is replaced by a newline character.  The string is then
+ * terminated with a null character.
+ *
+ * Returns the number of bytes stored in buff, or zero on end of
+ * transmission, or -1 on an error.
+ *
+ * Notes:
+ *  If null characters are exepected in the data stream, then
+ * buff should not be treated as a null terminated C string; instead
+ * the returned count should be used to determine the length of the
+ * string.
+ *  CR characters in the byte stream not immediately followed by a LF
+ * will be preserved.
+ */
+int
+bgets(char *buff, int n, BUFF *fb)
+{
+    int i, ch, ct;
+
+/* Can't do bgets on an unbuffered stream */
+    if (!(fb->flags & B_RD))
+    {
+       errno = EINVAL;
+       return -1;
+    }
+    if (fb->flags & B_RDERR) return -1;
+
+    ct = 0;
+    i = 0;
+    for (;;)
+    {
+       if (i == fb->incnt)
+       {
+/* no characters left */
+           fb->inptr = fb->inbase;
+           fb->incnt = 0;
+           if (fb->flags & B_EOF) break;
+           do i = read(fb->fd_in, fb->inptr, fb->bufsiz);
+           while (i == -1 && errno == EINTR);
+           if (i == -1)
+           {
+               buff[ct] = '\0';
+               if (ct == 0)
+               {
+                   if (errno != EAGAIN) doerror(fb, B_RD);
+                   return -1;
+               }
+               else return ct;
+           }
+           fb->incnt = i;
+           if (i == 0)
+           {
+               fb->flags |= B_EOF;
+               break; /* EOF */
+           }
+           i = 0;
+           continue;  /* restart with the new data */
+       }
+
+       ch = fb->inptr[i++];
+       if (ch == '\012')  /* got LF */
+       {
+           if (ct == 0) buff[ct++] = '\n';
+/* if just preceeded by CR, replace CR with LF */
+           else if (buff[ct-1] == '\015') buff[ct-1] = '\n';
+           else if (ct < n-1) buff[ct++] = '\n';
+           else i--; /* no room for LF */
+           break;
+       }
+       if (ct == n-1)
+       {
+           i--;  /* push back ch */
+           break;
+       }
+       
+       buff[ct++] = ch;
+    }
+    fb->incnt -= i;
+    fb->inptr += i;
+
+    buff[ct] = '\0';
+    return ct;
+}
+
+/*
+ * Skip data until a linefeed character is read
+ * Returns 1 on success, 0 if no LF found, or -1 on error
+ */
+int
+bskiplf(BUFF *fb)
+{
+    unsigned char *x;
+    int i;
+
+/* Can't do bskiplf on an unbuffered stream */
+    if (!(fb->flags & B_RD))
+    {
+       errno = EINVAL;
+       return -1;
+    }
+    if (fb->flags & B_RDERR) return -1;
+
+    for (;;)
+    {
+       x = memchr(fb->inptr, '\012', fb->incnt);
+       if (x != NULL)
+       {
+           x++;
+           fb->incnt -= x - fb->inptr;
+           fb->inptr = x;
+           return 1;
+       }
+
+       fb->inptr = fb->inbase;
+       fb->incnt = 0;
+       if (fb->flags & B_EOF) return 0;
+       do i = read(fb->fd_in, fb->inptr, fb->bufsiz);
+       while (i == -1 && errno == EINTR);
+       if (i == 0) fb->flags |= B_EOF;
+       if (i == -1 && errno != EAGAIN) doerror(fb, B_RD);
+       if (i == 0 || i == -1) return i;
+       fb->incnt = i;
+    }
+}
+
+/*
+ * Emtpy the buffer after putting a single character in it
+ */
+int
+bflsbuf(int c, BUFF *fb)
+{
+    char ss[1];
+
+    ss[0] = c;
+    return bwrite(fb, ss, 1);
+}
+
+/*
+ * Fill the buffer and read a character from it
+ */
+int
+bfilbuf(BUFF *fb)
+{
+    int i;
+    char buf[1];
+
+    i = bread(fb, buf, 1);
+    if (i == 0) errno = 0;  /* no error; EOF */
+    if (i != 1) return EOF;
+    else return buf[0];
+}
+
+/*
+ * Write nbyte bytes.
+ * Only returns fewer than nbyte if an error ocurred.
+ * Returns -1 if no bytes were written before the error ocurred.
+ */
+int
+bwrite(BUFF *fb, const void *buf, int nbyte)
+{
+    int i, nwr;
+
+    if (fb->flags & (B_WRERR|B_EOUT)) return -1;
+    if (nbyte == 0) return 0;
+
+    if (!(fb->flags & B_WR))
+    {
+/* unbuffered write */
+       do i = write(fb->fd, buf, nbyte);
+       while (i == -1 && errno == EINTR);
+       if (i > 0) fb->bytes_sent += i;
+       if (i == 0)
+       {
+           i = -1;  /* return of 0 means non-blocking */
+           errno = EAGAIN;
+       }
+       if (i == -1 && errno != EAGAIN) doerror(fb, B_WR);
+       return i;
+    }
+
+/*
+ * Whilst there is data in the buffer, keep on adding to it and writing it
+ * out
+ */
+    nwr = 0;
+    while (fb->outcnt > 0)
+    {
+/* can we accept some data? */
+       i = fb->bufsiz - fb->outcnt;
+       if (i > 0)
+       {
+           if (i > nbyte) i = nbyte;
+           memcpy(fb->outbase + fb->outcnt, buf, i);
+           fb->outcnt += i;
+           nbyte -= i;
+           buf = i + (const char *)buf;
+           nwr += i;
+           if (nbyte == 0) return nwr; /* return if none left */
+       }
+
+/* the buffer must be full */
+       do i = write(fb->fd, fb->outbase, fb->bufsiz);
+       while (i == -1 && errno == EINTR);
+       if (i > 0) fb->bytes_sent += i;
+       if (i == 0)
+       {
+           i = -1;  /* return of 0 means non-blocking */
+           errno = EAGAIN;
+       }
+       if (i == -1)
+       {
+           if (nwr == 0)
+           {
+               if (errno != EAGAIN) doerror(fb, B_WR);
+               return -1;
+           }
+           else return nwr;
+       }
+
+/*
+ * we should have written all the data, however if the fd was in a
+ * strange (non-blocking) mode, then we might not have done so.
+ */
+       if (i < fb->bufsiz)
+       {
+           int j, n=fb->bufsiz;
+           unsigned char *x=fb->outbase;
+           for (j=i; j < n; j++) x[j-i] = x[j];
+           fb->outcnt = fb->bufsiz - i;
+       } else
+           fb->outcnt = 0;
+    }
+/* we have emptied the file buffer. Now try to write the data from the
+ * original buffer until there is less than bufsiz left
+ */
+    while (nbyte > fb->bufsiz)
+    {
+       do i = write(fb->fd, buf, nbyte);
+       while (i == -1 && errno == EINTR);
+       if (i > 0) fb->bytes_sent += i;
+       if (i == 0)
+       {
+           i = -1;  /* return of 0 means non-blocking */
+           errno = EAGAIN;
+       }
+       if (i == -1)
+       {
+           if (nwr == 0)
+           {
+               if (errno != EAGAIN) doerror(fb, B_WR);
+               return -1;
+           }
+           else return nwr;
+       }
+
+       buf = i + (const char *)buf;
+       nwr += i;
+       nbyte -= i;
+    }
+/* copy what's left to the file buffer */
+    if (nbyte > 0) memcpy(fb->outbase, buf, nbyte);
+    fb->outcnt = nbyte;
+    nwr += nbyte;
+    return nwr;
+}
+
+/*
+ * Flushes the buffered stream.
+ * Returns 0 on success or -1 on error
+ */
+int
+bflush(BUFF *fb)
+{
+    int i, j;
+
+    if (!(fb->flags & B_WR) || (fb->flags & B_EOUT)) return 0;
+
+    if (fb->flags & B_WRERR) return -1;
+    
+    while (fb->outcnt > 0)
+    {
+/* the buffer must be full */
+       j = fb->outcnt;
+       do i = write(fb->fd, fb->outbase, fb->outcnt);
+       while (i == -1 && errno == EINTR);
+       if (i > 0) fb->bytes_sent += i;
+       if (i == 0)
+       {
+           errno = EAGAIN;
+           return -1;  /* return of 0 means non-blocking */
+       }
+       if (i == -1)
+       {
+           if (errno != EAGAIN) doerror(fb, B_WR);
+           return -1;
+       }
+
+/*
+ * we should have written all the data, however if the fd was in a
+ * strange (non-blocking) mode, then we might not have done so.
+ */
+       if (i < fb->outcnt)
+       {
+           int j, n=fb->outcnt;
+           unsigned char *x=fb->outbase;
+           for (j=i; j < n; j++) x[j-i] = x[j];
+       }
+       fb->outcnt -= i;
+    }
+    return 0;
+}
+
+/*
+ * Flushes and closes the file, even if an error occurred.
+ * Discards an data that was not read, or not written by bflush()
+ * Sets the EOF flag to indicate no futher data can be read,
+ * and the EOUT flag to indicate no further data can be written.
+ */
+int
+bclose(BUFF *fb)
+{
+    int rc1, rc2, rc3;
+
+    if (fb->flags & B_WR) rc1 = bflush(fb);
+    else rc1 = 0;
+    rc2 = close(fb->fd);
+    if (fb->fd_in != fb->fd) rc3 = close(fb->fd_in);
+    else rc3 = 0;
+
+    fb->inptr = fb->inbase;
+    fb->incnt = 0;
+    fb->outcnt = 0;
+
+    fb->flags |= B_EOF | B_EOUT;
+    fb->fd = -1;
+    fb->fd_in = -1;
+
+    if (rc1 != 0) return rc1;
+    else if (rc2 != 0) return rc2;
+    else return rc3;
+}
+
+/*
+ * returns the number of bytes written or -1 on error
+ */
+int
+bputs(const char *x, BUFF *fb)
+{
+    int i, j=strlen(x);
+    i = bwrite(fb, x, j);
+    if (i != j) return -1;
+    else return j;
+}
+
+/*
+ * returns the number of bytes written or -1 on error
+ */
+int
+bvputs(BUFF *fb, ...)
+{
+    int i, j, k;
+    va_list v;
+    const char *x;
+
+    va_start(v, fb);
+    for (k=0;;)
+    {
+       x = va_arg(v, const char *);
+       if (x == NULL) break;
+       j = strlen(x);
+       i = bwrite(fb, x, j);
+       if (i != j)
+       {
+           va_end(v);
+           return -1;
+       }
+       k += i;
+    }
+
+    va_end(v);
+
+    return k;
+}
+
+void
+bonerror(BUFF *fb, void (*error)(BUFF *, int, void *), void *data)
+{
+    fb->error = error;
+    fb->error_data = data;
+}
diff --git a/RELEASE_1_1_X/src/main/explain.c b/RELEASE_1_1_X/src/main/explain.c
new file mode 100644 (file)
index 0000000..6490c94
--- /dev/null
@@ -0,0 +1,14 @@
+#include <stdio.h>
+#include <stdarg.h>
+#include "explain.h"
+
+void _Explain(const char *szFile,int nLine,const char *szFmt,...)
+    {
+    va_list vlist;
+
+    fprintf(stderr,"%s(%d): ",szFile,nLine);
+    va_start(vlist,szFmt);
+    vfprintf(stderr,szFmt,vlist);
+    va_end(vlist);
+    fputc('\n',stderr);
+    }
diff --git a/RELEASE_1_1_X/src/main/http_bprintf.c b/RELEASE_1_1_X/src/main/http_bprintf.c
new file mode 100644 (file)
index 0000000..63443d7
--- /dev/null
@@ -0,0 +1,590 @@
+/*
+ * printf() style routines stolen from FastCGI
+ * Copyright (c) 1996 Open Market, Inc.
+ */
+
+/*
+ * Modified to work with Apache buffering routines by Ben Laurie
+ * <ben@algroup.co.uk>.
+ *
+ * Modifications Copyright (C) 1996 Ben Laurie.
+ *
+ * History:
+ * 18 May 1996 Initial revision [Ben Laurie]
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#ifndef QNX
+#include <memory.h>
+#endif
+#include <assert.h>
+#include <math.h>
+#include "alloc.h"
+#include "buff.h"
+
+#if !defined(max)
+#define max(a,b)       (a > b ? a : b)
+#endif
+
+#define LONG_DOUBLE    long double
+
+#define FALSE  0
+#define TRUE   1
+
+#define PRINTF_BUFFLEN 100
+    /*
+     * More than sufficient space for all unmodified conversions
+     * except %s and %f.
+     */
+#define FMT_BUFFLEN 25
+    /*
+     * Max size of a format specifier is 1 + 5 + 7 + 7 + 2 + 1 + slop
+     */
+
+/*
+ * Copy n characters from *srcPtr to *destPtr, then increment
+ * both *srcPtr and *destPtr by n.
+ */
+static void CopyAndAdvance(char **destPtr, const char **srcPtr, int n)
+    {
+    char *dest = *destPtr;
+    const char *src = *srcPtr;
+    int i;
+    
+    for (i = 0; i < n; i++)
+        *dest++ = *src++;
+    *destPtr = dest;
+    *srcPtr = src;
+    }
+
+int vbprintf(BUFF *bp, const char *format, va_list arg)
+    {
+    const char *f,*fStop,*percentPtr,*p;
+    char *fmtBuffPtr, *buffPtr;
+    int op, performedOp, sizeModifier, buffLen, specifierLength;
+    int fastPath, n, buffReqd, minWidth, precision, exp;
+    int buffCount = 0;
+    int auxBuffLen = 0;
+    char *auxBuffPtr = NULL;
+    int streamCount = 0;
+    char fmtBuff[FMT_BUFFLEN];
+    char buff[PRINTF_BUFFLEN];
+
+    int intArg;
+    short shortArg;
+    long longArg;
+    unsigned unsignedArg;
+    unsigned long uLongArg;
+    unsigned short uShortArg;
+    char *charPtrArg = NULL;
+    void *voidPtrArg;
+    int *intPtrArg;
+    long *longPtrArg;
+    short *shortPtrArg;
+    double doubleArg = 0.0;
+    LONG_DOUBLE lDoubleArg = 0.0;
+
+    fmtBuff[0] = '%';
+    f=format;
+    fStop = f + strlen(f);
+    while (f != fStop)
+       {
+        percentPtr = memchr(f, '%', fStop - f);
+        if(percentPtr == NULL) percentPtr = fStop;
+        if(percentPtr != f)
+           {
+            if(bwrite(bp,f,percentPtr - f) < 0)
+               goto ErrorReturn;
+            streamCount += percentPtr - f;
+            f = percentPtr;
+            if(f == fStop)
+               break;
+           }
+        fastPath = TRUE;
+        /*
+         * The following loop always executes either once or twice.
+         */
+        for (;;)
+           {
+            if(fastPath)
+               {
+                /*
+                 * Fast path: Scan optimistically, hoping that no flags,
+                 * minimum field width, or precision are specified.
+                 * Use the preallocated buffer, which is large enough
+                 * for all fast path cases.  If the conversion specifier
+                 * is really more complex, run the loop a second time
+                 * using the slow path.
+                 * Note that fast path execution of %s bypasses the buffer
+                 * and %f is not attempted on the fast path due to
+                 * its large buffering requirements.
+                 */
+                op = percentPtr[1];
+                switch(op)
+                   {
+               case 'l':
+               case 'L':
+                case 'h':
+                   sizeModifier = op;
+                   op = percentPtr[2];
+                   fmtBuff[1] = sizeModifier;
+                   fmtBuff[2] = op;
+                   fmtBuff[3] = '\0';
+                   specifierLength = 3;
+                   break;
+               default:
+                   sizeModifier = ' ';
+                   fmtBuff[1] = op;
+                   fmtBuff[2] = '\0';
+                   specifierLength = 2;
+                   break;
+                   }
+                buffPtr = buff;
+                buffLen = PRINTF_BUFFLEN;
+               }
+           else
+               {
+                /*
+                 * Slow path: Scan the conversion specifier and construct
+                 * a new format string, compute an upper bound on the
+                 * amount of buffering that sprintf will require,
+                 * and allocate a larger buffer if necessary.
+                 */
+                p = percentPtr + 1;
+                fmtBuffPtr = &fmtBuff[1];
+                /*
+                 * Scan flags
+                 */
+                n = strspn(p, "-0+ #");
+                if(n > 5)
+                   goto ErrorReturn;
+                CopyAndAdvance(&fmtBuffPtr, &p, n);
+
+               /* Optimiser bug in SCO 5 - p is not advanced here under -O2.
+                * -K noinline fixes it. Ben.
+                */
+
+                /*
+                 * Scan minimum field width
+                 */
+                n = strspn(p, "0123456789");
+                if(n == 0)
+                   {
+                    if(*p == '*')
+                       {
+                        minWidth = va_arg(arg, int);
+                        if(abs(minWidth) > 999999) goto ErrorReturn;
+                       /*
+                        * The following use of strlen rather than the
+                        * value returned from sprintf is because SUNOS4
+                        * returns a char * instead of an int count.
+                        */
+                       sprintf(fmtBuffPtr, "%d", minWidth);
+                        fmtBuffPtr += strlen(fmtBuffPtr);
+                        p++;
+                       }
+                   else
+                        minWidth = 0;
+                   }
+               else if(n <= 6)
+                   {
+                    minWidth = strtol(p, NULL, 10);
+                    CopyAndAdvance(&fmtBuffPtr, &p, n);
+                   }
+               else
+                    goto ErrorReturn;
+                /*
+                 * Scan precision
+                 */
+               if(*p == '.')
+                   {
+                    p++;
+                    n = strspn(p, "0123456789");
+                    if(n == 0)
+                       {
+                        if(*p == '*')
+                           {
+                            precision = va_arg(arg, int);
+                            if(precision < 0) precision = 0;
+                            if(precision > 999999) goto ErrorReturn;
+                           /*
+                            * The following use of strlen rather than the
+                            * value returned from sprintf is because SUNOS4
+                            * returns a char * instead of an int count.
+                            */
+                           sprintf(fmtBuffPtr, ".%d", precision);
+                           fmtBuffPtr += strlen(fmtBuffPtr);
+                            p++;
+                           }
+                       else
+                            precision = 0;
+                       }
+                   else if(n <= 6)
+                       {
+                        precision = strtol(p, NULL, 10);
+                       *fmtBuffPtr++='.';
+                        CopyAndAdvance(&fmtBuffPtr, &p, n);
+                       }
+                   else
+                        goto ErrorReturn;
+                   }
+               else
+                    precision = -1;
+                /*
+                 * Scan size modifier and conversion operation
+                 */
+                switch(*p)
+                   {
+               case 'l':
+                case 'L':
+                case 'h':
+                   sizeModifier = *p;
+                   CopyAndAdvance(&fmtBuffPtr, &p, 1);
+                   break;
+               
+               default:
+                   sizeModifier = ' ';
+                   break;
+                   }
+                op = *p;
+                CopyAndAdvance(&fmtBuffPtr, &p, 1);
+                assert(fmtBuffPtr - fmtBuff < FMT_BUFFLEN);
+                *fmtBuffPtr = '\0';
+               /*
+               bwrite(bp,"[",1);
+               bwrite(bp,fmtBuff,strlen(fmtBuff));
+               bwrite(bp,"]",1);
+               */
+                specifierLength = p - percentPtr;
+                /*
+                 * Bound the required buffer size.  For s and f
+                 * conversions this requires examining the argument.
+                 */
+                switch(op)
+                   {
+               case 'd':
+                case 'i':
+                case 'u':
+                case 'o':
+                case 'x':
+                case 'X':
+                case 'c':
+                case 'p':
+                   buffReqd = max(precision, 46);
+                   break;
+
+               case 's':
+                   charPtrArg = va_arg(arg, char *);
+                   if(precision == -1)
+                       buffReqd = strlen(charPtrArg);
+                   else
+                       {
+                       p = memchr(charPtrArg, '\0', precision);
+                       buffReqd=(p == NULL) ? precision : p - charPtrArg;
+                       }
+                   break;
+
+               case 'f':
+                   switch(sizeModifier)
+                       {
+                   case ' ':
+                       doubleArg = va_arg(arg, double);
+                       frexp(doubleArg, &exp);
+                       break;
+
+                   case 'L':
+                       lDoubleArg = va_arg(arg, LONG_DOUBLE);
+                       frexp(lDoubleArg, &exp);
+                       break;
+
+                   default:
+                       goto ErrorReturn;
+                        }
+                   if(precision == -1)
+                       precision = 6;
+                   buffReqd = precision + 3 + ((exp > 0) ? exp/3 : 0);
+                   break;
+                   
+               case 'e':
+               case 'E':
+               case 'g':
+               case 'G':
+                   if(precision == -1)
+                       precision = 6;
+                   buffReqd = precision + 8;
+                   break;
+
+               case 'n':
+               case '%':
+               default:
+                   goto ErrorReturn;
+                   }
+                buffReqd = max(buffReqd + 10, minWidth);
+                /*
+                 * Allocate the buffer
+                 */
+               if(buffReqd <= PRINTF_BUFFLEN)
+                   {
+                    buffPtr = buff;
+                   buffLen = PRINTF_BUFFLEN;
+                   }
+               else
+                   {
+                    if(auxBuffPtr == NULL || buffReqd > auxBuffLen)
+                       {
+                       if(auxBuffPtr != NULL) free(auxBuffPtr);
+                        auxBuffPtr = malloc(buffReqd);
+                        auxBuffLen = buffReqd;
+                        if(auxBuffPtr == NULL)
+                           goto ErrorReturn;
+                       }
+                    buffPtr = auxBuffPtr;
+                   buffLen = auxBuffLen;
+                   }
+               }
+            /*
+             * This giant switch statement requires the following variables
+             * to be set up: op, sizeModifier, arg, buffPtr, fmtBuff.
+             * When fastPath == FALSE and op == 's' or 'f', the argument
+             * has been read into charPtrArg, doubleArg, or lDoubleArg.
+             * The statement produces the boolean performedOp, TRUE iff
+             * the op/sizeModifier were executed and argument consumed;
+             * if performedOp, the characters written into buffPtr[]
+             * and the character count buffCount (== EOF meaning error).
+             *
+             * The switch cases are arranged in the same order as in the
+             * description of fprintf in section 15.11 of Harbison and Steele.
+             */
+            performedOp = TRUE;
+            switch(op)
+               {
+           case 'd':
+           case 'i':
+               switch(sizeModifier)
+                   {
+               case ' ':
+                   intArg = va_arg(arg, int);
+                   sprintf(buffPtr, fmtBuff, intArg);
+                   buffCount = strlen(buffPtr);
+                   break;
+               
+               case 'l':
+                   longArg = va_arg(arg, long);
+                   sprintf(buffPtr, fmtBuff, longArg);
+                   buffCount = strlen(buffPtr);
+                   break;
+                   
+               case 'h':
+                   shortArg = va_arg(arg, short);
+                   sprintf(buffPtr, fmtBuff, shortArg);
+                   buffCount = strlen(buffPtr);
+                   break;
+               
+               default:
+                   goto ErrorReturn;
+                   }
+               break;
+
+           case 'u':
+           case 'o':
+           case 'x':
+           case 'X':
+               switch(sizeModifier)
+                   {
+               case ' ':
+                   unsignedArg = va_arg(arg, unsigned);
+                   sprintf(buffPtr, fmtBuff, unsignedArg);
+                   buffCount = strlen(buffPtr);
+                   break;
+               
+               case 'l':
+                   uLongArg = va_arg(arg, unsigned long);
+                   sprintf(buffPtr, fmtBuff, uLongArg);
+                   buffCount = strlen(buffPtr);
+                   break;
+               
+               case 'h':
+                   uShortArg = va_arg(arg, unsigned short);
+                   sprintf(buffPtr, fmtBuff, uShortArg);
+                   buffCount = strlen(buffPtr);
+                   break;
+               
+               default:
+                   goto ErrorReturn;
+                    }
+               break;
+
+           case 'c':
+               switch(sizeModifier)
+                   {
+               case ' ':
+                   intArg = va_arg(arg, int);
+                   sprintf(buffPtr, fmtBuff, intArg);
+                   buffCount = strlen(buffPtr);
+                   break;
+
+               case 'l':
+                   /*
+                    * XXX: Allowed by ISO C Amendment 1, but
+                    * many platforms don't yet support wint_t
+                    */
+                   goto ErrorReturn;
+
+               default:
+                   goto ErrorReturn;
+                    }
+               break;
+
+           case 's':
+               switch(sizeModifier)
+                   {
+               case ' ':
+                   if(fastPath)
+                       {
+                       buffPtr = va_arg(arg, char *);
+                       buffCount = strlen(buffPtr);
+                       buffLen = buffCount + 1;
+                       }
+                   else
+                       {
+                       sprintf(buffPtr, fmtBuff, charPtrArg);
+                       buffCount = strlen(buffPtr);
+                       }
+                   break;
+
+               case 'l':
+                   /*
+                    * XXX: Don't know how to convert a sequence
+                    * of wide characters into a byte stream, or
+                    * even how to predict the buffering required.
+                    */
+                   goto ErrorReturn;
+
+               default:
+                   goto ErrorReturn;
+                    }
+               break;
+
+           case 'p':
+               if(sizeModifier != ' ')
+                   goto ErrorReturn;
+               voidPtrArg = va_arg(arg, void *);
+               sprintf(buffPtr, fmtBuff, voidPtrArg);
+               buffCount = strlen(buffPtr);
+               break;
+
+           case 'n':
+               switch(sizeModifier)
+                   {
+               case ' ':
+                   intPtrArg = va_arg(arg, int *);
+                   *intPtrArg = streamCount;
+                   break;
+
+               case 'l':
+                   longPtrArg = va_arg(arg, long *);
+                   *longPtrArg = streamCount;
+                   break;
+
+               case 'h':
+                   shortPtrArg = va_arg(arg, short *);
+                   *shortPtrArg = streamCount;
+                   break;
+
+               default:
+                   goto ErrorReturn;
+                   }
+               buffCount = 0;
+               break;
+
+           case 'f':
+               if(fastPath)
+                   {
+                   performedOp = FALSE;
+                   break;
+                   }
+
+               switch(sizeModifier)
+                   {
+               case ' ':
+                   sprintf(buffPtr, fmtBuff, doubleArg);
+                   buffCount = strlen(buffPtr);
+                   break;
+
+               case 'L':
+                   sprintf(buffPtr, fmtBuff, lDoubleArg);
+                   buffCount = strlen(buffPtr);
+                   break;
+
+               default:
+                   goto ErrorReturn;
+                    }
+               break;
+               /* FIXME: Used to flow through here? Should it? Ben */
+
+           case 'e':
+           case 'E':
+           case 'g':
+           case 'G':
+               switch(sizeModifier)
+                   {
+               case ' ':
+                   doubleArg = va_arg(arg, double);
+                   sprintf(buffPtr, fmtBuff, doubleArg);
+                   buffCount = strlen(buffPtr);
+                   break;
+
+               case 'L':
+                   lDoubleArg = va_arg(arg, LONG_DOUBLE);
+                   sprintf(buffPtr, fmtBuff, lDoubleArg);
+                   buffCount = strlen(buffPtr);
+                   break;
+
+               default:
+                   goto ErrorReturn;
+                    }
+               break;
+
+           case '%':
+               if(sizeModifier != ' ')
+                   goto ErrorReturn;
+               buff[0] = '%';
+               buffCount = 1;
+               break;
+
+           case '\0':
+               goto ErrorReturn;
+
+           default:
+               performedOp = FALSE;
+               break;
+               } /* switch(op) */
+
+            if(performedOp)
+               break;
+            if(!fastPath)
+               goto ErrorReturn;
+            fastPath = FALSE;
+           } /* for (;;) */
+        assert(buffCount < buffLen);
+        if(buffCount > 0)
+           {
+            if(bwrite(bp,buffPtr,buffCount) < 0)
+                goto ErrorReturn;
+            streamCount += buffCount;
+           }
+       else if(buffCount < 0)
+            goto ErrorReturn;
+        f += specifierLength;
+       } /* while(f != fStop) */
+    goto NormalReturn;
+ErrorReturn:
+    streamCount = -1;
+NormalReturn:
+    if(auxBuffPtr != NULL)
+       free(auxBuffPtr);
+    return streamCount;
+    }
diff --git a/RELEASE_1_1_X/src/main/http_config.c b/RELEASE_1_1_X/src/main/http_config.c
new file mode 100644 (file)
index 0000000..8d2d586
--- /dev/null
@@ -0,0 +1,782 @@
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * http_config.c: once was auxillary functions for reading httpd's config
+ * file and converting filenames into a namespace
+ *
+ * Rob McCool 
+ * 
+ * Wall-to-wall rewrite for Shambhala... commands which are part of the
+ * server core can now be found next door in "http_core.c".  Now contains
+ * general command loop, and functions which do bookkeeping for the new
+ * Shambhala config stuff (modules and configuration vectors).
+ *
+ * rst
+ *
+ */
+
+#define CORE_PRIVATE
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_core.h"
+#include "http_log.h"          /* for errors in parse_htaccess */
+#include "http_request.h"      /* for default_handler (see invoke_handler) */
+#include "http_conf_globals.h" /* Sigh... */
+
+/****************************************************************
+ *
+ * We begin with the functions which deal with the linked list
+ * of modules which control just about all of server operation in
+ * Shambhala.
+ */
+
+static int num_modules = 0;    
+module *top_module = NULL;
+    
+typedef int (*handler)(request_rec *);
+typedef void *(*maker)(pool *);
+typedef void *(*dir_maker)(pool *, char *);
+typedef void *(*merger)(pool *, void *, void *);    
+
+/* Dealing with config vectors.  These are associated with per-directory,
+ * per-server, and per-request configuration, and have a void* pointer for
+ * each modules.  The nature of the structure pointed to is private to the
+ * module in question... the core doesn't (and can't) know.  However, there
+ * are defined interfaces which allow it to create instances of its private
+ * per-directory and per-server structures, and to merge the per-directory
+ * structures of a directory and its subdirectory (producing a new one in
+ * which the defaults applying to the base directory have been properly
+ * overridden).
+ */
+
+void *    
+get_module_config (void *conf_vector, module *m)
+{
+   void **confv = (void**)conf_vector;
+   return confv[m->module_index];
+}
+
+void
+set_module_config (void *conf_vector, module *m, void *val)
+{
+   void **confv = (void**)conf_vector;
+   confv[m->module_index] = val;
+}
+
+void *
+create_empty_config (pool *p)
+{
+   void **conf_vector = (void **)pcalloc(p, sizeof(void*) * num_modules);
+   return (void *)conf_vector;
+}
+
+void *
+create_default_per_dir_config (pool *p)
+{
+   void **conf_vector = (void **)pcalloc(p, sizeof(void*) * (num_modules+DYNAMIC_MODULE_LIMIT));
+   module *modp;
+
+   for (modp = top_module; modp; modp = modp->next) {
+       dir_maker df = modp->create_dir_config;
+
+       if (df) conf_vector[modp->module_index] = (*df)(p, NULL);
+   }
+
+   return (void*)conf_vector;
+}
+
+void *
+merge_per_dir_configs (pool *p, void *base, void *new)
+{
+   void **conf_vector = (void **)pcalloc(p, sizeof(void*) * num_modules);
+   void **base_vector = (void **) base;
+   void **new_vector = (void **) new;
+   module *modp;
+
+   for (modp = top_module; modp; modp = modp->next) {
+       merger df = modp->merge_dir_config;
+       int i = modp->module_index;
+
+       if (df && new_vector[i])
+          conf_vector[i] = (*df)(p, base_vector[i], new_vector[i]);
+       else
+          conf_vector[i] = new_vector[i]? new_vector[i] : base_vector[i];
+   }
+
+   return (void*)conf_vector;
+}
+
+void *
+create_server_config (pool *p, server_rec *s)
+{
+   void **conf_vector = (void **)pcalloc(p, sizeof(void*) * (num_modules+DYNAMIC_MODULE_LIMIT));
+   module *modp;
+
+   for (modp = top_module; modp; modp = modp->next) {
+       if (modp->create_server_config)
+          conf_vector[modp->module_index]=(*modp->create_server_config)(p,s);
+   }
+
+   return (void*)conf_vector;
+}
+
+void merge_server_configs (pool *p, void *base, void *virt)
+{
+    /* Can reuse the 'virt' vector for the spine of it, since we don't
+     * have to deal with the moral equivalent of .htaccess files here...
+     */
+
+    void **base_vector = (void **)base;
+    void **virt_vector = (void **)virt;
+    module *modp;
+    
+    for (modp = top_module; modp; modp = modp->next) {
+       merger df = modp->merge_server_config;
+       int i = modp->module_index;
+
+       if (!virt_vector[i])
+           virt_vector[i] = base_vector[i];
+       else if (df)
+           virt_vector[i] = (*df)(p, base_vector[i], virt_vector[i]);
+    }
+}
+void *create_connection_config (pool *p) {
+    return create_empty_config (p);
+}
+
+void *create_request_config (pool *p) {
+    return create_empty_config (p);
+}
+
+void *create_per_dir_config (pool *p) {
+    return create_empty_config (p);
+}
+
+/****************************************************************
+ *
+ * Dispatch through the modules to find handlers for various phases
+ * of request handling.  These are invoked by http_request.c to actually
+ * do the dirty work of slogging through the module structures.
+ */
+
+int
+run_method (request_rec *r, int offset, int run_all)
+{
+   module *modp;
+   for (modp = top_module; modp; modp = modp->next) {
+       handler mod_handler = *(handler *)(offset + (char *)(modp));
+
+       if (mod_handler) {
+          int result = (*mod_handler)(r);
+
+          if (result != DECLINED && (!run_all || result != OK))
+              return result;
+       }
+   }
+
+   return run_all ? OK : DECLINED;
+}
+
+int translate_name(request_rec *r) {
+   return run_method (r, XtOffsetOf (module, translate_handler), 0);
+}
+
+int check_access(request_rec *r) {
+   return run_method (r, XtOffsetOf (module, access_checker), 1);
+}
+
+int find_types (request_rec *r) {
+   return run_method (r, XtOffsetOf (module, type_checker), 0);
+}
+
+int run_fixups (request_rec *r) {
+   return run_method (r, XtOffsetOf (module, fixer_upper), 1);
+}
+
+int log_transaction (request_rec *r) {
+   return run_method (r, XtOffsetOf (module, logger), 1);
+}
+
+/* Auth stuff --- anything that defines one of these will presumably
+ * want to define something for the other.  Note that check_auth is
+ * separate from check_access to make catching some config errors easier.
+ */
+
+int check_user_id (request_rec *r) {
+   return run_method (r, XtOffsetOf (module, check_user_id), 0);
+}
+
+int check_auth (request_rec *r) {
+   return run_method (r, XtOffsetOf (module, auth_checker), 0);
+}
+
+int invoke_handler (request_rec *r)
+{
+   module *modp;
+   handler_rec *handp;
+   char *content_type = r->content_type ? r->content_type : default_type (r);
+   char *handler = r->handler ? r->handler : content_type;
+  
+   /* Pass one --- direct matches */
+   
+   for (modp = top_module; modp; modp = modp->next) 
+   {
+       if (!modp->handlers) continue;
+       
+       for (handp = modp->handlers; handp->content_type; ++handp) {
+          if (!strcasecmp (handler, handp->content_type)) {
+              int result = (*handp->handler)(r);
+
+              if (result != DECLINED) return result;
+          }
+       }
+   }
+   
+   /* Pass two --- wildcard matches */
+   
+   for (modp = top_module; modp; modp = modp->next) 
+   {
+       if (!modp->handlers) continue;
+       
+       for (handp = modp->handlers; handp->content_type; ++handp) {
+          char *starp = strchr (handp->content_type, '*');
+          int len;
+
+          if (!starp) continue;
+
+          len = starp - handp->content_type;
+          
+          if (!len || !strncasecmp (handler, handp->content_type, len))
+          {
+              int result = (*handp->handler)(r);
+
+              if (result != DECLINED) return result;
+          }
+       }
+   }
+   
+   return NOT_IMPLEMENTED;
+}
+
+/* One-time setup for precompiled modules --- NOT to be done on restart */
+
+void add_module (module *m)
+{
+    /* This could be called from an AddModule httpd.conf command,
+     * after the file has been linked and the module structure within it
+     * teased out...
+     */
+
+    m->next = top_module;
+    top_module = m;
+    m->module_index = num_modules++;
+}
+
+void setup_prelinked_modules ()
+{
+    extern module *prelinked_modules[];
+    module **m = prelinked_modules;
+
+    while (*m) {
+        add_module (*m);
+       ++m;
+    }
+}
+
+/*****************************************************************
+ *
+ * Resource, access, and .htaccess config files now parsed by a common
+ * command loop.
+ *
+ * Let's begin with the basics; parsing the line and
+ * invoking the function...
+ */
+
+char *invoke_cmd(command_rec *cmd, cmd_parms *parms, void *mconfig, char *args)
+{
+    char *w, *w2, *errmsg;
+
+    if ((parms->override & cmd->req_override) == 0)
+        return pstrcat (parms->pool, cmd->name, " not allowed here", NULL);
+    
+    parms->info = cmd->cmd_data;
+    
+    switch (cmd->args_how) {
+    case RAW_ARGS:
+        return (*cmd->func) (parms, mconfig, args);
+
+    case NO_ARGS:
+       if (*args != 0)
+           return pstrcat (parms->pool, cmd->name, " takes no arguments",
+                           NULL);
+
+       return (*cmd->func) (parms, mconfig);
+       
+    case TAKE1:
+       w = getword_conf (parms->pool, &args);
+       
+       if (*w == '\0' || *args != 0) 
+           return pstrcat (parms->pool, cmd->name, " takes one argument",
+                           cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL);
+
+       return (*cmd->func) (parms, mconfig, w);
+       
+    case TAKE2:
+
+       w = getword_conf (parms->pool, &args);
+       w2 = getword_conf (parms->pool, &args);
+       
+       if (*w == '\0' || *w2 == '\0' || *args != 0) 
+           return pstrcat (parms->pool, cmd->name, " takes two arguments",
+                           cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL);
+
+       return (*cmd->func) (parms, mconfig, w, w2);
+       
+    case ITERATE:
+
+       while (*(w = getword_conf (parms->pool, &args)) != '\0')
+           if ((errmsg = (*cmd->func) (parms, mconfig, w)))
+               return errmsg;
+
+       return NULL;
+       
+    case ITERATE2:
+
+       w = getword_conf (parms->pool, &args);
+       
+       if (*w == '\0' || *args == 0) 
+           return pstrcat(parms->pool, cmd->name,
+                          " requires at least two arguments",
+                          cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL);
+         
+
+       while (*(w2 = getword_conf (parms->pool, &args)) != '\0')
+           if ((errmsg = (*cmd->func) (parms, mconfig, w, w2)))
+               return errmsg;
+
+       return NULL;
+       
+    case FLAG:
+
+       w = getword_conf (parms->pool, &args);
+
+       if (*w == '\0' || ((!strcasecmp(w, "on")) && (!strcasecmp (w, "off"))))
+           return pstrcat (parms->pool, cmd->name, " must be On or Off",
+                           NULL);
+
+       return (*cmd->func) (parms, mconfig, strcasecmp (w, "off") != 0);
+
+    default:
+
+       return pstrcat (parms->pool, cmd->name,
+                       " is improperly configured internally (server bug)",
+                       NULL);
+    }
+}
+
+command_rec *find_command (char *name, command_rec *cmds)
+{
+    while (cmds->name) 
+        if (!strcasecmp (name, cmds->name))
+           return cmds;
+       else
+           ++cmds;
+
+    return NULL;
+}
+    
+command_rec *find_command_in_modules (char *cmd_name, module **mod)
+{
+   command_rec *cmdp;
+   module *modp;
+
+   for (modp = top_module; modp; modp = modp->next) 
+       if (modp->cmds && (cmdp = find_command (cmd_name, modp->cmds))) {
+          *mod = modp;
+          return cmdp;
+       }
+
+   return NULL;
+}
+
+char *handle_command (cmd_parms *parms, void *config, char *l)
+{
+    char *args, *cmd_name;
+    command_rec *cmd;
+    module *mod;
+
+    ++parms->config_line;
+    if((l[0] == '#') || (!l[0])) return NULL;
+       
+    args = l;
+    cmd_name = getword_conf (parms->temp_pool, &args);
+    if (*cmd_name == '\0') return NULL;
+       
+    if (!(cmd = find_command_in_modules (cmd_name, &mod))) {
+       return pstrcat (parms->pool, "Invalid command ", cmd_name, NULL);
+    }
+    else {
+       void *mconfig = get_module_config (config, mod);
+       void *sconfig = get_module_config (parms->server->module_config, mod);
+             
+       if (!mconfig && mod->create_dir_config) {
+           mconfig = (*mod->create_dir_config) (parms->pool, parms->path);
+           set_module_config (config, mod, mconfig);
+       }
+           
+       if (!sconfig && mod->create_server_config) {
+           sconfig = (*mod->create_server_config)(parms->pool, parms->server);
+           set_module_config (parms->server->module_config, mod, sconfig);
+       }
+       
+       return invoke_cmd (cmd, parms, mconfig, args);
+    }
+}
+
+char *srm_command_loop (cmd_parms *parms, void *config)
+{
+    char l[MAX_STRING_LEN];
+    
+    while (!(cfg_getline (l, MAX_STRING_LEN, parms->infile))) {
+       char *errmsg = handle_command (parms, config, l);
+       if (errmsg) return errmsg;
+    }
+
+    return NULL;
+}
+
+/*
+ * Generic command functions...
+ */
+
+char *set_string_slot (cmd_parms *cmd, char *struct_ptr, char *arg)
+{
+    /* This one's pretty generic... */
+  
+    int offset = (int)cmd->info; 
+    *(char **)(struct_ptr + offset) = pstrdup (cmd->pool, arg);
+    return NULL;
+}
+
+/*****************************************************************
+ *
+ * Reading whole config files...
+ */
+
+cmd_parms default_parms = { NULL, 0, -1, NULL, 0, NULL, NULL, NULL, NULL };
+
+char *server_root_relative (pool *p, char *file)
+{
+#ifdef __EMX__
+    /* Add support for OS/2 drive names */
+    if ((file[0] == '/') || (file[1] == ':')) return file;
+#else
+    if (file[0] == '/') return file;
+#endif    
+    return make_full_path (p, server_root, file);
+}
+
+void process_resource_config(server_rec *s, char *fname, pool *p, pool *ptemp)
+{
+    FILE *cfg;
+    char *errmsg;
+    cmd_parms parms;
+    
+    fname = server_root_relative (p, fname);
+    
+    /* GCC's initialization extensions are soooo nice here... */
+    
+    parms = default_parms;
+    parms.config_file = fname;
+    parms.pool = p;
+    parms.temp_pool = ptemp;
+    parms.server = s;
+    parms.override = (RSRC_CONF|OR_ALL)&~(OR_AUTHCFG|OR_LIMIT);
+    
+    if(!(cfg = fopen(fname, "r"))) {
+        fprintf(stderr,"httpd: could not open document config file %s\n",
+                fname);
+        perror("fopen");
+        exit(1);
+    } 
+
+    parms.infile = cfg;
+    
+    errmsg = srm_command_loop (&parms, s->lookup_defaults);
+    
+    if (errmsg) {
+        fprintf (stderr, "Syntax error on line %d of %s:\n",
+                parms.config_line, fname);
+       fprintf (stderr, "%s\n", errmsg);
+       exit(1);
+    }
+    
+    fclose(cfg);
+}
+
+
+int parse_htaccess(void **result, request_rec *r, int override,
+                  char *d, char *filename)
+{
+    FILE *f;
+    cmd_parms parms;
+    char *errmsg;
+    const struct htaccess_result *cache;
+    struct htaccess_result *new;
+    void *dc;
+
+/* firstly, search cache */
+    for (cache=r->htaccess; cache != NULL; cache=cache->next)
+       if (cache->override == override && strcmp(cache->dir, d) == 0)
+       {
+           if (cache->htaccess != NULL) *result = cache->htaccess;
+           return OK;
+       }
+
+    parms = default_parms;
+    parms.override = override;
+    parms.pool = r->pool;
+    parms.temp_pool = r->pool;
+    parms.server = r->server;
+    parms.path = d;
+
+    if((f=pfopen(r->pool, filename, "r"))) {
+        dc = create_per_dir_config (r->pool);
+       
+        parms.infile = f;
+       parms.config_file = filename;
+
+       errmsg = srm_command_loop (&parms, dc);
+       
+        pfclose(r->pool, f);
+
+       if (errmsg) {
+           log_reason (errmsg, filename, r);
+           return SERVER_ERROR;
+       }
+       
+       *result = dc;
+    } else
+       dc = NULL;
+
+/* cache it */
+    new = palloc(r->pool, sizeof(struct htaccess_result));
+    new->dir = pstrdup(r->pool, d);
+    new->override = override;
+    new->htaccess = dc;
+/* add to head of list */
+    new->next = r->htaccess;
+    r->htaccess = new;
+
+    return OK;
+}
+
+/*****************************************************************
+ *
+ * Virtual host stuff; note that the commands that invoke this stuff
+ * are with the command table in http_core.c.
+ */
+
+server_rec *init_virtual_host (pool *p, char *hostname)
+{
+    server_rec *s = (server_rec *)pcalloc (p, sizeof (server_rec));
+
+#ifdef RLIMIT_NOFILE
+    struct rlimit limits;
+
+    getrlimit ( RLIMIT_NOFILE, &limits );
+    if ( limits.rlim_cur < limits.rlim_max ) {
+      limits.rlim_cur += 2;
+      if ( setrlimit ( RLIMIT_NOFILE, &limits ) < 0 )
+       fprintf (stderr, "Cannot exceed hard limit for open files");
+    }
+#endif
+
+    s->server_admin = NULL;
+    s->server_hostname = NULL; 
+    s->error_fname = NULL;
+    s->srm_confname = NULL;
+    s->access_confname = NULL;
+    s->timeout = 0;
+    s->keep_alive_timeout = 0;
+    s->keep_alive = -1;
+    s->host_addr.s_addr = get_virthost_addr (hostname, &s->host_port);
+    s->port = s->host_port;  /* set them the same, by default */
+    s->next = NULL;
+
+    s->is_virtual = 1;
+    s->virthost = pstrdup(p, hostname);
+    s->names = NULL;
+
+    s->module_config = create_empty_config (p);
+    s->lookup_defaults = create_per_dir_config (p);
+    
+    return s;
+}
+
+int is_virtual_server (server_rec *s)
+{
+    return s->is_virtual;
+}
+
+void fixup_virtual_hosts (pool *p, server_rec *main_server)
+{
+    server_rec *virt;
+
+    for (virt = main_server->next; virt; virt = virt->next) {
+       merge_server_configs (p, main_server->module_config,
+                             virt->module_config);
+       
+       virt->lookup_defaults =
+           merge_per_dir_configs (p, main_server->lookup_defaults,
+                                  virt->lookup_defaults);
+
+       if (virt->port == 0)
+           virt->port = main_server->port;
+
+       if (virt->server_admin == NULL)
+           virt->server_admin = main_server->server_admin;
+
+       if (virt->srm_confname == NULL)
+           virt->srm_confname = main_server->srm_confname;
+
+       if (virt->access_confname == NULL)
+           virt->access_confname = main_server->access_confname;
+
+       if (virt->timeout == 0)
+           virt->timeout = main_server->timeout;
+
+       if (virt->keep_alive_timeout == 0)
+           virt->keep_alive_timeout = main_server->keep_alive_timeout;
+
+       if (virt->keep_alive == -1)
+           virt->keep_alive = main_server->keep_alive;
+    }
+}
+
+/*****************************************************************
+ *
+ * Getting *everything* configured... 
+ */
+
+void init_config_globals (pool *p)
+{
+    /* ServerRoot, server_confname set in httpd.c */
+    
+    standalone = 1;
+    user_name = DEFAULT_USER;
+    user_id = uname2id(DEFAULT_USER);
+    group_id = gname2id(DEFAULT_GROUP);
+    daemons_to_start = DEFAULT_START_DAEMON;
+    daemons_min_free = DEFAULT_MIN_FREE_DAEMON;
+    daemons_max_free = DEFAULT_MAX_FREE_DAEMON;
+    daemons_limit = HARD_SERVER_LIMIT;
+    pid_fname = DEFAULT_PIDLOG;
+    scoreboard_fname = DEFAULT_SCOREBOARD;
+    max_requests_per_child = DEFAULT_MAX_REQUESTS_PER_CHILD;
+    bind_address.s_addr = htonl(INADDR_ANY);
+    listeners = NULL;
+}
+
+server_rec *init_server_config(pool *p)
+{
+    server_rec *s = (server_rec *)pcalloc (p, sizeof (server_rec));
+
+    s->port = DEFAULT_PORT;
+    s->server_admin = DEFAULT_ADMIN;
+    s->server_hostname = NULL; 
+    s->error_fname = DEFAULT_ERRORLOG;
+    s->srm_confname = RESOURCE_CONFIG_FILE;
+    s->access_confname = ACCESS_CONFIG_FILE;
+    s->timeout = DEFAULT_TIMEOUT;
+    s->keep_alive_timeout = DEFAULT_KEEPALIVE_TIMEOUT;
+    s->keep_alive = DEFAULT_KEEPALIVE;
+    s->next = NULL;
+    s->host_addr.s_addr = htonl (INADDR_ANY); /* NOT virtual host;
+                                              * don't match any real network
+                                              * interface.
+                                              */
+    s->host_port = 0; /* matches any port */
+
+    s->module_config = create_server_config (p, s);
+    s->lookup_defaults = create_default_per_dir_config (p);
+    
+    return s;
+}
+
+server_rec *read_config(pool *p, pool *ptemp, char *confname)
+{
+    server_rec *s = init_server_config(p);
+    module *m;
+    
+    init_config_globals(p);
+    
+    /* All server-wide config files now have the SAME syntax... */
+    
+    process_resource_config (s, confname, p, ptemp);
+    process_resource_config (s, s->srm_confname, p, ptemp);
+    process_resource_config (s, s->access_confname, p, ptemp);
+    
+    fixup_virtual_hosts (p, s);
+    
+    for (m = top_module; m; m = m->next)
+        if (m->init)
+           (*m->init) (s, p);
+    
+    return s;
+}
+
diff --git a/RELEASE_1_1_X/src/main/http_core.c b/RELEASE_1_1_X/src/main/http_core.c
new file mode 100644 (file)
index 0000000..e365be6
--- /dev/null
@@ -0,0 +1,950 @@
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+#define CORE_PRIVATE
+#include "httpd.h"
+#include "http_config.h"
+#include "http_core.h"
+#include "http_protocol.h"     /* For index_of_response().  Grump. */
+#include "http_conf_globals.h"
+
+#include "http_main.h"         /* For the default_handler below... */
+#include "http_log.h"
+#include "rfc1413.h"
+#include "util_md5.h"
+#include "scoreboard.h"
+
+/* Server core module... This module provides support for really basic
+ * server operations, including options and commands which control the
+ * operation of other modules.  Consider this the bureaucracy module.
+ *
+ * The core module also defines handlers, etc., do handle just enough
+ * to allow a server with the core module ONLY to actually serve documents
+ * (though it slaps DefaultType on all of 'em); this was useful in testing,
+ * but may not be worth preserving.
+ *
+ * This file could almost be mod_core.c, except for the stuff which affects
+ * the http_conf_globals.
+ */
+
+void *create_core_dir_config (pool *a, char *dir)
+{
+    core_dir_config *conf =
+      (core_dir_config *)pcalloc(a, sizeof(core_dir_config));
+  
+    if (!dir || dir[strlen(dir) - 1] == '/') conf->d = dir;
+    else conf->d = pstrcat (a, dir, "/", NULL);
+
+    conf->opts = dir ? OPT_UNSET : OPT_ALL;
+    conf->override = dir ? OR_UNSET : OR_ALL;
+
+    conf->content_md5 = 2;
+
+    conf->hostname_lookups = 2;/* binary, but will use 2 as an "unset = on" */
+    conf->do_rfc1413 = DEFAULT_RFC1413 | 2;  /* set bit 1 to indicate default */
+    return (void *)conf;
+}
+
+void *merge_core_dir_configs (pool *a, void *basev, void *newv)
+{
+    core_dir_config *base = (core_dir_config *)basev;
+    core_dir_config *new = (core_dir_config *)newv;
+    core_dir_config *conf =
+      (core_dir_config *)pcalloc (a, sizeof(core_dir_config));
+    int i;
+  
+    memcpy ((char *)conf, (const char *)base, sizeof(core_dir_config));
+    
+    conf->d = new->d;
+    
+    if (new->opts != OPT_UNSET) conf->opts = new->opts;
+    if (new->override != OR_UNSET) conf->override = new->override;
+    if (new->default_type) conf->default_type = new->default_type;
+    
+    if (new->auth_type) conf->auth_type = new->auth_type;
+    if (new->auth_name) conf->auth_name = new->auth_name;
+    if (new->requires) conf->requires = new->requires;
+
+    for (i = 0; i <= RESPONSE_CODES; ++i)
+        if (new->response_code_strings[i] != NULL)
+          conf->response_code_strings[i] = new->response_code_strings[i];
+    if (new->hostname_lookups != 2)
+       conf->hostname_lookups = new->hostname_lookups;
+    if ((new->do_rfc1413 & 2) == 0) conf->do_rfc1413 = new->do_rfc1413;
+    if ((new->content_md5 & 2) == 0) conf->content_md5 = new->content_md5;
+
+    return (void*)conf;
+}
+
+void *create_core_server_config (pool *a, server_rec *s)
+{
+    core_server_config *conf =
+      (core_server_config *)pcalloc(a, sizeof(core_server_config));
+    int is_virtual = s->is_virtual;
+  
+    conf->access_name = is_virtual ? NULL : DEFAULT_ACCESS_FNAME;
+    conf->document_root = is_virtual ? NULL : DOCUMENT_LOCATION;
+    conf->sec = make_array (a, 40, sizeof(void *));
+    conf->sec_url = make_array (a, 40, sizeof(void *));
+    
+    return (void *)conf;
+}
+
+void *merge_core_server_configs (pool *p, void *basev, void *virtv)
+{
+    core_server_config *base = (core_server_config *)basev;
+    core_server_config *virt = (core_server_config *)virtv;
+    core_server_config *conf = 
+       (core_server_config *)pcalloc(p, sizeof(core_server_config));
+
+    *conf = *virt;
+    if (!conf->access_name) conf->access_name = base->access_name;
+    if (!conf->document_root) conf->document_root = base->document_root;
+    conf->sec = append_arrays (p, virt->sec, base->sec);
+    conf->sec_url = append_arrays (p, virt->sec_url, base->sec_url);
+
+    return conf;
+}
+
+/* Add per-directory configuration entry (for <directory> section);
+ * these are part of the core server config.
+ */
+
+void add_per_dir_conf (server_rec *s, void *dir_config)
+{
+    core_server_config *sconf = get_module_config (s->module_config,
+                                                  &core_module);
+    void **new_space = (void **) push_array (sconf->sec);
+    
+    *new_space = dir_config;
+}
+
+void add_per_url_conf (server_rec *s, void *url_config)
+{
+    core_server_config *sconf = get_module_config (s->module_config,
+                                                  &core_module);
+    void **new_space = (void **) push_array (sconf->sec_url);
+    
+    *new_space = url_config;
+}
+
+/*****************************************************************
+ *
+ * There are some elements of the core config structures in which
+ * other modules have a legitimate interest (this is ugly, but necessary
+ * to preserve NCSA back-compatibility).  So, we have a bunch of accessors
+ * here...
+ */
+
+int allow_options (request_rec *r)
+{
+    core_dir_config *conf = 
+      (core_dir_config *)get_module_config(r->per_dir_config, &core_module); 
+
+    return conf->opts; 
+} 
+
+int allow_overrides (request_rec *r) 
+{ 
+    core_dir_config *conf = 
+      (core_dir_config *)get_module_config(r->per_dir_config, &core_module); 
+
+    return conf->override; 
+} 
+
+char *auth_type (request_rec *r)
+{
+    core_dir_config *conf = 
+      (core_dir_config *)get_module_config(r->per_dir_config, &core_module); 
+
+    return conf->auth_type;
+}
+
+char *auth_name (request_rec *r)
+{
+    core_dir_config *conf = 
+      (core_dir_config *)get_module_config(r->per_dir_config, &core_module); 
+
+    return conf->auth_name;
+}
+
+char *default_type (request_rec *r)
+{
+    core_dir_config *conf = 
+      (core_dir_config *)get_module_config(r->per_dir_config, &core_module); 
+
+    return conf->default_type ? conf->default_type : DEFAULT_TYPE;
+}
+
+char *document_root (request_rec *r) /* Don't use this!!! */
+{
+    core_server_config *conf = 
+      (core_server_config *)get_module_config(r->server->module_config,
+                                             &core_module); 
+
+    return conf->document_root;
+}
+
+array_header *requires (request_rec *r)
+{
+    core_dir_config *conf = 
+      (core_dir_config *)get_module_config(r->per_dir_config, &core_module); 
+
+    return conf->requires;
+}
+
+
+/* Should probably just get rid of this... the only code that cares is
+ * part of the core anyway (and in fact, it isn't publicised to other
+ * modules).
+ */
+
+char *response_code_string (request_rec *r, int error_index)
+{
+    core_dir_config *conf = 
+      (core_dir_config *)get_module_config(r->per_dir_config, &core_module); 
+
+    return conf->response_code_strings[error_index];
+}
+
+const char *
+get_remote_host(conn_rec *conn, void *dir_config, int type)
+{
+    struct in_addr *iaddr;
+    struct hostent *hptr;
+#ifdef MAXIMUM_DNS
+    char **haddr;
+#endif
+    core_dir_config *dir_conf;
+
+/* If we haven't checked the host name, and we want to */
+    dir_conf = (core_dir_config *)get_module_config(dir_config, &core_module);
+
+    if (conn->remote_host == NULL && dir_conf->hostname_lookups)
+    {
+#ifdef STATUS
+       int old_stat = update_child_status(conn->child_num,
+                                               SERVER_BUSY_DNS,
+                                               (request_rec*)NULL);
+#endif /* STATUS */
+       iaddr = &(conn->remote_addr.sin_addr);
+       hptr = gethostbyaddr((char *)iaddr, sizeof(struct in_addr), AF_INET);
+       if (hptr != NULL)
+       {
+           conn->remote_host = pstrdup(conn->pool, (void *)hptr->h_name);
+           str_tolower (conn->remote_host);
+          
+#ifdef MAXIMUM_DNS
+    /* Grrr. Check THAT name to make sure it's really the name of the addr. */
+    /* Code from Harald Hanche-Olsen <hanche@imf.unit.no> */
+
+           hptr = gethostbyname(conn->remote_host);
+           if (hptr)
+           {
+               for(haddr=hptr->h_addr_list; *haddr; haddr++)
+                   if(((struct in_addr *)(*haddr))->s_addr == iaddr->s_addr)
+                       break;
+           }
+           if((!hptr) || (!(*haddr)))
+               conn->remote_host = NULL;
+#endif
+       }
+/* if failed, set it to the NULL string to indicate error */
+       if (conn->remote_host == NULL) conn->remote_host = "";
+#ifdef STATUS
+       (void)update_child_status(conn->child_num,old_stat,(request_rec*)NULL);
+#endif /* STATUS */
+    }
+
+/*
+ * Return the desired information; either the remote DNS name, if found,
+ * or either NULL (if the hostname was requested) or the IP address
+ * (if any identifier was requested).
+ */
+    if (conn->remote_host != NULL && conn->remote_host[0] != '\0')
+       return conn->remote_host;
+    else
+    {
+       if (type == REMOTE_HOST) return NULL;
+       else return conn->remote_ip;
+    }
+}
+
+const char *
+get_remote_logname(request_rec *r)
+{
+    core_dir_config *dir_conf;
+
+    if (r->connection->remote_logname != NULL)
+       return r->connection->remote_logname;
+
+/* If we haven't checked the identity, and we want to */
+    dir_conf = (core_dir_config *)
+       get_module_config(r->per_dir_config, &core_module);
+
+    if (dir_conf->do_rfc1413 & 1)
+       return rfc1413(r->connection, r->server);
+    else
+       return NULL;
+}
+
+/*****************************************************************
+ *
+ * Commands... this module handles almost all of the NCSA httpd.conf
+ * commands, but most of the old srm.conf is in the the modules.
+ */
+
+char *set_access_name (cmd_parms *cmd, void *dummy, char *arg)
+{
+    void *sconf = cmd->server->module_config;
+    core_server_config *conf = get_module_config (sconf, &core_module);
+  
+    conf->access_name = arg;
+    return NULL;
+}
+
+char *set_document_root (cmd_parms *cmd, void *dummy, char *arg)
+{
+    void *sconf = cmd->server->module_config;
+    core_server_config *conf = get_module_config (sconf, &core_module);
+  
+    if (!is_directory (arg))
+       if (cmd->server->is_virtual)
+           fprintf (stderr, "Warning: DocumentRoot [%s] does not exist\n", arg);
+       else
+           return "DocumentRoot must be a directory";
+    
+    conf->document_root = arg;
+    return NULL;
+}
+
+char *set_error_document (cmd_parms *cmd, core_dir_config *conf, char *line)
+{
+    int error_number, index_number;
+    char *w;
+                
+    /* 1st parameter should be a 3 digit number, which we recognize;
+     * convert it into an array index
+     */
+  
+    w = getword_conf (cmd->pool, &line);
+    error_number = atoi(w);
+    index_number = index_of_response(error_number);
+  
+    if (index_number < 0)
+        return pstrcat (cmd->pool, "Illegal HTTP response code ", w, NULL);
+                
+    /* Nuke trailing '"', if present */
+    
+    if (line[strlen(line) - 1] == '"') line[strlen(line) - 1] = '\0';
+  
+    /* Store it... */
+
+    conf->response_code_strings[index_number] = pstrdup (cmd->pool, line);
+
+    return NULL;
+}
+
+/* access.conf commands...
+ *
+ * The *only* thing that can appear in access.conf at top level is a
+ * <Directory> section.  NB we need to have a way to cut the srm_command_loop
+ * invoked by dirsection (i.e., <Directory>) short when </Directory> is seen.
+ * We do that by returning an error, which dirsection itself recognizes and
+ * discards as harmless.  Cheesy, but it works.
+ */
+
+char *set_override (cmd_parms *cmd, core_dir_config *d, char *l)
+{
+    char *w;
+  
+    d->override = OR_NONE;
+    while(l[0]) {
+        w = getword_conf (cmd->pool, &l);
+       if(!strcasecmp(w,"Limit"))
+           d->override |= OR_LIMIT;
+       else if(!strcasecmp(w,"Options"))
+           d->override |= OR_OPTIONS;
+       else if(!strcasecmp(w,"FileInfo"))
+            d->override |= OR_FILEINFO;
+       else if(!strcasecmp(w,"AuthConfig"))
+           d->override |= OR_AUTHCFG;
+       else if(!strcasecmp(w,"Indexes"))
+            d->override |= OR_INDEXES;
+       else if(!strcasecmp(w,"None"))
+           d->override = OR_NONE;
+       else if(!strcasecmp(w,"All")) 
+           d->override = OR_ALL;
+       else 
+           return pstrcat (cmd->pool, "Illegal override option ", w, NULL);
+    }
+
+    return NULL;
+}
+
+char *set_options (cmd_parms *cmd, core_dir_config *d, char *l)
+{
+    d->opts = OPT_NONE;
+    while(l[0]) {
+        char *w = getword_conf(cmd->pool, &l);
+       if(!strcasecmp(w,"Indexes"))
+           d->opts |= OPT_INDEXES;
+       else if(!strcasecmp(w,"Includes"))
+           d->opts |= OPT_INCLUDES;
+       else if(!strcasecmp(w,"IncludesNOEXEC"))
+           d->opts |= (OPT_INCLUDES | OPT_INCNOEXEC);
+       else if(!strcasecmp(w,"FollowSymLinks"))
+           d->opts |= OPT_SYM_LINKS;
+       else if(!strcasecmp(w,"SymLinksIfOwnerMatch"))
+           d->opts |= OPT_SYM_OWNER;
+       else if(!strcasecmp(w,"execCGI"))
+           d->opts |= OPT_EXECCGI;
+       else if (!strcasecmp(w,"MultiViews"))
+           d->opts |= OPT_MULTI;
+       else if (!strcasecmp(w,"RunScripts")) /* AI backcompat. Yuck */
+           d->opts |= OPT_MULTI|OPT_EXECCGI;
+       else if(!strcasecmp(w,"None")) 
+           d->opts = OPT_NONE;
+       else if(!strcasecmp(w,"All")) 
+           d->opts = OPT_ALL;
+       else 
+           return pstrcat (cmd->pool, "Illegal option ", w, NULL);
+    }
+
+    return NULL;
+}
+
+char *require (cmd_parms *cmd, core_dir_config *c, char *arg)
+{
+    require_line *r;
+  
+    if (!c->requires)
+        c->requires = make_array (cmd->pool, 2, sizeof(require_line));
+    
+    r = (require_line *)push_array (c->requires);
+    r->requirement = pstrdup (cmd->pool, arg);
+    r->method_mask = cmd->limited;
+    return NULL;
+}
+
+char *limit (cmd_parms *cmd, void *dummy, char *arg)
+{
+    char *limited_methods = getword(cmd->pool,&arg,'>');
+    int limited = 0;
+  
+    if (cmd->limited > 0) return "Can't nest <Limit> sections";
+    
+    while(limited_methods[0]) {
+        char *method = getword_conf (cmd->pool, &limited_methods);
+       if(!strcasecmp(method,"GET")) limited |= (1 << M_GET);
+       else if(!strcasecmp(method,"PUT")) limited |= (1 << M_PUT);
+       else if(!strcasecmp(method,"POST")) limited |= (1 << M_POST);
+       else if(!strcasecmp(method,"DELETE")) limited |= (1 << M_DELETE);
+        else if(!strcasecmp(method,"CONNECT")) limited |= (1 << M_CONNECT);
+       else return "unknown method in <Limit>";
+    }
+
+    cmd->limited = limited;
+    return NULL;
+}
+
+char *endlimit (cmd_parms *cmd, void *dummy, void *dummy2)
+{
+    if (cmd->limited == -1) return "</Limit> unexpected";
+    
+    cmd->limited = -1;
+    return NULL;
+}
+
+static char *end_dir_magic = "</Directory> outside of any <Directory> section";
+
+char *end_dirsection (cmd_parms *cmd, void *dummy) {
+    return end_dir_magic;
+}
+
+char *dirsection (cmd_parms *cmd, void *dummy, char *arg)
+{
+    char *errmsg, *endp = strrchr (arg, '>');
+    int old_overrides = cmd->override;
+    char *old_path = cmd->path;
+    void *new_dir_conf = create_per_dir_config (cmd->pool);
+
+    if (endp) *endp = '\0';
+
+    if (cmd->path) return "<Directory> sections don't nest";
+    if (cmd->limited != -1) return "Can't have <Directory> within <Limit>";
+    
+    cmd->path = getword_conf (cmd->pool, &arg);
+    cmd->override = OR_ALL|ACCESS_CONF;
+
+    errmsg = srm_command_loop (cmd, new_dir_conf);
+    add_per_dir_conf (cmd->server, new_dir_conf);
+    
+    cmd->path = old_path;
+    cmd->override = old_overrides;
+
+    if (errmsg == end_dir_magic) return NULL;
+    return errmsg;
+}
+
+static char *end_url_magic = "</Location> outside of any <Location> section";
+
+char *end_urlsection (cmd_parms *cmd, void *dummy) {
+    return end_url_magic;
+}
+
+char *urlsection (cmd_parms *cmd, void *dummy, char *arg)
+{
+    char *errmsg, *endp = strrchr (arg, '>');
+    int old_overrides = cmd->override;
+    char *old_path = cmd->path;
+    core_dir_config *conf;
+
+    void *new_url_conf = create_per_dir_config (cmd->pool);
+
+    if (endp) *endp = '\0';
+
+    if (cmd->path) return "<Location> sections don't nest";
+    if (cmd->limited != -1) return "Can't have <Location> within <Limit>";
+    
+    cmd->path = getword_conf (cmd->pool, &arg);
+    cmd->override = OR_ALL|ACCESS_CONF;
+
+    errmsg = srm_command_loop (cmd, new_url_conf);
+    if (errmsg != end_url_magic) return errmsg;
+
+    conf = (core_dir_config *)get_module_config(new_url_conf, &core_module);
+    conf->d = pstrdup(cmd->pool, cmd->path);   /* No mangling, please */
+
+    add_per_url_conf (cmd->server, new_url_conf);
+    
+    cmd->path = old_path;
+    cmd->override = old_overrides;
+
+    return NULL;
+}
+
+/* httpd.conf commands... beginning with the <VirtualHost> business */
+
+char *end_virthost_magic = "</Virtualhost> out of place";
+
+char *end_virtualhost_section (cmd_parms *cmd, void *dummy) {
+    return end_virthost_magic;
+}
+
+char *virtualhost_section (cmd_parms *cmd, void *dummy, char *arg)
+{
+    server_rec *main_server = cmd->server, *s;
+    char *errmsg, *endp = strrchr (arg, '>');
+    pool *p = cmd->pool, *ptemp = cmd->temp_pool;
+
+    if (endp) *endp = '\0';
+    
+    if (main_server->is_virtual)
+       return "<VirtualHost> doesn't nest!";
+    
+    s = init_virtual_host (p, arg);
+    s->next = main_server->next;
+    main_server->next = s;
+       
+    cmd->server = s;
+    errmsg = srm_command_loop (cmd, s->lookup_defaults);
+    cmd->server = main_server;
+
+    if (s->srm_confname)
+       process_resource_config (s, s->srm_confname, p, ptemp);
+
+    if (s->access_confname)
+       process_resource_config (s, s->access_confname, p, ptemp);
+    
+    if (errmsg == end_virthost_magic) return NULL;
+    return errmsg;
+}
+
+char *set_server_string_slot (cmd_parms *cmd, void *dummy, char *arg)
+{
+    /* This one's pretty generic... */
+  
+    int offset = (int)cmd->info;
+    char *struct_ptr = (char *)cmd->server;
+    
+    *(char **)(struct_ptr + offset) = pstrdup (cmd->pool, arg);
+    return NULL;
+}
+
+char *server_type (cmd_parms *cmd, void *dummy, char *arg)
+{
+    if (!strcasecmp (arg, "inetd")) standalone = 0;
+    else if (!strcasecmp (arg, "standalone")) standalone = 1;
+    else return "ServerType must be either 'inetd' or 'standalone'";
+
+    return NULL;
+}
+
+char *server_port (cmd_parms *cmd, void *dummy, char *arg) {
+    cmd->server->port = atoi (arg);
+    return NULL;
+}
+
+char *set_user (cmd_parms *cmd, void *dummy, char *arg) {
+    user_name = pstrdup (cmd->pool, arg);
+    user_id = uname2id (user_name);
+    return NULL;
+}
+
+char *set_group (cmd_parms *cmd, void *dummy, char *arg) {
+    group_id = gname2id(arg);
+    return NULL;
+}
+
+char *set_server_root (cmd_parms *cmd, void *dummy, char *arg) {
+    if (!is_directory (arg)) return "ServerRoot must be a valid directory";
+    strcpy (server_root, arg);
+    return NULL;
+}
+
+char *set_timeout (cmd_parms *cmd, void *dummy, char *arg) {
+    cmd->server->timeout = atoi (arg);
+    return NULL;
+}
+
+char *set_keep_alive_timeout (cmd_parms *cmd, void *dummy, char *arg) {
+    cmd->server->keep_alive_timeout = atoi (arg);
+    return NULL;
+}
+
+char *set_keep_alive (cmd_parms *cmd, void *dummy, char *arg) {
+    cmd->server->keep_alive = atoi (arg);
+    return NULL;
+}
+
+char *set_pidfile (cmd_parms *cmd, void *dummy, char *arg) {
+    pid_fname = pstrdup (cmd->pool, arg);
+    return NULL;
+}
+
+char *set_scoreboard (cmd_parms *cmd, void *dummy, char *arg) {
+    scoreboard_fname = pstrdup (cmd->pool, arg);
+    return NULL;
+}
+
+char *set_idcheck (cmd_parms *cmd, core_dir_config *d, int arg) {
+    d->do_rfc1413 = arg;
+    return NULL;
+}
+
+char *set_hostname_lookups (cmd_parms *cmd, core_dir_config *d, int arg) {
+    d->hostname_lookups = arg;
+    return NULL;
+}
+
+char *set_serverpath (cmd_parms *cmd, void *dummy, char *arg) {
+    cmd->server->path = pstrdup (cmd->pool, arg);
+    cmd->server->pathlen = strlen (arg);
+    return NULL;
+}
+
+char *set_content_md5 (cmd_parms *cmd, core_dir_config *d, int arg) {
+    d->content_md5 = arg;
+    return NULL;
+}
+
+char *set_daemons_to_start (cmd_parms *cmd, void *dummy, char *arg) {
+    daemons_to_start = atoi (arg);
+    return NULL;
+}
+
+char *set_min_free_servers (cmd_parms *cmd, void *dummy, char *arg) {
+    daemons_min_free = atoi (arg);
+    if (daemons_min_free <= 0) {
+       fprintf(stderr, "WARNING: detected MinSpareServers set to non-positive.\n");
+       fprintf(stderr, "Resetting to 1 to avoid almost certain Apache failure.\n");
+       fprintf(stderr, "Please read the documentation.\n");
+       daemons_min_free = 1;
+    }
+       
+    return NULL;
+}
+
+char *set_max_free_servers (cmd_parms *cmd, void *dummy, char *arg) {
+    daemons_max_free = atoi (arg);
+    return NULL;
+}
+
+char *set_server_limit (cmd_parms *cmd, void *dummy, char *arg) {
+    daemons_limit = atoi (arg);
+    if (daemons_limit > HARD_SERVER_LIMIT)
+       daemons_limit = HARD_SERVER_LIMIT;
+    return NULL;
+}
+
+char *set_max_requests (cmd_parms *cmd, void *dummy, char *arg) {
+    max_requests_per_child = atoi (arg);
+    return NULL;
+}
+
+char *set_bind_address (cmd_parms *cmd, void *dummy, char *arg) {
+    bind_address.s_addr = get_virthost_addr (arg, NULL);
+    return NULL;
+}
+
+char *set_listener(cmd_parms *cmd, void *dummy, char *ips)
+{
+    listen_rec *new;
+    char *ports;
+
+    if (cmd->server->is_virtual) return "Listen not allowed in <VirtualHost>";
+    ports=strchr(ips, ':');
+    if (ports != NULL)
+    {
+       if (ports == ips) return "Missing IP address";
+       else if (ports[0] == '\0')
+           return "Address must end in :<port-number>";
+       *(ports++) = '\0';
+    } else
+       ports = ips;
+
+    new=palloc(cmd->pool, sizeof(listen_rec));
+    new->local_addr.sin_family = AF_INET;
+    if (ports == ips) /* no address */
+       new->local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+    else
+       new->local_addr.sin_addr.s_addr = get_virthost_addr(ips, NULL);
+    new->local_addr.sin_port = htons(atoi(ports));
+    new->next = listeners;
+    listeners = new;
+    return NULL;
+}
+
+/* Note --- ErrorDocument will now work from .htaccess files.  
+ * The AllowOverride of Fileinfo allows webmasters to turn it off
+ */
+
+command_rec core_cmds[] = {
+
+/* Old access config file commands */
+
+{ "<Directory", dirsection, NULL, RSRC_CONF, RAW_ARGS, NULL },
+{ "</Directory>", end_dirsection, NULL, ACCESS_CONF, NO_ARGS, NULL },
+{ "<Location", urlsection, NULL, RSRC_CONF, RAW_ARGS, NULL },
+{ "</Location>", end_urlsection, NULL, ACCESS_CONF, NO_ARGS, NULL },
+{ "<Limit", limit, NULL, OR_ALL, RAW_ARGS, NULL },
+{ "</Limit>", endlimit, NULL, OR_ALL, RAW_ARGS, NULL },
+{ "AuthType", set_string_slot, (void*)XtOffsetOf(core_dir_config, auth_type),
+    OR_AUTHCFG, TAKE1, "an HTTP authorization type (e.g., \"Basic\")" },
+{ "AuthName", set_string_slot, (void*)XtOffsetOf(core_dir_config, auth_name),
+    OR_AUTHCFG, RAW_ARGS, NULL },
+{ "Require", require, NULL, OR_AUTHCFG, RAW_ARGS, NULL },
+    
+/* Old resource config file commands */
+  
+{ "AccessFileName", set_access_name, NULL, RSRC_CONF, TAKE1, NULL },
+{ "DocumentRoot", set_document_root, NULL, RSRC_CONF, TAKE1, NULL },
+{ "ErrorDocument", set_error_document, NULL, OR_FILEINFO, RAW_ARGS, NULL },
+{ "AllowOverride", set_override, NULL, ACCESS_CONF, RAW_ARGS, NULL },
+{ "Options", set_options, NULL, OR_OPTIONS, RAW_ARGS, NULL },
+{ "DefaultType", set_string_slot,
+    (void*)XtOffsetOf (core_dir_config, default_type),
+    OR_FILEINFO, TAKE1, "the default MIME type for untypable files" },
+
+/* Old server config file commands */
+
+{ "ServerType", server_type, NULL, RSRC_CONF, TAKE1,"'inetd' or 'standalone'"},
+{ "Port", server_port, NULL, RSRC_CONF, TAKE1, "a TCP port number"},
+{ "HostnameLookups", set_hostname_lookups, NULL, ACCESS_CONF|RSRC_CONF, FLAG, NULL },
+{ "User", set_user, NULL, RSRC_CONF, TAKE1, "a username"},
+{ "Group", set_group, NULL, RSRC_CONF, TAKE1, "a group name"},
+{ "ServerAdmin", set_server_string_slot,
+  (void *)XtOffsetOf (server_rec, server_admin), RSRC_CONF, TAKE1,
+  "The email address of the server administrator" },
+{ "ServerName", set_server_string_slot,
+  (void *)XtOffsetOf (server_rec, server_hostname), RSRC_CONF, TAKE1,
+  "The hostname of the server" },
+{ "ServerRoot", set_server_root, NULL, RSRC_CONF, TAKE1, "a directory"},
+{ "ErrorLog", set_server_string_slot,
+  (void *)XtOffsetOf (server_rec, error_fname), RSRC_CONF, TAKE1,
+  "the filename of the error log" },
+{ "PidFile", set_pidfile, NULL, RSRC_CONF, TAKE1,
+    "a file for logging the server process ID"},
+{ "ScoreBoardFile", set_scoreboard, NULL, RSRC_CONF, TAKE1,
+    "a file for apache to maintain runtime process management information"},
+{ "AccessConfig", set_server_string_slot,
+  (void *)XtOffsetOf (server_rec, access_confname), RSRC_CONF, TAKE1,
+  "the filename of the access config file" },
+{ "ResourceConfig", set_server_string_slot,
+  (void *)XtOffsetOf (server_rec, srm_confname), RSRC_CONF, TAKE1,
+  "the filename of the resource config file" },
+{ "ServerAlias", set_server_string_slot,
+   (void *)XtOffsetOf (server_rec, names), RSRC_CONF, RAW_ARGS,
+   "a name or names alternately used to access the server" },
+{ "ServerPath", set_serverpath, NULL, RSRC_CONF, TAKE1,
+  "The pathname the server can be reached at" },
+{ "Timeout", set_timeout, NULL, RSRC_CONF, TAKE1, "timeout duration (sec)"},
+{ "KeepAliveTimeout", set_keep_alive_timeout, NULL, RSRC_CONF, TAKE1, "Keep-Alive timeout duration (sec)"},
+{ "KeepAlive", set_keep_alive, NULL, RSRC_CONF, TAKE1, "Maximum Keep-Alive requests per connection (0 to disable)" },
+{ "IdentityCheck", set_idcheck, NULL, RSRC_CONF|ACCESS_CONF, FLAG, NULL },
+{ "ContentDigest", set_content_md5, NULL, RSRC_CONF|ACCESS_CONF|OR_AUTHCFG, FLAG, "whether or not to send a Content-MD5 header with each request" },
+{ "CacheNegotiatedDocs", },
+{ "StartServers", set_daemons_to_start, NULL, RSRC_CONF, TAKE1, NULL },
+{ "MinSpareServers", set_min_free_servers, NULL, RSRC_CONF, TAKE1, NULL },
+{ "MaxSpareServers", set_max_free_servers, NULL, RSRC_CONF, TAKE1, NULL },
+{ "MaxServers", set_max_free_servers, NULL, RSRC_CONF, TAKE1, NULL },
+{ "ServersSafetyLimit", set_server_limit, NULL, RSRC_CONF, TAKE1, NULL },
+{ "MaxClients", set_server_limit, NULL, RSRC_CONF, TAKE1, NULL },
+{ "MaxRequestsPerChild", set_max_requests, NULL, RSRC_CONF, TAKE1, NULL },
+{ "BindAddress", set_bind_address, NULL, RSRC_CONF, TAKE1,
+  "'*', a numeric IP address, or the name of a host with a unique IP address"},
+{ "Listen", set_listener, NULL, RSRC_CONF, TAKE1,
+      "a port number or a numeric IP address and a port number"},
+{ "<VirtualHost", virtualhost_section, NULL, RSRC_CONF, RAW_ARGS, NULL },
+{ "</VirtualHost>", end_virtualhost_section, NULL, RSRC_CONF, NO_ARGS, NULL },
+{ NULL },
+};
+
+/*****************************************************************
+ *
+ * Core handlers for various phases of server operation...
+ */
+
+int core_translate (request_rec *r)
+{
+    void *sconf = r->server->module_config;
+    core_server_config *conf = get_module_config (sconf, &core_module);
+  
+    if (r->proxyreq) return NOT_IMPLEMENTED;
+    if (r->uri[0] != '/') return BAD_REQUEST;
+    
+    if (r->server->path &&
+       !strncmp(r->uri, r->server->path, r->server->pathlen))
+      r->filename = pstrcat (r->pool, conf->document_root,
+                            (r->uri + r->server->pathlen), NULL);
+    else
+      r->filename = pstrcat (r->pool, conf->document_root, r->uri, NULL);
+
+    return OK;
+}
+
+int do_nothing (request_rec *r) { return OK; }
+
+/*
+ * Default handler for MIME types without other handlers.  Only GET
+ * at this point... anyone who wants to write a generic handler for
+ * PUT or POST is free to do so, but it seems unwise to provide any
+ * defaults yet...
+ */
+
+int default_handler (request_rec *r)
+{
+    core_dir_config *d =
+      (core_dir_config *)get_module_config(r->per_dir_config, &core_module);
+    int errstatus;
+    FILE *f;
+    
+    if (r->method_number != M_GET) return DECLINED;
+
+    if (r->finfo.st_mode == 0 || (r->path_info && *r->path_info)) {
+       log_reason("File does not exist", r->filename, r);
+       return NOT_FOUND;
+    }
+       
+    if ((errstatus = set_content_length (r, r->finfo.st_size))
+       || (errstatus = set_last_modified (r, r->finfo.st_mtime)))
+        return errstatus;
+    
+#ifdef __EMX__
+    /* Need binary mode for OS/2 */
+    f = fopen (r->filename, "rb");
+#else
+    f = fopen (r->filename, "r");
+#endif
+
+    if (f == NULL) {
+        log_reason("file permissions deny server access", r->filename, r);
+        return FORBIDDEN;
+    }
+
+    if (d->content_md5 & 1) {
+      table_set (r->headers_out, "Content-MD5", md5digest(r->pool, f));
+    }
+
+    soft_timeout ("send", r);
+    
+    send_http_header (r);
+    if (!r->header_only) send_fd (f, r);
+    fclose (f);
+    return OK;
+}
+
+handler_rec core_handlers[] = {
+{ "*/*", default_handler },
+{ NULL }
+};
+
+module core_module = {
+   STANDARD_MODULE_STUFF,
+   NULL,                       /* initializer */
+   create_core_dir_config,     /* create per-directory config structure */
+   merge_core_dir_configs,     /* merge per-directory config structures */
+   create_core_server_config,  /* create per-server config structure */
+   merge_core_server_configs,  /* merge per-server config structures */
+   core_cmds,                  /* command table */
+   core_handlers,              /* handlers */
+   core_translate,             /* translate_handler */
+   NULL,                       /* check_user_id */
+   NULL,                       /* check auth */
+   do_nothing,                 /* check access */
+   do_nothing,                 /* type_checker */
+   NULL,                       /* pre-run fixups */
+   NULL                                /* logger */
+};
diff --git a/RELEASE_1_1_X/src/main/http_log.c b/RELEASE_1_1_X/src/main/http_log.c
new file mode 100644 (file)
index 0000000..51fc2e1
--- /dev/null
@@ -0,0 +1,193 @@
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * http_log.c: Dealing with the logs and errors
+ * 
+ * Rob McCool
+ * 
+ */
+
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_core.h"
+#include "http_log.h"
+
+#include <stdarg.h>
+
+void error_log_child (void *cmd)
+{
+    /* Child process code for 'ErrorLog "|..."';
+     * may want a common framework for this, since I expect it will
+     * be common for other foo-loggers to want this sort of thing...
+     */
+    
+    cleanup_for_exec();
+    signal (SIGHUP, SIG_IGN);
+    execl (SHELL_PATH, SHELL_PATH, "-c", (char *)cmd, NULL);
+    exit (1);
+}
+
+void open_error_log(server_rec *s, pool *p)
+{
+    char *fname;
+  
+    fname = server_root_relative (p, s->error_fname);
+
+    if (*fname == '|') {
+      FILE *dummy;
+
+      spawn_child(p, error_log_child, (void *)(fname+1),
+                    kill_after_timeout, &dummy, NULL);
+
+        if (dummy == NULL) {
+            fprintf (stderr, "Couldn't fork child for ErrorLog process\n");
+            exit (1);
+      }
+    } else {
+        if(!(s->error_log = pfopen(p, fname, "a"))) {
+            fprintf(stderr,"httpd: could not open error log file %s.\n", fname);
+            perror("fopen");
+            exit(1);
+      }
+    }
+}
+
+void open_logs (server_rec *s_main, pool *p)
+{
+    server_rec *virt, *q;
+
+    open_error_log (s_main, p);
+
+    for (virt = s_main->next; virt; virt = virt->next) {
+       if (virt->error_fname)
+       {
+           for (q=s_main; q != virt; q = q->next)
+               if (q->error_fname != NULL &&
+                   strcmp(q->error_fname, virt->error_fname) == 0)
+                   break;
+           if (q == virt) open_error_log (virt, p);
+           else virt->error_log = q->error_log;
+       }
+       else
+           virt->error_log = s_main->error_log;
+    }
+}
+
+void error_log2stderr(server_rec *s) {
+    if(fileno(s->error_log) != STDERR_FILENO)
+        dup2(fileno(s->error_log),STDERR_FILENO);
+}
+
+void log_pid(pool *p, char *pid_fname) {
+    FILE *pid_file;
+
+    if (!pid_fname) return;
+    pid_fname = server_root_relative (p, pid_fname);
+    if(!(pid_file = fopen(pid_fname,"w"))) {
+       perror("fopen");
+        fprintf(stderr,"httpd: could not log pid to file %s\n", pid_fname);
+        exit(1);
+    }
+    fprintf(pid_file,"%ld\n",(long)getpid());
+    fclose(pid_file);
+}
+
+void log_error(char *err, server_rec *s) {
+    fprintf(s->error_log, "[%s] %s\n",get_time(),err);
+    fflush(s->error_log);
+}
+
+void
+log_unixerr(const char *routine, const char *file, const char *msg,
+           server_rec *s)
+{
+    const char *p, *q;
+
+    p = strerror(errno);
+    q = get_time();
+
+    if (file != NULL)
+       fprintf(s->error_log, "[%s] %s: %s: %s\n", q, routine, file, p);
+    else
+       fprintf(s->error_log, "[%s] %s: %s\n", q, routine, p);
+    if (msg != NULL) fprintf(s->error_log, "[%s] - %s\n", q, msg);
+
+    fflush(s->error_log);
+}
+
+void
+log_printf(const server_rec *s, const char *fmt, ...)
+{
+    va_list args;
+    
+    fprintf(s->error_log, "[%s] ", get_time());
+    va_start (args, fmt);
+    vfprintf (s->error_log, fmt, args);
+    va_end (args);
+
+    fputc('\n', s->error_log);
+    fflush(s->error_log);
+}
+
+void log_reason(char *reason, char *file, request_rec *r) {
+    fprintf (r->server->error_log,
+            "[%s] access to %s failed for %s, reason: %s\n",
+            get_time(), file,
+            get_remote_host(r->connection, r->per_dir_config, REMOTE_NAME),
+            reason);
+    fflush (r->server->error_log);
+}
+
diff --git a/RELEASE_1_1_X/src/main/http_main.c b/RELEASE_1_1_X/src/main/http_main.c
new file mode 100644 (file)
index 0000000..9d56683
--- /dev/null
@@ -0,0 +1,1574 @@
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * httpd.c: simple http daemon for answering WWW file requests
+ *
+ * 
+ * 03-21-93  Rob McCool wrote original code (up to NCSA HTTPd 1.3)
+ * 
+ * 03-06-95  blong
+ *  changed server number for child-alone processes to 0 and changed name
+ *   of processes
+ *
+ * 03-10-95  blong
+ *     Added numerous speed hacks proposed by Robert S. Thau (rst@ai.mit.edu) 
+ *     including set group before fork, and call gettime before to fork
+ *     to set up libraries.
+ *
+ * 04-14-95  rst / rh
+ *      Brandon's code snarfed from NCSA 1.4, but tinkered to work with the
+ *      Apache server, and also to have child processes do accept() directly.
+ *
+ * April-July '95 rst
+ *      Extensive rework for Shambhala.
+ */
+
+
+#define CORE_PRIVATE
+
+#include "httpd.h"
+#include "http_main.h"
+#include "http_log.h"
+#include "http_config.h"       /* for read_config */
+#include "http_protocol.h"     /* for read_request */
+#include "http_request.h"      /* for process_request */
+#include "http_conf_globals.h"
+#include "http_core.h"          /* for get_remote_host */
+#include "scoreboard.h"
+#include <setjmp.h>
+#ifdef HAVE_SHMGET
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#if defined(AUX)               /* Aren't defined anyplace */
+extern char *shmat(int, char *, int);
+extern int  shmctl(int, int, struct shmid_ds *);
+extern int  shmget(key_t, int, int);
+extern char *sbrk(int);
+#endif
+#endif
+#ifdef SecureWare
+#include <sys/security.h>
+#include <sys/audit.h>
+#include <prot.h>
+#endif
+
+/*
+ * Actual definitions of config globals... here because this is
+ * for the most part the only code that acts on 'em.  (Hmmm... mod_main.c?)
+ */
+
+int standalone;
+uid_t user_id;
+char *user_name;
+gid_t group_id;
+int max_requests_per_child;
+char *pid_fname;
+char *scoreboard_fname;
+char *server_argv0;
+struct in_addr bind_address;
+listen_rec *listeners;
+int daemons_to_start;
+int daemons_min_free;
+int daemons_max_free;
+int daemons_limit;
+time_t restart_time;
+
+char server_root[MAX_STRING_LEN];
+char server_confname[MAX_STRING_LEN];
+
+/* *Non*-shared http_main globals... */
+
+server_rec *server_conf;
+JMP_BUF jmpbuffer;
+JMP_BUF restart_buffer;
+int sd;
+static fd_set listenfds;
+static int listenmaxfd;
+pid_t pgrp;
+
+/* 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 --- Shambhala 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.).
+ */
+
+int one_process = 0;
+
+#if defined(FCNTL_SERIALIZED_ACCEPT)
+static struct flock lock_it = { F_WRLCK, 0, 0, 0 };
+static struct flock unlock_it = { F_UNLCK, 0, 0, 0 };
+
+static int lock_fd=-1;
+
+/*
+ * Initialize mutex lock.
+ * Must be safe to call this on a restart.
+ */
+void
+accept_mutex_init(pool *p)
+{
+    char lock_fname[30];
+
+    strcpy(lock_fname, "/usr/tmp/htlock.XXXXXX");
+    
+    if (mktemp(lock_fname) == NULL || lock_fname[0] == '\0')
+    {
+       fprintf (stderr, "Cannot assign name to lock file!\n");
+       exit (1);
+    }
+
+    lock_fd = popenf(p, lock_fname, O_CREAT | O_WRONLY, 0644);
+    if (lock_fd == -1)
+    {
+       perror ("open");
+       fprintf (stderr, "Cannot open lock file: %s\n", lock_fname);
+       exit (1);
+    }
+    unlink(lock_fname);
+}
+
+void accept_mutex_on()
+{
+    int ret;
+    
+    while ((ret = fcntl(lock_fd, F_SETLKW, &lock_it)) < 0 && errno == EINTR)
+       continue;
+
+    if (ret < 0) {
+       log_unixerr("fcntl", "F_SETLKW", "Error getting accept lock. Exiting!",
+                   server_conf);
+       exit(1);
+    }
+}
+
+void accept_mutex_off()
+{
+    if (fcntl (lock_fd, F_SETLKW, &unlock_it) < 0)
+    {
+       log_unixerr("fcntl", "F_SETLKW", "Error freeing accept lock. Exiting!",
+                   server_conf);
+       exit(1);
+    }
+}
+#elif defined(FLOCK_SERIALIZED_ACCEPT)
+
+static int lock_fd=-1;
+
+/*
+ * Initialize mutex lock.
+ * Must be safe to call this on a restart.
+ */
+void
+accept_mutex_init(pool *p)
+{
+    char lock_fname[30];
+
+    strcpy(lock_fname, "/usr/tmp/htlock.XXXXXX");
+    
+    if (mktemp(lock_fname) == NULL || lock_fname[0] == '\0')
+    {
+       fprintf (stderr, "Cannot assign name to lock file!\n");
+       exit (1);
+    }
+
+    lock_fd = popenf(p, lock_fname, O_CREAT | O_WRONLY, 0644);
+    if (lock_fd == -1)
+    {
+       perror ("open");
+       fprintf (stderr, "Cannot open lock file\n");
+       exit (1);
+    }
+    unlink(lock_fname);
+}
+
+void accept_mutex_on()
+{
+    int ret;
+    
+    while ((ret = flock(lock_fd, LOCK_EX)) < 0 && errno == EINTR)
+       continue;
+
+    if (ret < 0) {
+       log_unixerr("flock", "LOCK_EX", "Error getting accept lock. Exiting!",
+                   server_conf);
+       exit(1);
+    }
+}
+
+void accept_mutex_off()
+{
+    if (flock (lock_fd, LOCK_UN) < 0)
+    {
+       log_unixerr("flock", "LOCK_UN", "Error freeing accept lock. Exiting!",
+                   server_conf);
+       exit(1);
+    }
+}
+#else
+/* Default --- no serialization.  Other methods *could* go here,
+ * as #elifs...
+ */
+#define accept_mutex_init(x)
+#define accept_mutex_on()
+#define accept_mutex_off()
+#endif
+
+void usage(char *bin)
+{
+    fprintf(stderr,"Usage: %s [-d directory] [-f file] [-v]\n",bin);
+    fprintf(stderr,"-d directory : specify an alternate initial ServerRoot\n");
+    fprintf(stderr,"-f file : specify an alternate ServerConfigFile\n");
+    exit(1);
+}
+
+/*****************************************************************
+ *
+ * Timeout handling.  DISTINCTLY not thread-safe, but all this stuff
+ * has to change for threads anyway.  Note that this code allows only
+ * one timeout in progress at a time...
+ */
+
+static conn_rec *current_conn;
+static request_rec *timeout_req;
+static char *timeout_name = NULL;
+static int alarms_blocked = 0;
+static int alarm_pending = 0;
+
+void abort_connection (conn_rec *);
+
+void timeout(sig)                      /* Also called on SIGPIPE */
+int sig;
+{
+    char errstr[MAX_STRING_LEN];
+    void *dirconf;
+
+    signal(SIGPIPE, SIG_IGN);          /* Block SIGPIPE */
+    if (alarms_blocked) {
+       alarm_pending = 1;
+       return;
+    }
+    
+    if (!current_conn) {
+#ifdef NEXT
+       longjmp(jmpbuffer,1);
+#else
+       siglongjmp(jmpbuffer,1);
+#endif
+    }
+    
+    if (timeout_req != NULL) dirconf = timeout_req->per_dir_config;
+    else dirconf = current_conn->server->lookup_defaults;
+    if (sig == SIGPIPE) {
+        sprintf(errstr,"%s lost connection to client %s",
+           timeout_name ? timeout_name : "request",
+           get_remote_host(current_conn, dirconf, REMOTE_NAME));
+    } else {
+        sprintf(errstr,"%s timed out for %s",
+           timeout_name ? timeout_name : "request",
+           get_remote_host(current_conn, dirconf, REMOTE_NAME));
+    }
+    
+    if (!current_conn->keptalive) 
+       log_error(errstr, current_conn->server);
+      
+    if (timeout_req) {
+       /* Someone has asked for this transaction to just be aborted
+        * if it times out...
+        */
+       
+       request_rec *log_req = timeout_req;
+       
+       while (log_req->main || log_req->prev) {
+           /* Get back to original request... */
+           if (log_req->main) log_req = log_req->main;
+           else log_req = log_req->prev;
+       }
+       
+       if (!current_conn->keptalive) 
+            log_transaction(log_req);
+
+       bclose(timeout_req->connection->client);
+    
+       if (!standalone) exit(0);
+#ifdef NEXT
+       longjmp(jmpbuffer,1);
+#else
+       siglongjmp(jmpbuffer,1);
+#endif
+    }
+    else {
+       abort_connection (current_conn);
+    }
+}
+
+/*
+ * These two called from alloc.c to protect its critical sections...
+ * Note that they can nest (as when destroying the sub_pools of a pool
+ * which is itself being cleared); we have to support that here.
+ */
+
+void block_alarms() {
+    ++alarms_blocked;
+}
+
+void unblock_alarms() {
+    --alarms_blocked;
+    if (alarms_blocked == 0 && alarm_pending) {
+       alarm_pending = 0;
+       timeout(0);
+    }
+}
+
+void hard_timeout (char *name, request_rec *r)
+{
+    timeout_req = r;
+    timeout_name = name;
+    
+    signal(SIGALRM,(void (*)())timeout);
+    if (r->connection->keptalive) 
+       alarm (r->server->keep_alive_timeout);
+    else
+       alarm (r->server->timeout);
+}
+
+void soft_timeout (char *name, request_rec *r)
+{
+    timeout_name = name;
+    
+    signal(SIGALRM,(void (*)())timeout);
+    alarm (r->server->timeout);
+}
+
+void kill_timeout (request_rec *dummy) {
+    alarm (0);
+    timeout_req = NULL;
+    timeout_name = NULL;
+}
+
+/* reset_timeout (request_rec *) resets the timeout in effect,
+ * as long as it hasn't expired already.
+ */
+
+void reset_timeout (request_rec *r) {
+    int i;
+
+    if (timeout_name) { /* timeout has been set */
+        i = alarm(r->server->timeout);
+        if (i == 0) /* timeout already expired, so set it back to 0 */
+           alarm(0);
+    }
+}
+
+/*****************************************************************
+ *
+ * Dealing with the scoreboard... a lot of these variables are global
+ * only to avoid getting clobbered by the longjmp() that happens when
+ * a hard timeout expires...
+ *
+ * We begin with routines which deal with the file itself... 
+ */
+
+#if defined(HAVE_MMAP)
+static short_score *scoreboard_image=NULL;
+
+static void setup_shared_mem(void)
+{
+    caddr_t m;
+#if defined(MAP_ANON) || defined(MAP_FILE)
+/* BSD style */
+    m = mmap((caddr_t)0, HARD_SERVER_LIMIT*sizeof(short_score),
+            PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0);
+    if (m == (caddr_t)-1)
+    {
+       perror("mmap");
+       fprintf(stderr, "httpd: Could not mmap memory\n");
+       exit(1);
+    }
+#else
+/* Sun style */
+    int fd;
+
+    fd = open("/dev/zero", O_RDWR);
+    if (fd == -1)
+    {
+       perror("open");
+       fprintf(stderr, "httpd: Could not open /dev/zero\n");
+       exit(1);
+    }
+    m = mmap((caddr_t)0, HARD_SERVER_LIMIT*sizeof(short_score),
+            PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+    if (m == (caddr_t)-1)
+    {
+       perror("mmap");
+       fprintf(stderr, "httpd: Could not mmap /dev/zero\n");
+       exit(1);
+    }
+    close(fd);
+#endif
+    scoreboard_image = (short_score *)m;
+}
+
+#elif defined(HAVE_SHMGET)
+static short_score *scoreboard_image=NULL;
+static key_t shmkey = IPC_PRIVATE;
+static int shmid = -1;
+
+static void setup_shared_mem(void)
+{
+    int score_size = HARD_SERVER_LIMIT*sizeof(short_score);
+    char errstr[MAX_STRING_LEN];
+    struct shmid_ds shmbuf;
+#ifdef MOVEBREAK
+    char *obrk;
+#endif
+
+    if ((shmid = shmget(shmkey, score_size, IPC_CREAT|SHM_R|SHM_W)) == -1)
+    {
+       perror("shmget");
+       fprintf(stderr, "httpd: Could not call shmget\n");
+       exit(1);
+    }
+
+    sprintf(errstr, "created shared memory segment #%d", shmid);
+    log_error(errstr, server_conf);
+
+#ifdef MOVEBREAK
+    /*
+     * Some SysV systems place the shared segment WAY too close
+     * to the dynamic memory break point (sbrk(0)). This severely
+     * limits the use of malloc/sbrk in the program since sbrk will
+     * refuse to move past that point.
+     *
+     * To get around this, we move the break point "way up there",
+     * attach the segment and then move break back down. Ugly
+     */
+    if ((obrk=sbrk(MOVEBREAK)) == (char *)-1)
+    {
+       perror("sbrk");
+       fprintf(stderr, "httpd: Could not move break\n");
+    }
+#endif
+
+#define BADSHMAT       ((short_score*)(-1))
+    if ((scoreboard_image = (short_score*)shmat(shmid, 0, 0)) == BADSHMAT)
+    {
+       perror("shmat");
+       fprintf(stderr, "httpd: Could not call shmat\n");
+       /*
+        * We exit below, after we try to remove the segment
+        */
+    }
+    else       /* only worry about permissions if we attached the segment */
+    {
+       if (shmctl(shmid, IPC_STAT, &shmbuf) != 0) {
+           perror("shmctl");
+           fprintf(stderr, "httpd: Could not stat segment #%d\n", shmid);
+       }
+       else
+       {
+           shmbuf.shm_perm.uid = user_id;
+           shmbuf.shm_perm.gid = group_id;
+           if (shmctl(shmid, IPC_SET, &shmbuf) != 0) {
+               perror("shmctl");
+               fprintf(stderr, "httpd: Could not set segment #%d\n", shmid);
+           }
+       }
+    }
+    /*
+     * We must avoid leaving segments in the kernel's
+     * (small) tables.
+     */
+    if (shmctl(shmid, IPC_RMID, NULL) != 0) {
+       perror("shmctl");
+       fprintf(stderr, "httpd: Could not delete segment #%d\n", shmid);
+       sprintf(errstr, "could not remove shared memory segment #%d", shmid);
+       log_unixerr("shmctl","IPC_RMID",errstr, server_conf);
+    }
+    if (scoreboard_image == BADSHMAT)  /* now bailout */
+       exit(1);
+
+#ifdef MOVEBREAK
+    if (obrk == (char *)-1)
+       return;         /* nothing else to do */
+    if (sbrk(-(MOVEBREAK)) == (char *)-1)
+    {
+       perror("sbrk");
+       fprintf(stderr, "httpd: Could not move break back\n");
+    }
+#endif
+}
+
+#else
+static short_score scoreboard_image[HARD_SERVER_LIMIT];
+static int have_scoreboard_fname = 0;
+static int scoreboard_fd;
+
+static int force_write (int fd, char *buffer, int bufsz)
+{
+    int rv, orig_sz = bufsz;
+    
+    do {
+       rv = write (fd, buffer, bufsz);
+       if (rv > 0) {
+           buffer += rv;
+           bufsz -= rv;
+       }
+    } while (rv > 0 && bufsz > 0);
+
+    return rv < 0? rv : orig_sz - bufsz;
+}
+
+static int force_read (int fd, char *buffer, int bufsz)
+{
+    int rv, orig_sz = bufsz;
+    
+    do {
+       rv = read (fd, buffer, bufsz);
+       if (rv > 0) {
+           buffer += rv;
+           bufsz -= rv;
+       }
+    } while (rv > 0 && bufsz > 0);
+    
+    return rv < 0? rv : orig_sz - bufsz;
+}
+#endif
+
+/* Called by parent process */
+void reinit_scoreboard (pool *p)
+{
+#if defined(HAVE_SHMGET) || defined(HAVE_MMAP)
+    if (scoreboard_image == NULL)
+    {
+       setup_shared_mem();
+    }
+    memset(scoreboard_image, 0, HARD_SERVER_LIMIT*sizeof(short_score));
+#else
+    scoreboard_fname = server_root_relative (p, scoreboard_fname);
+
+    have_scoreboard_fname = 1;
+    
+    scoreboard_fd = popenf(p, scoreboard_fname, O_CREAT|O_RDWR, 0644);
+    if (scoreboard_fd == -1)
+    {
+       fprintf (stderr, "Cannot open scoreboard file:\n");
+       perror (scoreboard_fname);
+       exit (1);
+    }
+
+    memset ((char*)scoreboard_image, 0, sizeof(scoreboard_image));
+    force_write (scoreboard_fd, (char*)scoreboard_image,
+                sizeof(scoreboard_image));
+#endif
+}
+
+/* called by child */
+void reopen_scoreboard (pool *p)
+{
+#if !defined(HAVE_MMAP) && !defined(HAVE_SHMGET)
+    if (scoreboard_fd != -1) pclosef (p, scoreboard_fd);
+    
+    scoreboard_fd = popenf(p, scoreboard_fname, O_CREAT|O_RDWR, 0666);
+    if (scoreboard_fd == -1)
+    {
+       fprintf (stderr, "Cannot open scoreboard file:\n");
+       perror (scoreboard_fname);
+       exit (1);
+    }
+#endif
+}
+
+void cleanup_scoreboard ()
+{
+#if !defined(HAVE_MMAP) && !defined(HAVE_SHMGET)
+    unlink (scoreboard_fname);
+#endif
+}
+
+/* Routines called to deal with the scoreboard image
+ * --- note that we do *not* need write locks, since update_child_status
+ * only updates a *single* record in place, and only one process writes to
+ * a given scoreboard slot at a time (either the child process owning that
+ * slot, or the parent, noting that the child has died).
+ *
+ * As a final note --- setting the score entry to getpid() is always safe,
+ * since when the parent is writing an entry, it's only noting SERVER_DEAD
+ * anyway.
+ */
+
+void sync_scoreboard_image ()
+{
+#if !defined(HAVE_MMAP) && !defined(HAVE_SHMGET)
+    lseek (scoreboard_fd, 0L, 0);
+    force_read (scoreboard_fd, (char*)scoreboard_image,
+               sizeof(scoreboard_image));
+#endif
+}
+
+int update_child_status (int child_num, int status, request_rec *r)
+{
+    short_score new_score_rec;
+    int old_status;
+
+    if (child_num < 0)
+       return -1;
+    
+    memcpy(&new_score_rec,&scoreboard_image[child_num],sizeof new_score_rec);
+    new_score_rec.pid = getpid();
+    old_status = new_score_rec.status;
+    new_score_rec.status = status;
+
+#if defined(STATUS)
+    new_score_rec.last_used=time(NULL);
+    if (status == SERVER_DEAD) {
+       /*
+        * Reset individual counters
+        */
+       new_score_rec.my_access_count = 0L;
+       new_score_rec.my_bytes_served = 0L;
+       new_score_rec.conn_count = (unsigned short)0;
+       new_score_rec.conn_bytes = (unsigned long)0;
+    }
+    if (r) {
+       int slot_size;
+       conn_rec *c = r->connection;
+       slot_size = sizeof(new_score_rec.client) - 1;
+       strncpy(new_score_rec.client, get_remote_host(c, r->per_dir_config,
+        REMOTE_NAME), slot_size);
+       new_score_rec.client[slot_size] = '\0';
+       slot_size = sizeof(new_score_rec.request) - 1;
+       strncpy(new_score_rec.request, (r->the_request ? r->the_request :
+        "NULL"), slot_size);
+       new_score_rec.request[slot_size] = '\0';
+    }
+#endif
+
+#if defined(HAVE_MMAP) || defined(HAVE_SHMGET)
+    memcpy(&scoreboard_image[child_num], &new_score_rec, sizeof(short_score));
+#else
+    lseek (scoreboard_fd, (long)child_num * sizeof(short_score), 0);
+    force_write (scoreboard_fd, (char*)&new_score_rec, sizeof(short_score));
+#endif
+
+    return old_status;
+}
+
+int get_child_status (int child_num)
+{
+    if (child_num<0 || child_num>=HARD_SERVER_LIMIT)
+       return -1;
+    else
+       return scoreboard_image[child_num].status;
+}
+
+int count_busy_servers ()
+{
+    int i;
+    int res = 0;
+
+    for (i = 0; i < HARD_SERVER_LIMIT; ++i)
+      if (scoreboard_image[i].status == SERVER_BUSY_READ ||
+              scoreboard_image[i].status == SERVER_BUSY_WRITE ||
+              scoreboard_image[i].status == SERVER_BUSY_KEEPALIVE ||
+              scoreboard_image[i].status == SERVER_BUSY_LOG ||
+              scoreboard_image[i].status == SERVER_BUSY_DNS)
+          ++res;
+    return res;
+}
+
+short_score get_scoreboard_info(int i)
+{
+    return (scoreboard_image[i]);
+}
+
+#if defined(STATUS)
+void increment_counts (int child_num, request_rec *r, int flag)
+{
+    long int bs=0;
+    short_score new_score_rec=scoreboard_image[child_num];
+
+    if (r->sent_bodyct)
+        bgetopt(r->connection->client, BO_BYTECT, &bs);
+
+    if (flag) {
+       new_score_rec.conn_count = (unsigned short)0;
+       new_score_rec.conn_bytes = (unsigned long)0;
+    }
+    new_score_rec.access_count ++;
+    new_score_rec.my_access_count ++;
+    new_score_rec.conn_count ++;
+    new_score_rec.bytes_served += (unsigned long)bs;
+    new_score_rec.my_bytes_served += (unsigned long)bs;
+    new_score_rec.conn_bytes += (unsigned long)bs;
+
+    times(&new_score_rec.times);
+
+#if defined(HAVE_MMAP) || defined(HAVE_SHMGET)
+    memcpy(&scoreboard_image[child_num], &new_score_rec, sizeof(short_score));
+#else
+    lseek (scoreboard_fd, (long)child_num * sizeof(short_score), 0);
+    force_write (scoreboard_fd, (char*)&new_score_rec, sizeof(short_score));
+#endif
+}
+#endif
+
+int count_idle_servers ()
+{
+    int i;
+    int res = 0;
+
+    for (i = 0; i < HARD_SERVER_LIMIT; ++i)
+       if (scoreboard_image[i].status == SERVER_READY
+         || scoreboard_image[i].status == SERVER_STARTING)
+           ++res;
+
+    return res;
+}
+
+int find_free_child_num ()
+{
+    int i;
+
+    for (i = 0; i < HARD_SERVER_LIMIT; ++i)
+       if (scoreboard_image[i].status == SERVER_DEAD)
+           return i;
+
+    return -1;
+}
+
+int find_child_by_pid (int pid)
+{
+    int i;
+
+    for (i = 0; i < HARD_SERVER_LIMIT; ++i)
+       if (scoreboard_image[i].pid == pid)
+           return i;
+
+    return -1;
+}
+
+void reclaim_child_processes ()
+{
+    int i, status;
+    int my_pid = getpid();
+
+    sync_scoreboard_image();
+    for (i = 0; i < HARD_SERVER_LIMIT; ++i) {
+       int pid = scoreboard_image[i].pid;
+
+       if (pid != my_pid && pid != 0)
+           waitpid (scoreboard_image[i].pid, &status, 0);
+    }
+}
+
+/* Finally, this routine is used by the caretaker process to wait for
+ * a while...
+ */
+
+static JMP_BUF wait_timeout_buf;
+static int wait_or_timeout_retval = -1;
+
+static void longjmp_out_of_alarm (int sig) {
+#ifdef NEXT
+    longjmp (wait_timeout_buf, 1);
+#else
+    siglongjmp (wait_timeout_buf, 1);
+#endif
+}
+
+int wait_or_timeout (int *status)
+{
+    wait_or_timeout_retval = -1;
+    
+#if defined(NEXT)
+    if (setjmp(wait_timeout_buf) != 0) {
+#else 
+    if (sigsetjmp(wait_timeout_buf, 1) != 0) {
+#endif
+       errno = ETIMEDOUT;
+       return wait_or_timeout_retval;
+    }
+    
+    signal (SIGALRM, longjmp_out_of_alarm);
+    alarm(1);
+#if defined(NEXT)
+    wait_or_timeout_retval = wait((union wait *)status);
+#else
+    wait_or_timeout_retval = wait(status);
+#endif
+    alarm(0);
+    return wait_or_timeout_retval;
+}
+
+
+/*****************************************************************
+ * Here follows a long bunch of generic server bookkeeping stuff...
+ */
+
+void detach()
+{
+    int x;
+
+    chdir("/");
+    if((x = fork()) > 0)
+        exit(0);
+    else if(x == -1) {
+        fprintf(stderr,"httpd: unable to fork new process\n");
+        perror("fork");
+        exit(1);
+    }
+#ifndef NO_SETSID
+    if((pgrp=setsid()) == -1) {
+        fprintf(stderr,"httpd: setsid failed\n");
+        perror("setsid");
+        exit(1);
+    }
+#else
+#if defined(NEXT)
+    if(setpgrp(0,getpid()) == -1 || (pgrp = getpgrp(0)) == -1) {
+        fprintf(stderr,"httpd: setpgrp or getpgrp failed\n");
+        perror("setpgrp");
+        exit(1);
+    }
+#else
+#ifdef __EMX__
+    /* OS/2 doesn't support process group IDs */
+    pgrp=getpid();
+#else
+    if((pgrp=setpgrp(getpid(),0)) == -1) {
+        fprintf(stderr,"httpd: setpgrp failed\n");
+        perror("setpgrp");
+        exit(1);
+    }
+#endif    
+#endif
+#endif
+}
+
+void sig_term() {
+    log_error("httpd: caught SIGTERM, shutting down", server_conf);
+    cleanup_scoreboard();
+#ifndef NO_KILLPG
+    killpg(pgrp,SIGKILL);
+#else
+    kill(-pgrp,SIGKILL);
+#endif
+    shutdown(sd,2);
+    close(sd);
+    exit(1);
+}
+
+void bus_error() {
+    log_error("httpd: caught SIGBUS, dumping core", server_conf);
+    chdir(server_root);
+    abort();         
+    exit(1);
+}
+
+void seg_fault() {
+    log_error("httpd: caught SIGSEGV, dumping core", server_conf);
+    chdir(server_root);
+    abort();
+    exit(1);
+}
+
+void just_die()                        /* SIGHUP to child process??? */
+{
+    exit (0);
+}
+
+/* Reset group privileges, after rereading the config files
+ * (our uid may have changed, and if so, we want the new perms).
+ *
+ * Don't reset the uid yet --- we do that only in the child process,
+ * so as not to lose any root privs.  But we can set the group stuff
+ * now, once, as opposed to once per each new child.
+ *
+ * Note that we use the username as set in the config files, rather than
+ * the lookup of to uid --- the same uid may have multiple passwd entries,
+ * with different sets of groups for each.
+ */
+  
+static void set_group_privs()
+{
+  if(!geteuid()) {
+    char *name;
+  
+    /* Get username if passed as a uid */
+    
+    if (user_name[0] == '#') {
+      struct passwd* ent;
+      uid_t uid=atoi(&user_name[1]);
+
+      if ((ent = getpwuid(uid)) == NULL) {
+        log_unixerr("getpwuid",NULL,"couldn't determine user name from uid", server_conf);
+        exit(1);
+      }
+      
+      name = ent->pw_name;
+    } else name = user_name;
+
+#ifndef __EMX__ 
+    /* OS/2 dosen't support groups. */
+
+    /* Reset `groups' attributes. */
+    
+    if (initgroups(name, group_id) == -1) {
+       log_unixerr("initgroups", NULL, "unable to set groups", server_conf);
+       exit (1);
+    }
+
+    if (setgid(group_id) == -1) {
+       log_unixerr("setgid", NULL, "unable to set group id", server_conf);
+       exit (1);
+    }
+#endif 
+  }
+}
+
+void restart() {
+    signal (SIGALRM, SIG_IGN);
+    alarm (0);
+#ifdef NEXT
+    longjmp(restart_buffer,1);
+#else
+    siglongjmp(restart_buffer,1);
+#endif
+}
+
+void set_signals() {
+#ifndef NO_USE_SIGACTION
+    struct sigaction sa;
+#endif
+    if(!one_process) {
+       signal(SIGSEGV,(void (*)())seg_fault);
+       signal(SIGBUS,(void (*)())bus_error);
+       }
+
+#ifdef NO_USE_SIGACTION
+    signal(SIGTERM,(void (*)())sig_term);
+    signal(SIGHUP,(void (*)())restart);
+#else
+    memset(&sa,0,sizeof sa);
+    sa.sa_handler=(void (*)())sig_term;
+    if(sigaction(SIGTERM,&sa,NULL) < 0)
+       log_unixerr("sigaction(SIGTERM)", NULL, NULL, server_conf);
+    sa.sa_handler=(void (*)())restart;
+    if(sigaction(SIGHUP,&sa,NULL) < 0)
+       log_unixerr("sigaction(SIGHUP)", NULL, NULL, server_conf);
+#endif
+}
+
+/*****************************************************************
+ * Connection structures and accounting...
+ * Should these be global?  Only to this file, at least...
+ */
+
+pool *pconf;                   /* Pool for config stuff */
+pool *ptrans;                  /* Pool for per-transaction stuff */
+
+server_rec *find_virtual_server (struct in_addr server_ip, int port,
+                                server_rec *server)
+{
+    server_rec *virt;
+
+    for (virt = server->next; virt; virt = virt->next)
+       if ((virt->is_virtual == 1) &&  /* VirtualHost */
+           (virt->host_addr.s_addr == htonl(INADDR_ANY) ||
+            virt->host_addr.s_addr == server_ip.s_addr) &&
+           (virt->host_port == 0 || virt->host_port == port))
+           return virt;
+
+    return server;
+}
+
+void default_server_hostnames(server_rec *s)
+{
+    struct hostent *h, *main;
+    char *def_hostname;
+    int n;
+
+    /* Main host first */
+    
+    if (!s->server_hostname)
+       s->server_hostname = get_local_host(pconf);
+
+    def_hostname = s->server_hostname;
+    main = gethostbyname(def_hostname);
+
+    /* Then virtual hosts */
+    
+    for (s = s->next; s; s = s->next) {
+       /* Check to see if we might be a HTTP/1.1 virtual host - same IP */
+       for (n = 0; main->h_addr_list[n] != NULL; n++) {
+         if (s->host_addr.s_addr ==
+             (((struct in_addr *)(main->h_addr_list[n]))->s_addr))
+           s->is_virtual = 2;
+       }
+
+        if (!s->server_hostname) {
+           if (s->is_virtual == 2)
+               s->server_hostname = s->virthost;
+           else if (s->host_addr.s_addr == htonl(INADDR_ANY))
+               s->server_hostname = def_hostname;
+           else
+           {
+               h = gethostbyaddr ((char *)&(s->host_addr),
+                                  sizeof (struct in_addr), AF_INET);
+               if (h != NULL)
+                   s->server_hostname = pstrdup (pconf, (char *)h->h_name);
+           }
+       }
+    }
+}
+       
+void abort_connection (conn_rec *c)
+{
+    /* Make sure further I/O DOES NOT HAPPEN */
+    shutdown (c->client->fd, 2);
+    signal (SIGPIPE, SIG_IGN); /* Ignore further complaints */
+    c->aborted = 1;
+}
+
+conn_rec *new_connection (pool *p, server_rec *server, BUFF *inout,
+                         const struct sockaddr_in *remaddr,
+                         const struct sockaddr_in *saddr,
+                         int child_num)
+{
+    conn_rec *conn = (conn_rec *)pcalloc (p, sizeof(conn_rec));
+    
+    /* Get a connection structure, and initialize what fields we can
+     * (the rest are zeroed out by pcalloc).
+     */
+    
+    conn = (conn_rec *)pcalloc(p, sizeof(conn_rec));
+    conn->child_num = child_num;
+    
+    conn->pool = p;
+    conn->local_addr = *saddr;
+    conn->server = find_virtual_server(saddr->sin_addr, ntohs(saddr->sin_port),
+                                      server);
+    conn->client = inout;
+    
+    conn->remote_addr = *remaddr;
+    conn->remote_ip = pstrdup (conn->pool,
+                              inet_ntoa(conn->remote_addr.sin_addr));
+
+    return conn;
+}
+
+/*****************************************************************
+ * Child process main loop.
+ * The following vars are static to avoid getting clobbered by longjmp();
+ * they are really private to child_main.
+ */
+
+static int csd;
+static int dupped_csd;
+static int requests_this_child;
+static int child_num;
+
+void child_main(int child_num_arg)
+{
+    int clen;
+    struct sockaddr sa_server;
+    struct sockaddr sa_client;
+
+    csd = -1;
+    dupped_csd = -1;
+    child_num = child_num_arg;
+    requests_this_child = 0;
+    reopen_scoreboard (pconf);
+    (void)update_child_status (child_num, SERVER_READY, (request_rec*)NULL);
+
+    /* Only try to switch if we're running as root */
+    if(!geteuid() && setuid(user_id) == -1) {
+        log_unixerr("setuid", NULL, "unable to change uid", server_conf);
+       exit (1);
+    }
+
+#ifdef NEXT
+    setjmp(jmpbuffer);
+#else
+    sigsetjmp(jmpbuffer,1);
+#endif
+#ifndef __EMX__
+    signal(SIGURG, timeout);
+#endif    
+
+    while (1) {
+       BUFF *conn_io;
+       request_rec *r;
+      
+        alarm(0);              /* Cancel any outstanding alarms. */
+        timeout_req = NULL;    /* No request in progress */
+       current_conn = NULL;
+        signal(SIGPIPE, timeout);  
+    
+       clear_pool (ptrans);
+       
+       sync_scoreboard_image();
+       
+       if ((count_idle_servers() >= daemons_max_free)
+           || (max_requests_per_child > 0
+               && ++requests_this_child >= max_requests_per_child))
+       {
+           exit(0);
+       }
+
+       clen=sizeof(sa_client);
+       (void)update_child_status (child_num, SERVER_READY, (request_rec*)NULL);
+       
+       accept_mutex_on();  /* Lock around "accept", if necessary */
+
+       if (listeners != NULL)
+       {
+           fd_set fds;
+
+           for (;;) {
+               memcpy(&fds, &listenfds, sizeof(fd_set));
+#ifdef HPUX
+               csd = select(listenmaxfd+1, (int*)&fds, NULL, NULL, NULL);
+#else
+                csd = select(listenmaxfd+1, &fds, NULL, NULL, NULL);
+#endif
+               if (csd == -1 && errno != EINTR)
+                   log_unixerr("select",NULL,"select error", server_conf);
+               if (csd <= 0) continue;
+               for (sd=listenmaxfd; sd >= 0; sd--)
+                   if (FD_ISSET(sd, &fds)) break;
+               if (sd < 0) continue;
+
+               clen=sizeof(sa_client);
+               do csd=accept(sd, &sa_client, &clen);
+               while (csd == -1 && errno == EINTR);
+               if (csd != -1) break;
+               log_unixerr("accept", "(client socket)", NULL, server_conf);
+           }
+       } else
+           while ((csd=accept(sd, &sa_client, &clen)) == -1) 
+               if (errno != EINTR) 
+                   log_unixerr("accept",NULL,"socket error: accept failed", server_conf);
+
+       accept_mutex_off(); /* unlock after "accept" */
+
+       clen = sizeof(sa_server);
+       if(getsockname(csd, &sa_server, &clen) < 0) {
+           log_unixerr("getsockname", NULL, NULL, server_conf);
+           continue;
+       }
+       
+       (void)update_child_status (child_num, SERVER_BUSY_READ, (request_rec*)NULL);
+       conn_io = bcreate(ptrans, B_RDWR);
+       dupped_csd = csd;
+#if defined(NEED_DUPPED_CSD)
+       if ((dupped_csd = dup(csd)) < 0) {
+           log_unixerr("dup", NULL, "couldn't duplicate csd", server_conf);
+           dupped_csd = csd;   /* Oh well... */
+       }
+#endif
+       bpushfd(conn_io, csd, dupped_csd);
+
+       current_conn = new_connection (ptrans, server_conf, conn_io,
+                                      (struct sockaddr_in *)&sa_client,
+                                      (struct sockaddr_in *)&sa_server,
+                                      child_num);
+       
+       r = read_request (current_conn);
+       (void)update_child_status (child_num, SERVER_BUSY_WRITE, r);
+       if (r) process_request (r); /* else premature EOF --- ignore */
+
+#if defined(STATUS)
+        if (r) increment_counts(child_num,r,1);
+#endif
+       while (r && current_conn->keepalive) {
+         bflush(conn_io);
+         destroy_pool(r->pool);
+         (void)update_child_status (child_num, SERVER_BUSY_KEEPALIVE, (request_rec*)NULL);
+         r = read_request (current_conn);
+         (void)update_child_status (child_num, SERVER_BUSY_WRITE, r);
+         if (r) process_request (r);
+
+#if defined(STATUS)
+         if (r) increment_counts(child_num,r,0);
+#endif
+       }
+#if 0  
+       if (bytes_in_pool (ptrans) > 80000)
+           log_printf(r->server,
+                      "Memory hog alert: allocated %ld bytes for %s",
+                      bytes_in_pool (ptrans), r->the_request);
+#endif         
+       bflush(conn_io);
+       bclose(conn_io);
+    }    
+}
+
+void make_child(server_rec *server_conf, int child_num)
+{
+    int pid;
+
+    if (one_process) {
+       signal (SIGHUP, (void (*)())just_die);
+       signal (SIGTERM, (void (*)())just_die);
+       child_main (child_num);
+    }
+
+    if ((pid = fork()) == -1) {
+       log_unixerr("fork", NULL, "Unable to fork new process", server_conf);
+       return;
+    } 
+    
+    if (!pid) {
+       signal (SIGHUP, (void (*)())just_die);
+       signal (SIGTERM, (void (*)())just_die);
+       child_main (child_num);
+    }
+}
+
+static int
+make_sock(pool *pconf, const struct sockaddr_in *server)
+{
+    int s;
+    const int one = 1;
+    const int keepalive_value = 1;  
+
+    if ((s = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)) == -1) {
+        perror("socket");
+        fprintf(stderr,"httpd: could not get socket\n");
+        exit(1);
+    }
+
+    note_cleanups_for_fd (pconf, s); /* arrange to close on exec or restart */
+    
+    if((setsockopt(s, SOL_SOCKET,SO_REUSEADDR,(char *)&one,sizeof(one)))
+       == -1) {
+       perror("setsockopt(SO_REUSEADDR)");
+       fprintf(stderr,"httpd: could not set socket option SO_REUSEADDR\n");
+        exit(1);
+    }
+    if((setsockopt(s, SOL_SOCKET,SO_KEEPALIVE,(char *)&keepalive_value,
+        sizeof(keepalive_value))) == -1) {
+       perror("setsockopt(SO_KEEPALIVE)"); 
+        fprintf(stderr,"httpd: could not set socket option SO_KEEPALIVE\n"); 
+        exit(1); 
+    }
+
+#ifdef NEED_LINGER   /* If puts don't complete, you could try this. */
+    {
+       struct linger li;
+       li.l_onoff = 1;
+       li.l_linger = 900;
+
+       if (setsockopt(s, SOL_SOCKET, SO_LINGER,
+           (char *)&li, sizeof(struct linger)) < 0) {
+           perror("setsockopt(SO_LINGER)");
+           fprintf(stderr,"httpd: could not set socket option SO_LINGER\n");
+           exit(1);
+       }
+    }
+#endif  /* NEED_LINGER */
+
+    if(bind(s, (struct sockaddr *)server,sizeof(struct sockaddr_in)) == -1)
+    {
+        perror("bind");
+       if (server->sin_addr.s_addr != htonl(INADDR_ANY))
+           fprintf(stderr,"httpd: could not bind to address %s port %d\n",
+                   inet_ntoa(server->sin_addr), ntohs(server->sin_port));
+       else
+           fprintf(stderr,"httpd: could not bind to port %d\n",
+                   ntohs(server->sin_port));
+        exit(1);
+    }
+    listen(s, 512);
+    return s;
+}
+
+
+/*****************************************************************
+ * Executive routines.
+ */
+
+static int num_children = 0;
+
+void standalone_main(int argc, char **argv)
+{
+    struct sockaddr_in sa_server;
+
+    standalone = 1;
+    sd = listenmaxfd = -1;
+    
+    if (!one_process) detach(); 
+    
+#ifdef NEXT
+    setjmp(restart_buffer);
+#else
+    sigsetjmp(restart_buffer,1);
+#endif
+
+    signal (SIGHUP, SIG_IGN);  /* Until we're done (re)reading config */
+    
+    if(!one_process)
+    {
+#ifndef NO_KILLPG
+      if (killpg(pgrp,SIGHUP) < 0)    /* Kill 'em off */
+#else
+      if (kill(-pgrp,SIGHUP) < 0)
+#endif
+        log_unixerr ("killpg SIGHUP", NULL, NULL, server_conf);
+    }
+    
+    if (sd != -1 || listenmaxfd != -1) {
+       reclaim_child_processes(); /* Not when just starting up */
+       log_error ("SIGHUP received.  Attempting to restart", server_conf);
+    }
+    
+    restart_time = time(NULL);
+    clear_pool (pconf);
+    ptrans = make_sub_pool (pconf);
+    
+    server_conf = read_config(pconf, ptrans, server_confname); 
+    open_logs(server_conf, pconf);
+    set_group_privs();
+    accept_mutex_init(pconf);
+    reinit_scoreboard(pconf);
+    
+    default_server_hostnames (server_conf);
+
+    if (listeners == NULL)
+    {
+       memset((char *) &sa_server, 0, sizeof(sa_server));
+       sa_server.sin_family=AF_INET;
+       sa_server.sin_addr=bind_address;
+       sa_server.sin_port=htons(server_conf->port);
+
+       sd = make_sock(pconf, &sa_server);
+    } else
+    {
+       listen_rec *lr;
+       int fd;
+
+       listenmaxfd = -1;
+       FD_ZERO(&listenfds);
+       for (lr=listeners; lr != NULL; lr=lr->next)
+       {
+           fd = make_sock(pconf, &lr->local_addr);
+           FD_SET(fd, &listenfds);
+           if (fd > listenmaxfd) listenmaxfd = fd;
+       }
+       sd = -1;
+    }
+
+    set_signals();
+    log_pid(pconf, pid_fname);
+
+    num_children = 0;
+    
+    if (daemons_max_free < daemons_min_free + 1) /* Don't thrash... */
+       daemons_max_free = daemons_min_free + 1;
+
+    while (num_children < daemons_to_start) {
+       make_child(server_conf, num_children++);
+    }
+
+    log_error ("Server configured -- resuming normal operations", server_conf);
+    
+    while (1) {
+       int status, child_slot;
+       int pid = wait_or_timeout(&status);
+       
+       if (pid >= 0) {
+           /* Child died... note that it's gone in the scoreboard. */
+           sync_scoreboard_image();
+           child_slot = find_child_by_pid (pid);
+           if (child_slot >= 0)
+               (void)update_child_status (child_slot, SERVER_DEAD,
+                (request_rec*)NULL);
+        }
+
+       sync_scoreboard_image();
+       if ((count_idle_servers() < daemons_min_free)
+        && (child_slot = find_free_child_num()) >= 0
+        && child_slot <= daemons_limit) {
+           (void)update_child_status(child_slot,SERVER_STARTING,
+            (request_rec*)NULL);
+           make_child(server_conf, child_slot);
+       }
+    }
+
+} /* standalone_main */
+
+extern char *optarg;
+extern int optind;
+
+int
+main(int argc, char *argv[])
+{
+    int c;
+
+#ifdef AUX
+    (void)set42sig();
+#endif
+
+#ifdef SecureWare
+    if(set_auth_parameters(argc,argv) < 0)
+       perror("set_auth_parameters");
+    if(getluid() < 0)
+       if(setluid(getuid()) < 0)
+           perror("setluid");
+    if(setreuid(0, 0) < 0)
+       perror("setreuid");
+#endif
+
+    init_alloc();
+    pconf = permanent_pool;
+    ptrans = make_sub_pool(pconf);
+    
+    server_argv0 = argv[0];
+    strcpy (server_root, HTTPD_ROOT);
+    strcpy (server_confname, SERVER_CONFIG_FILE);
+
+    while((c = getopt(argc,argv,"Xd:f:v")) != -1) {
+        switch(c) {
+          case 'd':
+            strcpy (server_root, optarg);
+            break;
+          case 'f':
+            strcpy (server_confname, optarg);
+            break;
+          case 'v':
+            printf("Server version %s.\n",SERVER_VERSION);
+            exit(1);
+         case 'X':
+           ++one_process;      /* Weird debugging mode. */
+           break;
+          case '?':
+            usage(argv[0]);
+        }
+    }
+
+#ifdef __EMX__
+    printf("%s \n",SERVER_VERSION);
+    printf("OS/2 port by Garey Smiley <garey@slink.com> \n");
+#endif
+
+    setup_prelinked_modules();
+    
+    server_conf = read_config (pconf, ptrans, server_confname);
+    
+    if(standalone) {
+        clear_pool (pconf);    /* standalone_main rereads... */
+        standalone_main(argc, argv);
+    }
+    else {
+        conn_rec *conn;
+       request_rec *r;
+       struct sockaddr sa_server, sa_client;
+       BUFF *cio;
+      
+       open_logs(server_conf, pconf);
+       set_group_privs();
+       default_server_hostnames (server_conf);
+
+      /* Only try to switch if we're running as root */
+      if(!geteuid() && setuid(user_id) == -1) {
+          log_unixerr("setuid", NULL, "unable to change uid", server_conf);
+          exit (1);
+      }
+
+       c = sizeof(sa_client);
+       if ((getpeername(fileno(stdin), &sa_client, &c)) < 0)
+       {
+/* get peername will fail if the input isn't a socket */
+           perror("getpeername");
+           memset(&sa_client, '\0', sizeof(sa_client));
+       }
+
+       c = sizeof(sa_server);
+       if(getsockname(fileno(stdin), &sa_server, &c) < 0) {
+           perror("getsockname");
+           fprintf(stderr, "Error getting local address\n");
+           exit(1);
+       }
+       server_conf->port =ntohs(((struct sockaddr_in *)&sa_server)->sin_port);
+       cio = bcreate(ptrans, B_RDWR);
+       cio->fd = fileno(stdout);
+       cio->fd_in = fileno(stdin);
+       conn = new_connection (ptrans, server_conf, cio,
+                              (struct sockaddr_in *)&sa_client,
+                              (struct sockaddr_in *)&sa_server,-1);
+       r = read_request (conn);
+       if (r) process_request (r); /* else premature EOF (ignore) */
+
+        while (r && conn->keepalive) {
+         bflush(cio);
+         destroy_pool(r->pool);
+          r = read_request (conn);
+          if (r) process_request (r);
+        }
+
+       bflush(cio);
+       bclose(cio);
+    }
+    exit (0);
+}
+
+
diff --git a/RELEASE_1_1_X/src/main/http_protocol.c b/RELEASE_1_1_X/src/main/http_protocol.c
new file mode 100644 (file)
index 0000000..258d49c
--- /dev/null
@@ -0,0 +1,960 @@
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * http_protocol.c --- routines which directly communicate with the
+ * client.
+ *
+ * Code originally by Rob McCool; much redone by rst.
+ */
+
+#define CORE_PRIVATE
+#include "httpd.h"
+#include "http_config.h"
+#include "http_core.h"
+#include "http_protocol.h"
+#include "http_main.h"
+#include "http_log.h"          /* For errors detected in basic auth
+                                * common support code...
+                                */
+
+#include <stdarg.h>
+
+#define SET_BYTES_SENT(r) \
+  do { if (r->sent_bodyct) \
+         bgetopt (r->connection->client, BO_BYTECT, &r->bytes_sent); \
+  } while (0)
+
+/* Handling of conditional gets (if-modified-since); Roy owes Rob beer. 
+ * This would be considerably easier if strptime or timegm were portable...
+ */
+
+const char month_snames[12][4] = {
+    "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"
+};
+
+int find_month(char *mon) {
+    register int x;
+
+    for(x=0;x<12;x++)
+        if(!strcmp(month_snames[x],mon))
+            return x;
+    return -1;
+}
+
+int later_than(struct tm *lms, char *ims) {
+    char *ip;
+    char mname[MAX_STRING_LEN];
+    int year = 0, month = 0, day = 0, hour = 0, min = 0, sec = 0, x;
+
+    /* Whatever format we're looking at, it will start with weekday. */
+    /* Skip to first space. */
+    if(!(ip = strchr(ims,' ')))
+        return 0;
+    else
+        while(isspace(*ip))
+            ++ip;
+
+    if(isalpha(*ip)) {
+        /* ctime */
+        sscanf(ip,"%s %d %d:%d:%d %d",mname,&day,&hour,&min,&sec,&year);
+    }
+    else if(ip[2] == '-') {
+        /* RFC 850 (normal HTTP) */
+        char t[MAX_STRING_LEN];
+        sscanf(ip,"%s %d:%d:%d",t,&hour,&min,&sec);
+        t[2] = '\0';
+        day = atoi(t);
+        t[6] = '\0';
+        strcpy(mname,&t[3]);
+        x = atoi(&t[7]);
+        /* Prevent wraparound from ambiguity */
+        if(x < 70)
+            x += 100;
+        year = 1900 + x;
+    }
+    else {
+        /* RFC 822 */
+        sscanf(ip,"%d %s %d %d:%d:%d",&day,mname,&year,&hour,&min,&sec);
+    }
+    month = find_month(mname);
+
+    if((x = (1900+lms->tm_year) - year))
+        return x < 0;
+    if((x = lms->tm_mon - month))
+        return x < 0;
+    if((x = lms->tm_mday - day))
+        return x < 0;
+    if((x = lms->tm_hour - hour))
+        return x < 0;
+    if((x = lms->tm_min - min))
+        return x < 0;
+    if((x = lms->tm_sec - sec))
+        return x < 0;
+
+    return 1;
+}
+
+
+int set_content_length (request_rec *r, long clength)
+{
+    char ts[MAX_STRING_LEN];
+    
+    sprintf (ts, "%ld", (long)r->finfo.st_size);
+    table_set (r->headers_out, "Content-length", pstrdup (r->pool, ts));
+    return 0;
+}
+
+int set_keepalive(request_rec *r)
+{
+  char *conn = table_get (r->headers_in, "Connection");
+  char *length = table_get (r->headers_out, "Content-length");
+
+  if (conn && length && !strncasecmp(conn, "Keep-Alive", 10) &&
+      r->server->keep_alive_timeout &&
+      (r->server->keep_alive > r->connection->keepalives)) {
+    char header[26];
+    int left = r->server->keep_alive - r->connection->keepalives;
+
+    r->connection->keepalive = 1;
+    r->connection->keepalives++;
+    sprintf(header, "timeout=%d, max=%d", r->server->keep_alive_timeout,
+           left);
+    table_set (r->headers_out, "Connection", "Keep-Alive");
+    table_set (r->headers_out, "Keep-Alive", pstrdup(r->pool, header));
+
+    return 1;
+  }
+
+      return 0;
+}
+
+int set_last_modified(request_rec *r, time_t mtime)
+{
+    char *ts;
+    char *if_modified_since = table_get (r->headers_in, "If-modified-since");
+
+    /* Cacheing proxies use the absence of a Last-modified header
+     * to indicate that a document is dynamic and shouldn't be cached.
+     * For the moment, we enforce that here, though it would probably
+     * work just as well to generate an Expires: header in send_http_header.
+     *
+     * However, even in that case, if no_cache is set, we would *not*
+     * want to send USE_LOCAL_COPY, since the client isn't *supposed*
+     * to have it cached.
+     */
+    
+    if (r->no_cache) return OK;
+    
+    ts = gm_timestr_822(r->pool, mtime);
+    table_set (r->headers_out, "Last-modified", ts);
+
+    /* Check for conditional GETs --- note that we only want this check
+     * to succeed if the GET was successful; ErrorDocuments *always* get sent.
+     */
+    
+    if (r->status == 200 &&
+       if_modified_since && later_than(gmtime(&mtime), if_modified_since))
+      
+        return USE_LOCAL_COPY;
+    else
+        return OK;
+}
+
+/*
+ * Finally, real protocol stuff.
+ */
+
+static char *
+getline(char *s, int n, BUFF *in)
+{
+    int retval = bgets (s, n, in);
+
+    if (retval == -1) return NULL;
+
+    if (retval > 0 && s[retval-1] == '\n') s[retval-1] = '\0';
+
+    return s;
+}
+
+void parse_uri (request_rec *r, char *uri)
+{
+    const char *s;
+    /* If we ever want to do byte-ranges a la Netscape & Franks,
+     * this is the place to parse them; with proper support in
+     * rprintf and rputc, and the sub-request setup and finalizers
+     * here, it'll all just work, even for vile cases like
+     * inclusion of byte-ranges of the output of CGI scripts, with
+     * the client requesting only a byte-range of *that*!
+     *
+     * But for now...
+     */
+
+#ifdef __EMX__
+    /* Variable for OS/2 fix below. */
+    int loop;
+#endif
+
+/* A proxy request contains a ':' early on, but not as first character */
+    for (s=uri; s != '\0'; s++)
+       if (!isalnum(*s) && *s != '+' && *s != '-' && *s != '.') break;
+
+    if (*s == ':' && s != uri)
+    {
+       r->proxyreq = 1;
+       r->uri = uri;
+       r->args = NULL;
+    } else
+    {
+       r->proxyreq = 0;
+       r->uri = getword (r->pool, &uri, '?');
+
+#ifdef __EMX__
+    /* Handle path translations for OS/2 and plug security hole. */
+    /* This will prevent "http://www.wherever.com/..\..\/" from
+       returning a directory for the root drive. */
+    for (loop = 0; loop <= strlen(r->uri); ++loop) {
+        if (r->uri[loop] == '\\')
+            r->uri[loop] = '/';
+};
+#endif
+
+       if (*uri) r->args= uri;
+       else r->args = NULL;
+    }
+}
+
+char *check_fulluri (request_rec *r, char *uri) {
+  char *name, *host;
+  int i, port;
+
+  /* This routine parses full URLs, if they match the server */
+  if (strncmp(uri, "http://", 7)) return uri;
+  name = pstrdup(r->pool, uri + 7);
+  
+  /* Find the hostname, assuming a valid request */
+  i = ind(name, '/');
+  name[i] = '\0';
+
+  /* Find the port */
+  host = getword(r->pool, &name, ':');
+  if (*name) port = atoi(name);
+  else port = 80;
+
+  /* Make sure ports patch */
+  if (port != r->server->port) return uri;
+
+  /* Save it for later use */
+  r->hostname = pstrdup(r->pool, host);
+  r->hostlen = 7 + i;
+
+  /* The easy cases first */
+  if (!strcasecmp(host, r->server->server_hostname)) {
+    return (uri + r->hostlen);
+  }
+  else if (!strcmp(host, inet_ntoa(r->connection->local_addr.sin_addr))) {
+    return (uri + r->hostlen);
+  }
+
+  /* Now things get a bit trickier - check the IP address(es) of the host */
+  /* they gave, see if it matches ours.                                   */
+  else {
+    struct hostent *hp;
+    int n;
+
+    if ((hp = gethostbyname(host))) {
+      for (n = 0; hp->h_addr_list[n] != NULL; n++) {
+       if (r->connection->local_addr.sin_addr.s_addr ==
+           (((struct in_addr *)(hp->h_addr_list[n]))->s_addr)) {
+         return (uri + r->hostlen);
+       }
+      }
+    }
+  }
+  
+  return uri;
+}
+
+int read_request_line (request_rec *r)
+{
+    char l[HUGE_STRING_LEN];
+    char *ll = l, *uri;
+    conn_rec *conn = r->connection;
+    int major = 1, minor = 0;  /* Assume HTTP/1.0 if non-"HTTP" protocol*/
+    
+    l[0] = '\0';
+    if(!getline(l, HUGE_STRING_LEN, conn->client))
+        return 0;
+    if(!l[0]) 
+        return 0;
+
+    r->the_request = pstrdup (r->pool, l);
+    r->method = getword(r->pool, &ll,' ');
+    uri = getword(r->pool, &ll,' ');
+    uri = check_fulluri(r, uri);
+    parse_uri (r, uri);
+    
+    r->assbackwards = (ll[0] == '\0');
+    r->protocol = pstrdup (r->pool, ll[0] ? ll : "HTTP/0.9");
+    sscanf(r->protocol, "HTTP/%d.%d", &major, &minor);
+    r->proto_num = 1000*major + minor;
+
+    return 1;
+}
+
+void get_mime_headers(request_rec *r)
+{
+    char w[MAX_STRING_LEN];
+    char *t;
+    conn_rec *c = r->connection;
+
+    while(getline(w, MAX_STRING_LEN-1, c->client)) {
+        if(!w[0]) 
+            return;
+        if(!(t = strchr(w,':')))
+            continue;
+        *t++ = '\0';
+        while(isspace(*t)) ++t;
+
+       table_merge (r->headers_in, w, t);
+    }
+}
+
+void check_hostalias (request_rec *r) {
+  char *host = getword(r->pool, &r->hostname, ':');    /* Get rid of port */
+  int port = (*r->hostname) ? atoi(r->hostname) : 0;
+  server_rec *s;
+
+  if (port && (port != r->server->port))
+    return;
+
+  if ((host[strlen(host)-1]) == '.') {
+    host[strlen(host)-1] = '\0';
+  }
+
+  r->hostname = host;
+
+  for (s = r->server->next; s; s = s->next) {
+    char *names = s->names;
+    
+    if ((!strcasecmp(host, s->server_hostname)) &&
+       (!port || (port == s->port))) {
+      r->server = r->connection->server = s;
+      if (r->hostlen && !strncmp(r->uri, "http://", 7)) {
+       r->uri += r->hostlen;
+       parse_uri(r, r->uri);
+      }
+    }
+
+    if (!names) continue;
+
+    while (*names) {
+      char *name = getword_conf (r->pool, &names);
+
+      if ((is_matchexp(name) && !strcasecmp_match(host, name)) ||
+         (!strcasecmp(host, name))) {
+       r->server = r->connection->server = s;
+       if (r->hostlen && !strncmp(r->uri, "http://", 7)) {
+         r->uri += r->hostlen;
+         r->proxyreq = 0;
+       }
+      }
+    }
+  }
+}
+
+void check_serverpath (request_rec *r) {
+  server_rec *s;
+
+  /* This is in conjunction with the ServerPath code in
+   * http_core, so we get the right host attached to a non-
+   * Host-sending request.
+   */
+
+  for (s = r->server->next; s; s = s->next) {
+    if (s->path && !strncmp(r->uri, s->path, s->pathlen))
+      r->server = r->connection->server = s;
+  }
+}
+
+request_rec *read_request (conn_rec *conn)
+{
+    request_rec *r = (request_rec *)pcalloc (conn->pool, sizeof(request_rec));
+  
+    r->connection = conn;
+    r->server = conn->server;
+    r->pool = make_sub_pool(conn->pool);
+
+    conn->keptalive = conn->keepalive;
+    conn->keepalive = 0;
+
+    conn->user = NULL;
+    conn->auth_type = NULL;
+
+    r->headers_in = make_table (r->pool, 50);
+    r->subprocess_env = make_table (r->pool, 50);
+    r->headers_out = make_table (r->pool, 5);
+    r->err_headers_out = make_table (r->pool, 5);
+    r->notes = make_table (r->pool, 5);
+
+    r->request_config = create_request_config (r->pool);
+    r->per_dir_config = r->server->lookup_defaults; /* For now. */
+
+    r->sent_bodyct = 0; /* bytect isn't for body */
+    
+    r->status = 200;           /* Until further notice.
+                                * Only changed by die(), or (bletch!)
+                                * scan_script_header...
+                                */
+
+    /* Get the request... */
+    
+    hard_timeout ("read", r);
+    if (!read_request_line (r)) return NULL;
+    if (!r->assbackwards) get_mime_headers(r);
+
+/* handle Host header here, to get virtual server */
+
+    if (r->hostname || (r->hostname = table_get(r->headers_in, "Host")))
+      check_hostalias(r);
+    else
+      check_serverpath(r);
+
+    kill_timeout (r);
+    conn->keptalive = 0;   /* We now have a request - so no more short timeouts */
+    
+    if(!strcmp(r->method, "HEAD")) {
+        r->header_only=1;
+       r->method_number = M_GET;
+    }
+    else if(!strcmp(r->method, "GET")) 
+       r->method_number = M_GET;
+    else if(!strcmp(r->method,"POST")) 
+        r->method_number = M_POST;
+    else if(!strcmp(r->method,"PUT")) 
+        r->method_number = M_PUT;
+    else if(!strcmp(r->method,"DELETE")) 
+        r->method_number = M_DELETE;
+    else if(!strcmp(r->method,"CONNECT"))
+        r->method_number = M_CONNECT;
+    else 
+        r->method_number = M_INVALID; /* Will eventually croak. */
+
+    return r;
+}
+
+/*
+ * A couple of other functions which initialize some of the fields of
+ * a request structure, as appropriate for adjuncts of one kind or another
+ * to a request in progress.  Best here, rather than elsewhere, since
+ * *someone* has to set the protocol-specific fields...
+ */
+
+void set_sub_req_protocol (request_rec *rnew, request_rec *r)
+{
+    rnew->assbackwards = 1;    /* Don't send headers from this. */
+    rnew->no_cache = 1;                /* Don't try to send USE_LOCAL_COPY for a
+                                * fragment.
+                                */
+    rnew->method = "GET"; rnew->method_number = M_GET;
+    rnew->protocol = "INCLUDED";
+
+    rnew->status = 200;
+
+    rnew->headers_in = r->headers_in;
+    rnew->subprocess_env = copy_table (rnew->pool, r->subprocess_env);
+    rnew->headers_out = make_table (rnew->pool, 5);
+    rnew->err_headers_out = make_table (rnew->pool, 5);
+    rnew->notes = make_table (rnew->pool, 5);
+    
+    rnew->main = r;
+}
+
+void finalize_sub_req_protocol (request_rec *sub)
+{
+    SET_BYTES_SENT (sub->main);
+} 
+
+/* Support for the Basic authentication protocol, and a bit for Digest.
+ */
+
+void note_auth_failure(request_rec *r)
+{
+    if (!strcasecmp(auth_type(r), "Basic"))
+      note_basic_auth_failure(r);
+    else if(!strcasecmp(auth_type(r), "Digest"))
+      note_digest_auth_failure(r);
+}
+
+void note_basic_auth_failure(request_rec *r)
+{
+    if (strcasecmp(auth_type(r), "Basic"))
+      note_auth_failure(r);
+    else
+      table_set (r->err_headers_out, "WWW-Authenticate",
+                pstrcat(r->pool, "Basic realm=\"", auth_name(r), "\"", NULL));
+}
+
+void note_digest_auth_failure(request_rec *r)
+{
+    char nonce[10];
+
+    sprintf(nonce, "%lu", time(NULL));
+    table_set (r->err_headers_out, "WWW-Authenticate",
+               pstrcat(r->pool, "Digest realm=\"", auth_name(r),
+                       "\", nonce=\"", nonce, "\"", NULL));
+}
+
+int get_basic_auth_pw (request_rec *r, char **pw)
+{
+    char *auth_line = table_get (r->headers_in, "Authorization");
+    char *t;
+    
+    if(!(t = auth_type(r)) || strcasecmp(t, "Basic"))
+        return DECLINED;
+
+    if (!auth_name (r)) {
+        log_reason ("need AuthName", r->uri, r);
+       return SERVER_ERROR;
+    }
+    
+    if(!auth_line) {
+        note_basic_auth_failure (r);
+       return AUTH_REQUIRED;
+    }
+
+    if (strcmp(getword (r->pool, &auth_line, ' '), "Basic")) {
+        /* Client tried to authenticate using wrong auth scheme */
+        log_reason ("client used wrong authentication scheme", r->uri, r);
+        note_basic_auth_failure (r);
+       return AUTH_REQUIRED;
+    }
+
+    t = uudecode (r->pool, auth_line);
+    r->connection->user = getword_nulls (r->pool, &t, ':');
+    r->connection->auth_type = "Basic";
+
+    *pw = t;
+
+    return OK;
+}
+
+#define RESPONSE_CODE_LIST " 200 302 304 400 401 403 404 500 503 501 502 "
+
+/* New Apache routine to map error responses into array indicies 
+ *  e.g.  400 -> 0,  500 -> 1,  502 -> 2 ...                     
+ * the indicies have no significance
+ */
+
+char *status_lines[] = {
+   "200 OK",
+   "302 Found",
+   "304 Not Modified",
+   "400 Bad Request",
+   "401 Unauthorized",
+   "403 Forbidden",
+   "404 Not found",
+   "500 Server error",
+   "503 Out of resources",
+   "501 Not Implemented",
+   "502 Bad Gateway"
+}; 
+
+char *response_titles[] = {
+   "200 OK",                   /* Never actually sent, barring die(200,...) */
+   "Document moved",           /* 302 Redirect */
+   "304 Not Modified",         /* Never sent... 304 MUST be header only */
+   "Bad Request",
+   "Authorization Required",
+   "Forbidden",
+   "File Not found",
+   "Server Error",
+   "Out of resources",
+   "Method not implemented",
+   "Bad Gateway"
+};
+
+int index_of_response(int err_no) {
+   char *cptr, err_string[10];
+   static char *response_codes = RESPONSE_CODE_LIST;
+   int index_number;
+   
+   sprintf(err_string,"%3d",err_no);
+   
+   cptr = response_codes;
+   cptr++;
+   index_number = 0;
+   while (*cptr && strncmp(cptr, err_string, 3)) { 
+      cptr += 4;
+      index_number++;
+   }
+   if (!*cptr) return -1;
+   return index_number;
+}
+
+
+void basic_http_header (request_rec *r)
+{
+    BUFF *fd = r->connection->client;
+    
+    if (r->assbackwards) return;
+    
+    if (!r->status_line)
+        r->status_line = status_lines[index_of_response(r->status)];
+    
+    bvputs(fd, SERVER_PROTOCOL, " ", r->status_line, "\015\012", NULL);
+    bvputs(fd,"Date: ",gm_timestr_822 (r->pool, time(NULL)), "\015\012", NULL);
+    bvputs(fd,"Server: ", SERVER_VERSION, "\015\012", NULL);
+}
+
+char *nuke_mime_parms (pool *p, char *content_type)
+{
+    /* How marvelous.  Arena doesn't *accept* "text/html; level=3"
+     * as a MIME type, so we have to strip off the parms.
+     */
+
+#ifndef ARENA_BUG_WORKAROUND
+    return content_type;
+#else
+
+    char *cp = strchr(content_type, ';');
+
+    if (cp) {
+        content_type = pstrdup (p, content_type);
+       cp = strchr (content_type, ';');
+       
+        while (cp > content_type && isspace (cp[-1]))
+           --cp;
+       *cp = '\0';
+    }
+
+    return content_type;
+#endif
+}
+
+void send_http_header(request_rec *r)
+{
+    conn_rec *c = r->connection;
+    BUFF *fd = c->client;
+    const long int zero=0L;
+    array_header *hdrs_arr;
+    table_entry *hdrs;
+    int i;
+    
+    core_dir_config *dir_conf =
+      (core_dir_config *)get_module_config(r->per_dir_config, &core_module);
+    char *default_type = dir_conf->default_type;
+  
+    if (r->assbackwards) {
+       bsetopt(fd, BO_BYTECT, &zero);
+       r->sent_bodyct = 1;
+       return;
+    }
+    
+    basic_http_header (r);
+
+    set_keepalive (r);
+    
+    if (r->content_type)
+        bvputs(fd, "Content-type: ", 
+                nuke_mime_parms (r->pool, r->content_type), "\015\012", NULL);
+    else if(default_type)
+        bvputs(fd, "Content-type: ", default_type, "\015\012", NULL);
+    
+    if (r->content_encoding)
+        bvputs(fd,"Content-encoding: ", r->content_encoding, "\015\012", NULL);
+    
+    if (r->content_language)
+        bvputs(fd,"Content-language: ", r->content_language, "\015\012", NULL);
+    
+    hdrs_arr = table_elts(r->headers_out);
+    hdrs = (table_entry *)hdrs_arr->elts;
+    for (i = 0; i < hdrs_arr->nelts; ++i) {
+        if (!hdrs[i].key) continue;
+       bvputs(fd, hdrs[i].key, ": ", hdrs[i].val, "\015\012", NULL);
+    }
+
+    hdrs_arr = table_elts(r->err_headers_out);
+    hdrs = (table_entry *)hdrs_arr->elts;
+    for (i = 0; i < hdrs_arr->nelts; ++i) {
+        if (!hdrs[i].key) continue;
+       bvputs(fd, hdrs[i].key, ": ", hdrs[i].val, "\015\012", NULL);
+    }
+
+    bputs("\015\012",fd);
+
+    if (c->keepalive)
+       bflush(r->connection->client);  /* For bugs in Netscape, perhaps */
+
+    bsetopt(fd, BO_BYTECT, &zero);
+    r->sent_bodyct = 1;                /* Whatever follows is real body stuff... */
+}
+
+long read_client_block (request_rec *r, char *buffer, int bufsiz)
+{
+    return bread(r->connection->client, buffer, bufsiz);
+}
+
+long send_fd(FILE *f, request_rec *r)
+{
+    char buf[IOBUFSIZE];
+    long total_bytes_sent;
+    register int n,o,w;
+    conn_rec *c = r->connection;
+    
+    total_bytes_sent = 0;
+    while (!r->connection->aborted) {
+        while ((n= fread(buf, sizeof(char), IOBUFSIZE, f)) < 1
+              && ferror(f) && errno == EINTR)
+           continue;
+       
+       if (n < 1) {
+            break;
+        }
+        o=0;
+       total_bytes_sent += n;
+       
+        while(n && !r->connection->aborted) {
+            w=bwrite(c->client, &buf[o], n);
+           if(w <= 0)
+               break;
+           reset_timeout(r); /* reset timeout after successfule write */
+            n-=w;
+            o+=w;
+        }
+    }
+    bflush(c->client);
+    
+    SET_BYTES_SENT(r);
+    return total_bytes_sent;
+}
+
+int rputc (int c, request_rec *r)
+{
+    if (r->connection->aborted) return EOF;
+    bputc(c, r->connection->client);
+    SET_BYTES_SENT(r);
+    return c;
+}
+
+int
+rputs(const char *str, request_rec *r)
+{
+    if (r->connection->aborted) return EOF;
+    SET_BYTES_SENT(r);
+    return bputs(str, r->connection->client);
+}
+
+int rprintf(request_rec *r,const char *fmt,...)
+    {
+    va_list vlist;
+    int n;
+
+    if(r->connection->aborted) return EOF;
+    va_start(vlist,fmt);
+    n=vbprintf(r->connection->client,fmt,vlist);
+    va_end(vlist);
+    SET_BYTES_SENT(r);
+    return n;
+    }
+
+int
+rvputs(request_rec *r, ...)
+{
+    va_list args;
+    int i, j, k;
+    const char *x;
+    BUFF *fb=r->connection->client;
+    
+    if (r->connection->aborted) return EOF;
+    
+    va_start (args, r);
+    for (k=0;;)
+    {
+       x = va_arg(args, const char *);
+       if (x == NULL) break;
+       j = strlen(x);
+       i = bwrite(fb, x, j);
+       if (i != j)
+       {
+           va_end(args);
+           return -1;
+       }
+       k += i;
+    }
+    va_end(args);
+
+    SET_BYTES_SENT(r);
+    return k;
+}
+
+void send_error_response (request_rec *r, int recursive_error)
+{
+    conn_rec *c = r->connection;
+    char *custom_response;
+    int status = r->status;
+    int idx = index_of_response (status);
+    char *location = table_get (r->headers_out, "Location");
+
+    if (!r->assbackwards) {
+       int i;
+       table *err_hdrs_arr = r->err_headers_out;
+       table_entry *err_hdrs = (table_entry *)err_hdrs_arr->elts;
+  
+        basic_http_header (r);
+       
+       /* For conditional get's which didn't send anything, *don't*
+        * send a bogus content-type, or any body --- but must still
+        * terminate header.
+        */
+       
+       if (status == USE_LOCAL_COPY) {
+           if (set_keepalive(r))
+               bputs("Connection: Keep-Alive\015\012", c->client);
+           bputs("\015\012", c->client);
+           return;
+       }
+       
+       if (status == REDIRECT)
+           bvputs(c->client, "Location: ", location, "\015\012", NULL);
+       
+       for (i = 0; i < err_hdrs_arr->nelts; ++i) {
+           if (!err_hdrs[i].key) continue;
+           bvputs(c->client, err_hdrs[i].key, ": ", err_hdrs[i].val,
+                  "\015\012", NULL);
+       }
+
+       bputs("Content-type: text/html\015\012\015\012", c->client);
+    }
+
+    if (r->header_only) return;
+    
+    if ((custom_response = response_code_string (r, idx)))
+        bputs(custom_response, c->client);
+    else {
+       char *title = response_titles[idx];
+       BUFF *fd = c->client;
+       
+        bvputs(fd,"<HEAD><TITLE>", title, "</TITLE></HEAD>\n<BODY><H1>", title,
+              "</H1>\n", NULL);
+       
+        switch (r->status) {
+       case REDIRECT:
+           bvputs(fd, "The document has moved <A HREF=\"",
+                   escape_html(r->pool, location), "\">here</A>.<P>\n", NULL);
+           break;
+       case AUTH_REQUIRED:
+           bputs("This server could not verify that you\n", fd);
+           bputs("are authorized to access the document you\n", fd);
+           bputs("requested.  Either you supplied the wrong\n", fd);
+           bputs("credentials (e.g., bad password), or your\n", fd);
+           bputs("browser doesn't understand how to supply\n", fd);
+           bputs("the credentials required.<P>\n", fd);
+           break;
+       case BAD_REQUEST:
+           bputs("Your browser sent a query that\n", fd);
+           bputs("this server could not understand.<P>\n", fd);
+           break;
+       case FORBIDDEN:
+           bvputs(fd, "You don't have permission to access ",
+                    escape_html(r->pool, r->uri), "\non this server.<P>\n",
+                  NULL);
+           break;
+       case NOT_FOUND:
+            bvputs(fd, "The requested URL ", escape_html(r->pool, r->uri),
+                   " was not found on this server.<P>\n", NULL);
+           break;
+       case SERVER_ERROR:
+           bputs("The server encountered an internal error or\n", fd);
+           bputs("misconfiguration and was unable to complete\n", fd);
+           bputs("your request.<P>\n", fd);
+           bputs("Please contact the server administrator,\n ", fd);
+           bputs(escape_html(r->pool, r->server->server_admin), fd);
+           bputs(" and inform them of the time the error occurred,\n", fd);
+           bputs("and anything you might have done that may have\n", fd);
+           bputs("caused the error.<P>\n", fd);
+           break;
+       case NOT_IMPLEMENTED:
+           bvputs(fd, escape_html(r->pool, r->method), " to ",
+                  escape_html(r->pool, r->uri), " not supported.<P>\n", NULL);
+           break;
+       case BAD_GATEWAY:
+           bputs("The proxy server received an invalid\015\012", fd);
+           bputs("response from an upstream server.<P>\015\012", fd);
+           break;
+       }
+
+        if (recursive_error) {
+           char x[80];
+           sprintf (x, "Additionally, an error of type %d was encountered\n",
+                    recursive_error);
+           bputs(x, fd);
+           bputs("while trying to use an ErrorDocument to\n", fd);
+           bputs("handle the request.\n", fd);
+       }
+       bputs("</BODY>\n", fd);
+    }
+        
+}
+
+/* Finally, this... it's here to support nph- scripts
+ * Now what ever are we going to do about them when HTTP-NG packetization
+ * comes along?
+ */
+
+void client_to_stdout (conn_rec *c)
+{
+    bflush(c->client);
+    dup2(c->client->fd, STDOUT_FILENO);
+}
diff --git a/RELEASE_1_1_X/src/main/http_request.c b/RELEASE_1_1_X/src/main/http_request.c
new file mode 100644 (file)
index 0000000..db5b13c
--- /dev/null
@@ -0,0 +1,870 @@
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * http_request.c: functions to get and process requests
+ * 
+ * Rob McCool 3/21/93
+ *
+ * Thoroughly revamped by rst for Shambhala.  NB this file reads
+ * best from the bottom up.
+ * 
+ */
+
+#define CORE_PRIVATE
+#include "httpd.h"
+#include "http_config.h"
+#include "http_request.h"
+#include "http_core.h"
+#include "http_protocol.h"
+#include "http_log.h"
+#include "http_main.h"
+#include "scoreboard.h"
+
+/*****************************************************************
+ *
+ * Getting and checking directory configuration.  Also checks the
+ * FollowSymlinks and FollowSymOwner stuff, since this is really the
+ * only place that can happen (barring a new mid_dir_walk callout).
+ *
+ * We can't do it as an access_checker module function which gets
+ * called with the final per_dir_config, since we could have a directory
+ * with FollowSymLinks disabled, which contains a symlink to another
+ * with a .htaccess file which turns FollowSymLinks back on --- and
+ * access in such a case must be denied.  So, whatever it is that
+ * checks FollowSymLinks needs to know the state of the options as
+ * they change, all the way down.
+ */
+
+int check_symlinks (char *d, int opts)
+{
+    struct stat lfi, fi;
+    char *lastp;
+    int res;
+  
+#ifdef __EMX__
+    /* OS/2 dosen't have symlinks */
+    return OK;
+#else
+  
+    if (opts & OPT_SYM_LINKS) return OK;
+
+    /* Strip trailing '/', if any, off what we're checking; trailing
+     * slashes make some systems follow symlinks to directories even in
+     * lstat().  After we've done the lstat, put it back.  Also, don't
+     * bother checking '/' at all...
+     *
+     * Note that we don't have to worry about multiple slashes here
+     * because of no2slash() below...
+     */
+
+    lastp = d + strlen(d) - 1;
+    if (lastp == d) return OK; /* Root directory, '/' */
+    
+    if (*lastp == '/') *lastp = '\0';
+    else lastp = NULL;
+       
+    res = lstat (d, &lfi);
+
+    if (lastp) *lastp = '/';
+    
+    /* Note that we don't reject accesses to nonexistent files (multiviews
+     * or the like may cons up a way to run the transaction anyway)...
+     */
+                   
+    if (!(res >= 0) || !S_ISLNK(lfi.st_mode)) return OK;
+
+    /* OK, it's a symlink.  May still be OK with OPT_SYM_OWNER */
+    
+    if (!(opts & OPT_SYM_OWNER)) return FORBIDDEN;
+       
+    if (stat (d, &fi) < 0) return FORBIDDEN;
+    
+    return (fi.st_uid == lfi.st_uid) ? OK : FORBIDDEN;
+
+#endif    
+}
+    
+/* Dealing with the file system to get PATH_INFO
+ */
+
+void get_path_info(request_rec *r)
+{
+    char *cp;
+    char *path = r->filename;
+    char *end = &path[strlen(path)];
+    char *last_cp = NULL;
+    int rv;
+
+    /* Advance over trailing slashes ... NOT part of filename */
+
+    for (cp = end; cp > path && cp[-1] == '/'; --cp)
+       continue;
+    
+    while (cp > path) {
+      
+       /* See if the pathname ending here exists... */
+      
+       *cp = '\0';
+       rv = stat(path, &r->finfo);
+       if (cp != end) *cp = '/';
+      
+       if (!rv) {
+
+           /* Aha!  Found something.  If it was a directory, we will
+            * search contents of that directory for a multi_match, so
+            * the PATH_INFO argument starts with the component after that.
+            */
+       
+           if (S_ISDIR(r->finfo.st_mode) && last_cp) {
+               r->finfo.st_mode = 0; /* No such file... */
+               cp = last_cp;
+           }
+       
+           r->path_info = pstrdup (r->pool, cp);
+           *cp = '\0';
+           return;
+       }
+       else {
+           last_cp = cp;
+       
+           while (--cp > path && *cp != '/')
+               continue;
+
+           while (cp > path && cp[-1] == '/')
+               --cp;
+       }
+    }
+}
+
+int directory_walk (request_rec *r)
+{
+    core_server_config *sconf = get_module_config (r->server->module_config,
+                                                  &core_module);
+    array_header *sec_array = copy_array (r->pool, sconf->sec);
+    void *per_dir_defaults = r->server->lookup_defaults;
+    
+    core_dir_config **sec = (core_dir_config **)sec_array->elts;
+    int num_sec = sec_array->nelts;
+    char *test_filename = pstrdup (r->pool, r->filename);
+
+    int num_dirs, res;
+    int i;
+
+    /* Are we dealing with a file? If not, we can (hopefuly) safely assume
+     * we have a handler that doesn't require one, but for safety's sake,
+     * and so we have something find_types() can get something out of,
+     * fake one. But don't run through the directory entries.
+     */
+
+    if (test_filename == NULL) {
+        r->filename = pstrdup(r->pool, r->uri);
+       r->finfo.st_mode = 0;   /* Not really a file... */
+        r->per_dir_config = per_dir_defaults;
+
+        return OK;
+    }
+
+    /* Go down the directory hierarchy.  Where we have to check for symlinks,
+     * do so.  Where a .htaccess file has permission to override anything,
+     * try to find one.  If either of these things fails, we could poke
+     * around, see why, and adjust the lookup_rec accordingly --- this might
+     * save us a call to get_path_info (with the attendant stat()s); however,
+     * for the moment, that's not worth the trouble.
+     */
+
+    if (test_filename[0] != '/')
+    {
+/* fake filenames only match Directory sections */
+        void *this_conf, *entry_config;
+        core_dir_config *entry_core;
+       char *entry_dir;
+       int j;
+
+       for (j = 0; j < num_sec; ++j) {
+
+           entry_config = sec[j];
+           if (!entry_config) continue;
+           
+           entry_core =(core_dir_config *)
+               get_module_config(entry_config, &core_module);
+           entry_dir = entry_core->d;
+
+           this_conf = NULL;
+           if (is_matchexp(entry_dir)) {
+               if (!strcmp_match(test_filename, entry_dir))
+                   this_conf = entry_config;
+           }
+           else if (!strncmp (test_filename, entry_dir, strlen(entry_dir)))
+               this_conf = entry_config;
+
+           if (this_conf)
+               per_dir_defaults = merge_per_dir_configs (r->pool,
+                                          per_dir_defaults, this_conf);
+       }
+
+       r->per_dir_config = per_dir_defaults;
+
+       return OK;
+    }
+
+    no2slash (test_filename);
+    num_dirs = count_dirs(test_filename);
+    get_path_info (r);
+    
+    if (S_ISDIR (r->finfo.st_mode)) ++num_dirs;
+
+    for (i = 1; i <= num_dirs; ++i) {
+        core_dir_config *core_dir =
+         (core_dir_config *)get_module_config(per_dir_defaults, &core_module);
+       int allowed_here = core_dir->opts;
+       int overrides_here = core_dir->override;
+        void *this_conf = NULL, *htaccess_conf = NULL;
+       char *this_dir = make_dirstr (r->pool, test_filename, i);
+       char *config_name = make_full_path(r->pool, this_dir,
+                                          sconf->access_name);
+       int j;
+      
+       /* Do symlink checks first, because they are done with the
+        * permissions appropriate to the *parent* directory...
+        */
+       
+       if ((res = check_symlinks (this_dir, allowed_here)))
+       {
+           log_reason("Symbolic link not allowed", this_dir, r);
+           return res;
+       }
+       
+       /* Begin *this* level by looking for matching <Directory> sections from
+        * access.conf.
+        */
+    
+       for (j = 0; j < num_sec; ++j) {
+           void *entry_config = sec[j];
+           core_dir_config *entry_core;
+           char *entry_dir;
+
+           if (!entry_config) continue;
+           
+           entry_core =
+             (core_dir_config *)get_module_config(entry_config, &core_module);
+           entry_dir = entry_core->d;
+       
+           if (is_matchexp(entry_dir) && !strcmp_match(this_dir, entry_dir)) {
+               /* Don't try this wildcard again --- if it ends in '*'
+                * it'll match again, and subdirectories won't be able to
+                * override it...
+                */
+               sec[j] = NULL;  
+               this_conf = entry_config;
+           }
+           else if (!strcmp (this_dir, entry_dir))
+               this_conf = entry_config;
+       }
+
+       if (this_conf)
+       {
+           per_dir_defaults =
+               merge_per_dir_configs (r->pool, per_dir_defaults, this_conf);
+           core_dir =(core_dir_config *)get_module_config(per_dir_defaults,
+                                                          &core_module);
+       }
+       overrides_here = core_dir->override;
+
+       /* If .htaccess files are enabled, check for one.
+        */
+       
+       if (overrides_here) {
+           res = parse_htaccess (&htaccess_conf, r, overrides_here,
+                                 this_dir, config_name);
+           if (res) return res;
+       }
+
+       if (htaccess_conf)
+           per_dir_defaults =
+               merge_per_dir_configs (r->pool, per_dir_defaults,
+                                      htaccess_conf);
+       
+    }
+
+    r->per_dir_config = per_dir_defaults;
+
+    if ((res = check_symlinks (r->filename, allow_options(r))))
+    {
+       log_reason("Symbolic link not allowed", r->filename, r);
+       return res;
+    }
+    
+    return OK;                 /* Can only "fail" if access denied
+                                * by the symlink goop.
+                                */
+}
+
+int location_walk (request_rec *r)
+{
+    core_server_config *sconf = get_module_config (r->server->module_config,
+                                                  &core_module);
+    array_header *url_array = copy_array (r->pool, sconf->sec_url);
+    void *per_dir_defaults = r->per_dir_config;
+    
+    core_dir_config **url = (core_dir_config **)url_array->elts;
+    int num_url = url_array->nelts;
+    char *test_location = pstrdup (r->pool, r->uri);
+
+    /* Go through the location entries, and check for matches. */
+
+    if (num_url) {
+        void *this_conf, *entry_config;
+       core_dir_config *entry_core;
+       char *entry_url;
+       int j;
+
+/* 
+ * we apply the directive sections in some order; should really try them
+ * with the most general first.
+ */
+       for (j = 0; j < num_url; ++j) {
+
+           entry_config = url[j];
+           if (!entry_config) continue;
+           
+           entry_core =(core_dir_config *)
+               get_module_config(entry_config, &core_module);
+           entry_url = entry_core->d;
+
+           this_conf = NULL;
+           if (is_matchexp(entry_url)) {
+               if (!strcmp_match(test_location, entry_url))
+                   this_conf = entry_config;
+           }
+           else if (!strncmp (test_location, entry_url, strlen(entry_url)))
+               this_conf = entry_config;
+
+           if (this_conf)
+               per_dir_defaults = merge_per_dir_configs (r->pool,
+                                           per_dir_defaults, this_conf);
+       }
+
+       r->per_dir_config = per_dir_defaults;
+    }
+
+    return OK;
+}
+
+/*****************************************************************
+ *
+ * The sub_request mechanism.
+ *
+ * Fns to look up a relative URI from, e.g., a map file or SSI document.
+ * These do all access checks, etc., but don't actually run the transaction
+ * ... use run_sub_req below for that.  Also, be sure to use destroy_sub_req
+ * as appropriate if you're likely to be creating more than a few of these.
+ * (An early Shambhala version didn't destroy the sub_reqs used in directory
+ * indexing.  The result, when indexing a directory with 800-odd files in
+ * it, was massively excessive storage allocation).
+ *
+ * Note more manipulation of protocol-specific vars in the request
+ * structure...
+ */
+
+request_rec *make_sub_request (request_rec *r)
+{
+    pool *rrp = make_sub_pool (r->pool);
+    request_rec *rr = pcalloc (rrp, sizeof (request_rec));
+    
+    rr->pool = rrp;
+    return rr;
+}
+
+request_rec *sub_req_lookup_simple (char *new_file, request_rec *r)
+{
+    /* This handles the simple case, common to ..._lookup_uri and _file,
+     * of looking up another file in the same directory.
+     */
+    request_rec *rnew = make_sub_request (r);
+    pool *rnewp = rnew->pool;
+    int res;
+    
+    char *udir = make_dirstr(rnewp, r->uri, count_dirs(r->uri));
+    char *fdir = make_dirstr(rnewp, r->filename, count_dirs(r->filename));
+
+    *rnew = *r;                        /* Copy per_dir config, etc. */
+    rnew->pool = rnewp;
+    rnew->uri = make_full_path (rnewp, udir, new_file);
+    rnew->filename = make_full_path (rnewp, fdir, new_file);
+    set_sub_req_protocol (rnew, r);
+       
+    rnew->finfo.st_mode = 0;
+    
+    if ((res = check_symlinks (rnew->filename, allow_options (rnew))))
+    {
+        rnew->status = res;
+    }
+
+    if (rnew->finfo.st_mode == 0 && stat (rnew->filename, &rnew->finfo) < 0)
+        rnew->finfo.st_mode = 0;
+
+    if ((rnew->status == 200) && (res = find_types (rnew)))
+        rnew->status = res;
+    
+    if ((rnew->status == 200) && (res = run_fixups (rnew)))
+        rnew->status = res;
+    
+    return rnew;
+}
+
+
+static int some_auth_required (request_rec *r);
+
+request_rec *sub_req_lookup_uri (char *new_file, request_rec *r)
+{
+    request_rec *rnew;
+    int res;
+    char *udir;
+    
+    rnew = make_sub_request (r);
+    rnew->connection = r->connection; 
+    rnew->server = r->server;
+    rnew->request_config = create_request_config (rnew->pool);
+    rnew->htaccess = r->htaccess; /* copy htaccess cache */
+    set_sub_req_protocol (rnew, r);
+       
+    if (new_file[0] == '/')
+       parse_uri(rnew, new_file);
+    else
+    {
+       udir = make_dirstr (rnew->pool, r->uri, count_dirs (r->uri));
+       udir = escape_uri(rnew->pool, udir); /* re-escape it */
+       parse_uri (rnew, make_full_path (rnew->pool, udir, new_file));
+    }
+       
+    res = unescape_url (rnew->uri);
+    if (res)
+    {
+       rnew->status = res;
+       return rnew;
+    }
+
+    getparents (rnew->uri);
+       
+    res = translate_name(rnew);
+    if (res)
+    {
+       rnew->status = res;
+       return rnew;
+    }
+
+    /* We could be clever at this point, and avoid calling directory_walk, etc.
+     * However, we'd need to test that the old and new filenames contain the
+     * same directory components, so it would require duplicating the start
+     * of translate_name.
+     * Instead we rely on the cache of .htaccess results.
+     */
+    
+    if ((res = directory_walk (rnew))
+       || (!some_auth_required (rnew) ? 0 :
+            ((res = check_user_id (rnew)) || (res = check_auth (rnew))))
+       || (res = check_access (rnew))
+       || (res = find_types (rnew))
+       || (res = run_fixups (rnew))
+       )
+    {
+        rnew->status = res;
+    }
+
+    return rnew;
+}
+
+request_rec *sub_req_lookup_file (char *new_file, request_rec *r)
+{
+    request_rec *rnew;
+    int res;
+    char *fdir;
+    
+    /* Check for a special case... if there are no '/' characters in new_file
+     * at all, then we are looking at a relative lookup in the same directory.
+     * That means we don't have to redo any access checks.
+     */
+
+    if (strchr (new_file, '/') == NULL) 
+        return sub_req_lookup_simple (new_file, r);
+
+    rnew = make_sub_request (r);
+    fdir = make_dirstr (rnew->pool, r->filename, count_dirs (r->filename));
+    
+    rnew->connection = r->connection; /* For now... */
+    rnew->server = r->server;
+    rnew->request_config = create_request_config (rnew->pool);
+    rnew->htaccess = r->htaccess; /* copy htaccess cache */
+    set_sub_req_protocol (rnew, r);
+       
+    rnew->uri = "INTERNALLY GENERATED file-relative req";
+    rnew->filename = ((new_file[0] == '/') ?
+                     new_file :
+                     make_full_path (rnew->pool, fdir, new_file));
+       
+    if ((res = directory_walk (rnew))
+       || (res = check_access (rnew))
+       || (!some_auth_required (rnew) ? 0 :
+            ((res = check_user_id (rnew)) && (res = check_auth (rnew))))
+       || (res = find_types (rnew))
+       || (res = run_fixups (rnew))
+       )
+    {
+        rnew->status = res;
+    }
+
+    return rnew;
+}
+
+int run_sub_req (request_rec *r)
+{
+    int retval = invoke_handler (r);
+    finalize_sub_req_protocol (r);
+    return retval;
+}
+
+void destroy_sub_req (request_rec *r)
+{
+    /* Reclaim the space */
+    destroy_pool (r->pool);
+}
+
+/*****************************************************************
+ *
+ * Mainline request processing...
+ */
+
+void die(int type, request_rec *r)
+{
+    int error_index = index_of_response (type);
+    char *custom_response = response_code_string(r, error_index);
+    int recursive_error = 0;
+    
+    /* The following takes care of Apache redirects to custom response URLs
+     * Note that if we are already dealing with the response to some other
+     * error condition, we just report on the original error, and give up on
+     * any attempt to handle the other thing "intelligently"...
+     */
+
+    if (r->status != 200) {
+        recursive_error = type;
+
+       while (r->prev && r->prev->status != 200)
+         r = r->prev; /* Get back to original error */
+       
+       type = r->status;
+       custom_response = NULL; /* Do NOT retry the custom thing! */
+    }
+       
+    r->status = type;
+    
+    /* Two types of custom redirects --- plain text, and URLs.
+     * Plain text has a leading '"', so the URL code, here, is triggered
+     * on its absence
+     */
+    
+    if (custom_response && custom_response[0] != '"') {
+          
+        if (is_url(custom_response)) {
+           /* The URL isn't local, so lets drop through the rest of
+            * this apache code, and continue with the usual REDIRECT
+            * handler.  But note that the client will ultimately see
+            * the wrong status...
+            */
+           r->status = REDIRECT;
+           table_set (r->headers_out, "Location", custom_response);
+       } else if ( custom_response[0] == '/') {
+           r->no_cache = 1;    /* Do NOT send USE_LOCAL_COPY for
+                                * error documents!
+                                */
+           /* This redirect needs to be a GET no matter what the original
+            * method was.
+            */
+           r->method = pstrdup(r->pool, "GET");
+           r->method_number = M_GET;
+           internal_redirect (custom_response, r);
+           return;
+       } else {
+           /* Dumb user has given us a bad url to redirect to
+            * --- fake up dying with a recursive server error...
+            */
+           recursive_error = SERVER_ERROR;
+           log_reason("Invalid error redirection directive", custom_response,
+                      r);
+       }       
+    }
+
+    send_error_response (r, recursive_error);
+}
+
+static void decl_die (int status, char *phase, request_rec *r)
+{
+    if (status == DECLINED) {
+       log_reason (pstrcat (r->pool,
+                            "configuration error:  couldn't ",
+                            phase, NULL),
+                   r->uri,
+                   r);
+       die (SERVER_ERROR, r);
+    }
+    else die (status, r);
+}
+
+static int some_auth_required (request_rec *r)
+{
+    /* Is there a require line configured for the type of *this* req? */
+    
+    array_header *reqs_arr = requires (r);
+    require_line *reqs;
+    int i;
+    
+    if (!reqs_arr) return 0;
+    
+    reqs = (require_line *)reqs_arr->elts;
+
+    for (i = 0; i < reqs_arr->nelts; ++i)
+       if (reqs[i].method_mask & (1 << r->method_number))
+           return 1;
+
+    return 0;
+}
+
+void process_request_internal (request_rec *r)
+{
+    int access_status;
+  
+    /* Kludge to be reading the assbackwards field outside of protocol.c,
+     * but we've got to check for this sort of nonsense somewhere...
+     */
+    
+    if (r->assbackwards && r->header_only) {
+       /* Client asked for headers only with HTTP/0.9, which doesn't
+        * send headers!  Have to dink things even to make sure the
+        * error message comes through...
+        */
+       log_reason ("client sent illegal HTTP/0.9 request", r->uri, r);
+       r->header_only = 0;
+       die (BAD_REQUEST, r);
+       return;
+    }
+
+    if (!r->hostname && (r->proto_num >= 1001)) {
+        /* Client sent us a HTTP/1.1 or later request without telling
+        * us the hostname, either with a full URL or a Host: header.
+        * We therefore need to (as per the 1.1 spec) send an error
+        */
+        log_reason ("client sent HTTP/1.1 request without hostname",
+                   r->uri, r);
+       die (BAD_REQUEST, r);
+       return;
+    }
+
+    if (!r->proxyreq)
+    {
+       access_status = unescape_url(r->uri);
+       if (access_status)
+       {
+           die(access_status, r);
+           return;
+       }
+
+       getparents(r->uri);     /* OK --- shrinking transformations... */
+    }
+
+    if ((access_status = translate_name (r))) {
+        decl_die (access_status, "translate", r);
+       return;
+    }
+    
+    if ((access_status = directory_walk (r))) {
+        die (access_status, r);
+       return;
+    }  
+    
+    if ((access_status = location_walk (r))) {
+        die (access_status, r);
+       return;
+    }  
+    
+    if ((access_status = check_access (r)) != 0) {
+        decl_die (access_status, "check access", r);
+       return;
+    }
+    
+    if (some_auth_required (r)) {
+        if ((access_status = check_user_id (r)) != 0) {
+           decl_die (access_status, "check user.  No user file?", r);
+           return;
+       }
+
+       if ((access_status = check_auth (r)) != 0) {
+           decl_die (access_status, "check access.  No groups file?", r);
+           return;
+       }
+    }
+
+    if ((access_status = find_types (r)) != 0) {
+        decl_die (access_status, "find types", r);
+       return;
+    }
+
+    if ((access_status = run_fixups (r)) != 0) {
+        die (access_status, r);
+       return;
+    }
+
+    if ((access_status = invoke_handler (r)) != 0)
+        die (access_status, r);
+}
+
+void process_request (request_rec *r)
+{
+#ifdef STATUS
+    int old_stat;
+#endif /* STATUS */
+    process_request_internal (r);
+#ifdef STATUS
+    old_stat = update_child_status (r->connection->child_num, SERVER_BUSY_LOG,
+     r);
+#endif /* STATUS */
+    log_transaction (r);
+#ifdef STATUS
+    (void)update_child_status (r->connection->child_num, old_stat, r);
+#endif /* STATUS */
+}
+
+table *rename_original_env (pool *p, table *t)
+{
+    array_header *env_arr = table_elts (t);
+    table_entry *elts = (table_entry *)env_arr->elts;
+    table *new = make_table (p, env_arr->nelts);
+    int i;
+    
+    for (i = 0; i < env_arr->nelts; ++i) {
+        if (!elts[i].key) continue;
+       table_set (new, pstrcat (p, "REDIRECT_", elts[i].key, NULL),
+                  elts[i].val);
+    }
+
+    return new;
+}
+
+request_rec *internal_internal_redirect (char *new_uri, request_rec *r)
+{
+    request_rec *new = (request_rec *)pcalloc(r->pool, sizeof(request_rec));
+    char t[10];                        /* Long enough... */
+  
+    new->connection = r->connection;
+    new->server = r->server;
+    new->pool = r->pool;
+    
+    /* A whole lot of this really ought to be shared with protocol.c...
+     * another missing cleanup.  It's particularly inappropriate to be
+     * setting header_only, etc., here.
+     */
+    
+    parse_uri (new, new_uri);
+    new->request_config = create_request_config (r->pool);
+    new->per_dir_config = r->server->lookup_defaults;
+    
+    new->prev = r;
+    r->next = new;
+    
+    /* Inherit the rest of the protocol info... */
+
+    new->method = r->method;
+    new->method_number = r->method_number;
+    
+    new->status = r->status;
+    new->assbackwards = r->assbackwards;
+    new->header_only = r->header_only;
+    new->protocol = r->protocol;
+    new->main = r->main;
+
+    new->headers_in = r->headers_in;
+    new->headers_out = make_table (r->pool, 5);
+    new->err_headers_out = r->err_headers_out;
+    new->subprocess_env = rename_original_env (r->pool, r->subprocess_env);
+    new->notes = make_table (r->pool, 5);
+    new->htaccess = r->htaccess; /* copy .htaccess cache */
+    
+    new->no_cache = r->no_cache; /* If we've already made up our minds
+                                 * about this, don't change 'em back!
+                                 */
+
+    sprintf (t, "%d", r->status);
+    table_set (new->subprocess_env, "REDIRECT_STATUS", pstrdup (r->pool, t));
+
+    return new;
+}
+
+void internal_redirect (char *new_uri, request_rec *r)
+{
+    request_rec *new = internal_internal_redirect(new_uri, r);
+    process_request_internal (new);
+}
+
+/* This function is designed for things like actions or CGI scripts, when
+ * using AddHandler, and you want to preserve the content type across
+ * an internal redirect.
+ */
+
+void internal_redirect_handler (char *new_uri, request_rec *r)
+{
+    request_rec *new = internal_internal_redirect(new_uri, r);
+    if (r->handler)
+        new->content_type = r->content_type;
+    process_request_internal (new);
+}
diff --git a/RELEASE_1_1_X/src/main/md5c.c b/RELEASE_1_1_X/src/main/md5c.c
new file mode 100644 (file)
index 0000000..4ec60cb
--- /dev/null
@@ -0,0 +1,354 @@
+/*
+ * This is work is derived from material Copyright RSA Data Security, Inc.
+ *
+ * The RSA copyright statement and Licence for that original material is
+ * included below. This is followed by the Apache copyright statement and
+ * licence for the modifications made to that material.
+ */
+
+/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
+ */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+ */
+
+/* ====================================================================
+ * Copyright (c) 1996 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+#include <string.h>
+
+#include "md5.h"
+
+/* Constants for MD5Transform routine.
+ */
+
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+static void MD5Transform(UINT4 state[4], const unsigned char block[64]);
+static void Encode(unsigned char *output, const UINT4 *input,
+                  unsigned int len);
+static void Decode(UINT4 *output, const unsigned char *input,
+                  unsigned int len);
+
+static unsigned char PADDING[64] =
+{
+    0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* F, G, H and I are basic MD5 functions.
+ */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits.
+ */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+Rotation is separate from addition to prevent recomputation.
+ */
+#define FF(a, b, c, d, x, s, ac) { \
+ (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+  }
+#define GG(a, b, c, d, x, s, ac) { \
+ (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+  }
+#define HH(a, b, c, d, x, s, ac) { \
+ (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+  }
+#define II(a, b, c, d, x, s, ac) { \
+ (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+  }
+
+/* MD5 initialization. Begins an MD5 operation, writing a new context.
+ */
+void
+MD5Init(MD5_CTX *context)
+{
+    context->count[0] = context->count[1] = 0;
+  /* Load magic initialization constants. */
+    context->state[0] = 0x67452301;
+    context->state[1] = 0xefcdab89;
+    context->state[2] = 0x98badcfe;
+    context->state[3] = 0x10325476;
+}
+
+/* MD5 block update operation. Continues an MD5 message-digest
+  operation, processing another message block, and updating the
+  context.
+ */
+void
+MD5Update(MD5_CTX *context, const unsigned char *input, unsigned int inputLen)
+{
+    unsigned int i, index, partLen;
+
+  /* Compute number of bytes mod 64 */
+    index = (unsigned int)((context->count[0] >> 3) & 0x3F);
+
+  /* Update number of bits */
+    if ((context->count[0] += ((UINT4)inputLen << 3)) < ((UINT4)inputLen << 3))
+       context->count[1]++;
+    context->count[1] += (UINT4)inputLen >> 29;
+
+    partLen = 64 - index;
+
+  /* Transform as many times as possible. */
+    if (inputLen >= partLen)
+    {
+       memcpy(&context->buffer[index], input, partLen);
+       MD5Transform(context->state, context->buffer);
+
+       for (i = partLen; i + 63 < inputLen; i += 64)
+           MD5Transform(context->state, &input[i]);
+
+       index = 0;
+    }
+    else
+       i = 0;
+
+  /* Buffer remaining input */
+    memcpy(&context->buffer[index], &input[i], inputLen-i);
+}
+
+/* MD5 finalization. Ends an MD5 message-digest operation, writing the
+  the message digest and zeroizing the context.
+ */
+void
+MD5Final(unsigned char digest[16], MD5_CTX *context)
+{
+    unsigned char bits[8];
+    unsigned int index, padLen;
+
+  /* Save number of bits */
+    Encode (bits, context->count, 8);
+
+  /* Pad out to 56 mod 64. */
+    index = (unsigned int)((context->count[0] >> 3) & 0x3f);
+    padLen = (index < 56) ? (56 - index) : (120 - index);
+    MD5Update(context, PADDING, padLen);
+
+  /* Append length (before padding) */
+    MD5Update(context, bits, 8);
+
+  /* Store state in digest */
+    Encode(digest, context->state, 16);
+
+  /* Zeroize sensitive information. */
+    memset(context, 0, sizeof (*context));
+}
+
+/* MD5 basic transformation. Transforms state based on block. */
+static void
+MD5Transform(UINT4 state[4], const unsigned char block[64])
+{
+    UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+
+    Decode (x, block, 64);
+
+  /* Round 1 */
+    FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
+    FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
+    FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
+    FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
+    FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
+    FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
+    FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
+    FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
+    FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
+    FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
+    FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+    FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+    FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+    FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+    FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+    FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+    
+ /* Round 2 */
+    GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
+    GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
+    GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+    GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
+    GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
+    GG (d, a, b, c, x[10], S22,  0x2441453); /* 22 */
+    GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+    GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
+    GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
+    GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+    GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
+    GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
+    GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+    GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
+    GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
+    GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+    
+  /* Round 3 */
+    HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
+    HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
+    HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+    HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+    HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
+    HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
+    HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
+    HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+    HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+    HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
+    HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
+    HH (b, c, d, a, x[ 6], S34,  0x4881d05); /* 44 */
+    HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
+    HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+    HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+    HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
+
+  /* Round 4 */
+    II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
+    II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
+    II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+    II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
+    II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+    II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
+    II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+    II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
+    II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
+    II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+    II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
+    II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+    II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
+    II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+    II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
+    II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
+
+    state[0] += a;
+    state[1] += b;
+    state[2] += c;
+    state[3] += d;
+
+  /* Zeroize sensitive information. */
+    memset(x, 0, sizeof (x));
+}
+
+/* Encodes input (UINT4) into output (unsigned char). Assumes len is
+  a multiple of 4.
+ */
+static void
+Encode(unsigned char *output, const UINT4 *input, unsigned int len)
+{
+    unsigned int i, j;
+    UINT4 k;
+
+    for (i = 0, j = 0; j < len; i++, j += 4)
+    {
+       k = input[i];
+       output[j] = (unsigned char)(k & 0xff);
+       output[j+1] = (unsigned char)((k >> 8) & 0xff);
+       output[j+2] = (unsigned char)((k >> 16) & 0xff);
+       output[j+3] = (unsigned char)((k >> 24) & 0xff);
+    }
+}
+
+/* Decodes input (unsigned char) into output (UINT4). Assumes len is
+  a multiple of 4.
+ */
+static void
+Decode(UINT4 *output, const unsigned char *input, unsigned int len)
+{
+    unsigned int i, j;
+
+    for (i = 0, j = 0; j < len; i++, j += 4)
+       output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
+           (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
+}
diff --git a/RELEASE_1_1_X/src/main/rfc1413.c b/RELEASE_1_1_X/src/main/rfc1413.c
new file mode 100644 (file)
index 0000000..556cb8a
--- /dev/null
@@ -0,0 +1,233 @@
+/* ====================================================================
+ * Copyright (c) 1995,1996 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * rfc1413() speaks a common subset of the RFC 1413, AUTH, TAP and IDENT
+ * protocols. The code queries an RFC 1413 etc. compatible daemon on a remote
+ * host to look up the owner of a connection. The information should not be
+ * used for authentication purposes. This routine intercepts alarm signals.
+ * 
+ * Diagnostics are reported through syslog(3).
+ * 
+ * Author: Wietse Venema, Eindhoven University of Technology,
+ * The Netherlands.
+ */
+
+/* Some small additions for Shambhala --- ditch the "sccsid" var if
+ * compiling with gcc (it *has* changed), include conf.h for the
+ * prototypes it defines on at least one system (SunlOSs) which has
+ * them missing from the standard header files, and one minor change
+ * below (extra parens around assign "if (foo = bar) ..." to shut up
+ * gcc -Wall).
+ */
+
+/* Rewritten by David Robinson */
+
+#include "httpd.h"    /* for server_rec, conn_rec */
+#include "http_log.h" /* for log_unixerr */
+#include "rfc1413.h"
+
+#ifndef _HPUX_SOURCE
+#define _HPUX_SOURCE
+#endif
+
+/* System libraries. */
+
+#include <setjmp.h>
+
+#ifndef SCO
+extern char *strchr();
+extern char *inet_ntoa();
+#endif
+
+/* Local stuff. */
+/* Semi-well-known port */
+#define        RFC1413_PORT    113
+/* maximum allowed length of userid */
+#define RFC1413_USERLEN 512
+/* rough limit on the amount of data we accept. */
+#define RFC1413_MAXDATA 1000
+
+#define RFC1413_TIMEOUT        60
+#define        ANY_PORT        0               /* Any old port will do */
+#define FROM_UNKNOWN  "unknown"
+
+int rfc1413_timeout = RFC1413_TIMEOUT;/* Global so it can be changed */
+
+static jmp_buf timebuf;
+
+/* bind_connect - bind both ends of a socket */
+
+static int
+get_rfc1413(int sock, const struct sockaddr_in *our_sin,
+         const struct sockaddr_in *rmt_sin, char user[256], server_rec *srv)
+{
+    struct sockaddr_in rmt_query_sin, our_query_sin;
+    unsigned int rmt_port, our_port;
+    int i;
+    char *cp;
+    char buffer[RFC1413_MAXDATA+1];
+
+    /*
+     * Bind the local and remote ends of the query socket to the same
+     * IP addresses as the connection under investigation. We go
+     * through all this trouble because the local or remote system
+     * might have more than one network address. The RFC1413 etc.
+     * client sends only port numbers; the server takes the IP
+     * addresses from the query socket.
+     */
+
+    our_query_sin = *our_sin;
+    our_query_sin.sin_port = htons(ANY_PORT);
+    rmt_query_sin = *rmt_sin;
+    rmt_query_sin.sin_port = htons(RFC1413_PORT);
+
+    if (bind(sock, (struct sockaddr *)&our_query_sin,
+            sizeof(struct sockaddr_in)) < 0)
+    {
+       log_unixerr("bind", NULL, "rfc1413: Error binding to local port", srv);
+       return -1;
+    }
+
+/*
+ * errors from connect usually imply the remote machine doesn't support
+ * the service
+ */
+    if (connect(sock, (struct sockaddr *)&rmt_query_sin,
+               sizeof(struct sockaddr_in)) < 0)
+       return -1;
+
+/* send the data */
+    sprintf(buffer, "%u,%u\r\n", ntohs(rmt_sin->sin_port),
+           ntohs(our_sin->sin_port));
+    do i = write(sock, buffer, strlen(buffer));
+    while (i == -1 && errno == EINTR);
+    if (i == -1)
+    {
+       log_unixerr("write", NULL, "rfc1413: error sending request", srv);
+       return -1;
+    }
+
+    /*
+     * Read response from server. We assume that all the data
+     * comes in a single packet.
+     */
+    
+    do i = read(sock, buffer, RFC1413_MAXDATA);
+    while (i == -1 && errno == EINTR);
+    if (i == -1)
+    {
+       log_unixerr("read", NULL, "rfc1413: error reading response", srv);
+       return -1;
+    }
+
+    buffer[i] = '\0';
+/* RFC1413_USERLEN = 512 */
+    if (sscanf(buffer, "%u , %u : USERID :%*[^:]:%512s", &rmt_port, &our_port,
+              user) != 3 || ntohs(rmt_sin->sin_port) != rmt_port
+       || ntohs(our_sin->sin_port) != our_port) return -1;
+
+    /*
+     * Strip trailing carriage return. It is part of the
+     * protocol, not part of the data.
+     */
+    
+    if ((cp = strchr(user, '\r'))) *cp = '\0';
+
+    return 0;
+}
+
+/* timeout - handle timeouts */
+static void
+timeout(int sig)
+{
+    longjmp(timebuf, sig);
+}
+
+/* rfc1413 - return remote user name, given socket structures */
+char *
+rfc1413(conn_rec *conn, server_rec *srv)
+{
+    static char user[RFC1413_USERLEN+1]; /* XXX */
+    static char *result;
+    static int sock;
+
+    result = FROM_UNKNOWN;
+
+    sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    if (sock < 0)
+    {
+       log_unixerr("socket", NULL, "rfc1413: error creating socket", srv);
+       conn->remote_logname = result;
+    }
+
+    /*
+     * Set up a timer so we won't get stuck while waiting for the server.
+     */
+    if (setjmp(timebuf) == 0)
+    {
+       signal(SIGALRM, timeout);
+       alarm(rfc1413_timeout);
+       
+       if (get_rfc1413(sock, &conn->local_addr, &conn->remote_addr, user,
+                     srv)
+           >= 0)
+           result = user;
+
+       alarm(0);
+    }
+    close(sock);
+    conn->remote_logname = result;
+
+    return conn->remote_logname;
+}
diff --git a/RELEASE_1_1_X/src/main/util.c b/RELEASE_1_1_X/src/main/util.c
new file mode 100644 (file)
index 0000000..84a7824
--- /dev/null
@@ -0,0 +1,1196 @@
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * str.c: string utility things
+ * 
+ * 3/21/93 Rob McCool
+ * 
+ */
+
+
+#include "httpd.h"
+#include "http_conf_globals.h" /* for user_id & group_id */
+#ifdef QNX
+#include <time.h>
+#endif
+
+#ifdef NOTDEF
+extern char** environ;
+
+/* taken from bdflush-1.5 for Linux source code */
+void inststr(char *dst[], int argc, char *src)
+{
+    if (strlen(src) <= strlen(dst[0]))
+    {
+        char *ptr;
+
+        for (ptr = dst[0]; *ptr; *(ptr++) = '\0');
+
+        strcpy(dst[0], src);
+    } else
+    {
+        /* stolen from the source to perl 4.036 (assigning to $0) */
+        char *ptr, *ptr2;
+        int count;
+        ptr = dst[0] + strlen(dst[0]);
+        for (count = 1; count < argc; count++) {
+            if (dst[count] == ptr + 1)
+                ptr += strlen(++ptr);
+        }
+        if (environ[0] == ptr + 1) {
+            for (count = 0; environ[count]; count++)
+                if (environ[count] == ptr + 1)
+                    ptr += strlen(++ptr);
+        }
+        count = 0;
+        for (ptr2 = dst[0]; ptr2 <= ptr; ptr2++) {
+            *ptr2 = '\0';
+            count++;
+        }
+        strncpy(dst[0], src, count);
+    }
+}
+#endif
+
+char *get_time() {
+    time_t t;
+    char *time_string;
+
+    t=time(NULL);
+    time_string = ctime(&t);
+    time_string[strlen(time_string) - 1] = '\0';
+    return (time_string);
+}
+
+char *ht_time(pool *p, time_t t, char *fmt, int gmt) {
+    char ts[MAX_STRING_LEN];
+    struct tm *tms;
+
+    tms = (gmt ? gmtime(&t) : localtime(&t));
+
+    /* check return code? */
+    strftime(ts,MAX_STRING_LEN,fmt,tms);
+    return pstrdup (p, ts);
+}
+
+char *gm_timestr_822(pool *p, time_t sec) {
+    static const char *const days[7]=
+       {"Sun","Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
+    char ts[50];
+    struct tm *tms;
+
+    tms = gmtime(&sec);
+
+/* RFC date format; as strftime '%a, %d %b %Y %T GMT' */
+    sprintf(ts, "%s, %.2d %s %d %.2d:%.2d:%.2d GMT", days[tms->tm_wday],
+           tms->tm_mday, month_snames[tms->tm_mon], tms->tm_year + 1900,
+           tms->tm_hour, tms->tm_min, tms->tm_sec);
+
+    return pstrdup (p, ts);
+}
+
+/* What a pain in the ass. */
+struct tm *get_gmtoff(long *tz) {
+    time_t tt;
+    struct tm *t;
+
+    tt = time(NULL);
+    t = localtime(&tt);
+#if defined(HAS_GMTOFF)
+    *tz = t->tm_gmtoff;
+#elif !defined(NO_TIMEZONE)
+    *tz = - timezone;
+    if(t->tm_isdst)
+        *tz += 3600;
+#else
+  {
+    static struct tm loc_t;
+
+    loc_t = *t;   /* save it */
+    t = gmtime(&tt);
+    *tz = mktime(&loc_t) - mktime(t);
+    t = &loc_t; /* return pointer to saved time */
+  }
+#endif
+    return t;
+}
+
+
+/* Match = 0, NoMatch = 1, Abort = -1 */
+/* Based loosely on sections of wildmat.c by Rich Salz
+ * Hmmm... shouldn't this really go component by component?
+ */
+int strcmp_match(char *str, char *exp) {
+    int x,y;
+
+    for(x=0,y=0;exp[y];++y,++x) {
+        if((!str[x]) && (exp[y] != '*'))
+            return -1;
+        if(exp[y] == '*') {
+            while(exp[++y] == '*');
+            if(!exp[y])
+                return 0;
+            while(str[x]) {
+                int ret;
+                if((ret = strcmp_match(&str[x++],&exp[y])) != 1)
+                    return ret;
+            }
+            return -1;
+        } else 
+            if((exp[y] != '?') && (str[x] != exp[y]))
+                return 1;
+    }
+    return (str[x] != '\0');
+}
+
+int strcasecmp_match(char *str, char *exp) {
+    int x,y;
+
+    for(x=0,y=0;exp[y];++y,++x) {
+        if((!str[x]) && (exp[y] != '*'))
+            return -1;
+        if(exp[y] == '*') {
+            while(exp[++y] == '*');
+            if(!exp[y])
+                return 0;
+            while(str[x]) {
+                int ret;
+                if((ret = strcasecmp_match(&str[x++],&exp[y])) != 1)
+                    return ret;
+            }
+            return -1;
+        } else 
+            if((exp[y] != '?') && (tolower(str[x]) != tolower(exp[y])))
+                return 1;
+    }
+    return (str[x] != '\0');
+}
+
+int is_matchexp(char *str) {
+    register int x;
+
+    for(x=0;str[x];x++)
+        if((str[x] == '*') || (str[x] == '?'))
+            return 1;
+    return 0;
+}
+
+/*
+ * Parse .. so we don't compromise security
+ */
+void getparents(char *name)
+{
+    int l, w;
+
+    /* Four paseses, as per RFC 1808 */
+    /* a) remove ./ path segments */
+
+    for (l=0, w=0; name[l] != '\0';)
+    {
+       if (name[l] == '.' && name[l+1] == '/' && (l == 0 || name[l-1] == '/'))
+           l += 2;
+       else
+           name[w++] = name[l++];
+    }
+
+    /* b) remove trailing . path, segment */
+    if (w == 1 && name[0] == '.') w--;
+    else if (w > 1 && name[w-1] == '.' && name[w-2] == '/') w--;
+    name[w] = '\0';
+
+    /* c) remove all xx/../ segments. (including leading ../ and /../) */
+    l = 0;
+
+    while(name[l]!='\0') {
+        if(name[l] == '.' && name[l+1] == '.' && name[l+2] == '/' &&
+           (l == 0 || name[l-1] == '/')) {
+               register int m=l+3,n;
+
+               l=l-2;
+               if(l>=0) {
+                   while(l >= 0 && name[l] != '/') l--;
+                   l++;
+               }
+               else l=0;
+               n=l;
+               while((name[n]=name[m])) (++n,++m);
+            }
+       else ++l;
+    }
+
+    /* d) remove trailing xx/.. segment. */
+    if (l == 2 && name[0] == '.' && name[1] == '.') name[0] = '\0';
+    else if (l > 2 && name[l-1] == '.' && name[l-2] == '.' && name[l-3] == '/')
+    {
+       l = l - 4;
+       if (l >= 0)
+       {
+           while (l >= 0 && name[l] != '/') l--;
+           l++;
+       }
+       else l = 0;
+       name[l] = '\0';
+    }
+} 
+
+void no2slash(char *name) {
+    register int x,y;
+
+    for(x=0; name[x];)
+        if(x && (name[x-1] == '/') && (name[x] == '/'))
+            for(y=x+1;name[y-1];y++)
+                name[y-1] = name[y];
+       else x++;
+}
+
+char *make_dirstr(pool *p, char *s, int n) {
+    register int x,f;
+    char *res;
+
+    for(x=0,f=0;s[x];x++) {
+        if(s[x] == '/')
+            if((++f) == n) {
+               res = palloc(p, x + 2);
+               strncpy (res, s, x);
+               res[x] = '/';
+               res[x+1] = '\0';
+                return res;
+            }
+    }
+
+    if (s[strlen(s) - 1] == '/')
+        return pstrdup (p, s);
+    else
+        return pstrcat (p, s, "/", NULL);
+}
+
+int count_dirs(char *path) {
+    register int x,n;
+
+    for(x=0,n=0;path[x];x++)
+        if(path[x] == '/') n++;
+    return n;
+}
+
+
+void chdir_file(char *file) {
+    int i;
+
+    if((i = rind(file,'/')) == -1)
+        return;
+    file[i] = '\0';
+    chdir(file);
+    file[i] = '/';
+}
+
+char *getword(pool* atrans, char **line, char stop) {
+    int pos = ind(*line, stop);
+    char *res;
+
+    if (pos == -1) {
+        res = pstrdup (atrans, *line);
+       *line += strlen (*line);
+       return res;
+    }
+  
+    res = palloc(atrans, pos + 1);
+    strncpy (res, *line, pos);
+    res[pos] = '\0';
+    
+    while ((*line)[pos] == stop) ++pos;
+    
+    *line += pos;
+    
+    return res;
+}
+char *getword_nulls(pool* atrans, char **line, char stop) {
+    int pos = ind(*line, stop);
+    char *res;
+
+    if (pos == -1) {
+        res = pstrdup (atrans, *line);
+       *line += strlen (*line);
+       return res;
+    }
+  
+    res = palloc(atrans, pos + 1);
+    strncpy (res, *line, pos);
+    res[pos] = '\0';
+    
+    ++pos;
+    
+    *line += pos;
+    
+    return res;
+}
+
+/* Get a word, (new) config-file style --- quoted strings and backslashes
+ * all honored
+ */
+
+char *substring_conf (pool *p, char *start, int len)
+{
+    char *result = palloc (p, len + 2);
+    char *resp = result;
+    int i;
+
+    for (i = 0; i < len; ++i) {
+        if (start[i] == '\\') 
+           *resp++ = start[++i];
+       else
+           *resp++ = start[i];
+    }
+
+    *resp++ = '\0';
+    return result;
+}
+
+char *getword_conf(pool* p, char **line) {
+    char *str = *line, *strend, *res;
+    char quote;
+
+    while (*str && isspace (*str))
+        ++str;
+
+    if (!*str) {
+        *line = str;
+        return "";
+    }
+
+    if ((quote = *str) == '"' || quote == '\'') {
+        strend = str + 1;
+       while (*strend && *strend != quote) {
+           if (*strend == '\\' && strend[1]) strend += 2;
+           else ++strend;
+       }
+       res = substring_conf (p, str + 1, strend - str - 1);
+
+       if (*strend == quote) ++strend;
+    } else {
+        strend = str;
+       while (*strend && !isspace (*strend))
+           if (*strend == '\\' && strend[1]) strend += 2;
+           else ++strend;
+
+       res = substring_conf (p, str, strend - str);
+    }
+
+    while (*strend && isspace(*strend)) ++ strend;
+    *line = strend;
+    return res;
+}
+
+void cfg_getword(char *word, char *line) {
+    int x=0,y;
+    
+    for(x=0;line[x] && isspace(line[x]);x++);
+    y=0;
+    while(1) {
+        if(!(word[y] = line[x]))
+            break;
+        if(isspace(line[x]))
+            if((!x) || (line[x-1] != '\\'))
+                break;
+        if(line[x] != '\\') ++y;
+        ++x;
+    }
+    word[y] = '\0';
+    while(line[x] && isspace(line[x])) ++x;
+    for(y=0;(line[y] = line[x]);++x,++y);
+}
+
+int
+cfg_getline(char *s, int n, FILE *f) {
+    register int i=0, c;
+
+    s[0] = '\0';
+    /* skip leading whitespace */
+    do {
+        c = getc(f);
+    } while (c == '\t' || c == ' ');
+
+    while(1) {
+        if((c == '\t') || (c == ' ')) {
+            s[i++] = ' ';
+            while((c == '\t') || (c == ' ')) 
+                c = getc(f);
+        }
+        if(c == CR) {
+            c = getc(f);
+        }
+        if(c == EOF || c == 0x4 || c == LF || i == (n-1)) {
+            /* blast trailing whitespace */
+            while(i && (s[i-1] == ' ')) --i;
+            s[i] = '\0';
+            return (feof(f) ? 1 : 0);
+        }
+        s[i] = c;
+        ++i;
+        c = getc(f);
+    }
+}
+
+/* Retrieve a token, spacing over it and returning a pointer to
+ * the first non-white byte afterwards.  Note that these tokens
+ * are delimited by semis and commas; and can also be delimited
+ * by whitespace at the caller's option.
+ */
+
+char *get_token (pool *p, char **accept_line, int accept_white)
+{
+    char *ptr = *accept_line;
+    char *tok_start;
+    char *token;
+    int tok_len;
+  
+    /* Find first non-white byte */
+    
+    while (*ptr && isspace(*ptr))
+      ++ptr;
+
+    tok_start = ptr;
+    
+    /* find token end, skipping over quoted strings.
+     * (comments are already gone).
+     */
+    
+    while (*ptr && (accept_white || !isspace(*ptr))
+          && *ptr != ';' && *ptr != ',')
+    {
+       if (*ptr++ == '"')
+           while (*ptr)
+               if (*ptr++ == '"') break;
+    }
+         
+    tok_len = ptr - tok_start;
+    token = palloc (p, tok_len + 1);
+    strncpy (token, tok_start, tok_len);
+    token[tok_len] = '\0';
+    
+    /* Advance accept_line pointer to the next non-white byte */
+
+    while (*ptr && isspace(*ptr))
+      ++ptr;
+
+    *accept_line = ptr;
+    return token;
+}
+
+char *escape_shell_cmd(pool *p, char *s) {
+    register int x,y,l;
+    char *cmd;
+
+    l=strlen(s);
+    cmd = palloc (p, 2 * l + 1); /* Be safe */
+    strcpy (cmd, s);
+    
+    for(x=0;cmd[x];x++) {
+    
+#ifdef __EMX__
+        /* Don't allow '&' in parameters under OS/2. */
+        /* This can be used to send commands to the shell. */
+        if (cmd[x] == '&') {
+            cmd[x] = ' ';
+        }
+#endif
+
+        if(ind("&;`'\"|*?~<>^()[]{}$\\\n",cmd[x]) != -1){
+            for(y=l+1;y>x;y--)
+                cmd[y] = cmd[y-1];
+            l++; /* length has been increased */
+            cmd[x] = '\\';
+            x++; /* skip the character */
+        }
+    }
+
+    return cmd;
+}
+
+void plustospace(char *str) {
+    register int x;
+
+    for(x=0;str[x];x++) if(str[x] == '+') str[x] = ' ';
+}
+
+void spacetoplus(char *str) {
+    register int x;
+
+    for(x=0;str[x];x++) if(str[x] == ' ') str[x] = '+';
+}
+
+char x2c(char *what) {
+    register char digit;
+
+    digit = ((what[0] >= 'A') ? ((what[0] & 0xdf) - 'A')+10 : (what[0] - '0'));
+    digit *= 16;
+    digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A')+10 : (what[1] - '0'));
+    return(digit);
+}
+
+/*
+ * Unescapes a URL.
+ * Returns 0 on success, non-zero on error
+ * Failure is due to
+ *   bad % escape       returns BAD_REQUEST
+ *
+ *   decoding %00 -> \0
+ *   decoding %2f -> /   (a special character)
+ *                      returns NOT_FOUND
+ */
+int
+unescape_url(char *url) {
+    register int x,y, badesc, badpath;
+
+    badesc = 0;
+    badpath = 0;
+    for(x=0,y=0;url[y];++x,++y) {
+       if (url[y] != '%') url[x] = url[y];
+       else
+       {
+           if (!isxdigit(url[y+1]) || !isxdigit(url[y+2]))
+           {
+               badesc = 1;
+               url[x] = '%';
+           } else
+           {
+               url[x] = x2c(&url[y+1]);
+               y += 2;
+               if (url[x] == '/' || url[x] == '\0') badpath = 1;
+           }
+        }
+    }
+    url[x] = '\0';
+    if (badesc) return BAD_REQUEST;
+    else if (badpath) return NOT_FOUND;
+    else return OK;
+}
+
+char *construct_url(pool *p, char *uri, server_rec *s) {
+    char portnum[10];          /* Long enough.  Really! */
+  
+    if (s->port == 80) {
+        return pstrcat (p, "http://", s->server_hostname, uri, NULL);
+    } else {
+        sprintf (portnum, "%d", s->port);
+       return pstrcat (p, "http://", s->server_hostname, ":", portnum, uri,
+                       NULL);
+    }
+}
+
+#define c2x(what,where) sprintf(where,"%%%02x",what)
+
+/*
+escape_path_segment() escapes a path segment, as defined in RFC 1808. This
+routine is (should be) OS independent.
+
+os_escape_path() converts an OS path to a URL, in an OS dependent way. In all
+cases if a ':' occurs before the first '/' in the URL, the URL should be
+prefixed with "./" (or the ':' escaped). In the case of Unix, this means
+leaving '/' alone, but otherwise doing what escape_path_segment() does. For
+efficiency reasons, we don't use escape_path_segment(), which is provided for
+reference. Again, RFC 1808 is where this stuff is defined.
+
+If partial is set, os_escape_path() assumes that the path will be appended to
+something with a '/' in it (and thus does not prefix "./").
+*/
+
+char *escape_path_segment(pool *p, const char *segment) {
+    register int x,y;
+    char *copy = palloc (p, 3 * strlen (segment) + 1);
+            
+    for(x=0,y=0; segment[x]; x++,y++) {
+      char c=segment[x];
+      if((c < 'A' || c > 'Z') && (c < 'a' || c > 'z') && (c < '0' || c >'9')
+        && ind("$-_.+!*'(),:@&=~",c) == -1)
+       {
+         c2x(c,&copy[y]);
+         y+=2;
+       }
+      else
+       copy[y]=c;
+    }
+    copy[y] = '\0';
+    return copy;
+}
+
+char *os_escape_path(pool *p,const char *path,int partial) {
+  char *copy=palloc(p,3*strlen(path)+3);
+  char *s=copy;
+
+  if(!partial)
+    {
+      int colon=ind(path,':');
+      int slash=ind(path,'/');
+
+      if(colon >= 0 && (colon < slash || slash < 0))
+       {
+         *s++='.';
+         *s++='/';
+       }
+    }
+  for( ; *path ; ++path)
+    {
+      char c=*path;
+      if((c < 'A' || c > 'Z') && (c < 'a' || c > 'z') && (c < '0' || c >'9')
+        && ind("$-_.+!*'(),:@&=/~",c) == -1)
+       {
+         c2x(c,s);
+         s+=3;
+       }
+      else
+       *s++=c;
+    }
+  *s='\0';
+  return copy;
+}
+
+char *escape_uri(pool *p, char *uri) {
+    register int x,y;
+    char *copy = palloc (p, 3 * strlen (uri) + 1);
+            
+    for(x=0,y=0; uri[x]; x++,y++) {
+        if (ind (":% ?+&",(copy[y] = uri[x])) != -1) {
+            c2x(uri[x],&copy[y]);
+            y+=2;
+        }
+    }
+    copy[y] = '\0';
+    return copy;
+}
+
+char *
+escape_html(pool *p, const char *s)
+{
+    int i, j;
+    char *x;
+
+/* first, count the number of extra characters */
+    for (i=0, j=0; s[i] != '\0'; i++)
+       if (s[i] == '<' || s[i] == '>') j += 3;
+       else if (s[i] == '&') j += 4;
+
+    if (j == 0) return pstrdup(p, s);
+    x = palloc(p, i + j + 1);
+    for (i=0, j=0; s[i] != '\0'; i++, j++)
+       if (s[i] == '<')
+       {
+           memcpy(&x[j], "&lt;", 4);
+           j += 3;
+       } else if (s[i] == '>')
+       {
+           memcpy(&x[j], "&gt;", 4);
+           j += 3;
+       } else if (s[i] == '&')
+       {
+           memcpy(&x[j], "&amp;", 5);
+           j += 4;
+       } else
+            x[j] = s[i];
+
+    x[j] = '\0';
+    return x;
+}
+
+#ifdef NOTDEF
+
+void escape_url(char *url) {
+    register int x,y;
+    register char digit;
+    char *copy;
+
+    copy = strdup(url);
+            
+    for(x=0,y=0;copy[x];x++,y++) {
+        if(ind("% ?+&",url[y] = copy[x]) != -1) {
+            c2x(copy[x],&url[y]);
+            y+=2;
+        }
+    }
+    url[y] = '\0';
+    free(copy);
+}
+
+#endif
+
+int is_directory(char *path) {
+    struct stat finfo;
+
+    if(stat(path,&finfo) == -1)
+        return 0; /* in error condition, just return no */
+
+    return(S_ISDIR(finfo.st_mode));
+}
+
+char *make_full_path(pool *a, char *src1,char *src2) {
+    register int x;
+
+    x = strlen(src1);
+    if (x == 0) return pstrcat (a, "/", src2, NULL);
+
+    if (src1[x - 1] != '/') return pstrcat (a, src1, "/", src2, NULL);
+    else return pstrcat (a, src1, src2, NULL);
+}
+
+int is_url(char *u) {
+    register int x;
+
+    for(x=0;u[x] != ':';x++)
+        if((!u[x]) || (!isalpha(u[x])))
+            return 0;
+
+    if((u[x+1] == '/') && (u[x+2] == '/'))
+        return 1;
+    else return 0;
+}
+
+int can_exec(struct stat *finfo) {
+#ifdef __EMX__
+    /* OS/2 dosen't have Users and Groups */
+    return (finfo->st_mode & S_IEXEC);
+#else    
+    if(user_id == finfo->st_uid)
+        if(finfo->st_mode & S_IXUSR)
+            return 1;
+    if(group_id == finfo->st_gid)
+        if(finfo->st_mode & S_IXGRP)
+            return 1;
+    return (finfo->st_mode & S_IXOTH);
+#endif    
+}
+
+#ifdef NEED_STRDUP
+char *strdup (char *str)
+{
+  char *dup;
+
+  if(!(dup = (char *)malloc (strlen (str) + 1)))
+      return NULL;
+  dup = strcpy (dup, str);
+
+  return dup;
+}
+#endif
+
+/* The following two routines were donated for SVR4 by Andreas Vogel */
+#ifdef NEED_STRCASECMP
+int strcasecmp (const char *a, const char *b)
+{
+    const char *p = a;
+    const char *q = b;
+    for (p = a, q = b; *p && *q; p++, q++)
+    {
+      int diff = tolower(*p) - tolower(*q);
+      if (diff) return diff;
+    }
+    if (*p) return 1;       /* p was longer than q */
+    if (*q) return -1;      /* p was shorter than q */
+    return 0;               /* Exact match */
+}
+
+#endif
+
+#ifdef NEED_STRNCASECMP
+int strncasecmp (const char *a, const char *b, int n)
+{
+    const char *p = a;
+    const char *q = b;
+
+    for (p = a, q = b; /*NOTHING*/; p++, q++)
+    {
+      int diff;
+      if (p == a + n) return 0;     /*   Match up to n characters */
+      if (!(*p && *q)) return *p - *q;
+      diff = tolower(*p) - tolower(*q);
+      if (diff) return diff;
+    }
+    /*NOTREACHED*/
+}
+#endif
+
+
+
+#ifdef NEED_INITGROUPS
+int initgroups(const char *name, gid_t basegid)
+{
+#ifdef QNX
+/* QNX does not appear to support supplementary groups.
+Ben <ben@algroup.co.uk> */
+       return 0;
+#else /* ndef QNX */
+  gid_t groups[NGROUPS_MAX];
+  struct group *g;
+  int index = 0;
+
+  setgrent();
+
+  groups[index++] = basegid;
+
+  while (index < NGROUPS_MAX && ((g = getgrent()) != NULL))
+    if (g->gr_gid != basegid)
+    {
+      char **names;
+
+      for (names = g->gr_mem; *names != NULL; ++names)
+        if (!strcmp(*names, name))
+          groups[index++] = g->gr_gid;
+    }
+
+  endgrent();
+
+  return setgroups(index, groups);
+#endif /* def QNX */
+}
+#endif /* def NEED_INITGROUPS */
+
+#ifdef NEED_WAITPID
+/* From ikluft@amdahl.com */
+/* this is not ideal but it works for SVR3 variants */
+/* httpd does not use the options so this doesn't implement them */
+int waitpid(pid_t pid, int *statusp, int options)
+{
+    int tmp_pid;
+    if ( kill ( pid,0 ) == -1) {
+        errno=ECHILD;
+        return -1;
+    }
+    while ((( tmp_pid = wait(statusp)) != pid) && ( tmp_pid != -1 ));
+    return tmp_pid;
+}
+#endif
+
+int ind(const char *s, char c) {
+    register int x;
+
+    for(x=0;s[x];x++)
+        if(s[x] == c) return x;
+
+    return -1;
+}
+
+int rind(const char *s, char c) {
+    register int x;
+
+    for(x=strlen(s)-1;x != -1;x--)
+        if(s[x] == c) return x;
+
+    return -1;
+}
+
+void str_tolower(char *str) {
+    while(*str) {
+        *str = tolower(*str);
+        ++str;
+    }
+}
+        
+uid_t uname2id(char *name) {
+    struct passwd *ent;
+
+    if(name[0] == '#') 
+        return(atoi(&name[1]));
+
+    if(!(ent = getpwnam(name))) {
+        fprintf(stderr,"httpd: bad user name %s\n",name);
+        exit(1);
+    }
+    else return(ent->pw_uid);
+}
+
+gid_t gname2id(char *name) {
+    struct group *ent;
+
+    if(name[0] == '#') 
+        return(atoi(&name[1]));
+
+    if(!(ent = getgrnam(name))) {
+        fprintf(stderr,"httpd: bad group name %s\n",name);
+        exit(1);
+    }
+    else return(ent->gr_gid);
+}
+
+#if 0
+int get_portnum(int sd) {
+    struct sockaddr addr;
+    int len;
+
+    len = sizeof(struct sockaddr);
+    if(getsockname(sd,&addr,&len) < 0)
+        return -1;
+    return ntohs(((struct sockaddr_in *)&addr)->sin_port);
+}
+
+struct in_addr get_local_addr(int sd) {
+    struct sockaddr addr;
+    int len;
+
+    len = sizeof(struct sockaddr);
+    if(getsockname(sd,&addr,&len) < 0) {
+        fprintf (stderr, "Can't get local host address!\n");
+       perror ("getsockname");
+       exit(1);
+    }
+         
+    return ((struct sockaddr_in *)&addr)->sin_addr;
+}
+#endif
+
+/*
+ * Parses a host of the form <address>[:port]
+ * :port is permitted if 'port' is not NULL
+ */
+unsigned long get_virthost_addr (char *w, short int *ports) {
+    struct hostent *hep;
+    unsigned long my_addr;
+    char *p;
+
+    p = strchr(w, ':');
+    if (ports != NULL)
+    {
+       *ports = 0;
+       if (p != NULL && strcmp(p+1, "*") != 0) *ports = atoi(p+1);
+    }
+
+    if (p != NULL) *p = '\0';
+    if (strcmp(w, "*") == 0)
+    {
+       if (p != NULL) *p = ':';
+       return htonl(INADDR_ANY);
+    }
+       
+#ifdef DGUX
+    my_addr = inet_network(w);
+#else
+    my_addr = inet_addr(w);
+#endif
+    if (my_addr != ((unsigned long) 0xffffffff))
+    {
+       if (p != NULL) *p = ':';
+       return my_addr;
+    }
+
+    hep = gethostbyname(w);
+           
+    if ((!hep) || (hep->h_addrtype != AF_INET || !hep->h_addr_list[0])) {
+       fprintf (stderr, "Cannot resolve host name %s --- exiting!\n", w);
+       exit(1);
+    }
+           
+    if (hep->h_addr_list[1]) {
+       fprintf(stderr, "Host %s has multiple addresses ---\n", w);
+       fprintf(stderr, "you must choose one explicitly for use as\n");
+       fprintf(stderr, "a virtual host.  Exiting!!!\n");
+       exit(1);
+    }
+           
+    if (p != NULL) *p = ':';
+
+    return ((struct in_addr *)(hep->h_addr))->s_addr;
+}
+
+
+#ifdef NOTDEF    
+    
+char *get_remote_logname(FILE *fd) {
+    int len;
+    char *result;
+#if defined(NEXT) || defined(BSD4_4) || defined(SOLARIS2) || defined(LINUX) || defined(__EMX__)
+    struct sockaddr sa_server, sa_client;
+#else
+    struct sockaddr_in sa_server,sa_client;
+#endif
+
+    len = sizeof(sa_client);
+    if(getpeername(fileno(stdout),&sa_client,&len) != -1) {
+        len = sizeof(sa_server);
+        if(getsockname(fileno(stdout),&sa_server,&len) == -1)
+            result = "unknown";
+        else
+            result = rfc931((struct sockaddr_in *) & sa_client,
+                                    (struct sockaddr_in *) & sa_server);
+    }
+    else result = "unknown";
+
+    return result; /* robm=pinhead */
+}
+#endif    
+
+static char *find_fqdn(pool *a, struct hostent *p) {
+    int x;
+
+    if(ind(p->h_name,'.') == -1) {
+        for(x=0;p->h_aliases[x];++x) {
+            if((ind(p->h_aliases[x],'.') != -1) && 
+               (!strncmp(p->h_aliases[x],p->h_name,strlen(p->h_name))))
+                return pstrdup(a, p->h_aliases[x]);
+        }
+        return NULL;
+    } else return pstrdup(a, (void *)p->h_name);
+}
+
+char *get_local_host(pool *a)
+{
+    char str[128];
+    int len = 128;
+    char *server_hostname;
+
+    struct hostent *p;
+    gethostname(str, len);
+    if((!(p=gethostbyname(str))) || (!(server_hostname = find_fqdn(a, p)))) {
+        fprintf(stderr,"httpd: cannot determine local host name.\n");
+       fprintf(stderr,"Use ServerName to set it manually.\n");
+       exit(1);
+    }
+
+    return server_hostname;
+}
+
+/* aaaack but it's fast and const should make it shared text page. */
+const int pr2six[256]={
+    64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
+    64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,62,64,64,64,63,
+    52,53,54,55,56,57,58,59,60,61,64,64,64,64,64,64,64,0,1,2,3,4,5,6,7,8,9,
+    10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,64,64,64,64,64,64,26,27,
+    28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,
+    64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
+    64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
+    64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
+    64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
+    64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
+    64,64,64,64,64,64,64,64,64,64,64,64,64
+};
+
+char *uudecode(pool *p, char *bufcoded) {
+    int nbytesdecoded;
+    register unsigned char *bufin;
+    register char *bufplain;
+    register unsigned char *bufout;
+    register int nprbytes;
+    
+    /* Strip leading whitespace. */
+    
+    while(*bufcoded==' ' || *bufcoded == '\t') bufcoded++;
+    
+    /* Figure out how many characters are in the input buffer.
+     * Allocate this many from the per-transaction pool for the result.
+     */
+    bufin = (unsigned char *)bufcoded;
+    while(pr2six[*(bufin++)] <= 63);
+    nprbytes = (char *)bufin - bufcoded - 1;
+    nbytesdecoded = ((nprbytes+3)/4) * 3;
+
+    bufplain = palloc(p, nbytesdecoded + 1);
+    bufout = (unsigned char *)bufplain;
+    
+    bufin = (unsigned char *)bufcoded;
+    
+    while (nprbytes > 0) {
+        *(bufout++) = 
+            (unsigned char) (pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4);
+        *(bufout++) = 
+            (unsigned char) (pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2);
+        *(bufout++) = 
+            (unsigned char) (pr2six[bufin[2]] << 6 | pr2six[bufin[3]]);
+        bufin += 4;
+        nprbytes -= 4;
+    }
+    
+    if(nprbytes & 03) {
+        if(pr2six[bufin[-2]] > 63)
+            nbytesdecoded -= 2;
+        else
+            nbytesdecoded -= 1;
+    }
+    bufplain[nbytesdecoded] = '\0';
+    return bufplain;
+}
+
+#ifdef __EMX__
+void os2pathname(char *path) {
+    char newpath[MAX_STRING_LEN];
+    int loop;
+    int offset;
+
+    offset = 0;
+    for (loop=0; loop < (strlen(path) + 1); loop++) {
+        if (path[loop] == '/') {
+            newpath[offset] = '\\';
+            /*
+            offset = offset + 1;
+            newpath[offset] = '\\';
+            */
+        } else
+            newpath[offset] = path[loop];
+        offset = offset + 1;
+    };
+    /* Debugging code */
+    /* fprintf(stderr, "%s \n", newpath); */
+
+    strcpy(path, newpath);
+};
+#endif
+
+
+#ifdef NEED_STRERROR
+char *
+strerror (int err) {
+
+    char *p;
+    extern char *const sys_errlist[];
+
+    p = sys_errlist[err];
+    return (p);
+}
+#endif
diff --git a/RELEASE_1_1_X/src/main/util_md5.c b/RELEASE_1_1_X/src/main/util_md5.c
new file mode 100644 (file)
index 0000000..4d8fd1c
--- /dev/null
@@ -0,0 +1,193 @@
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+/************************************************************************
+ * NCSA HTTPd Server
+ * Software Development Group
+ * National Center for Supercomputing Applications
+ * University of Illinois at Urbana-Champaign
+ * 605 E. Springfield, Champaign, IL 61820
+ * httpd@ncsa.uiuc.edu
+ *
+ * Copyright  (C)  1995, Board of Trustees of the University of Illinois
+ *
+ ************************************************************************
+ *
+ * md5.c: NCSA HTTPd code which uses the md5c.c RSA Code
+ *
+ *  Original Code Copyright (C) 1994, Jeff Hostetler, Spyglass, Inc.
+ *  Portions of Content-MD5 code Copyright (C) 1993, 1994 by Carnegie Mellon
+ *     University (see Copyright below).
+ *  Portions of Content-MD5 code Copyright (C) 1991 Bell Communications 
+ *     Research, Inc. (Bellcore) (see Copyright below).
+ *  Portions extracted from mpack, John G. Myers - jgm+@cmu.edu
+ *  Content-MD5 Code contributed by Martin Hamilton (martin@net.lut.ac.uk)
+ *
+ */
+
+
+
+/* md5.c --Module Interface to MD5. */
+/* Jeff Hostetler, Spyglass, Inc., 1994. */
+
+#include "httpd.h"
+#include "util_md5.h"
+
+char *md5 (pool *p, unsigned char *string)
+{
+    MD5_CTX my_md5;
+    unsigned char hash[16];
+    char *r, result[33];
+    int i;
+       
+    /*
+     * Take the MD5 hash of the string argument.
+     */
+
+    MD5Init(&my_md5);
+    MD5Update(&my_md5, string, strlen((const char *)string));
+    MD5Final(hash, &my_md5);
+
+    for (i=0, r=result; i<16; i++, r+=2)
+        sprintf(r, "%02x", hash[i]);
+    *r = '\0';
+
+    return pstrdup(p, result);
+}
+
+/* these portions extracted from mpack, John G. Myers - jgm+@cmu.edu */
+
+/* (C) Copyright 1993,1994 by Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of Carnegie
+ * Mellon University not be used in advertising or publicity
+ * pertaining to distribution of the software without specific,
+ * written prior permission.  Carnegie Mellon University makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied
+ * warranty.
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/*
+ * Copyright (c) 1991 Bell Communications Research, Inc. (Bellcore)
+ *
+ * Permission to use, copy, modify, and distribute this material
+ * for any purpose and without fee is hereby granted, provided
+ * that the above copyright notice and this permission notice
+ * appear in all copies, and that the name of Bellcore not be
+ * used in advertising or publicity pertaining to this
+ * material without the specific, prior written permission
+ * of an authorized representative of Bellcore.  BELLCORE
+ * MAKES NO REPRESENTATIONS ABOUT THE ACCURACY OR SUITABILITY
+ * OF THIS MATERIAL FOR ANY PURPOSE.  IT IS PROVIDED "AS IS",
+ * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.  
+ */
+
+static char basis_64[] =
+   "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+char *md5contextTo64(pool *a, MD5_CTX *context)
+{
+    unsigned char digest[18];
+    char *encodedDigest;
+    int i;
+    char *p;
+
+    encodedDigest = (char *)pcalloc(a, 25 * sizeof(char));
+
+    MD5Final(digest, context);
+    digest[sizeof(digest)-1] = digest[sizeof(digest)-2] = 0;
+
+    p = encodedDigest;
+    for (i=0; i < sizeof(digest); i+=3) {
+        *p++ = basis_64[digest[i]>>2];
+        *p++ = basis_64[((digest[i] & 0x3)<<4) | ((int)(digest[i+1] & 0xF0)>>4)];
+        *p++ = basis_64[((digest[i+1] & 0xF)<<2) | ((int)(digest[i+2] & 0xC0)>>6)];
+        *p++ = basis_64[digest[i+2] & 0x3F];
+    }
+    *p-- = '\0';
+    *p-- = '=';
+    *p-- = '=';
+    return encodedDigest;
+}
+
+char *md5digest(pool *p, FILE *infile)
+{
+    MD5_CTX context;
+    unsigned char buf[1000];
+    long length = 0;
+    int nbytes;
+
+    MD5Init(&context);
+    while ((nbytes = fread(buf, 1, sizeof(buf), infile))) {
+        length += nbytes;
+        MD5Update(&context, buf, nbytes);
+    }
+    rewind(infile);
+    return md5contextTo64(p, &context);
+}
+
diff --git a/RELEASE_1_1_X/src/main/util_script.c b/RELEASE_1_1_X/src/main/util_script.c
new file mode 100644 (file)
index 0000000..05b3310
--- /dev/null
@@ -0,0 +1,364 @@
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+
+#include "httpd.h"
+#include "http_main.h"
+#include "http_log.h"
+#include "http_protocol.h"
+#include "http_core.h"         /* For document_root.  Sigh... */
+#include "http_request.h"       /* for sub_req_lookup_uri() */
+#include "util_script.h"
+
+/*
+ * Various utility functions which are common to a whole lot of
+ * script-type extensions mechanisms, and might as well be gathered
+ * in one place (if only to avoid creating inter-module dependancies
+ * where there don't have to be).
+ */
+#define MALFORMED_MESSAGE "malformed header from script. Bad header="
+#define MALFORMED_HEADER_LENGTH_TO_SHOW 30
+
+char **create_argv(pool *p, char *av0, char *args) {
+    register int x,n;
+    char **av;
+    char *w;
+
+    for(x=0,n=2;args[x];x++)
+        if(args[x] == '+') ++n;
+
+    av = (char **)palloc(p, (n+1)*sizeof(char *));
+    av[0] = av0;
+
+    for(x=1;x<n;x++) {
+        w = getword_nulls(p, &args, '+');
+        unescape_url(w);
+        av[x] = escape_shell_cmd(p, w);
+    }
+    av[n] = NULL;
+    return av;
+}
+
+static char *http2env(pool *a, char *w)
+{
+    char *res = pstrcat (a, "HTTP_", w, NULL);
+    char *cp = res;
+  
+    while (*++cp)
+      if (*cp == '-') *cp = '_';
+      else *cp = toupper(*cp);
+
+    return res;
+}
+
+char **create_environment(pool *p, table *t)
+{
+    array_header *env_arr = table_elts (t);
+    table_entry *elts = (table_entry *)env_arr->elts;
+    char **env = (char **)palloc (p, (env_arr->nelts + 2) *sizeof (char *));
+    int i, j;
+    char *tz;
+
+    j = 0;
+    tz = getenv("TZ");
+    if (tz!= NULL) env[j++] = pstrcat(p, "TZ=", tz, NULL);
+    for (i = 0; i < env_arr->nelts; ++i) {
+        if (!elts[i].key) continue;
+       env[j++] = pstrcat (p, elts[i].key, "=", elts[i].val, NULL);
+    }
+
+    env[j] = NULL;
+    return env;
+}
+
+void add_common_vars(request_rec *r)
+{
+    table *e = r->subprocess_env;
+    server_rec *s = r->server;
+    conn_rec *c = r->connection;
+    const char *rem_logname;
+    
+    char port[40],*env_path;
+    
+    array_header *hdrs_arr = table_elts (r->headers_in);
+    table_entry *hdrs = (table_entry *)hdrs_arr->elts;
+    int i;
+    
+    /* First, add environment vars from headers... this is as per
+     * CGI specs, though other sorts of scripting interfaces see
+     * the same vars...
+     */
+    
+    for (i = 0; i < hdrs_arr->nelts; ++i) {
+        if (!hdrs[i].key) continue;
+
+       /* A few headers are special cased --- Authorization to prevent
+        * rogue scripts from capturing passwords; content-type and -length
+        * for no particular reason.
+        */
+       
+       if (!strcasecmp (hdrs[i].key, "Content-type")) 
+           table_set (e, "CONTENT_TYPE", hdrs[i].val);
+       else if (!strcasecmp (hdrs[i].key, "Content-length"))
+           table_set (e, "CONTENT_LENGTH", hdrs[i].val);
+       else if (!strcasecmp (hdrs[i].key, "Authorization"))
+           continue;
+       else
+           table_set (e, http2env (r->pool, hdrs[i].key), hdrs[i].val);
+    }
+    
+    sprintf(port, "%d", s->port);
+
+    if(!(env_path = getenv("PATH")))
+        env_path=DEFAULT_PATH;
+    
+    table_set (e, "PATH", env_path);
+    table_set (e, "SERVER_SOFTWARE", SERVER_VERSION);
+    table_set (e, "SERVER_NAME", s->server_hostname);
+    table_set (e, "SERVER_PORT", port);
+    table_set (e, "REMOTE_HOST",
+              get_remote_host(c, r->per_dir_config, REMOTE_NAME));
+    table_set (e, "REMOTE_ADDR", c->remote_ip);
+    table_set (e, "DOCUMENT_ROOT", document_root(r)); /* Apache */
+    table_set (e, "SERVER_ADMIN", s->server_admin); /* Apache */
+    table_set (e, "SCRIPT_FILENAME", r->filename); /* Shambhala */
+    
+    if (c->user) table_set(e, "REMOTE_USER", c->user);
+    if (c->auth_type) table_set(e, "AUTH_TYPE", c->auth_type);
+    rem_logname = get_remote_logname(r);
+    if (rem_logname) table_set(e, "REMOTE_IDENT", rem_logname);
+    
+    /* Apache custom error responses. If we have redirected set two new vars */
+    
+    if (r->prev) {
+        if (r->prev->args) table_set(e,"REDIRECT_QUERY_STRING", r->prev->args);
+       if (r->prev->uri) table_set (e, "REDIRECT_URL", r->prev->uri);
+    }
+}
+
+
+void add_cgi_vars(request_rec *r)
+{
+    table *e = r->subprocess_env;
+
+    table_set (e, "GATEWAY_INTERFACE","CGI/1.1");
+    table_set (e, "SERVER_PROTOCOL", r->protocol);
+    table_set (e, "REQUEST_METHOD", r->method);
+    table_set (e, "QUERY_STRING", r->args ? r->args : "");
+    
+    /* Note that the code below special-cases scripts run from includes,
+     * because it "knows" that the sub_request has been hacked to have the
+     * args and path_info of the original request, and not any that may have
+     * come with the script URI in the include command.  Ugh.
+     */
+    
+    if (!r->path_info || !*r->path_info || !strcmp (r->protocol, "INCLUDED")) {
+        table_set (e, "SCRIPT_NAME", r->uri);
+    } else {
+        int path_info_start = strlen (r->uri) - strlen (r->path_info);
+       
+       r->uri[path_info_start] = '\0';
+       table_set (e, "SCRIPT_NAME", r->uri);
+       r->uri[path_info_start] = '/';
+    }
+       
+    if (r->path_info && r->path_info[0]) {
+       /*
+        * To get PATH_TRANSLATED, treat PATH_INFO as a URI path.
+        * Need to re-escape it for this, since the entire URI was
+        * un-escaped before we determined where the PATH_INFO began.
+        */
+       request_rec *pa_req = sub_req_lookup_uri(
+                                   escape_uri(r->pool, r->path_info), r);
+      
+        table_set (e, "PATH_INFO", r->path_info);
+
+       /* Don't bother destroying pa_req --- it's only created in
+        * child processes which are about to jettison their address
+        * space anyway.  BTW, we concatenate filename and path_info
+        * from the sub_request to be compatible in case the PATH_INFO
+        * is pointing to an object which doesn't exist.
+        */
+       
+       if (pa_req->filename)
+           table_set (e, "PATH_TRANSLATED",
+                      pstrcat (r->pool, pa_req->filename, pa_req->path_info,
+                               NULL));
+    }
+}
+
+int scan_script_header(request_rec *r, FILE *f)
+{
+    char w[MAX_STRING_LEN];
+    char *l;
+    int p;
+
+    hard_timeout ("read script header", r);
+    
+    while(1) {
+
+       if (fgets(w, MAX_STRING_LEN-1, f) == NULL) {
+           log_reason ("Premature end of script headers", r->filename, r);
+           return SERVER_ERROR;
+        }
+
+       /* Delete terminal (CR?)LF */
+       
+       p = strlen(w);
+       if (p > 0 && w[p-1] == '\n')
+       {
+           if (p > 1 && w[p-2] == '\015') w[p-2] = '\0';
+           else w[p-1] = '\0';
+       }
+
+        if(w[0] == '\0') {
+           kill_timeout (r);
+           return OK;
+       }
+                                   
+       /* if we see a bogus header don't ignore it. Shout and scream */
+       
+        if(!(l = strchr(w,':'))) {
+           char malformed[(sizeof MALFORMED_MESSAGE)+1+MALFORMED_HEADER_LENGTH_TO_SHOW];
+            strcpy(malformed, MALFORMED_MESSAGE);
+            strncat(malformed, w, MALFORMED_HEADER_LENGTH_TO_SHOW);
+            /* Soak up all the script output --- may save an outright kill */
+           while (fgets(w, MAX_STRING_LEN-1, f) != NULL)
+               continue;
+           
+           kill_timeout (r);
+           log_reason (malformed, r->filename, r);
+           return SERVER_ERROR;
+        }
+
+        *l++ = '\0';
+       while (*l && isspace (*l)) ++l;
+       
+        if(!strcasecmp(w,"Content-type")) {
+
+           /* Nuke trailing whitespace */
+           
+           char *endp = l + strlen(l) - 1;
+           while (endp > l && isspace(*endp)) *endp-- = '\0';
+           
+           r->content_type = pstrdup (r->pool, l);
+       }
+        else if(!strcasecmp(w,"Status")) {
+            sscanf(l, "%d", &r->status);
+            r->status_line = pstrdup(r->pool, l);
+        }
+        else if(!strcasecmp(w,"Location")) {
+           table_set (r->headers_out, w, l);
+        }   
+
+/* The HTTP specification says that it is legal to merge duplicate
+ * headers into one.  Some browsers that support Cookies don't like
+ * merged headers and prefer that each Set-Cookie header is sent
+ * separately.  Lets humour those browsers.
+ */
+       else if(!strcasecmp(w, "Set-Cookie")) {
+           table_add(r->err_headers_out, w, l);
+       }
+        else {
+           table_merge (r->err_headers_out, w, l);
+        }
+    }
+}
+
+void send_size(size_t size, request_rec *r) {
+    char ss[20];
+
+    if(size == -1) 
+        strcpy(ss, "    -");
+    else if(!size) 
+        strcpy(ss, "   0k");
+    else if(size < 1024) 
+        strcpy(ss, "   1k");
+    else if(size < 1048576)
+        sprintf(ss, "%4dk", size / 1024);
+    else
+        sprintf(ss, "%4dM", size / 1048576);
+    rputs(ss, r);
+}
+
+#ifdef __EMX__
+char **create_argv_cmd(pool *p, char *av0, char *args, char *path) {
+    register int x,n;
+    char **av;
+    char *w;
+
+    for(x=0,n=2;args[x];x++)
+        if(args[x] == '+') ++n;
+
+    /* Add extra strings to array. */
+    n = n + 2;
+
+    av = (char **)palloc(p, (n+1)*sizeof(char *));
+    av[0] = av0;
+
+    /* Now insert the extra strings we made room for above. */
+    av[1] = strdup("/C");
+    av[2] = strdup(path);
+
+    for(x=(1+2);x<n;x++) {
+        w = getword(p, &args, '+');
+        unescape_url(w);
+        av[x] = escape_shell_cmd(p, w);
+    }
+    av[n] = NULL;
+    return av;
+}
+#endif
+
diff --git a/RELEASE_1_1_X/src/mod_ai_backcompat.c b/RELEASE_1_1_X/src/mod_ai_backcompat.c
new file mode 100644 (file)
index 0000000..834d4cb
--- /dev/null
@@ -0,0 +1,94 @@
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_core.h"
+
+/* Why are you even thinking about using this? */
+
+int ai_backcompat_kludge (request_rec *r)
+{
+    if (r->method_number != M_GET ||
+       (r->args && r->args[0]) || (r->path_info && r->path_info[0]))
+    {
+        char *doit_filename = pstrcat (r->pool, r->filename, ".doit", NULL);
+       struct stat finfo;
+
+       if (stat (doit_filename, &finfo) >= 0) {
+           r->filename = doit_filename;
+           r->finfo = finfo;
+       }
+    }
+    
+    return DECLINED;
+}
+
+module ai_backcompat_module = {
+   STANDARD_MODULE_STUFF,
+   NULL,                       /* initializer */
+   NULL,                       /* dir config creater */
+   NULL,                       /* dir merger --- default is to override */
+   NULL,                       /* server config */
+   NULL,                       /* merge server config */
+   NULL,                       /* command table */
+   NULL,                       /* handlers */
+   NULL,                       /* filename translation */
+   NULL,                       /* check_user_id */
+   NULL,                       /* check auth */
+   NULL,                       /* check access */
+   ai_backcompat_kludge,       /* type_checker */
+   NULL,                       /* fixups */
+   NULL                                /* logger */
+};
diff --git a/RELEASE_1_1_X/src/mod_cookies.c b/RELEASE_1_1_X/src/mod_cookies.c
new file mode 100644 (file)
index 0000000..241c10b
--- /dev/null
@@ -0,0 +1,299 @@
+
+/* ====================================================================
+ * Copyright (c) 1995, 1996 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/* User Tracking Module
+ *
+ * This Apache module is designed to track users paths through a site.
+ * It uses the client-side state ("Cookie") protocol developed by Netscape.
+ * It is known to work on Netscape browsers, Microsoft Internet 
+ * Explorer and others currently being developed.
+ *
+ * Each time a page is requested we look to see if the browser is sending
+ * us a Cookie: header that we previously generated.
+ *
+ * If we don't find one then the user hasn't been to this site since
+ * starting their browser or their browser doesn't support cookies.  So
+ * we generate a unique Cookie for the transaction and send it back to
+ * the browser (via a "Set-Cookie" header)
+ * Future requests from the same browser should keep the same Cookie line.
+ *
+ * The cookie and request are logged to a file.  Use the directive
+ * "CookieLog somefilename" in one of the config files to enable the Cookie
+ * module.  By matching up all the requests with the same cookie you can
+ * work out exactly what path a user took through your site.
+ *
+ * Notes:
+ * 1.  This code doesn't log the initial transaction (the one that created
+ *     the cookie to start with).  If it did then the cookie log file would
+ *     be bigger than a normal access log.
+ * 2.  This module has been designed to not interfere with other Cookies
+ *     your site may be using; just avoid sending out cookies with
+ *     the name "Apache=" or things will get confused.
+ * 3.  If you want you can modify the Set-Cookie line so that the Cookie
+ *     never expires.  You would then get the same Cookie each time the
+ *     user revisits your site.
+ *
+ * Mark Cox, mark@ukweb.com, http://www.ukweb.com/~mark/, 6 July 95
+ *
+ * 6.12.95 MJC Now be more friendly.  Allow our cookies to overlap with
+ *             others the site may be using.  Use a more descriptive 
+ *             cookie name.
+ *
+ * 18.3.96 MJC Generate cookies for EVERY request no matter what the 
+ *             browser.  We never know when a new browser writer will
+ *             add cookie support.
+ *
+ * 96/03/31 -JimC Allow the log to be sent to a pipe.  Copies the relevant
+ *                code from mod_log_agent.c.
+ *
+ * 24.5.96 MJC Improved documentation after receiving comments from users
+ */
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_core.h"
+#include <sys/time.h>
+
+module cookies_module;
+
+typedef struct {
+    char *fname;
+    int log_fd;
+    int always;
+} cookie_log_state;
+
+/* Make Cookie: Now we have to generate something that is going to be
+ * pretty unique.  We can base it on the pid, time, hostip */
+
+#define COOKIE_NAME "Apache="
+
+void make_cookie(request_rec *r)
+{
+    struct timeval tv;
+    char new_cookie[100];      /* blurgh */
+    char *dot;
+    const char *rname = pstrdup(r->pool, 
+                               get_remote_host(r->connection, r->per_dir_config,
+                                               REMOTE_NAME));
+    
+    struct timezone tz = { 0 , 0 };
+
+    if ((dot = strchr(rname,'.'))) *dot='\0';  /* First bit of hostname */
+    gettimeofday(&tv, &tz);
+    sprintf(new_cookie,"%s%s%d%ld%d; path=/",
+        COOKIE_NAME, rname,
+        (int)getpid(),  
+        (long)tv.tv_sec, (int)tv.tv_usec/1000 );
+
+    table_set(r->headers_out,"Set-Cookie",new_cookie);
+    return;
+}
+
+int spot_cookie(request_rec *r)
+{
+    char *cookie;
+
+    if ((cookie = table_get (r->headers_in, "Cookie")))
+        if (strstr(cookie,COOKIE_NAME))
+            return DECLINED;          /* Theres already a cookie, no new one */
+    make_cookie(r);
+    return OK;                        /* We set our cookie */
+}
+
+static int cookie_flags = ( O_WRONLY | O_APPEND | O_CREAT );
+
+#ifdef __EMX__
+/* OS/2 lacks support for users and groups */
+static mode_t cookie_mode = ( S_IREAD | S_IWRITE );
+#else
+static mode_t cookie_mode = ( S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH );
+#endif
+
+void *make_cookie_log_state (pool *p, server_rec *s)
+{
+    cookie_log_state *cls =
+      (cookie_log_state *)palloc (p, sizeof (cookie_log_state));
+
+    cls->fname = "";
+    cls->log_fd = -1;
+
+    return (void *)cls;
+}
+
+char *set_cookie_log (cmd_parms *parms, void *dummy, char *arg)
+{
+    cookie_log_state *cls = get_module_config (parms->server->module_config,
+                           &cookies_module);
+    cls->fname = arg;
+    return NULL;
+}
+
+command_rec cookie_log_cmds[] = {
+{ "CookieLog", set_cookie_log, NULL, RSRC_CONF, TAKE1,
+    "the filename of the cookie log" },
+{ NULL }
+};
+
+void cookie_log_child (void *cmd)
+{
+    /* Child process code for 'CookieLog "|..."';
+     * may want a common framework for this, since I expect it will
+     * be common for other foo-loggers to want this sort of thing...
+     */
+    
+    cleanup_for_exec();
+    signal (SIGHUP, SIG_IGN);
+    execl (SHELL_PATH, SHELL_PATH, "-c", (char *)cmd, NULL);
+    exit (1);
+}
+
+void open_cookie_log (server_rec *s, pool *p)
+{
+    cookie_log_state *cls = get_module_config (s->module_config,
+                           &cookies_module);
+    char *fname = server_root_relative (p, cls->fname);
+
+    if (cls->log_fd > 0) return; 
+
+    if (*cls->fname == '|') {
+      FILE *dummy;
+      
+      spawn_child(p, cookie_log_child, (void *)(cls->fname+1),
+                kill_after_timeout, &dummy, NULL);
+      
+      if (dummy == NULL) {
+      fprintf (stderr, "Couldn't fork child for CookieLog process\n");
+      exit (1);
+      }
+      
+      cls->log_fd = fileno (dummy);
+    }
+    else if(*cls->fname != '\0') {
+      if((cls->log_fd = popenf(p, fname, cookie_flags, cookie_mode)) < 0) {
+       fprintf(stderr, "httpd: could not open cookie log file %s.\n", fname);
+       perror("open");
+       exit(1);
+      }
+    }
+}
+
+void init_cookie_log (server_rec *s, pool *p)
+{
+    for (; s; s = s->next) open_cookie_log (s, p);
+}
+
+int cookie_log_transaction(request_rec *orig)
+{
+    cookie_log_state *cls = get_module_config (orig->server->module_config,
+                           &cookies_module);
+    char *str;
+    long timz;
+    struct tm *t;
+    char tstr[MAX_STRING_LEN],sign;
+    request_rec *r;
+    char *cookie,*cookiebuf,*cookieend;
+    char *value;
+
+    for (r = orig; r->next; r = r->next)
+        continue;
+    if (*cls->fname == '\0')   /* Don't log cookies */
+      return DECLINED;
+
+    if (!(cookie = table_get (r->headers_in, "Cookie")))
+        return DECLINED;    /* Theres no cookie, don't bother logging */
+    value=strstr(cookie,COOKIE_NAME);
+    if (!value) /* Only log cookies we generated! */
+        return DECLINED;
+    value+=strlen(COOKIE_NAME);
+    cookiebuf=pstrdup( r->pool, value );
+    cookieend=strchr(cookiebuf,';');
+    if (cookieend) *cookieend='\0';    /* Ignore anything after a ; */
+
+    t = get_gmtoff(&timz);
+    sign = (timz < 0 ? '-' : '+');
+    if(timz < 0) 
+        timz = -timz;
+
+    strftime(tstr,MAX_STRING_LEN,"\" [%d/%b/%Y:%H:%M:%S ",t);
+    if (r->status != -1)
+       sprintf(&tstr[strlen(tstr)], "%c%02ld%02ld] %d\n", sign, timz/3600,
+               timz%3600, r->status);
+       sprintf(&tstr[strlen(tstr)], "%c%02ld%02ld] -\n", sign, timz/3600,
+               timz%3600);
+
+    str = pstrcat(orig->pool, cookiebuf, " \"", orig->the_request, tstr, NULL);
+    
+    write(cls->log_fd, str, strlen(str));
+
+    return OK;
+}
+
+
+module cookies_module = {
+   STANDARD_MODULE_STUFF,
+   init_cookie_log,                            /* initializer */
+   NULL,                                               /* dir config creater */
+   NULL,                                               /* dir merger --- default is to override */
+   make_cookie_log_state,              /* server config */
+   NULL,                                               /* merge server configs */
+   cookie_log_cmds,                            /* command table */
+   NULL,                                               /* handlers */
+   NULL,                                               /* filename translation */
+   NULL,                                               /* check_user_id */
+   NULL,                                               /* check auth */
+   NULL,                                               /* check access */
+   NULL,                                               /* type_checker */
+   spot_cookie,                                        /* fixups */
+   cookie_log_transaction,             /* logger */
+};
diff --git a/RELEASE_1_1_X/src/mod_log_common.c b/RELEASE_1_1_X/src/mod_log_common.c
new file mode 100644 (file)
index 0000000..a18d976
--- /dev/null
@@ -0,0 +1,220 @@
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+
+#include "httpd.h"
+#include "http_core.h"
+#include "http_config.h"
+
+module common_log_module;
+
+static int xfer_flags = ( O_WRONLY | O_APPEND | O_CREAT );
+
+#ifdef __EMX__
+/* OS/2 lacks support for users and groups */
+static mode_t xfer_mode = ( S_IREAD | S_IWRITE );
+#else
+static mode_t xfer_mode = ( S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH );
+#endif
+
+typedef struct {
+    char *fname;
+    int log_fd;
+} common_log_state;
+
+void *make_common_log_state (pool *p, server_rec *s)
+{
+    common_log_state *cls =
+      (common_log_state *)palloc (p, sizeof (common_log_state));
+
+    cls->fname = DEFAULT_XFERLOG;
+    cls->log_fd = -1;
+
+    return (void *)cls;
+}
+
+char *set_common_log (cmd_parms *parms, void *dummy, char *arg)
+{
+    common_log_state *cls = get_module_config (parms->server->module_config,
+                                              &common_log_module);
+  
+    cls->fname = arg;
+    return NULL;
+}
+
+command_rec common_log_cmds[] = {
+{ "TransferLog", set_common_log, NULL, RSRC_CONF, TAKE1,
+    "the filename of the access log" },
+{ NULL }
+};
+
+void common_log_child (void *cmd)
+{
+    /* Child process code for 'TransferLog "|..."';
+     * may want a common framework for this, since I expect it will
+     * be common for other foo-loggers to want this sort of thing...
+     */
+    
+    cleanup_for_exec();
+    signal (SIGHUP, SIG_IGN);
+    execl (SHELL_PATH, SHELL_PATH, "-c", (char *)cmd, NULL);
+    fprintf (stderr, "Exec of shell for logging failed!!!\n");
+    exit (1);
+}
+
+void open_common_log (server_rec *s, pool *p)
+{
+    common_log_state *cls = get_module_config (s->module_config,
+                                              &common_log_module);
+  
+    char *fname = server_root_relative (p, cls->fname);
+    
+    if (cls->log_fd > 0) return; /* virtual log shared w/main server */
+    
+    if (*cls->fname == '|') {
+       FILE *dummy;
+       
+       spawn_child(p, common_log_child, (void *)(cls->fname+1),
+                   kill_after_timeout, &dummy, NULL);
+
+       if (dummy == NULL) {
+           fprintf (stderr, "Couldn't fork child for TransferLog process\n");
+           exit (1);
+       }
+
+       cls->log_fd = fileno (dummy);
+    }
+    else if((cls->log_fd = popenf(p, fname, xfer_flags, xfer_mode)) < 0) {
+        fprintf(stderr,"httpd: could not open transfer log file %s.\n", fname);
+        perror("open");
+        exit(1);
+    }
+}
+
+void init_common_log (server_rec *s, pool *p)
+{
+    for (; s; s = s->next) open_common_log (s, p);
+}
+
+int common_log_transaction(request_rec *orig)
+{
+    common_log_state *cls = get_module_config (orig->server->module_config,
+                                              &common_log_module);
+  
+    char *str;
+    long timz;
+    struct tm *t;
+    const char *rem_logname;
+    char tstr[MAX_STRING_LEN], status[MAX_STRING_LEN], sign;
+    conn_rec *c = orig->connection;
+    request_rec *r;
+
+    /* Common log format records an unholy melange of the original request
+     * and whatever it was that we actually served.  Just stay compatible
+     * here; the whole point of the module scheme is to allow people to
+     * create better alternatives, but screwing up is an option we wish
+     * to preserve...
+     */
+    
+    for (r = orig; r->next; r = r->next)
+        continue;
+
+    t = get_gmtoff(&timz);
+    sign = (timz < 0 ? '-' : '+');
+    if(timz < 0) 
+        timz = -timz;
+
+    sprintf(tstr, " [%.2d/%s/%d:%.2d:%.2d:%.2d %c%02ld%02ld] \"", t->tm_mday,
+           month_snames[t->tm_mon], t->tm_year + 1900, t->tm_hour, t->tm_min,
+           t->tm_sec, sign, timz/3600, timz%3600);
+
+    if (r->status != -1) sprintf(status,"%d ", r->status);
+    else                 strcpy(status, "- ");
+
+    if (r->bytes_sent > 0) 
+       sprintf(&status[strlen(status)], "%ld\n", r->bytes_sent);
+    else
+        strcat(status, "-\n");
+
+    rem_logname = get_remote_logname(r);
+    if (rem_logname == NULL) rem_logname = "-";
+
+    str = pstrcat(orig->pool,
+                 get_remote_host(c, r->per_dir_config, REMOTE_NAME), " ",
+                 rem_logname, " ", (c->user != NULL ? c->user : "-"), tstr, 
+                 (orig->the_request != NULL ? orig->the_request : "NULL"), 
+                 "\" ", status, NULL);
+    
+    write(cls->log_fd, str, strlen(str));
+
+    return OK;
+}
+
+module common_log_module = {
+   STANDARD_MODULE_STUFF,
+   init_common_log,            /* initializer */
+   NULL,                       /* create per-dir config */
+   NULL,                       /* merge per-dir config */
+   make_common_log_state,      /* server config */
+   NULL,                       /* merge server config */
+   common_log_cmds,            /* command table */
+   NULL,                       /* handlers */
+   NULL,                       /* filename translation */
+   NULL,                       /* check_user_id */
+   NULL,                       /* check auth */
+   NULL,                       /* check access */
+   NULL,                       /* type_checker */
+   NULL,                       /* fixups */
+   common_log_transaction      /* logger */
+};
diff --git a/RELEASE_1_1_X/src/mod_proxy.c b/RELEASE_1_1_X/src/mod_proxy.c
new file mode 100644 (file)
index 0000000..9eb695c
--- /dev/null
@@ -0,0 +1,3262 @@
+/* ====================================================================
+ * Copyright (c) 1996 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+/*
+Note that the Explain() stuff is not yet complete.
+Also note numerous FIXMEs and CHECKMEs which should be eliminated.
+
+If TESTING is set, then garbage collection doesn't delete ... probably a good
+idea when hacking.
+
+This code is still experimental!
+
+Things to do:
+
+1. Make it garbage collect in the background, not while someone is waiting for
+a response!
+
+2. Check the logic thoroughly.
+
+3. Empty directories are only removed the next time round (but this does avoid
+two passes). Consider doing them the first time round.
+
+Ben Laurie <ben@algroup.co.uk> 30 Mar 96
+
+More changes:
+
+0) tested w/SOCKS proxy for http
+1) fixed IP address formation in host2addr()
+2) fixed SIGALRM on big cache cleanup
+3) fixed temp files #tmp not removed
+4) changed PF_INET to AF_INET in socket() calls
+5) installed CONNECT code from Troy Morrison <spiffnet@zoom.com> for testing
+6) added NoCache config directive to disallow caching for selected hosts
+
+Chuck Murcko <chuck@telebase.com> 2 Jun 96
+
+*/
+
+#define TESTING        0
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_log.h"
+#include "http_main.h"
+#include "http_protocol.h"
+
+#include "md5.h"
+
+#include <utime.h>
+
+#include "explain.h"
+
+DEF_Explain
+
+#define        SEC_ONE_DAY             86400   /* one day, in seconds */
+#define        SEC_ONE_HR              3600    /* one hour, in seconds */
+
+#define        DEFAULT_FTP_DATA_PORT   20
+#define        DEFAULT_FTP_PORT        21
+#define        DEFAULT_GOPHER_PORT     70
+#define        DEFAULT_NNTP_PORT       119
+#define        DEFAULT_WAIS_PORT       210
+#define        DEFAULT_HTTPS_PORT      443
+#define        DEFAULT_SNEWS_PORT      563
+#define        DEFAULT_PROSPERO_PORT   1525    /* WARNING: conflict w/Oracle */
+
+/* Some WWW schemes and their default ports; this is basically /etc/services */
+static struct
+{
+    const char *scheme;
+    int port;
+} defports[]={
+    { "ftp",      DEFAULT_FTP_PORT},
+    { "gopher",   DEFAULT_GOPHER_PORT},
+    { "http",     DEFAULT_PORT},
+    { "nntp",     DEFAULT_NNTP_PORT},
+    { "wais",     DEFAULT_WAIS_PORT},
+    { "https",    DEFAULT_HTTPS_PORT},
+    { "snews",    DEFAULT_SNEWS_PORT},
+    { "prospero", DEFAULT_PROSPERO_PORT},
+    { NULL, -1}  /* unknown port */
+};
+
+
+/* static information about a remote proxy */
+struct proxy_remote
+{
+    const char *scheme;    /* the schemes handled by this proxy, or '*' */
+    const char *protocol;  /* the scheme used to talk to this proxy */
+    const char *hostname;  /* the hostname of this proxy */
+    int port;              /* the port for this proxy */
+};
+
+struct proxy_alias {
+    char *real;
+    char *fake;
+};
+
+struct nocache_entry {
+    char *name;
+};
+
+#define DEFAULT_CACHE_SPACE 5
+#define DEFAULT_CACHE_MAXEXPIRE SEC_ONE_DAY
+#define DEFAULT_CACHE_EXPIRE    SEC_ONE_HR
+#define DEFAULT_CACHE_LMFACTOR (0.1)
+
+/* static information about the local cache */
+struct cache_conf
+{
+    const char *root;   /* the location of the cache directory */
+    int space;          /* Maximum cache size (in 1024 bytes) */
+    int maxexpire;      /* Maximum time to keep cached files in secs */
+    int defaultexpire;  /* default time to keep cached file in secs */
+    double lmfactor;    /* factor for estimating expires date */
+    int gcinterval;     /* garbage collection interval, in seconds */
+    int dirlevels;     /* Number of levels of subdirectories */
+    int dirlength;     /* Length of subdirectory names */
+};
+
+typedef struct
+{
+
+    struct cache_conf cache;  /* cache configuration */
+    array_header *proxies;
+    array_header *aliases;
+    array_header *nocaches;
+    int req;                 /* true if proxy requests are enabled */
+} proxy_server_conf;
+
+/*
+ * A Web proxy module. Stages:
+ *
+ *  translate_name: set filename to proxy:<URL>
+ *  type_checker:   set type to PROXY_MAGIC_TYPE if filename begins proxy:
+ *  fix_ups:        convert the URL stored in the filename to the
+ *                  canonical form.
+ *  handler:        handle proxy requests
+ */
+
+struct hdr_entry
+{
+    char *field;
+    char *value;
+};
+
+/* caching information about a request */
+struct cache_req
+{
+    request_rec *req;  /* the request */
+    char *url;         /* the URL requested */
+    char *filename;    /* name of the cache file, or NULL if no cache */
+    char *tempfile;    /* name of the temporary file, of NULL if not caching */
+    time_t ims;        /* if-modified-since date of request; -1 if no header */
+    BUFF *fp;          /* the cache file descriptor if the file is cached
+                          and may be returned, or NULL if the file is
+                          not cached (or must be reloaded) */
+    time_t expire;      /* calculated expire date of cached entity */
+    time_t lmod;        /* last-modified date of cached entity */
+    time_t date;        /* the date the cached file was last touched */
+    int version;        /* update count of the file */
+    unsigned int len;   /* content length */
+    char *protocol;     /* Protocol, and major/minor number, e.g. HTTP/1.1 */
+    int status;         /* the status of the cached file */
+    char *resp_line;    /* the whole status like (protocol, code + message) */
+    array_header *hdrs; /* the HTTP headers of the file */
+};
+      
+
+extern module proxy_module;
+
+
+static int http_canon(request_rec *r, char *url, const char *scheme,
+                     int def_port);
+static int ftp_canon(request_rec *r, char *url);
+
+static int http_handler(request_rec *r, struct cache_req *c, char *url,
+                       const char *proxyhost, int proxyport);
+static int ftp_handler(request_rec *r, struct cache_req *c, char *url);
+
+static int connect_handler(request_rec *r, struct cache_req *c, char *url);
+
+static BUFF *cache_error(struct cache_req *r);
+
+/* -------------------------------------------------------------- */
+/* Translate the URL into a 'filename' */
+
+static int
+alias_match(char *uri, char *alias_fakename)
+{
+    char *end_fakename = alias_fakename + strlen (alias_fakename);
+    char *aliasp = alias_fakename, *urip = uri;
+
+    while (aliasp < end_fakename)
+    {
+       if (*aliasp == '/')
+       {
+           /* any number of '/' in the alias matches any number in
+            * the supplied URI, but there must be at least one...
+            */
+           if (*urip != '/') return 0;
+           
+           while (*aliasp == '/') ++ aliasp;
+           while (*urip == '/') ++ urip;
+       }
+       else {
+           /* Other characters are compared literally */
+           if (*urip++ != *aliasp++) return 0;
+       }
+    }
+
+    /* Check last alias path component matched all the way */
+
+    if (aliasp[-1] != '/' && *urip != '\0' && *urip != '/')
+       return 0;
+
+    /* Return number of characters from URI which matched (may be
+     * greater than length of alias, since we may have matched
+     * doubled slashes)
+     */
+
+    return urip - uri;
+}
+
+static int
+proxy_trans(request_rec *r)
+{
+    void *sconf = r->server->module_config;
+    proxy_server_conf *conf =
+        (proxy_server_conf *)get_module_config(sconf, &proxy_module);
+
+    if (r->proxyreq)
+    {
+       if (!conf->req) return DECLINED;
+       
+       r->filename = pstrcat(r->pool, "proxy:", r->uri, NULL);
+       r->handler = "proxy-server";
+       return OK;
+    } else
+    {
+       int i, len;
+       struct proxy_alias *ent=(struct proxy_alias *)conf->aliases->elts;
+
+       for (i=0; i < conf->aliases->nelts; i++)
+       {
+           len = alias_match(r->uri, ent[i].fake);
+
+           if (len > 0)
+           {
+               r->filename = pstrcat(r->pool, "proxy:", ent[i].real,
+                                     r->uri + len, NULL);
+               r->handler = "proxy-server";
+               return OK;
+           }
+       }
+       return DECLINED;
+    }
+}
+
+/* -------------------------------------------------------------- */
+/* Fixup the filename */
+
+/*
+ * Canonicalise the URL
+ */
+static int
+proxy_fixup(request_rec *r)
+{
+    char *url, *p;
+    int i;
+
+    if (strncmp(r->filename, "proxy:", 6) != 0) return DECLINED;
+
+    url = &r->filename[6];
+/* lowercase the scheme */
+    p = strchr(url, ':');
+    if (p == NULL || p == url) return BAD_REQUEST;
+    for (i=0; i != p - url; i++) url[i] = tolower(url[i]);
+
+/* canonicalise each specific scheme */
+    if (strncmp(url, "http:", 5) == 0)
+       return http_canon(r, url+5, "http", DEFAULT_PORT);
+    else if (strncmp(url, "ftp:", 4) == 0) return ftp_canon(r, url+4);
+    else return OK; /* otherwise; we've done the best we can */
+}
+
+/* already called in the knowledge that the characters are hex digits */
+static int
+hex2c(const char *x)
+{
+    int i, ch;
+
+    ch = x[0];
+    if (isdigit(ch)) i = ch - '0';
+    else if (isupper(ch)) i = ch - ('A' - 10);
+    else i = ch - ('a' - 10);
+    i <<= 4;
+
+    ch = x[1];
+    if (isdigit(ch)) i += ch - '0';
+    else if (isupper(ch)) i += ch - ('A' - 10);
+    else i += ch - ('a' - 10);
+    return i;
+}
+
+
+static void
+c2hex(int ch, char *x)
+{
+    int i;
+
+    x[0] = '%';
+    i = (ch & 0xF0) >> 4;
+    if (i >= 10) x[1] = ('A' - 10) + i;
+    else x[1] = '0' + i;
+
+    i = ch & 0x0F;
+    if (i >= 10) x[2] = ('A' - 10) + i;
+    else x[2] = '0' + i;
+}
+
+/*
+ * canonicalise a URL-encoded string
+ */
+
+enum enctype { enc_path, enc_search, enc_user, enc_fpath, enc_parm };
+
+/*
+ * Decodes a '%' escaped string, and returns the number of characters
+ */
+static int
+decodeenc(char *x)
+{
+    int i, j, ch;
+
+    if (x[0] == '\0') return 0; /* special case for no characters */
+    for (i=0, j=0; x[i] != '\0'; i++, j++)
+    {
+/* decode it if not already done */
+       ch = x[i];
+       if ( ch == '%' && isxdigit(x[i+1]) && isxdigit(x[i+2]))
+       {
+           ch = hex2c(&x[i+1]);
+           i += 2;
+       }
+       x[j] = ch;
+    }
+    x[j] = '\0';
+    return j;
+}
+
+
+/*
+ * Convert a URL-encoded string to canonical form.
+ * It decodes characters which need not be encoded,
+ * and encodes those which must be encoded, and does not touch
+ * those which must not be touched.
+ */
+static char *
+canonenc(pool *p, const char *x, int len, enum enctype t, int isenc)
+{
+    int i, j, ispath, ch;
+    char *y;
+    const char *allowed;  /* characters which should not be encoded */
+    const char *reserved;  /* characters which much not be en/de-coded */
+
+/* N.B. in addition to :@&=, this allows ';' in an http path
+ * and '?' in an ftp path -- this may be revised
+ * 
+ * Also, it makes a '+' character in a search string reserved, as
+ * it may be form-encoded. (Although RFC 1738 doesn't allow this -
+ * it only permits ; / ? : @ = & as reserved chars.)
+ */
+    if (t == enc_path) allowed = "$-_.+!*'(),;:@&=";
+    else if (t == enc_search) allowed = "$-_.!*'(),;:@&=";
+    else if (t == enc_user) allowed = "$-_.+!*'(),;@&=";
+    else if (t == enc_fpath) allowed = "$-_.+!*'(),?:@&=";
+    else /* if (t == enc_parm) */ allowed = "$-_.+!*'(),?/:@&=";
+
+    if (t == enc_path) reserved = "/";
+    else if (t == enc_search) reserved = "+";
+    else reserved = "";
+
+    y = palloc(p, 3*len+1);
+    ispath = (t == enc_path);
+
+    for (i=0, j=0; i < len; i++, j++)
+    {
+/* always handle '/' first */
+       ch = x[i];
+       if (ind(reserved, ch) != -1)
+       {
+           y[j] = ch;
+           continue;
+       }
+/* decode it if not already done */
+       if (isenc && ch == '%')
+       {
+           if (!isxdigit(x[i+1]) || !isxdigit(x[i+2]))
+               return NULL;
+           ch = hex2c(&x[i+1]);
+           i += 2;
+           if (ch != 0 && ind(reserved, ch) != -1)
+           {  /* keep it encoded */
+               c2hex(ch, &y[j]);
+               j += 2;
+               continue;
+           }
+       }
+/* recode it, if necessary */
+       if (!isalnum(ch) && ind(allowed, ch) == -1)
+       {
+           c2hex(ch, &y[j]);
+           j += 2;
+       } else y[j] = ch;
+    }
+    y[j] = '\0';
+    return y;
+}
+
+/*
+ * Parses network-location.
+ *    urlp           on input the URL; on output the path, after the leading /
+ *    user           NULL if no user/password permitted
+ *    password       holder for password
+ *    host           holder for host
+ *    port           port number; only set if one is supplied.
+ *
+ * Returns an error string.
+ */
+static char *
+canon_netloc(pool *pool, char **const urlp, char **userp, char **passwordp,
+           char **hostp, int *port)
+{
+    int i;
+    char *p, *host, *url=*urlp;
+
+    if (url[0] != '/' || url[1] != '/') return "Malformed URL";
+    host = url + 2;
+    url = strchr(host, '/');
+    if (url == NULL)
+       url = "";
+    else
+       *(url++) = '\0';  /* skip seperating '/' */
+
+    if (userp != NULL)
+    {
+       char *user=NULL, *password = NULL;
+       p = strchr(host, '@');
+
+       if (p != NULL)
+       {
+           *p = '\0';
+           user = host;
+           host = p + 1;
+
+/* find password */
+           p = strchr(user, ':');
+           if (p != NULL)
+           {
+               *p = '\0';
+               password = canonenc(pool, p+1, strlen(p+1), enc_user, 1);
+               if (password == NULL)
+                   return "Bad %-escape in URL (password)";
+           }
+
+           user = canonenc(pool, user, strlen(user), enc_user, 1);
+           if (user == NULL) return "Bad %-escape in URL (username)";
+       }
+       *userp = user;
+       *passwordp = password;
+    }
+
+    p = strchr(host, ':');
+    if (p != NULL)
+    {
+       *(p++) = '\0';
+       
+       for (i=0; p[i] != '\0'; i++)
+           if (!isdigit(p[i])) break;
+
+       if (i == 0 || p[i] != '\0')
+           return "Bad port number in URL";
+       *port = atoi(p);
+       if (*port > 65535) return "Port number in URL > 65535";
+    }
+    str_tolower(host); /* DNS names are case-insensitive */
+    if (*host == '\0') return "Missing host in URL";
+/* check hostname syntax */
+    for (i=0; host[i] != '\0'; i++)
+       if (!isdigit(host[i]) && host[i] != '.')
+           break;
+ /* must be an IP address */
+    if (host[i] == '\0' && (inet_addr(host) == -1 || inet_network(host) == -1))
+           return "Bad IP address in URL";
+
+    *urlp = url;
+    *hostp = host;
+
+    return NULL;
+}
+
+/*
+ * checks an encoded ftp string for bad characters, namely, CR, LF or
+ * non-ascii character
+ */
+static int
+ftp_check_string(const char *x)
+{
+    int i, ch;
+
+    for (i=0; x[i] != '\0'; i++)
+    {
+       ch = x[i];
+       if ( ch == '%' && isxdigit(x[i+1]) && isxdigit(x[i+2]))
+       {
+           ch = hex2c(&x[i+1]);
+           i += 2;
+       }
+       if (ch == '\015' || ch == '\012' || (ch & 0x80)) return 0;
+    }
+    return 1;
+}
+
+/*
+ * Canonicalise ftp URLs.
+ */
+static int
+ftp_canon(request_rec *r, char *url)
+{
+    char *user, *password, *host, *path, *parms, *p, sport[7];
+    const char *err;
+    int port;
+
+    port = DEFAULT_FTP_PORT;
+    err = canon_netloc(r->pool, &url, &user, &password, &host, &port);
+    if (err) return BAD_REQUEST;
+    if (user != NULL && !ftp_check_string(user)) return BAD_REQUEST;
+    if (password != NULL && !ftp_check_string(password)) return BAD_REQUEST;
+
+/* now parse path/parameters args, according to rfc1738 */
+/* N.B. if this isn't a true proxy request, then the URL path
+ * (but not query args) has already been decoded.
+ * This gives rise to the problem of a ; being decoded into the
+ * path.
+ */
+    p = strchr(url, ';');
+    if (p != NULL)
+    {
+       *(p++) = '\0';
+       parms = canonenc(r->pool, p, strlen(p), enc_parm, r->proxyreq);
+       if (parms == NULL) return BAD_REQUEST;
+    } else
+       parms = "";
+
+    path = canonenc(r->pool, url, strlen(url), enc_path, r->proxyreq);
+    if (path == NULL) return BAD_REQUEST;
+    if (!ftp_check_string(path)) return BAD_REQUEST;
+
+    if (!r->proxyreq && r->args != NULL)
+    {
+       if (p != NULL)
+       {
+           p = canonenc(r->pool, r->args, strlen(r->args), enc_parm, 1);
+           if (p == NULL) return BAD_REQUEST;
+           parms = pstrcat(r->pool, parms, "?", p, NULL);
+       }
+       else
+       {
+           p = canonenc(r->pool, r->args, strlen(r->args), enc_path, 1);
+           if (p == NULL) return BAD_REQUEST;
+           path = pstrcat(r->pool, path, "?", p, NULL);
+       }
+       r->args = NULL;
+    }
+
+/* now, rebuild URL */
+
+    if (port != DEFAULT_FTP_PORT) sprintf(sport, ":%d", port);
+    else sport[0] = '\0';
+
+    r->filename = pstrcat(r->pool, "proxy:ftp://", (user != NULL) ? user : "",
+                         (password != NULL) ? ":" : "",
+                         (password != NULL) ? password : "",
+                         (user != NULL) ? "@" : "", host, sport, "/", path,
+                         (parms[0] != '\0') ? ";" : "", parms, NULL);
+
+    return OK;
+}
+
+
+/*
+ * Canonicalise http-like URLs.
+ *  scheme is the scheme for the URL
+ *  url    is the URL starting with the first '/'
+ *  def_port is the default port for this scheme.
+ */
+static int
+http_canon(request_rec *r, char *url, const char *scheme, int def_port)
+{
+    char *host, *path, *search, *p, sport[7];
+    const char *err;
+    int port;
+
+/* do syntatic check.
+ * We break the URL into host, port, path, search
+ */
+    port = def_port;
+    err = canon_netloc(r->pool, &url, NULL, NULL, &host, &port);
+    if (err) return BAD_REQUEST;
+
+/* now parse path/search args, according to rfc1738 */
+/* N.B. if this isn't a true proxy request, then the URL _path_
+ * has already been decoded
+ */
+    if (r->proxyreq)
+    {
+       p = strchr(url, '?');
+       if (p != NULL) *(p++) = '\0';
+    } else
+       p = r->args;
+
+/* process path */
+    path = canonenc(r->pool, url, strlen(url), enc_path, r->proxyreq);
+    if (path == NULL) return BAD_REQUEST;
+
+/* process search */
+    if (p != NULL)
+    {
+       search = p;
+       if (search == NULL) return BAD_REQUEST;
+    } else
+       search = "";
+
+    if (port != def_port) sprintf(sport, ":%d", port);
+    else sport[0] = '\0';
+
+    r->filename = pstrcat(r->pool, "proxy:", scheme, "://", host, sport, "/",
+                         path, (search[0] != '\0') ? "?" : "", search, NULL);
+    return OK;
+}
+
+static const char *lwday[7]=
+{"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
+static const char *wday[7]=
+{"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
+static const char *months[12]=
+{"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov",
+ "Dec"};
+
+/*
+ * If the date is a valid RFC 850 date or asctime() date, then it
+ * is converted to the RFC 1123 format, otherwise it is not modified.
+ * This routine is not very fast at doing conversions, as it uses
+ * sscanf and sprintf. However, if the date is already correctly
+ * formatted, then it exits very quickly.
+ */
+static char *
+date_canon(pool *p, char *x)
+{
+    int wk, mday, year, hour, min, sec, mon;
+    char *q, month[4], zone[4], week[4];
+    
+    q = strchr(x, ',');
+    /* check for RFC 850 date */
+    if (q != NULL && q - x > 3 && q[1] == ' ')
+    {
+       *q = '\0';
+       for (wk=0; wk < 7; wk++)
+           if (strcmp(x, lwday[wk]) == 0) break;
+       *q = ',';
+       if (wk == 7) return x;  /* not a valid date */
+       if (q[4] != '-' || q[8] != '-' || q[11] != ' ' || q[14] != ':' ||
+           q[17] != ':' || strcmp(&q[20], " GMT") != 0) return x;
+       if (sscanf(q+2, "%u-%3s-%u %u:%u:%u %3s", &mday, month, &year,
+                  &hour, &min, &sec, zone) != 7) return x;
+       if (year < 70) year += 2000;
+       else year += 1900;
+    } else
+    {
+/* check for acstime() date */
+       if (x[3] != ' ' || x[7] != ' ' || x[10] != ' ' || x[13] != ':' ||
+           x[16] != ':' || x[19] != ' ' || x[24] != '\0') return x;
+       if (sscanf(x, "%3s %3s %u %u:%u:%u %u", week, month, &mday, &hour,
+                  &min, &sec, &year) != 7) return x;
+       for (wk=0; wk < 7; wk++)
+           if (strcmp(week, wday[wk]) == 0) break;
+       if (wk == 7) return x;
+    }
+
+/* check date */
+    for (mon=0; mon < 12; mon++) if (strcmp(month, months[mon]) == 0) break;
+    if (mon == 12) return x;
+/*
+ *  it doesn't do any harm to convert an invalid date from one format to
+ * another
+ */
+#if 0
+    if (hour > 23 || min > 60 || sec > 62 || mday == 0 || mday > 31) return x;
+    if (mday == 31 && (mon == 1 || mon == 3 || mon == 5 || mon == 8 || mon == 10))
+       return x;
+    if (mday > 29 && mon == 1) return x;
+    if (mday == 29 && mon == 1)
+       if (year%4 != 0 || (year%100 == 0 && year%400 != 0)) return x;
+#endif
+
+    if (strlen(x) < 31) x = palloc(p, 31);
+    sprintf(x, "%s, %.2d %s %d %.2d:%.2d:%.2d GMT", wday[wk], mday,
+           months[mon], year, hour, min, sec);
+    return x;
+}
+
+
+/* -------------------------------------------------------------- */
+/* Invoke handler */
+
+/* Utility routines */
+
+/*
+ * Reads headers from a connection and returns an array of headers.
+ * Returns NULL on file error
+ */
+static array_header *
+read_headers(pool *pool, char *buffer, int size, BUFF *f)
+{
+    int gotcr, len, i, j;
+    array_header *resp_hdrs;
+    struct hdr_entry *hdr;
+    char *p;
+
+    resp_hdrs = make_array(pool, 10, sizeof(struct hdr_entry));
+    hdr = NULL;
+
+    gotcr = 1;
+    for (;;)
+    {
+       len = bgets(buffer, size, f);
+       if (len == -1) return NULL;
+       if (len == 0) break;
+       if (buffer[len-1] == '\n')
+       {
+           buffer[--len] = '\0';
+           i = 1;
+       } else
+           i = 0;
+
+       if (!gotcr || buffer[0] == ' ' || buffer[0] == '\t')
+       {
+           /* a continuation header */
+           if (hdr == NULL)
+           {
+               /* error!! */
+               if (!i)
+               {
+                   i = bskiplf(f);
+                   if (i == -1) return NULL;
+               }
+               gotcr = 1;
+               continue;
+           }
+           hdr->value = pstrcat(pool, hdr->value, buffer, NULL);
+       }
+       else if (gotcr && len == 0) break;
+       else
+       {
+           p = strchr(buffer, ':');
+           if (p == NULL)
+           {
+               /* error!! */
+               if (!gotcr)
+               {
+                   i = bskiplf(f);
+                   if (i == -1) return NULL;
+               }
+               gotcr = 1;
+               hdr = NULL;
+               continue;
+           }
+           hdr = push_array(resp_hdrs);
+           *(p++) = '\0';
+           hdr->field = pstrdup(pool, buffer);
+           while (*p == ' ' || *p == '\t') p++;
+           hdr->value = pstrdup(pool, p);
+           gotcr = i;
+       }
+    }
+
+    hdr = (struct hdr_entry *)resp_hdrs->elts;
+    for (i=0; i < resp_hdrs->nelts; i++)
+    {
+       p = hdr[i].value;
+       j = strlen(p);
+       while (j > 0 && (p[j-1] == ' ' || p[j-1] == '\t')) j--;
+       p[j] = '\0';
+    }
+
+    return resp_hdrs;
+}
+
+static long int
+send_fb(BUFF *f, request_rec *r, BUFF *f2, struct cache_req *c)
+{
+    char buf[IOBUFSIZE];
+    long total_bytes_sent;
+    register int n,o,w;
+    conn_rec *con = r->connection;
+    
+    total_bytes_sent = 0;
+    while (!con->aborted) {
+       n = bread(f, buf, IOBUFSIZE);
+       if (n == -1) /* input error */
+       {
+           if (f2 != NULL) f2 = cache_error(c);
+           break;
+       }
+       if (n == 0) break; /* EOF */
+        o=0;
+       total_bytes_sent += n;
+
+       if (f2 != NULL)
+           if (bwrite(f2, buf, n) != n) f2 = cache_error(c);
+       
+        while(n && !r->connection->aborted) {
+            w = bwrite(con->client, &buf[o], n);
+           if (w <= 0)
+               break;
+           reset_timeout(r); /* reset timeout after successfule write */
+            n-=w;
+            o+=w;
+        }
+    }
+    bflush(con->client);
+    
+    return total_bytes_sent;
+}
+
+/*
+ * Read a header from the array, returning the first entry
+ */
+static struct hdr_entry *
+get_header(array_header *hdrs_arr, const char *name)
+{
+    struct hdr_entry *hdrs;
+    int i;
+
+    hdrs = (struct hdr_entry *)hdrs_arr->elts;
+    for (i = 0; i < hdrs_arr->nelts; i++)
+        if (hdrs[i].field != NULL && strcasecmp(name, hdrs[i].field) == 0)
+           return &hdrs[i];
+
+    return NULL;
+}
+
+#define HDR_APP (0)
+#define HDR_REP (1)
+
+/*
+ * Add to the header reply, either concatenating, or replacing existin
+ * headers. It stores the pointers provided, so make sure the data
+ * is not subsequently overwritten
+ */
+static struct hdr_entry *
+add_header(array_header *hdrs_arr, char *field, char *value,
+          int rep)
+{
+    int i;
+    struct hdr_entry *hdrs;
+
+    hdrs = (struct hdr_entry *)hdrs_arr->elts;
+    if (rep)
+       for (i = 0; i < hdrs_arr->nelts; i++)
+           if (hdrs[i].field != NULL && strcasecmp(field, hdrs[i].field) == 0)
+           {
+               hdrs[i].value = value;
+               return hdrs;
+           }
+       
+    hdrs = push_array(hdrs_arr);
+    hdrs->field = field;
+    hdrs->value = value;
+
+    return hdrs;
+}
+
+#ifdef NEEDED
+static void
+del_header(array_header *hdrs_arr, const char *field)
+{
+    int i;
+    struct hdr_entry *hdrs;
+
+    hdrs = (struct hdr_entry *)hdrs_arr->elts;
+
+    for (i = 0; i < hdrs_arr->nelts; i++)
+       if (hdrs[i].field != NULL && strcasecmp(field, hdrs[i].field) == 0)
+           hdrs[i].value = NULL;
+}
+#endif
+
+/*
+ * Sends response line and headers
+ */
+static void
+send_headers(BUFF *fp, const char *respline, array_header *hdrs_arr)
+{
+    struct hdr_entry *hdrs;
+    int i;
+
+    hdrs = (struct hdr_entry *)hdrs_arr->elts;
+
+    bputs(respline, fp);
+    bputs("\015\012", fp);
+    for (i = 0; i < hdrs_arr->nelts; i++)
+    {
+        if (hdrs[i].field == NULL) continue;
+       bvputs(fp, hdrs[i].field, ": ", hdrs[i].value, "\015\012", NULL);
+    }
+
+    bputs("\015\012", fp);
+}
+
+
+/*
+ * 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.
+ */
+static int
+liststr(const char *list, const char *val)
+{
+    int len, i;
+    const char *p;
+
+    len = strlen(val);
+
+    while (list != NULL)
+    {
+       p = strchr(list, ',');
+       if (p != NULL)
+       {
+           i = p - list;
+           do p++; while (isspace(*p));
+       } 
+       else
+           i = strlen(list);
+
+       while (i > 0 && isspace(list[i-1])) i--;
+       if (i == len && strncasecmp(list, val, len) == 0) return 1;
+       list = p;
+    }
+    return 0;
+}
+
+/* number of characters in the hash */
+#define HASH_LEN (22*2)
+
+static void
+hash(const char *it, char *val,int ndepth,int nlength)
+{
+    MD5_CTX context;
+    unsigned char digest[16];
+    char tmp[22];
+    int i, k, d;
+    unsigned int x;
+    static const char table[64]=
+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_@";
+
+    MD5Init(&context);
+    MD5Update(&context, (const unsigned char *)it, strlen(it));
+    MD5Final(digest, &context);
+
+/* encode 128 bits as 22 characters, using a modified uuencoding */
+/* the encoding is 3 bytes -> 4 characters
+ * i.e. 128 bits is 5 x 3 bytes + 1 byte -> 5 * 4 characters + 2 characters
+ */
+    for (i=0, k=0; i < 15; i += 3)
+    {
+       x = (digest[i] << 16) | (digest[i+1] << 8) | digest[i+2];
+       tmp[k++] = table[x >> 18];
+       tmp[k++] = table[(x >> 12) & 0x3f];
+       tmp[k++] = table[(x >> 6) & 0x3f];
+       tmp[k++] = table[x & 0x3f];
+    }
+/* one byte left */
+    x = digest[15];
+    tmp[k++] = table[x >> 2];  /* use up 6 bits */
+    tmp[k++] = table[(x << 4) & 0x3f];
+    /* now split into directory levels */
+
+    for(i=k=d=0 ; d < ndepth ; ++d)
+       {
+       strncpy(&val[i],&tmp[k],nlength);
+       k+=nlength;
+       val[i+nlength]='/';
+       i+=nlength+1;
+       }
+    memcpy(&val[i],&tmp[k],22-k);
+    val[i+22-k]='\0';
+}
+
+/*
+ * Compare a string to a mask
+ * Mask characters:
+ *   @ - uppercase letter
+ *   # - lowercase letter
+ *   & - hex digit
+ *   # - digit
+ *   * - swallow remaining characters 
+ *  <x> - exact match for any other character
+ */
+static int
+checkmask(const char *data, const char *mask)
+{
+    int i, ch, d;
+
+    for (i=0; mask[i] != '\0' && mask[i] != '*'; i++)
+    {
+       ch = mask[i];
+       d = data[i];
+       if (ch == '@')
+       {
+           if (!isupper(d)) return 0;
+       } else if (ch == '$')
+       {
+           if (!islower(d)) return 0;
+       } else if (ch == '#')
+       {
+           if (!isdigit(d)) return 0;
+       } else if (ch == '&')
+       {
+           if (!isxdigit(d)) return 0;
+       } else if (ch != d) return 0;
+    }
+
+    if (mask[i] == '*') return 1;
+    else return (data[i] == '\0');
+}
+
+/*
+ * This routine converts a tm structure into the number of seconds
+ * since 1st January 1970 UT
+ * 
+ * The return value is a non-negative integer on success or -1 if the
+ * input date is out of the domain Thu, 01 Jan 1970 00:00:00 to
+ * Tue, 19 Jan 2038 03:14:07 inclusive
+ *
+ * Notes
+ *   This routine has been tested on 1000000 valid dates generated
+ *   at random by gmtime().
+ * 
+ *   This routine is very fast, much faster than mktime().
+ */
+static int
+tm2sec(const struct tm *t)
+{
+    int days, year;
+    static const int dayoffs[12]=
+    {306, 337, 0, 31, 61, 92, 122, 153, 184, 214, 245, 275};
+
+    year = t->tm_year;
+/* shift new year to 1st March; which is where it should be */
+    if (t->tm_mon < 2) year--;  /* now years and months since 1st March 1900 */
+    days = t->tm_mday - 1 + dayoffs[t->tm_mon];
+
+/* find the number of days since 1st March 1900 (in the Gregorian calendar) */
+    days += year * 365 + year/4 - year/100 + (year/100 + 3)/4;
+    days -= 25508; /* 1 jan 1970 is 25508 days since 1 mar 1900 */
+
+    days = ((days * 24 + t->tm_hour) * 60 + t->tm_min) * 60 + t->tm_sec;
+    if (year < 69 || year > 138 || days < 0) /* must have overflowed */
+       return -1;
+    else
+       return days;
+}
+
+/*
+ * Parses a standard HTTP date.
+ * 
+ * The restricted HTTP syntax is
+ *   rfc1123-date = day "," SP 2DIGIT SP date SP time SP "GMT"
+ *   date = 2DIGIT SP month SP 4DIGIT
+ *   time = 2DIGIT ":" 2DIGIT ":" 2DIGIT
+ *
+ *   day = "Mon" | "Tue" | "Wed" | "Thu" | "Fri" | "Sat" | "Sun"
+ *
+ *   month = "Jan" | "Feb" | "Mar" | "Apr" | "May" | "Jun" |
+ *           "Jul" | "Aug" | "Sep" | "Oct" | "Nov" | "Dec"
+ *
+ * The spec is not clear as to whether the day and months are
+ * case-sensitive or not. This code assumes they are.
+ *
+ * It fills in the year, month, mday, hour, min, sec and is_dst fields of
+ * date. It does not set the wday or yday fields.
+ * On failure is sets the year to 0.
+ * 
+ * It also returns the number of seconds since 1 Jan 1970 UT, or
+ * -1 if this would be out of range or if the date is invalid.
+ *
+ * Notes
+ *   This routine has been tested on 100000 valid dates generated
+ *   at random by strftime().
+ * 
+ *   This routine is very fast; it would be 10x slower if it
+ *   used sscanf.
+ */
+static int
+parsedate(const char *date, struct tm *d)
+{
+    int mint, mon, year;
+    struct tm x;
+    const int months[12]={
+       ('J' << 16) | ( 'a' << 8) | 'n', ('F' << 16) | ( 'e' << 8) | 'b',
+       ('M' << 16) | ( 'a' << 8) | 'r', ('A' << 16) | ( 'p' << 8) | 'r',
+       ('M' << 16) | ( 'a' << 8) | 'y', ('J' << 16) | ( 'u' << 8) | 'n',
+       ('J' << 16) | ( 'u' << 8) | 'l', ('A' << 16) | ( 'u' << 8) | 'g',
+       ('S' << 16) | ( 'e' << 8) | 'p', ('O' << 16) | ( 'c' << 8) | 't',
+       ('N' << 16) | ( 'o' << 8) | 'v', ('D' << 16) | ( 'e' << 8) | 'c'};
+    if (d == NULL) d = &x;
+
+    d->tm_year = 0;  /* bad date */
+    if (!checkmask(date, "@$$, ## @$$ #### ##:##:## GMT")) return -1;
+
+/* we don't test the weekday */
+    d->tm_mday = (date[5] - '0') * 10 + (date[6] - '0');
+    if (d->tm_mday == 0 || d->tm_mday > 31) return -1;
+
+    mint = (date[8] << 16) | (date[9] << 8) | date[10];
+    for (mon=0; mon < 12; mon++) if (mint == months[mon]) break;
+    if (mon == 12) return -1;
+    
+    d->tm_mon = mon;
+    year = date[12] * 1000 + date[13] * 100 + date[14] * 10 + date[15] -
+                ('0' * 1111);
+    d->tm_hour = date[17] * 10 + date[18] - '0' * 11;
+    d->tm_min  = date[20] * 10 + date[21] - '0' * 11;
+    d->tm_sec = date[23] * 10 + date[24] - '0' * 11;
+
+    if (d->tm_hour > 23 || d->tm_min > 59 || d->tm_sec > 61) return -1;
+
+    if (d->tm_mday == 31 && (mon == 1 || mon == 3 || mon == 5 || mon == 8 ||
+                            mon == 10)) return -1;
+    if (d->tm_mday > 29 && mon == 1) return -1;
+    if (d->tm_mday == 29 && mon == 1)
+       if (year%4 != 0 || (year%100 == 0 && year%400 != 0)) return -1;
+
+    d->tm_year = year - 1900;
+    d->tm_isdst = 0;
+    return tm2sec(d);
+}
+
+/*
+ * Converts 8 hex digits to a time integer
+ */
+static int
+hex2sec(const char *x)
+{
+    int i, ch;
+    unsigned int j;
+
+    for (i=0, j=0; i < 8; i++)
+    {
+       ch = x[i];
+       j <<= 4;
+       if (isdigit(ch)) j |= ch - '0';
+       else if (isupper(ch)) j |= ch - ('A' - 10);
+       else j |= ch - ('a' - 10);
+    }
+    if (j == 0xffffffff) return -1;  /* so that it works with 8-byte ints */
+    else return j;
+}
+
+/*
+ * Converts a time integer to 8 hex digits
+ */
+static void
+sec2hex(int t, char *y)
+{
+    int i, ch;
+    unsigned int j=t;
+
+    for (i=7; i >= 0; i--)
+    {
+       ch = j & 0xF;
+       j >>= 4;
+       if (ch >= 10) y[i] = ch + ('A' - 10);
+       else y[i] = ch + '0';
+    }
+    y[8] = '\0';
+}
+
+
+static void
+log_uerror(const char *routine, const char *file, const char *err,
+          server_rec *s)
+{
+    char *p, *q;
+
+    q = get_time();
+    p = strerror(errno);
+
+    if (err != NULL)
+    {
+       fprintf(s->error_log, "[%s] %s\n", q, err);
+       if (file != NULL)
+           fprintf(s->error_log, "- %s: %s: %s\n", routine, file, p);
+       else
+           fprintf(s->error_log, "- %s: %s\n", routine, p);
+    } else
+    {
+       if (file != NULL)
+           fprintf(s->error_log, "[%s] %s: %s: %s\n", q, routine, file, p);
+       else
+           fprintf(s->error_log, "[%s] %s: %s\n", q, routine, p);
+    }
+
+    fflush(s->error_log);
+}
+
+struct gc_ent
+{
+    unsigned long int len;
+    time_t expire;
+    char file[HASH_LEN+1];
+
+};
+
+static int
+gcdiff(const void *ap, const void *bp)
+{
+    const struct gc_ent *a=*(struct gc_ent **)ap, *b=*(struct gc_ent **)bp;
+
+    if (a->expire > b->expire) return 1;
+    else if (a->expire < b->expire) return -1;
+    else return 0;
+}
+
+static int curbytes, cachesize, every;
+static unsigned long int curblocks;
+static time_t now, expire;
+static char *filename;
+
+static int sub_garbage_coll(request_rec *r,array_header *files,
+                           const char *cachedir,const char *cachesubdir);
+
+static void garbage_coll(request_rec *r)
+    {
+    const char *cachedir;
+    void *sconf = r->server->module_config;
+    proxy_server_conf *pconf =
+        (proxy_server_conf *)get_module_config(sconf, &proxy_module);
+    const struct cache_conf *conf=&pconf->cache;
+    array_header *files;
+    struct stat buf;
+    struct gc_ent *fent,**elts;    
+    int i;
+    static time_t lastcheck=-1;  /* static data!!! */
+
+    cachedir = conf->root;
+    cachesize = conf->space;
+    every = conf->gcinterval;
+
+    if (cachedir == NULL || every == -1) return;
+    now = time(NULL);
+    if (now != -1 && lastcheck != -1 && now < lastcheck + every) return;
+
+    block_alarms();    /* avoid SIGALRM on big cache cleanup */
+
+    filename = palloc(r->pool, strlen(cachedir) + HASH_LEN + 2);
+    strcpy(filename, cachedir);
+    strcat(filename, "/.time");
+    if (stat(filename, &buf) == -1) /* does not exist */
+    {
+       if (errno != ENOENT)
+       {
+           log_uerror("stat", filename, NULL, r->server);
+           return;
+       }
+       if (creat(filename, 0666) == -1)
+       {
+           if (errno != EEXIST)
+               log_uerror("creat", filename, NULL, r->server);
+           else
+               lastcheck = now;  /* someone else got in there */
+           return;
+       }
+    } else
+    {
+       lastcheck = buf.st_mtime;  /* save the time */
+       if (now < lastcheck + every) return;
+       if (utime(filename, NULL) == -1)
+           log_uerror("utimes", filename, NULL, r->server);
+    }
+    files = make_array(r->pool, 100, sizeof(struct gc_ent *));
+    curblocks = 0;
+    curbytes = 0;
+
+    sub_garbage_coll(r,files,cachedir,"/");
+
+    if (curblocks < cachesize || curblocks + curbytes <= cachesize)
+       return;
+
+    qsort(files->elts, files->nelts, sizeof(struct gc_ent *), gcdiff);
+
+    elts = (struct gc_ent **)files->elts;
+    for (i=0; i < files->nelts; i++)
+    {
+       fent = elts[i];
+       sprintf(filename, "%s%s", cachedir, fent->file);
+       Explain3("GC Unlinking %s (expiry %ld, now %ld)",filename,fent->expire,now);
+#if TESTING
+       fprintf(stderr,"Would unlink %s\n",filename);
+#else
+       if (unlink(filename) == -1)
+       {
+           if (errno != ENOENT)
+               log_uerror("unlink", filename, NULL, r->server);
+       }
+       else
+#endif
+       {
+           curblocks -= fent->len >> 10;
+           curbytes -= fent->len & 0x3FF;
+           if (curbytes < 0)
+           {
+               curbytes += 1024;
+               curblocks--;
+           }
+           if (curblocks < cachesize || curblocks + curbytes <= cachesize)
+               break;
+       }
+    }
+    unblock_alarms();
+}
+
+static int sub_garbage_coll(request_rec *r,array_header *files,
+                            const char *cachebasedir,const char *cachesubdir)
+{
+    char line[27];
+    char cachedir[HUGE_STRING_LEN];
+    struct stat buf;
+    int fd,i;
+    DIR *dir;
+#if defined(NEXT)
+    struct DIR_TYPE *ent;
+#else
+    struct dirent *ent;
+#endif
+    struct gc_ent *fent;
+    int nfiles=0;
+
+    sprintf(cachedir,"%s%s",cachebasedir,cachesubdir);
+    Explain1("GC Examining directory %s",cachedir);
+    dir = opendir(cachedir);
+    if (dir == NULL)
+    {
+       log_uerror("opendir", cachedir, NULL, r->server);
+       return 0;
+    }
+
+    while ((ent = readdir(dir)) != NULL)
+    {
+       if (ent->d_name[0] == '.') continue;
+       sprintf(filename, "%s%s", cachedir, ent->d_name);
+       Explain1("GC Examining file %s",filename);
+/* is it a temporary file? */
+       if (strncmp(ent->d_name, "#tmp", 4) == 0)
+       {
+/* then stat it to see how old it is; delete temporary files > 1 day old */
+           if (stat(filename, &buf) == -1)
+           {
+               if (errno != ENOENT)
+                   log_uerror("stat", filename, NULL, r->server);
+           } else if (now != -1 && buf.st_atime < now - SEC_ONE_DAY &&
+                      buf.st_mtime < now - SEC_ONE_DAY)
+               {
+               Explain1("GC unlink %s",filename);
+#if TESTING
+               fprintf(stderr,"Would unlink %s\n",filename);
+#else
+               unlink(filename);
+#endif
+               }
+           continue;
+       }
+       ++nfiles;
+/* is it another file? */
+       /* FIXME: Shouldn't any unexpected files be deleted? */
+       /*      if (strlen(ent->d_name) != HASH_LEN) continue; */
+
+/* read the file */
+       fd = open(filename, O_RDONLY);
+       if (fd == -1)
+       {
+           if (errno  != ENOENT) log_uerror("open", filename,NULL, r->server);
+           continue;
+       }
+       if (fstat(fd, &buf) == -1)
+       {
+           log_uerror("fstat", filename, NULL, r->server);
+           close(fd);
+           continue;
+       }
+       if(S_ISDIR(buf.st_mode))
+           {
+           char newcachedir[HUGE_STRING_LEN];
+           close(fd);
+           sprintf(newcachedir,"%s%s/",cachesubdir,ent->d_name);
+           if(!sub_garbage_coll(r,files,cachebasedir,newcachedir))
+               {
+               sprintf(newcachedir,"%s%s",cachedir,ent->d_name);
+#if TESTING
+               fprintf(stderr,"Would remove directory %s\n",newcachedir);
+#else
+               rmdir(newcachedir);
+#endif
+               --nfiles;
+               }
+           continue;
+           }
+           
+       i = read(fd, line, 26);
+       if (i == -1)
+       {
+           log_uerror("read", filename, NULL, r->server);
+           close(fd);
+           continue;
+       }
+       close(fd);
+       line[i] = '\0';
+       expire = hex2sec(line+18);
+       if (!checkmask(line, "&&&&&&&& &&&&&&&& &&&&&&&&") || expire == -1)
+       {
+           /* bad file */
+           if (now != -1 && buf.st_atime > now + SEC_ONE_DAY &&
+               buf.st_mtime > now + SEC_ONE_DAY)
+           {
+               log_error("proxy: deleting bad cache file", r->server);
+#if TESTING
+               fprintf(stderr,"Would unlink bad file %s\n",filename);
+#else
+               unlink(filename);
+#endif
+           }
+           continue;
+       }
+
+/*
+ * we need to calculate an 'old' factor, and remove the 'oldest' files
+ * so that the space requirement is met; sort by the expires date of the
+ * file.
+ *
+ */
+       /* FIXME: We should make the array an array of gc_ents, not gc_ent *s
+        */
+       fent = palloc(r->pool, sizeof(struct gc_ent));
+       fent->len = buf.st_size;
+       fent->expire = expire;
+       strcpy(fent->file,cachesubdir);
+       strcat(fent->file, ent->d_name);
+       *(struct gc_ent **)push_array(files) = fent;
+
+/* accumulate in blocks, to cope with directories > 4Gb */
+       curblocks += buf.st_size >> 10; /* Kbytes */
+       curbytes += buf.st_size & 0x3FF;
+       if (curbytes >= 1024)
+       {
+           curbytes -= 1024;
+           curblocks++;
+       }
+    }
+
+    closedir(dir);
+
+    return nfiles;
+
+}
+
+/*
+ * read a cache file;
+ * returns 1 on success,
+ *         0 on failure (bad file or wrong URL)
+ *        -1 on UNIX error
+ */
+static int
+rdcache(pool *pool, BUFF *cachefp, struct cache_req *c)
+{
+    char urlbuff[1034], *p;
+    int len;
+/* read the data from the cache file */
+/* format
+ * date SP lastmod SP expire SP count SP content-length CRLF
+ * dates are stored as hex seconds since 1970
+ */
+    len = bgets(urlbuff, 1034, cachefp);
+    if (len == -1) return -1;
+    if (len == 0 || urlbuff[len-1] != '\n') return 0;
+    urlbuff[len-1] = '\0';
+
+    if (!checkmask(urlbuff, "&&&&&&&& &&&&&&&& &&&&&&&& &&&&&&&& &&&&&&&&"))
+       return 0;
+
+    c->date = hex2sec(urlbuff);
+    c->lmod = hex2sec(urlbuff+9);
+    c->expire = hex2sec(urlbuff+18);
+    c->version = hex2sec(urlbuff+27);
+    c->len = hex2sec(urlbuff+36);
+
+/* check that we have the same URL */
+    len = bgets(urlbuff, 1034, cachefp);
+    if (len == -1) return -1;
+    if (len == 0 || strncmp(urlbuff, "X-URL: ", 7) != 0 ||
+       urlbuff[len-1] != '\n')
+       return 0;
+    urlbuff[len-1] = '\0';
+    if (strcmp(urlbuff+7, c->url) != 0) return 0;
+
+/* What follows is the message */
+    len = bgets(urlbuff, 1034, cachefp);
+    if (len == -1) return -1;
+    if (len == 0 || urlbuff[len-1] != '\n') return 0;
+    urlbuff[--len] = '\0';
+
+    c->resp_line = pstrdup(pool, urlbuff);
+    p = strchr(urlbuff, ' ');
+    if (p == NULL) return 0;
+
+    c->status = atoi(p);
+    c->hdrs = read_headers(pool, urlbuff, 1034, cachefp);
+    if (c->hdrs == NULL) return -1;
+    if (c->len != -1) /* add a content-length header */
+    {
+       struct hdr_entry *q;
+       q = get_header(c->hdrs, "Content-Length");
+       if (q == NULL)
+       {
+           p = palloc(pool, 15);
+           sprintf(p, "%u", c->len);
+           add_header(c->hdrs, "Content-Length", p, HDR_REP);
+       }
+    }
+    return 1;
+}
+
+
+/*
+ * Call this to test for a resource in the cache
+ * Returns DECLINED if we need to check the remote host
+ * or an HTTP status code if successful
+ *
+ * Functions:
+ *   if URL is cached then
+ *      if cached file is not expired then
+ *         if last modified after if-modified-since then send body
+ *         else send 304 Not modified
+ *      else
+ *         if last modified after if-modified-since then add
+ *            last modified date to request
+ */
+static int
+cache_check(request_rec *r, char *url, struct cache_conf *conf,
+            struct cache_req **cr)
+{
+    char hashfile[33], *imstr, *pragma, *p, *auth;
+    struct cache_req *c;
+    time_t now;
+    BUFF *cachefp;
+    int cfd, i;
+    const long int zero=0L;
+    void *sconf = r->server->module_config;
+    proxy_server_conf *pconf =
+        (proxy_server_conf *)get_module_config(sconf, &proxy_module);
+
+    c = pcalloc(r->pool, sizeof(struct cache_req));
+    *cr = c;
+    c->req = r;
+    c->url = pstrdup(r->pool, url);
+
+/* get the If-Modified-Since date of the request */
+    c->ims = -1;
+    imstr = table_get(r->headers_in, "If-Modified-Since");
+    if (imstr != NULL)
+    {
+/* this may modify the value in the original table */
+       imstr = date_canon(r->pool, imstr);
+       c->ims = parsedate(imstr, NULL);
+       if (c->ims == -1)  /* bad or out of range date; remove it */
+           table_set(r->headers_in, "If-Modified-Since", NULL);
+    }
+
+/* find the filename for this cache entry */
+    hash(url, hashfile,pconf->cache.dirlevels,pconf->cache.dirlength);
+    if (conf->root != NULL)
+       c->filename = pstrcat(r->pool, conf->root, "/", hashfile, NULL);
+    else
+       c->filename = NULL;
+
+    cachefp = NULL;
+/* find out about whether the request can access the cache */
+    pragma = table_get(r->headers_in, "Pragma");
+    auth = table_get(r->headers_in, "Authorization");
+    Explain4("Request for %s, pragma=%s, auth=%s, ims=%ld",url,pragma,auth,c->ims);
+    if (c->filename != NULL && r->method_number == M_GET &&
+       strlen(url) < 1024 && !liststr(pragma, "no-cache") && auth == NULL)
+    {
+        Explain1("Check file %s",c->filename);
+       cfd = open(c->filename, O_RDWR);
+       if (cfd != -1)
+       {
+           note_cleanups_for_fd(r->pool, cfd);
+           cachefp = bcreate(r->pool, B_RD | B_WR);
+           bpushfd(cachefp, cfd, cfd);
+       } else if (errno != ENOENT)
+           log_uerror("open", c->filename, "proxy: error opening cache file",
+                      r->server);
+       else
+           Explain1("File %s not found",c->filename);
+    }
+    
+    if (cachefp != NULL)
+    {
+       i = rdcache(r->pool, cachefp, c);
+       if (i == -1)
+           log_uerror("read", c->filename, "proxy: error reading cache file",
+                      r->server);
+       else if (i == 0)
+           log_error("proxy: bad cache file", r->server);
+       if (i != 1)
+       {
+           pclosef(r->pool, cachefp->fd);
+           cachefp = NULL;
+       }
+    }
+    if (cachefp == NULL)
+       c->hdrs = make_array(r->pool, 2, sizeof(struct hdr_entry));
+    /* FIXME: Shouldn't we check the URL somewhere? */
+    now = time(NULL);
+/* Ok, have we got some un-expired data? */
+    if (cachefp != NULL && c->expire != -1 && now < c->expire)
+    {
+        Explain0("Unexpired data available");
+/* check IMS */
+       if (c->lmod != -1 && c->ims != -1 && c->ims >= c->lmod)
+       {
+/* has the cached file changed since this request? */
+           if (c->date == -1 || c->date > c->ims)
+           {
+/* No, but these header values may have changed, so we send them with the
+ * 304 response
+ */
+           /* CHECKME: surely this was wrong? (Ben)
+               p = table_get(r->headers_in, "Expires");
+               */
+               p = table_get(c->hdrs, "Expires");
+               if (p != NULL)  table_set(r->headers_out, "Expires", p);
+           }
+           pclosef(r->pool, cachefp->fd);
+           Explain0("Use local copy, cached file hasn't changed");
+           return USE_LOCAL_COPY;
+       }
+
+/* Ok, has been modified */
+       Explain0("Local copy modified, send it");
+       r->status_line = strchr(c->resp_line, ' ') + 1;
+       r->status = c->status;
+       soft_timeout ("send", r);
+       if (!r->assbackwards)
+           send_headers(r->connection->client, c->resp_line,  c->hdrs);
+       bsetopt(r->connection->client, BO_BYTECT, &zero);
+       r->sent_bodyct = 1;
+       if (!r->header_only) send_fb (cachefp, r, NULL, NULL);
+       pclosef(r->pool, cachefp->fd);
+       return OK;
+    }
+
+/* if we already have data and a last-modified date, and it is not a head
+ * request, then add an If-Modified-Since
+ */
+
+    if (cachefp != NULL && c->lmod != -1 && !r->header_only)
+    {
+/*
+ * use the later of the one from the request and the last-modified date
+ * from the cache
+ */
+       if (c->ims == -1 || c->ims < c->lmod)
+       {
+           struct hdr_entry *q;
+
+           q = get_header(c->hdrs, "Last-Modified");
+
+           if (q != NULL && q->value != NULL)
+               table_set(r->headers_in, "If-Modified-Since",
+                         (char *)q->value);
+       }
+    }
+    c->fp = cachefp;
+
+    Explain0("Local copy not present or expired. Declining.");
+
+    return DECLINED;
+}
+
+/*
+ * Having read the response from the client, decide what to do
+ * If the response is not cachable, then delete any previously cached
+ * response, and copy data from remote server to client.
+ * Functions:
+ *  parse dates
+ *  check for an uncachable response
+ *  calculate an expiry date, if one is not provided
+ *  if the remote file has not been modified, then return the document
+ *  from the cache, maybe updating the header line
+ *  otherwise, delete the old cached file and open a new temporary file
+ */
+static int
+cache_update(struct cache_req *c, array_header *resp_hdrs,
+            const char *protocol, int nocache)
+{
+    request_rec *r=c->req;
+    char *p;
+    int i;
+    struct hdr_entry *expire, *dates, *lmods, *clen;
+    time_t expc, date, lmod, now;
+    char buff[46];
+    void *sconf = r->server->module_config;
+    proxy_server_conf *conf =
+        (proxy_server_conf *)get_module_config(sconf, &proxy_module);
+    const long int zero=0L;
+
+    c->tempfile = NULL;
+
+/* we've received the response */
+/* read expiry date; if a bad date, then leave it so the client can
+ * read it
+ */
+    expire = get_header(resp_hdrs, "Expire");
+    if (expire != NULL) expc = parsedate(expire->value, NULL);
+    else expc = -1;
+
+/*
+ * read the last-modified date; if the date is bad, then delete it
+ */
+    lmods = get_header(resp_hdrs, "Last-Modified");
+    if (lmods != NULL)
+    {
+       lmod = parsedate(lmods->value, NULL);
+       if (lmod == -1)
+       {
+/* kill last modified date */
+           lmods->value = NULL;
+           lmods = NULL;
+       }
+    } else
+       lmod = -1;
+
+/*
+ * what responses should we not cache?
+ * Unknown status responses and those known to be uncacheable
+ * 304 response when we have no valid cache file, or
+ * 200 response from HTTP/1.0 and up without a Last-Modified header, or
+ * HEAD requests, or
+ * requests with an Authorization header, or
+ * protocol requests nocache (e.g. ftp with user/password)
+ */
+    if ((r->status != 200 && r->status != 301 && r->status != 304) ||
+       (expire != NULL && expc == -1) ||
+       (r->status == 304 && c->fp == NULL) ||
+       (r->status == 200 && lmods == NULL &&
+                            strncmp(protocol, "HTTP/1.", 7) == 0) ||
+       r->header_only ||
+       table_get(r->headers_in, "Authorization") != NULL ||
+       nocache)
+    {
+       Explain1("Response is not cacheable, unlinking %s",c->filename);
+/* close the file */
+       if (c->fp != NULL)
+       {
+           pclosef(r->pool, c->fp->fd);
+           c->fp = NULL;
+       }
+/* delete the previously cached file */
+       unlink(c->filename);
+       return DECLINED; /* send data to client but not cache */
+    }
+
+/* otherwise, we are going to cache the response */
+/*
+ * Read the date. Generate one if one is not supplied
+ */
+    dates = get_header(resp_hdrs, "Date");
+    if (dates != NULL) date = parsedate(dates->value, NULL);
+    else date = -1;
+       
+    now = time(NULL);
+
+    if (date == -1) /* No, or bad date */
+    {
+/* no date header! */
+/* add one; N.B. use the time _now_ rather than when we were checking the cache
+ */
+       date = now;
+       p = gm_timestr_822(r->pool, now);
+       dates = add_header(resp_hdrs, "Date", p, HDR_REP);
+       Explain0("Added date header");
+    }
+
+/* check last-modified date */
+    if (lmod != -1 && lmod > date)
+/* if its in the future, then replace by date */
+    {
+       lmod = date;
+       lmods->value = dates->value;
+       Explain0("Last modified is in the future, replacing with now");
+    }
+/* if the response did not contain the header, then use the cached version */
+    if (lmod == -1 && c->fp != NULL)
+       {
+       lmod = c->lmod;
+       Explain0("Reusing cached last modified");
+       }
+
+/* we now need to calculate the expire data for the object. */
+    if (expire == NULL && c->fp != NULL)  /* no expiry data sent in response */
+    {
+       expire = get_header(c->hdrs, "Expires");
+       if (expire != NULL) expc = parsedate(expire->value, NULL);
+    }
+/* so we now have the expiry date */
+/* if no expiry date then
+ *   if lastmod
+ *      expiry date = now + min((date - lastmod) * factor, maxexpire)
+ *   else
+ *      expire date = now + defaultexpire
+ */
+    Explain1("Expiry date is %ld",expc);
+    if (expc == -1)
+    {
+       if (lmod != -1)
+       {
+           double x = (double)(date - lmod)*conf->cache.lmfactor;
+           double maxex=conf->cache.maxexpire;
+           if (x > maxex) x = maxex;
+           expc = now + (int)x;
+       } else
+           expc = now + conf->cache.defaultexpire;
+       Explain1("Expiry date calculated %ld",expc);
+    }
+
+/* get the content-length header */
+    clen = get_header(c->hdrs, "Content-Length");
+    if (clen == NULL) c->len = -1;
+    else c->len = atoi(clen->value);
+
+    sec2hex(date, buff);
+    buff[8] = ' ';
+    sec2hex(lmod, buff+9);
+    buff[17] = ' ';
+    sec2hex(expc, buff+18);
+    buff[26] = ' ';
+    sec2hex(c->version++, buff+27);
+    buff[35] = ' ';
+    sec2hex(c->len, buff+36);
+    buff[44] = '\n';
+    buff[45] = '\0';
+
+/* if file not modified */
+    if (r->status == 304)
+    {
+       if (c->ims != -1 && lmod != -1 && lmod <= c->ims)
+       {
+/* set any changed headers somehow */
+/* update dates and version, but not content-length */
+           if (lmod != c->lmod || expc != c->expire || date != c->date)
+           {
+               off_t curpos=lseek(c->fp->fd, 0, SEEK_SET);
+               if (curpos == -1)
+                   log_uerror("lseek", c->filename,
+                              "proxy: error seeking on cache file",r->server);
+               else if (write(c->fp->fd, buff, 35) == -1)
+                   log_uerror("write", c->filename,
+                              "proxy: error updating cache file", r->server);
+           }
+           pclosef(r->pool, c->fp->fd);
+           Explain0("Remote document not modified, use local copy");
+           /* CHECKME: Is this right? Shouldn't we check IMS again here? */
+           return USE_LOCAL_COPY;
+       } else
+       {
+/* return the whole document */
+           Explain0("Remote document updated, sending");
+           r->status_line = strchr(c->resp_line, ' ') + 1;
+           r->status = c->status;
+           soft_timeout ("send", r);
+           if (!r->assbackwards)
+               send_headers(r->connection->client, c->resp_line,  c->hdrs);
+           bsetopt(r->connection->client, BO_BYTECT, &zero);
+           r->sent_bodyct = 1;
+           if (!r->header_only) send_fb (c->fp, r, NULL, NULL);
+/* set any changed headers somehow */
+/* update dates and version, but not content-length */
+           if (lmod != c->lmod || expc != c->expire || date != c->date)
+           {
+               off_t curpos=lseek(c->fp->fd, 0, SEEK_SET);
+
+               if (curpos == -1)
+                   log_uerror("lseek", c->filename,
+                              "proxy: error seeking on cache file",r->server);
+               else if (write(c->fp->fd, buff, 35) == -1)
+                   log_uerror("write", c->filename,
+                              "proxy: error updating cache file", r->server);
+           }
+           pclosef(r->pool, c->fp->fd);
+           return OK;
+       }
+    }
+/* new or modified file */         
+    if (c->fp != NULL)
+    {
+       pclosef(r->pool, c->fp->fd);
+       c->fp->fd = -1;
+    }
+    c->version = 0;
+    sec2hex(0, buff+27);
+    buff[35] = ' ';
+
+/* open temporary file */
+#define TMPFILESTR     "/#tmpXXXXXX"
+    c->tempfile=palloc(r->pool,strlen(conf->cache.root)+sizeof TMPFILESTR-1);
+    strcpy(c->tempfile,conf->cache.root);
+    /*
+    p = strrchr(c->tempfile, '/');
+    if (p == NULL) return DECLINED;
+    strcpy(p, TMPFILESTR);
+    */
+    strcat(c->tempfile,TMPFILESTR);
+#undef TMPFILESTR
+    p = mktemp(c->tempfile);
+    if (p == NULL) return DECLINED;
+
+    Explain1("Create temporary file %s",c->tempfile);
+
+    i = open(c->tempfile, O_WRONLY | O_CREAT | O_EXCL, 0622);
+    if (i == -1)
+    {
+       log_uerror("open", c->tempfile, "proxy: error creating cache file",
+                  r->server);
+       return DECLINED;
+    }
+    note_cleanups_for_fd(r->pool, i);
+    c->fp = bcreate(r->pool, B_WR);
+    bpushfd(c->fp, -1, i);
+
+    if (bvputs(c->fp, buff, "X-URL: ", c->url, "\n", NULL) == -1)
+    {
+       log_uerror("write", c->tempfile, "proxy: error writing cache file",
+                  r->server);
+       pclosef(r->pool, c->fp->fd);
+       unlink(c->tempfile);
+       c->fp = NULL;
+    }
+    return DECLINED;
+}
+
+static void
+cache_tidy(struct cache_req *c)
+{
+    server_rec *s=c->req->server;
+    long int bc;
+
+    if (c->fp == NULL) return;
+
+    bgetopt(c->req->connection->client, BO_BYTECT, &bc);
+
+    if (c->len != -1)
+    {
+/* file lengths don't match; don't cache it */
+       if (bc != c->len)
+       {
+           pclosef(c->req->pool, c->fp->fd);  /* no need to flush */
+           unlink(c->tempfile);
+           return;
+       }
+    } else
+    {
+/* update content-length of file */
+       char buff[9];
+       off_t curpos;
+
+       c->len = bc;
+       bflush(c->fp);
+       sec2hex(c->len, buff);
+       curpos = lseek(c->fp->fd, 36, SEEK_SET);
+       if (curpos == -1)
+           log_uerror("lseek", c->tempfile,
+                      "proxy: error seeking on cache file", s);
+       else if (write(c->fp->fd, buff, 8) == -1)
+           log_uerror("write", c->tempfile,
+                      "proxy: error updating cache file", s);
+    }
+
+    if (bflush(c->fp) == -1)
+    {
+       log_uerror("write", c->tempfile, "proxy: error writing to cache file",
+                  s);
+       pclosef(c->req->pool, c->fp->fd);
+       unlink(c->tempfile);
+       return;
+    }
+
+    if (pclosef(c->req->pool, c->fp->fd) == -1)
+    {
+       log_uerror("close", c->tempfile, "proxy: error closing cache file", s);
+       unlink(c->tempfile);
+       return;
+    }
+
+    if (unlink(c->filename) == -1 && errno != ENOENT)
+    {
+       log_uerror("unlink", c->filename,
+                  "proxy: error deleting old cache file", s);
+    } else
+       {
+       char *p;
+       proxy_server_conf *conf=
+         (proxy_server_conf *)get_module_config(s->module_config,&proxy_module);
+
+       for(p=c->filename+strlen(conf->cache.root)+1 ; ; )
+           {
+           p=strchr(p,'/');
+           if(!p)
+               break;
+           *p='\0';
+           if(mkdir(c->filename,S_IREAD|S_IWRITE|S_IEXEC) < 0 && errno != EEXIST)
+               log_uerror("mkdir",c->filename,"proxy: error creating cache directory",s);
+           *p='/';
+           ++p;
+           }
+#ifdef __EMX__
+        /* Under OS/2 use rename. */            
+        if (rename(c->tempfile, c->filename) == -1)
+            log_uerror("rename", c->filename, "proxy: error renaming cache file", s);
+}
+#else            
+
+       if (link(c->tempfile, c->filename) == -1)
+           log_uerror("link", c->filename, "proxy: error linking cache file", s);
+       }
+
+    if (unlink(c->tempfile) == -1)
+       log_uerror("unlink", c->tempfile, "proxy: error deleting temp file",s);
+#endif
+
+    garbage_coll(c->req);
+}
+
+static BUFF *
+cache_error(struct cache_req *c)
+{
+    log_uerror("write", c->tempfile, "proxy: error writing to cache file",
+              c->req->server);
+    pclosef(c->req->pool, c->fp->fd);
+    c->fp = NULL;
+    unlink(c->tempfile);
+    return NULL;
+}
+
+static int
+proxy_handler(request_rec *r)
+{
+    char *url, *scheme, *lenp, *p;
+    void *sconf = r->server->module_config;
+    proxy_server_conf *conf =
+        (proxy_server_conf *)get_module_config(sconf, &proxy_module);
+    array_header *proxies=conf->proxies;
+    struct proxy_remote *ents=(struct proxy_remote *)proxies->elts;
+    int i, rc;
+    struct cache_req *cr;
+
+    if (strncmp(r->filename, "proxy:", 6) != 0) return DECLINED;
+
+    lenp = table_get (r->headers_in, "Content-length");
+    if ((r->method_number == M_POST || r->method_number == M_PUT)
+       && lenp == NULL)
+       return BAD_REQUEST;
+
+    url = r->filename + 6;
+    p = strchr(url, ':');
+    if (p == NULL) return BAD_REQUEST;
+
+    rc = cache_check(r, url, &conf->cache, &cr);
+    if (rc != DECLINED) return rc;
+
+    *p = '\0';
+    scheme = pstrdup(r->pool, url);
+    *p = ':';
+
+/* firstly, try a proxy */
+
+    for (i=0; i < proxies->nelts; i++)
+    {
+       p = strchr(ents[i].scheme, ':');  /* is it a partial URL? */
+       if (strcmp(ents[i].scheme, "*") == 0 || 
+           (p == NULL && strcmp(scheme, ents[i].scheme) == 0) ||
+           (p != NULL &&
+              strncmp(url, ents[i].scheme, strlen(ents[i].scheme)) == 0))
+       {
+/* we only know how to handle communication to a proxy via http */
+           if (strcmp(ents[i].protocol, "http") == 0)
+               rc = http_handler(r, cr, url, ents[i].hostname, ents[i].port);
+           else rc = DECLINED;
+
+ /* an error or success */
+           if (rc != DECLINED && rc != BAD_GATEWAY) return rc;
+ /* we failed to talk to the upstream proxy */
+       }
+    }
+
+/* otherwise, try it direct */
+/* N.B. what if we're behind a firewall, where we must use a proxy or
+ * give up??
+ */
+    /* handle the scheme */
+    if (r->method_number == M_CONNECT) return connect_handler(r, cr, url);
+    if (strcmp(scheme, "http") == 0) return http_handler(r, cr, url, NULL, 0);
+    if (strcmp(scheme, "ftp") == 0) return ftp_handler(r, cr, url);
+    else return NOT_IMPLEMENTED;
+}
+
+
+static int
+proxyerror(request_rec *r, const char *message)
+{
+    r->status = SERVER_ERROR;
+    r->status_line = "500 Proxy Error";
+    r->content_type = "text/html";
+
+    send_http_header(r);
+    rvputs(r, "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\015\012\
+<html><head><title>Proxy Error</title><head>\015\012<body><h1>Proxy Error\
+</h1>\015\012The proxy server could not handle this request.\
+\015\012<p>\015\012Reason: <b>", message, "</b>\015\012</body><html>\015\012",
+          NULL);
+    return OK;
+}
+
+/*
+ * This routine returns its own error message
+ */
+static const char *
+host2addr(const char *host, struct in_addr *addr)
+{
+    int i;
+    unsigned long ipaddr;
+
+    for (i=0; host[i] != '\0'; i++)
+       if (!isdigit(host[i]) && host[i] != '.')
+           break;
+
+    if (host[i] != '\0')
+    {
+       struct hostent *hp;
+
+       hp = gethostbyname(host);
+       if (hp == NULL) return "Host not found";
+       memcpy(addr, hp->h_addr, sizeof(struct in_addr));
+    } else
+    {
+       if ((ipaddr = inet_addr(host)) == -1)
+           return "Bad IP address";
+       memcpy(addr, &ipaddr, sizeof(unsigned long));
+    }
+    return NULL;
+}
+
+/*
+ * Returns the ftp status code;
+ *  or -1 on I/O error, 0 on data error
+ */
+int
+ftp_getrc(BUFF *f)
+{
+    int i, len, status;
+    char linebuff[100], buff[5];
+
+    len = bgets(linebuff, 100, f);
+    if (len == -1) return -1;
+/* check format */
+    if (len < 5 || !isdigit(linebuff[0]) || !isdigit(linebuff[1]) ||
+       !isdigit(linebuff[2]) || (linebuff[3] != ' ' && linebuff[3] != '-'))
+       return 0;
+    status = 100 * linebuff[0] + 10 * linebuff[1] + linebuff[2] - 111 * '0';
+    
+    if (linebuff[len-1] != '\n')
+    {
+       i = bskiplf(f);
+       if (i != 1) return i;
+    }
+
+/* skip continuation lines */    
+    if (linebuff[3] == '-')
+    {
+       memcpy(buff, linebuff, 3);
+       buff[3] = ' ';
+       do
+       {
+           len = bgets(linebuff, 100, f);
+           if (len == -1) return -1;
+           if (len < 5) return 0;
+           if (linebuff[len-1] != '\n')
+           {
+               i = bskiplf(f);
+               if (i != 1) return i;
+           }
+       } while (memcmp(linebuff, buff, 4) != 0);
+    }
+
+    return status;
+}
+
+static int
+doconnect(int sock, struct sockaddr_in *addr, request_rec *r)
+{
+    int i;
+
+    hard_timeout ("proxy connect", r);
+    do i = connect(sock, (struct sockaddr *)addr, sizeof(struct sockaddr_in));
+    while (i == -1 && errno == EINTR);
+    if (i == -1) log_uerror("connect", NULL, NULL, r->server);
+    kill_timeout(r);
+
+    return i;
+}
+
+/*
+ * Handles direct access of ftp:// URLs
+ */
+static int
+ftp_handler(request_rec *r, struct cache_req *c, char *url)
+{
+    char *host, *path, *p, *user, *password, *parms;
+    const char *err;
+    int port, userlen, passlen, i, len, sock, dsock, csd, rc, nocache;
+    struct sockaddr_in server;
+    struct hdr_entry *hdr;
+    array_header *resp_hdrs;
+    BUFF *f, *cache, *data;
+    pool *pool=r->pool;
+    const int one=1;
+    const long int zero=0L;
+
+/* we only support GET and HEAD */
+    if (r->method_number != M_GET) return NOT_IMPLEMENTED;
+
+    host = pstrdup(r->pool, url+6);
+/* We break the URL into host, port, path-search */
+    port = DEFAULT_FTP_PORT;
+    path = strchr(host, '/');
+    if (path == NULL) path = "";
+    else *(path++) = '\0';
+
+    user = password = NULL;
+    nocache = 0;
+    passlen=0; /* not actually needed, but it shuts the compiler up */
+    p = strchr(host, '@');
+    if (p != NULL)
+    {
+       (*p++) = '\0';
+       user = host;
+       host = p;
+/* find password */
+       p = strchr(user, ':');
+       if (p != NULL)
+       {
+           *(p++) = '\0';
+           password = p;
+           passlen = decodeenc(password);
+       }
+       userlen = decodeenc(user);
+       nocache = 1; /* don't cache when a username is supplied */
+    } else
+    {
+       user = "anonymous";
+       userlen = 9;
+
+       password = "proxy_user@host";
+       passlen = strlen(password);
+    }
+
+    p = strchr(host, ':');
+    if (p != NULL)
+    {
+       *(p++) = '\0';
+       port = atoi(p);
+    }
+
+    parms = strchr(path, ';');
+    if (parms != NULL) *(parms++) = '\0';
+
+    memset(&server,'\0',sizeof server);
+    server.sin_family=AF_INET;
+    server.sin_port = htons(port);
+    err = host2addr(host, &server.sin_addr);
+    if (err != NULL) return proxyerror(r, err); /* give up */
+
+    sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    if (sock == -1)
+    {
+       log_uerror("socket", NULL, "proxy: error creating socket", r->server);
+       return SERVER_ERROR;
+    }
+    note_cleanups_for_fd(pool, sock);
+
+    if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char *)&one,
+                  sizeof(int)) == -1)
+    {
+       log_uerror("setsockopt", NULL, "proxy: error setting reuseaddr option",
+                  r->server);
+       pclosef(pool, sock);
+       return SERVER_ERROR;
+    }
+
+    i = doconnect(sock, &server, r);
+    if (i == -1) return proxyerror(r, "Could not connect to remote machine");
+
+    f = bcreate(pool, B_RDWR);
+    bpushfd(f, sock, sock);
+/* shouldn't we implement telnet control options here? */
+
+/* possible results: 120, 220, 421 */
+    hard_timeout ("proxy ftp", r);
+    i = ftp_getrc(f);
+    if (i == -1) return proxyerror(r, "Error reading from remote server");
+    if (i != 220) return BAD_GATEWAY;
+
+    bputs("USER ", f);
+    bwrite(f, user, userlen);
+    bputs("\015\012", f);
+    bflush(f); /* capture any errors */
+    
+/* possible results; 230, 331, 332, 421, 500, 501, 530 */
+/* states: 1 - error, 2 - success; 3 - send password, 4,5 fail */
+    i = ftp_getrc(f);
+    if (i == -1) return proxyerror(r, "Error sending to remote server");
+    if (i == 530) return FORBIDDEN;
+    else if (i != 230 && i != 331) return BAD_GATEWAY;
+       
+    if (i == 331) /* send password */
+    {
+       if (password == NULL) return FORBIDDEN;
+       bputs("PASS ", f);
+       bwrite(f, password, passlen);
+       bputs("\015\012", f);
+       bflush(f);
+/* possible results 202, 230, 332, 421, 500, 501, 503, 530 */
+       i = ftp_getrc(f);
+       if (i == -1) return proxyerror(r, "Error sending to remote server");
+       if (i == 332 || i == 530) return FORBIDDEN;
+       else if (i != 230 && i != 202) return BAD_GATEWAY;
+    }  
+
+/* set the directory */
+/* this is what we must do if we don't know the OS type of the remote
+ * machine
+ */
+    for (;;)
+    {
+       p = strchr(path, '/');
+       if (p == NULL) break;
+       *p = '\0';
+
+       len = decodeenc(path);
+       bputs("CWD ", f);
+       bwrite(f, path, len);
+       bputs("\015\012", f);
+        bflush(f);
+/* responses: 250, 421, 500, 501, 502, 530, 550 */
+/* 1,3 error, 2 success, 4,5 failure */
+       i = ftp_getrc(f);
+       if (i == -1) return proxyerror(r, "Error sending to remote server");
+       else if (i == 550) return NOT_FOUND;
+       else if (i != 250) return BAD_GATEWAY;
+
+       path = p + 1;
+    }
+
+    if (parms != NULL && strncmp(parms, "type=", 5) == 0)
+    {
+       parms += 5;
+       if ((parms[0] != 'd' && parms[0] != 'a' && parms[0] != 'i') ||
+           parms[1] != '\0') parms = "";
+    }
+    else parms = "";
+
+    if (parms[0] == 'i')
+    {
+       /* set type to image */
+       bputs("TYPE I", f);
+       bflush(f);
+/* responses: 200, 421, 500, 501, 504, 530 */
+       i = ftp_getrc(f);
+       if (i == -1) return proxyerror(r, "Error sending to remote server");
+       else if (i != 200 && i != 504) return BAD_GATEWAY;
+/* Allow not implemented */
+       else if (i == 504) parms[0] = '\0';
+    }
+
+/* set up data connection */
+    len = sizeof(struct sockaddr_in);
+    if (getsockname(sock, (struct sockaddr *)&server, &len) < 0)
+    {
+       log_uerror("getsockname", NULL,"proxy: error getting socket address",
+                  r->server);
+       pclosef(pool, sock);
+       return SERVER_ERROR;
+    }
+
+    dsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    if (dsock == -1)
+    {
+       log_uerror("socket", NULL, "proxy: error creating socket", r->server);
+       pclosef(pool, sock);
+       return SERVER_ERROR;
+    }
+    note_cleanups_for_fd(pool, dsock);
+
+    if (setsockopt(dsock, SOL_SOCKET, SO_REUSEADDR, (const char *)&one,
+                  sizeof(int)) == -1)
+    {
+       log_uerror("setsockopt", NULL, "proxy: error setting reuseaddr option",
+                  r->server);
+       pclosef(pool, dsock);
+       pclosef(pool, sock);
+       return SERVER_ERROR;
+    }
+
+    if (bind(dsock, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) ==
+       -1)
+    {
+       char buff[22];
+
+       sprintf(buff, "%s:%d", inet_ntoa(server.sin_addr), server.sin_port);
+       log_uerror("bind", buff, "proxy: error binding to ftp data socket",
+                  r->server);
+       pclosef(pool, sock);
+       pclosef(pool, dsock);
+    }
+    listen(dsock, 2); /* only need a short queue */
+
+/* set request */
+    len = decodeenc(path);
+    if (parms[0] == 'd')
+    {
+       if (len != 0) bputs("NLST ", f);
+       else bputs("NLST", f);
+    }
+    else bputs("RETR ", f);
+    bwrite(f, path, len);
+    bputs("\015\012", f);
+    bflush(f);
+/* RETR: 110, 125, 150, 226, 250, 421, 425, 426, 450, 451, 500, 501, 530, 550
+   NLST: 125, 150, 226, 250, 421, 425, 426, 450, 451, 500, 501, 502, 530 */
+    rc = ftp_getrc(f);
+    if (rc == -1) return proxyerror(r, "Error sending to remote server");
+    if (rc == 550) return NOT_FOUND;
+    if (rc != 125 && rc != 150 && rc != 226 && rc != 250) return BAD_GATEWAY;
+    kill_timeout(r);
+
+    r->status = 200;
+    r->status_line = "200 OK";
+
+    resp_hdrs = make_array(pool, 2, sizeof(struct hdr_entry));
+    if (parms[0] == 'd')
+       add_header(resp_hdrs, "Content-Type", "text/plain", HDR_REP);
+    i = cache_update(c, resp_hdrs, "FTP", nocache);
+    if (i != DECLINED)
+    {
+       pclosef(pool, dsock);
+       pclosef(pool, sock);
+       return i;
+    }
+    cache = c->fp;
+
+/* wait for connection */
+    hard_timeout ("proxy ftp data connect", r);
+    len = sizeof(struct sockaddr_in);
+    do csd = accept(dsock, (struct sockaddr *)&server, &len);
+    while (csd == -1 && errno == EINTR);       /* SHUDDER on SOCKS - cdm */
+    if (csd == -1)
+    {
+       log_uerror("accept", NULL, "proxy: failed to accept data connection",
+                  r->server);
+       pclosef(pool, dsock);
+       pclosef(pool, sock);
+       cache_error(c);
+       return BAD_GATEWAY;
+    }
+    note_cleanups_for_fd(pool, csd);
+    data = bcreate(pool, B_RD);
+    bpushfd(data, csd, -1);
+    kill_timeout(r);
+
+    hard_timeout ("proxy receive", r);
+/* send response */
+/* write status line */
+    if (!r->assbackwards)
+       rvputs(r, SERVER_PROTOCOL, " ", r->status_line, "\015\012", NULL);
+    if (cache != NULL)
+       if (bvputs(cache, SERVER_PROTOCOL, " ", r->status_line, "\015\012",
+                  NULL) == -1)
+           cache = cache_error(c);
+
+/* send headers */
+    len = resp_hdrs->nelts;
+    hdr = (struct hdr_entry *)resp_hdrs->elts;
+    for (i=0; i < len; i++)
+    {
+       if (hdr[i].field == NULL || hdr[i].value == NULL ||
+           hdr[i].value[0] == '\0') continue;
+       if (!r->assbackwards)
+           rvputs(r, hdr[i].field, ": ", hdr[i].value, "\015\012", NULL);
+       if (cache != NULL)
+           if (bvputs(cache, hdr[i].field, ": ", hdr[i].value, "\015\012",
+                      NULL) == -1)
+               cache = cache_error(c);
+    }
+
+    if (!r->assbackwards) rputs("\015\012", r);
+    if (cache != NULL)
+       if (bputs("\015\012", cache) == -1) cache = cache_error(c);
+
+    bsetopt(r->connection->client, BO_BYTECT, &zero);
+    r->sent_bodyct = 1;
+/* send body */
+    if (!r->header_only)
+    {
+       send_fb(data, r, cache, c);
+       if (rc == 125 || rc == 150) rc = ftp_getrc(f);
+       if (rc != 226 && rc != 250) cache_error(c);
+    }
+    else
+    {
+/* abort the transfer */
+       bputs("ABOR\015\012", f);
+       bflush(f);
+/* responses: 225, 226, 421, 500, 501, 502 */
+       i = ftp_getrc(f);
+    }
+
+    cache_tidy(c);
+
+/* finish */
+    bputs("QUIT\015\012", f);
+    bflush(f);
+/* responses: 221, 500 */    
+
+    pclosef(pool, csd);
+    pclosef(pool, dsock);
+    pclosef(pool, sock);
+
+    return OK;
+}
+
+/*  
+ * This handles Netscape CONNECT method secure proxy requests.
+ * A connection is opened to the specified host and data is
+ * passed through between the WWW site and the browser.
+ *
+ * This code is based on the INTERNET-DRAFT document
+ * "Tunneling SSL Through a WWW Proxy" currently at
+ * http://www.mcom.com/newsref/std/tunneling_ssl.html.
+ *
+ * FIXME: this is bad, because it does its own socket I/O
+ *        instead of using the I/O in buff.c.  However,
+ *        the I/O in buff.c blocks on reads, and because
+ *        this function doesn't know how much data will
+ *        be sent either way (or when) it can't use blocking
+ *        I/O.  This may be very implementation-specific
+ *        (to Linux).  Any suggestions?
+ * FIXME: this doesn't log the number of bytes sent, but
+ *        that may be okay, since the data is supposed to
+ *        be transparent. In fact, this doesn't log at all
+ *       yet. 8^)
+ * FIXME: doesn't check any headers initally sent from the
+ *        client.
+ * FIXME: should allow authentication, but hopefully the
+ *        generic proxy authentication is good enough.
+ * FIXME: no check for r->assbackwards, whatever that is.
+ */ 
+static int
+connect_handler(request_rec *r, struct cache_req *c, char *url)
+{
+    struct sockaddr_in server;
+    const char *host, *err;
+    char *p;
+    int   port, sock;
+    char buffer[HUGE_STRING_LEN];
+    int  nbytes, i;
+    fd_set fds;
+
+    memset(&server, '\0', sizeof(server));
+    server.sin_family=AF_INET;
+    /* Break the URL into host:port pairs */
+
+    host = url;
+    p = strchr(url, ':');
+    if (p==NULL) port = DEFAULT_HTTPS_PORT;
+    else
+    {
+      port = atoi(p+1);
+      *p='\0';
+    }
+    switch (port)
+    {
+       case DEFAULT_HTTPS_PORT:
+       case DEFAULT_SNEWS_PORT:
+           break;
+       default:
+           return SERVICE_UNAVAILABLE;
+    }
+
+    Explain2("CONNECT to %s on port %d", host, port);
+    server.sin_port = htons(port);
+    err = host2addr(host, &server.sin_addr);
+    if (err != NULL) return proxyerror(r, err); /* give up */
+    sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);  
+    if (sock == -1)
+    {     
+        log_error("proxy: error creating socket", r->server);
+        return SERVER_ERROR;
+    }     
+    note_cleanups_for_fd(r->pool, sock);
+    i = doconnect(sock, &server, r);
+    if (i == -1 )
+        return proxyerror(r, "Could not connect to remote machine");
+    Explain0("Returning 200 OK Status");
+    rvputs(r, "HTTP/1.0 200 Connection established\015\012", NULL);
+    rvputs(r, "Proxy-agent: ", SERVER_VERSION, "\015\012\015\012", NULL);
+    bflush(r->connection->client);
+
+    while (1) /* Infinite loop until error (one side closes the connection) */
+    {
+      FD_ZERO(&fds);
+      FD_SET(sock, &fds);
+      FD_SET(r->connection->client->fd, &fds);
+    
+      Explain0("Going to sleep (select)");
+      i = select((r->connection->client->fd > sock ?
+       r->connection->client->fd+1 :
+#ifdef HPUX
+       sock+1), (int*)&fds, NULL, NULL, NULL);
+#else
+       sock+1), &fds, NULL, NULL, NULL);
+#endif
+      Explain1("Woke from select(), i=%d",i);
+    
+      if (i)
+      {
+        if (FD_ISSET(sock, &fds))
+        {
+           Explain0("sock was set");
+           if((nbytes=read(sock,buffer,HUGE_STRING_LEN))!=0)
+           {
+              if(nbytes==-1) break;
+              if(write(r->connection->client->fd, buffer, nbytes)==EOF)break;
+              Explain1("Wrote %d bytes to client", nbytes);
+           }
+           else break;
+        }
+        else if (FD_ISSET(r->connection->client->fd, &fds))
+        { 
+           Explain0("client->fd was set");
+           if((nbytes=read(r->connection->client->fd,buffer,
+               HUGE_STRING_LEN))!=0)   
+           {
+              if(nbytes==-1) break;
+              if(write(sock,buffer,nbytes)==EOF) break;
+              Explain1("Wrote %d bytes to server", nbytes);
+           }
+           else break;
+        }
+        else break; /* Must be done waiting */
+      }
+      else break;
+    }
+
+    pclosef(r->pool,sock);
+    
+    return OK;
+}     
+
+/*
+ * This handles http:// URLs, and other URLs using a remote proxy over http
+ * If proxyhost is NULL, then contact the server directly, otherwise
+ * go via the proxy.
+ * Note that if a proxy is used, then URLs other than http: can be accessed,
+ * also, if we have trouble which is clearly specific to the proxy, then
+ * we return DECLINED so that we can try another proxy. (Or the direct
+ * route.)
+ */
+static int
+http_handler(request_rec *r, struct cache_req *c, char *url,
+            const char *proxyhost, int proxyport)
+{
+    char *p;
+    const char *err, *host;
+    int port, i, sock, len;
+    array_header *reqhdrs_arr, *resp_hdrs;
+    table_entry *reqhdrs;
+    struct sockaddr_in server;
+    BUFF *f, *cache;
+    struct hdr_entry *hdr;
+    char buffer[HUGE_STRING_LEN], inprotocol[9], outprotocol[9];
+    pool *pool=r->pool;
+    const long int zero=0L;
+
+    void *sconf = r->server->module_config;
+    proxy_server_conf *conf =
+        (proxy_server_conf *)get_module_config(sconf, &proxy_module);
+    struct nocache_entry *ent=(struct nocache_entry *)conf->nocaches->elts;
+    int nocache = 0;
+
+    memset(&server, '\0', sizeof(server));
+    server.sin_family = AF_INET;
+
+    if (proxyhost != NULL)
+    {
+       server.sin_port = htons(proxyport);
+       err = host2addr(proxyhost, &server.sin_addr);
+       if (err != NULL) return DECLINED;  /* try another */
+       host = proxyhost;
+    } else
+    {
+       url += 7;  /* skip http:// */
+/* We break the URL into host, port, path-search */
+       port = DEFAULT_PORT;
+       p = strchr(url, '/');
+       if (p == NULL)
+       {
+           host = pstrdup(pool, url);
+           url = "/";
+       } else
+       {
+           char *q = palloc(pool, p-url+1);
+           memcpy(q, url, p-url);
+           q[p-url] = '\0';
+           url = p;
+           host = q;
+       }
+
+       p = strchr(host, ':');
+       if (p != NULL)
+       {
+           *(p++) = '\0';
+           port = atoi(p);
+       }
+       server.sin_port = htons(port);
+       err = host2addr(host, &server.sin_addr);
+       if (err != NULL) return proxyerror(r, err); /* give up */
+    }
+
+    sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    if (sock == -1)
+    {
+       log_error("proxy: error creating socket", r->server);
+       return SERVER_ERROR;
+    }
+    note_cleanups_for_fd(pool, sock);
+
+    i = doconnect(sock, &server, r);
+    if (i == -1)
+    {
+       if (proxyhost != NULL) return DECLINED; /* try again another way */
+       else return proxyerror(r, "Could not connect to remote machine");
+    }
+
+    f = bcreate(pool, B_RDWR);
+    bpushfd(f, sock, sock);
+
+    hard_timeout ("proxy send", r);
+    bvputs(f, r->method, " ", url, " HTTP/1.0\015\012", NULL);
+
+    reqhdrs_arr = table_elts (r->headers_in);
+    reqhdrs = (table_entry *)reqhdrs_arr->elts;
+    for (i=0; i < reqhdrs_arr->nelts; i++)
+    {
+       if (reqhdrs[i].key == NULL || reqhdrs[i].val == NULL) continue;
+       if (!strcasecmp(reqhdrs[i].key, "Connection")) continue;
+       bvputs(f, reqhdrs[i].key, ": ", reqhdrs[i].val, "\015\012", NULL);
+    }
+
+    bputs("\015\012", f);
+/* send the request data, if any. N.B. should we trap SIGPIPE ? */
+
+    if (r->method_number == M_POST || r->method_number == M_PUT)
+    {
+       len = atoi(table_get (r->headers_in, "Content-length"));
+
+       while (len > 0)
+       {
+           i = len;
+           if (i > HUGE_STRING_LEN) i = HUGE_STRING_LEN;
+           
+           i = read_client_block(r, buffer, i);
+           bwrite(f, buffer, i);
+
+           len -= i;
+       }
+    }
+    bflush(f);
+    kill_timeout(r);
+
+    hard_timeout ("proxy receive", r);
+    
+    len = bgets(buffer, HUGE_STRING_LEN-1, f);
+    if (len == -1 || len == 0)
+    {
+       pclosef(pool, sock);
+       return proxyerror(r, "Error reading from remote server");
+    }
+
+/* Is it an HTTP/1 response? */
+    if (checkmask(buffer,  "HTTP/#.# ### *"))
+    {
+/* If not an HTTP/1 messsage or if the status line was > 8192 bytes */
+       if (buffer[5] != '1' || buffer[len-1] != '\n')
+       {
+           pclosef(pool, sock);
+           return BAD_GATEWAY;
+       }
+       buffer[--len] = '\0';
+       memcpy(inprotocol, buffer, 8);
+       inprotocol[8] = '\0';
+
+/* we use the same protocol on output as on input */
+       strcpy(outprotocol, inprotocol);
+       buffer[12] = '\0';
+       r->status = atoi(&buffer[9]);
+       buffer[12] = ' ';
+       r->status_line = pstrdup(pool, &buffer[9]);
+
+/* read the headers. */
+/* N.B. for HTTP/1.0 clients, we have to fold line-wrapped headers */
+/* Also, take care with headers with multiple occurences. */
+
+       resp_hdrs = read_headers(pool, buffer, HUGE_STRING_LEN, f);
+    } else
+    {
+/* an http/0.9 response */
+       strcpy(inprotocol, "HTTP/0.9");
+       strcpy(outprotocol, "HTTP/1.0");
+       r->status = 200;
+       r->status_line = "200 OK";
+
+/* no headers */
+       resp_hdrs = make_array(pool, 2, sizeof(struct hdr_entry));
+    }
+
+    kill_timeout(r);
+
+/*
+ * HTTP/1.0 requires us to accept 3 types of dates, but only generate
+ * one type
+ */
+    
+    len = resp_hdrs->nelts;
+    hdr = (struct hdr_entry *)resp_hdrs->elts;
+    for (i=0; i < len; i++)
+    {
+       if (hdr[i].value[0] == '\0') continue;
+       p = hdr[i].field;
+       if (strcasecmp(p, "Date") == 0 ||
+           strcasecmp(p, "Last-Modified") == 0 ||
+           strcasecmp(p, "Expires") == 0)
+           hdr[i].value = date_canon(pool, hdr[i].value);
+    }
+
+/* check if NoCache directive on this host */
+    for (i=0; i < conf->nocaches->nelts; i++)
+    {
+        if (ent[i].name != NULL && strstr(host, ent[i].name) != NULL)
+           nocache = 1; 
+    }
+
+    i = cache_update(c, resp_hdrs, inprotocol, nocache);
+    if (i != DECLINED)
+    {
+       pclosef(pool, sock);
+       return i;
+    }
+
+    cache = c->fp;
+
+    hard_timeout ("proxy receive", r);
+
+/* write status line */
+    if (!r->assbackwards)
+        rvputs(r, "HTTP/1.0 ", r->status_line, "\015\012", NULL);
+    if (cache != NULL)
+       if (bvputs(cache, outprotocol, " ", r->status_line, "\015\012", NULL)
+           == -1)
+           cache = cache_error(c);
+
+/* send headers */
+    len = resp_hdrs->nelts;
+    for (i=0; i < len; i++)
+    {
+       if (hdr[i].field == NULL || hdr[i].value == NULL ||
+           hdr[i].value[0] == '\0') continue;
+       if (!r->assbackwards)
+           rvputs(r, hdr[i].field, ": ", hdr[i].value, "\015\012", NULL);
+       if (cache != NULL)
+           if (bvputs(cache, hdr[i].field, ": ", hdr[i].value, "\015\012",
+                      NULL) == -1)
+               cache = cache_error(c);
+    }
+
+    if (!r->assbackwards) rputs("\015\012", r);
+    if (cache != NULL)
+       if (bputs("\015\012", cache) == -1) cache = cache_error(c);
+
+    bsetopt(r->connection->client, BO_BYTECT, &zero);
+    r->sent_bodyct = 1;
+/* Is it an HTTP/0.9 respose? If so, send the extra data */
+    if (strcmp(inprotocol, "HTTP/0.9") == 0)
+    {
+       bwrite(r->connection->client, buffer, len);
+       if (cache != NULL)
+           if (bwrite(f, buffer, len) != len) cache = cache_error(c);
+    }
+
+/* send body */
+/* if header only, then cache will be NULL */
+/* HTTP/1.0 tells us to read to EOF, rather than content-length bytes */
+    if (!r->header_only) send_fb(f, r, cache, c);
+
+    cache_tidy(c);
+
+    pclosef(pool, sock);
+
+    return OK;
+}
+
+static handler_rec proxy_handlers[] = {
+{ "proxy-server", proxy_handler },
+{ NULL }
+};
+
+
+static void *
+create_proxy_config(pool *p, server_rec *s)
+{
+  proxy_server_conf *ps = pcalloc(p, sizeof(proxy_server_conf));
+
+  ps->proxies = make_array(p, 10, sizeof(struct proxy_remote));
+  ps->aliases = make_array(p, 10, sizeof(struct proxy_alias));
+  ps->nocaches = make_array(p, 10, sizeof(struct nocache_entry));
+  ps->req = 0;
+
+  ps->cache.root = NULL;
+  ps->cache.space = DEFAULT_CACHE_SPACE;
+  ps->cache.maxexpire = DEFAULT_CACHE_MAXEXPIRE;
+  ps->cache.defaultexpire = DEFAULT_CACHE_EXPIRE;
+  ps->cache.lmfactor = DEFAULT_CACHE_LMFACTOR;
+  ps->cache.gcinterval = -1;
+  /* at these levels, the cache can have 2^18 directories (256,000)  */
+  ps->cache.dirlevels=3;
+  ps->cache.dirlength=1;
+
+  return ps;
+}
+
+static char *
+add_proxy(cmd_parms *cmd, void *dummy, char *f, char *r)
+{
+    server_rec *s = cmd->server;
+    proxy_server_conf *conf =
+        (proxy_server_conf *)get_module_config(s->module_config,&proxy_module);
+    struct proxy_remote *new;
+    char *p, *q;
+    int port;
+
+    p = strchr(r, ':');
+    if (p == NULL || p[1] != '/' || p[2] != '/' || p[3] == '\0')
+       return "Bad syntax for a remote proxy server";
+    q = strchr(p + 3, ':');
+    if (q != NULL)
+    {
+       if (sscanf(q+1, "%u", &port) != 1 || port > 65535)
+           return "Bad syntax for a remote proxy server (bad port number)";
+       *q = '\0';
+    } else port = -1;
+    *p = '\0';
+    if (strchr(f, ':') == NULL) str_tolower(f);     /* lowercase scheme */
+    str_tolower(p + 3); /* lowercase hostname */
+
+    if (port == -1)
+    {
+       int i;
+       for (i=0; defports[i].scheme != NULL; i++)
+           if (strcmp(defports[i].scheme, r) == 0) break;
+       port = defports[i].port;
+    }
+
+    new = push_array (conf->proxies);
+    new->scheme = f;
+    new->protocol = r;
+    new->hostname = p + 3;
+    new->port = port;
+    return NULL;
+}
+
+static char *
+add_pass(cmd_parms *cmd, void *dummy, char *f, char *r)
+{
+    server_rec *s = cmd->server;
+    proxy_server_conf *conf =
+        (proxy_server_conf *)get_module_config(s->module_config,&proxy_module);
+    struct proxy_alias *new;
+
+    new = push_array (conf->aliases);
+    new->fake = f;
+    new->real = r;
+    return NULL;
+}
+
+static char *
+set_proxy_req(cmd_parms *parms, void *dummy, int flag)
+{
+    proxy_server_conf *psf =
+       get_module_config (parms->server->module_config, &proxy_module);
+
+    psf->req = flag;
+    return NULL;
+}
+
+
+static char *
+set_cache_size(cmd_parms *parms, char *struct_ptr, char *arg)
+{
+    proxy_server_conf *psf =
+       get_module_config (parms->server->module_config, &proxy_module);
+    int val;
+
+    if (sscanf(arg, "%d", &val) != 1) return "Value must be an integer";
+    psf->cache.space = val;
+    return NULL;
+}
+
+static char *
+set_cache_root(cmd_parms *parms, void *dummy, char *arg)
+{
+    proxy_server_conf *psf =
+       get_module_config (parms->server->module_config, &proxy_module);
+
+    psf->cache.root = arg;
+
+    return NULL;
+}
+
+static char *
+set_cache_factor(cmd_parms *parms, void *dummy, char *arg)
+{
+    proxy_server_conf *psf =
+       get_module_config (parms->server->module_config, &proxy_module);
+    double val;
+
+    if (sscanf(arg, "%lg", &val) != 1) return "Value must be a float";
+    psf->cache.lmfactor = val;
+
+    return NULL;
+}
+
+static char *
+set_cache_maxex(cmd_parms *parms, void *dummy, char *arg)
+{
+    proxy_server_conf *psf =
+       get_module_config (parms->server->module_config, &proxy_module);
+    double val;
+
+    if (sscanf(arg, "%lg", &val) != 1) return "Value must be a float";
+    psf->cache.maxexpire = (int)(val * (double)SEC_ONE_HR);
+    return NULL;
+}
+
+static char *
+set_cache_defex(cmd_parms *parms, void *dummy, char *arg)
+{
+    proxy_server_conf *psf =
+       get_module_config (parms->server->module_config, &proxy_module);
+    double val;
+
+    if (sscanf(arg, "%lg", &val) != 1) return "Value must be a float";
+    psf->cache.defaultexpire = (int)(val * (double)SEC_ONE_HR);
+    return NULL;
+}
+
+static char *
+set_cache_gcint(cmd_parms *parms, void *dummy, char *arg)
+{
+    proxy_server_conf *psf =
+       get_module_config (parms->server->module_config, &proxy_module);
+    double val;
+
+    if (sscanf(arg, "%lg", &val) != 1) return "Value must be a float";
+    psf->cache.gcinterval = (int)(val * (double)SEC_ONE_HR);
+    return NULL;
+}
+
+static char *
+set_cache_dirlevels(cmd_parms *parms, char *struct_ptr, char *arg)
+{
+    proxy_server_conf *psf =
+       get_module_config (parms->server->module_config, &proxy_module);
+    int val;
+
+    if (sscanf(arg, "%d", &val) != 1) return "Value must be an integer";
+    psf->cache.dirlevels = val;
+    return NULL;
+}
+
+static char *
+set_cache_dirlength(cmd_parms *parms, char *struct_ptr, char *arg)
+{
+    proxy_server_conf *psf =
+       get_module_config (parms->server->module_config, &proxy_module);
+    int val;
+
+    if (sscanf(arg, "%d", &val) != 1) return "Value must be an integer";
+    psf->cache.dirlength = val;
+    return NULL;
+}
+
+static char *
+set_cache_exclude(cmd_parms *parms, void *dummy, char *arg)
+{
+    server_rec *s = parms->server;
+    proxy_server_conf *conf =
+       get_module_config (s->module_config, &proxy_module);
+    struct nocache_entry *new;
+    struct nocache_entry *list=(struct nocache_entry*)conf->nocaches->elts;
+    int found = 0;
+    int i;
+
+    /* Don't duplicate entries */
+    for (i=0; i < conf->nocaches->nelts; i++)
+    {
+       if (strcmp(arg, list[i].name) == 0)
+           found = 1;
+    }
+
+    if (!found)
+    {
+       new = push_array (conf->nocaches);
+       new->name = arg;
+    }
+    return NULL;
+}
+
+static command_rec proxy_cmds[] = {
+{ "ProxyRequests", set_proxy_req, NULL, RSRC_CONF, FLAG,
+  "on if the true proxy requests should be accepted"},
+{ "ProxyRemote", add_proxy, NULL, RSRC_CONF, TAKE2, 
+    "a scheme, partial URL or '*' and a proxy server"},
+{ "ProxyPass", add_pass, NULL, RSRC_CONF, TAKE2, 
+    "a virtual path and a URL"},
+{ "CacheRoot", set_cache_root, NULL, RSRC_CONF, TAKE1,
+      "The directory to store cache files"},
+{ "CacheSize", set_cache_size, NULL, RSRC_CONF, TAKE1,
+      "The maximum disk space used by the cache in Kb"},
+{ "CacheMaxExpire", set_cache_maxex, NULL, RSRC_CONF, TAKE1,
+      "The maximum time in hours to cache a document"},
+{ "CacheDefaultExpire", set_cache_defex, NULL, RSRC_CONF, TAKE1,
+      "The default time in hours to cache a document"},
+{ "CacheLastModifiedFactor", set_cache_factor, NULL, RSRC_CONF, TAKE1,
+      "The factor used to estimate Expires date from LastModified date"},
+{ "CacheGcInterval", set_cache_gcint, NULL, RSRC_CONF, TAKE1,
+      "The interval between garbage collections, in hours"},
+{ "CacheDirLevels", set_cache_dirlevels, NULL, RSRC_CONF, TAKE1,
+    "The number of levels of subdirectories in the cache" },
+{ "CacheDirLength", set_cache_dirlength, NULL, RSRC_CONF, TAKE1,
+    "The number of characters in subdirectory names" },
+{ "NoCache", set_cache_exclude, NULL, RSRC_CONF, ITERATE,
+    "A list of hosts or domains for which caching is *not* provided" },
+{ NULL }
+};
+
+
+module proxy_module = {
+   STANDARD_MODULE_STUFF,
+   NULL,                       /* initializer */
+   NULL,                       /* create per-directory config structure */
+   NULL,                       /* merge per-directory config structures */
+   create_proxy_config,                /* create per-server config structure */
+   NULL,                       /* merge per-server config structures */
+   proxy_cmds,                 /* command table */
+   proxy_handlers,             /* handlers */
+   proxy_trans,                        /* translate_handler */
+   NULL,                       /* check_user_id */
+   NULL,                       /* check auth */
+   NULL,                       /* check access */
+   NULL,                       /* type_checker */
+   proxy_fixup,                        /* pre-run fixups */
+   NULL                                /* logger */
+};
diff --git a/RELEASE_1_1_X/src/modules/standard/mod_access.c b/RELEASE_1_1_X/src/modules/standard/mod_access.c
new file mode 100644 (file)
index 0000000..2d91de2
--- /dev/null
@@ -0,0 +1,251 @@
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * Security options etc.
+ * 
+ * Module derived from code originally written by Rob McCool
+ * 
+ */
+
+#include "httpd.h"
+#include "http_core.h"
+#include "http_config.h"
+#include "http_log.h"
+
+typedef struct {
+    char *from;
+    int limited;
+} allowdeny;
+
+/* things in the 'order' array */
+#define DENY_THEN_ALLOW 0
+#define ALLOW_THEN_DENY 1
+#define MUTUAL_FAILURE 2
+
+typedef struct {
+    int order[METHODS];
+    array_header *allows;
+    array_header *denys;
+} access_dir_conf;
+
+module access_module;
+
+void *create_access_dir_config (pool *p, char *dummy)
+{
+    access_dir_conf *conf =
+        (access_dir_conf *)pcalloc(p, sizeof(access_dir_conf));
+    int i;
+    
+    for (i = 0; i < METHODS; ++i) conf->order[i] = DENY_THEN_ALLOW;
+    conf->allows = make_array (p, 1, sizeof (allowdeny));
+    conf->denys = make_array (p, 1, sizeof (allowdeny));
+    
+    return (void *)conf;
+}
+
+char *order (cmd_parms *cmd, void *dv, char *arg)
+{
+    access_dir_conf *d = (access_dir_conf *)dv;
+    int i, order;
+  
+    if (!strcasecmp (arg, "allow,deny")) order = ALLOW_THEN_DENY;
+    else if (!strcasecmp (arg, "deny,allow")) order = DENY_THEN_ALLOW;
+    else if (!strcasecmp (arg, "mutual-failure")) order = MUTUAL_FAILURE;
+    else return "unknown order";
+
+    for (i = 0; i < METHODS; ++i) 
+        if (cmd->limited & (1 << i))
+           d->order[i] = order;
+    
+    return NULL;
+}
+
+char *allow_cmd (cmd_parms *cmd, void *dv, char *from, char *where)
+{
+    access_dir_conf *d = (access_dir_conf *)dv;
+    allowdeny *a;
+  
+    if (strcasecmp (from, "from"))
+        return "allow and deny must be followed by 'from'";
+    
+    a = (allowdeny *)push_array (cmd->info ? d->allows : d->denys);
+    a->from = pstrdup (cmd->pool, where);
+    a->limited = cmd->limited;
+    return NULL;
+}
+
+static char its_an_allow;
+
+command_rec access_cmds[] = {
+{ "order", order, NULL, OR_LIMIT, TAKE1,
+    "'allow,deny', 'deny,allow', or 'mutual-failure'" },
+{ "allow", allow_cmd, &its_an_allow, OR_LIMIT, ITERATE2,
+    "'from' followed by hostnames or IP-address wildcards" },
+{ "deny", allow_cmd, NULL, OR_LIMIT, ITERATE2,
+    "'from' followed by hostnames or IP-address wildcards" },
+{NULL}
+};
+
+int in_domain(const char *domain, const char *what) {
+    int dl=strlen(domain);
+    int wl=strlen(what);
+
+    if((wl-dl) >= 0) {
+        if (strcmp(domain,&what[wl-dl]) != 0) return 0;
+
+       /* Make sure we matched an *entire* subdomain --- if the user
+        * said 'allow from good.com', we don't want people from nogood.com
+        * to be able to get in.
+        */
+       
+       if (wl == dl) return 1; /* matched whole thing */
+       else return (domain[0] == '.' || what[wl - dl - 1] == '.');
+    } else
+        return 0;
+}
+
+int in_ip(char *domain, char *what) {
+
+    /* Check a similar screw case to the one checked above ---
+     * "allow from 204.26.2" shouldn't let in people from 204.26.23
+     */
+    
+    int l = strlen(domain);
+    if (strncmp(domain,what,l) != 0) return 0;
+    if (domain[l - 1] == '.') return 1;
+    return (what[l] == '\0' || what[l] == '.');
+}
+
+int find_allowdeny (request_rec *r, array_header *a, int method)
+{
+    allowdeny *ap = (allowdeny *)a->elts;
+    int mmask = (1 << method);
+    int i, gothost=0;
+    const char *remotehost=NULL;
+
+    for (i = 0; i < a->nelts; ++i) {
+        if (!(mmask & ap[i].limited))
+           continue;
+       if (!strcmp (ap[i].from, "all"))
+           return 1;
+       if (!gothost)
+       {
+           remotehost = get_remote_host(r->connection, r->per_dir_config,
+                                        REMOTE_HOST);
+           gothost = 1;
+       }
+        if (remotehost != NULL && isalpha(remotehost[0]))
+            if (in_domain(ap[i].from, remotehost))
+                return 1;
+        if (in_ip (ap[i].from, r->connection->remote_ip))
+            return 1;
+    }
+
+    return 0;
+}
+
+int check_dir_access (request_rec *r)
+{
+    int method = r->method_number;
+    access_dir_conf *a =
+        (access_dir_conf *)
+          get_module_config (r->per_dir_config, &access_module);
+    int ret = OK;
+                                               
+    if (a->order[method] == ALLOW_THEN_DENY) {
+        ret = FORBIDDEN;
+        if (find_allowdeny (r, a->allows, method))
+            ret = OK;
+        if (find_allowdeny (r, a->denys, method))
+            ret = FORBIDDEN;
+    } else if (a->order[method] == DENY_THEN_ALLOW) {
+        if (find_allowdeny (r, a->denys, method))
+            ret = FORBIDDEN;
+        if (find_allowdeny (r, a->allows, method))
+            ret = OK;
+    }
+    else {
+        if (find_allowdeny(r, a->allows, method) 
+           && !find_allowdeny(r, a->denys, method))
+           ret = OK;
+       else
+           ret = FORBIDDEN;
+    }
+
+    if (ret == FORBIDDEN)
+       log_reason ("Client denied by server configuration", r->filename, r);
+
+    return ret;
+}
+
+
+
+module access_module = {
+   STANDARD_MODULE_STUFF,
+   NULL,                       /* initializer */
+   create_access_dir_config,   /* dir config creater */
+   NULL,                       /* dir merger --- default is to override */
+   NULL,                       /* server config */
+   NULL,                       /* merge server config */
+   access_cmds,
+   NULL,                       /* handlers */
+   NULL,                       /* filename translation */
+   NULL,                       /* check_user_id */
+   NULL,                       /* check auth */
+   check_dir_access,           /* check access */
+   NULL,                       /* type_checker */
+   NULL,                       /* fixups */
+   NULL                                /* logger */
+};
diff --git a/RELEASE_1_1_X/src/modules/standard/mod_actions.c b/RELEASE_1_1_X/src/modules/standard/mod_actions.c
new file mode 100644 (file)
index 0000000..c286860
--- /dev/null
@@ -0,0 +1,212 @@
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+/*
+ * mod_actions.c: executes scripts based on MIME type
+ *
+ * by Alexei Kosut; based on mod_cgi.c, mod_mime.c and mod_includes.c,
+ * adapted by rst from original NCSA code by Rob McCool
+ *
+ * Usage instructions:
+ *
+ * Action mime/type /cgi-bin/script
+ * 
+ * will activate /cgi-bin/script when a file of content type mime/type. It
+ * sends the URL and file path of the requested document using the standard
+ * CGI PATH_INFO and PATH_TRANSLATED environment variables.
+ *
+ */
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_request.h"
+#include "http_core.h"
+#include "http_protocol.h"
+#include "http_main.h"
+#include "http_log.h"
+#include "util_script.h"
+
+typedef struct {
+    table *action_types;       /* Added with Action... */
+    char *get;                 /* Added with Script GET */
+    char *post;                        /* Added with Script POST */
+    char *put;                 /* Added with Script PUT */
+    char *delete;              /* Added with Script DELETE */
+} action_dir_config;
+
+module action_module;
+
+void *create_action_dir_config (pool *p, char *dummy)
+{
+    action_dir_config *new =
+      (action_dir_config *) palloc (p, sizeof(action_dir_config));
+
+    new->action_types = make_table (p, 4);
+    new->get = NULL;
+    new->post = NULL;
+    new->put = NULL;
+    new->delete = NULL;
+    
+    return new;
+}
+
+void *merge_action_dir_configs (pool *p, void *basev, void *addv)
+{
+    action_dir_config *base = (action_dir_config *)basev;
+    action_dir_config *add = (action_dir_config *)addv;
+    action_dir_config *new =
+      (action_dir_config *)palloc (p, sizeof(action_dir_config));
+
+    new->action_types = overlay_tables (p, add->action_types,
+                                         base->action_types);
+
+    new->get = add->get ? add->get : base->get;
+    new->post = add->post ? add->post : base->post;
+    new->put = add->put ? add->put : base->put;
+    new->delete = add->delete ? add->delete : base->delete;
+
+    return new;
+}
+
+char *add_action(cmd_parms *cmd, action_dir_config *m, char *type, char *script)
+{
+    table_set (m->action_types, type, script);
+    return NULL;
+}
+
+char *set_script (cmd_parms *cmd, action_dir_config *m, char *method,
+                 char *script)
+{
+    if (!strcmp(method, "GET"))
+        m->get = pstrdup(cmd->pool, script);
+    else if (!strcmp(method, "POST"))
+        m->post = pstrdup(cmd->pool, script);
+    else if (!strcmp(method, "PUT"))
+        m->put = pstrdup(cmd->pool, script);
+    else if (!strcmp(method, "DELETE"))
+        m->delete = pstrdup(cmd->pool, script);
+    else
+        return "Unknown method type for Script";
+
+    return NULL;
+}
+
+command_rec action_cmds[] = {
+{ "Action", add_action, NULL, OR_FILEINFO, TAKE2, 
+    "a media type followed by a script name" },
+{ "Script", set_script, NULL, ACCESS_CONF|RSRC_CONF, TAKE2,
+    "a method followed by a script name" },
+{ NULL }
+};
+
+int action_handler (request_rec *r)
+{
+    action_dir_config *conf =
+      (action_dir_config *)get_module_config(r->per_dir_config,&action_module);
+    char *t, *action = r->handler ? r->handler : r->content_type;
+    char *script = NULL;
+
+    /* First, check for the method-handling scripts */
+    if ((r->method_number == M_GET) && r->args && conf->get)
+        script = conf->get;
+    else if ((r->method_number == M_POST) && conf->post)
+        script = conf->post;
+    else if ((r->method_number == M_PUT) && conf->put)
+        script = conf->put;
+    else if ((r->method_number == M_DELETE) && conf->delete)
+        script = conf->delete;
+
+    /* Check for looping, which can happen if the CGI script isn't */
+    if (script && r->prev && r->prev->prev)
+        return DECLINED;
+
+    /* Second, check for actions (which override the method scripts) */
+    if ((action || default_type(r)) && (t = table_get(conf->action_types,
+                                       action ? action : default_type(r)))) {
+        script = t;
+       if (r->finfo.st_mode == 0) {
+           log_reason("File does not exist", r->filename, r);
+           return NOT_FOUND;
+       }
+    }
+  
+    if (script == NULL)
+        return DECLINED;
+
+    internal_redirect_handler(pstrcat(r->pool, script, escape_uri(r->pool,
+                       r->uri), r->args ? "?" : NULL, r->args, NULL), r);
+    return OK;
+}
+
+handler_rec action_handlers[] = {
+{ "*/*", action_handler },
+{ NULL }
+};
+
+module action_module = {
+   STANDARD_MODULE_STUFF,
+   NULL,                       /* initializer */
+   create_action_dir_config,   /* dir config creater */
+   merge_action_dir_configs,   /* dir merger --- default is to override */
+   NULL,                       /* server config */
+   NULL,                       /* merge server config */
+   action_cmds,                        /* command table */
+   action_handlers,            /* handlers */
+   NULL,                       /* filename translation */
+   NULL,                       /* check_user_id */
+   NULL,                       /* check auth */
+   NULL,                       /* check access */
+   NULL,                       /* type_checker */
+   NULL,                       /* fixups */
+   NULL                                /* logger */
+};
diff --git a/RELEASE_1_1_X/src/modules/standard/mod_alias.c b/RELEASE_1_1_X/src/modules/standard/mod_alias.c
new file mode 100644 (file)
index 0000000..2e7b89f
--- /dev/null
@@ -0,0 +1,259 @@
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * http_alias.c: Stuff for dealing with directory aliases
+ * 
+ * Original by Rob McCool, rewritten in succession by David Robinson
+ * and rst.
+ * 
+ */
+
+#include "httpd.h"
+#include "http_config.h"
+
+typedef struct {
+    char *real;
+    char *fake;
+    char *handler;
+} alias_entry;
+
+typedef struct {
+    array_header *aliases;
+    array_header *redirects;
+} alias_server_conf;
+
+module alias_module;
+
+void *create_alias_config (pool *p, server_rec *s)
+{
+    alias_server_conf *a =
+      (alias_server_conf *)pcalloc (p, sizeof(alias_server_conf));
+
+    a->aliases = make_array (p, 20, sizeof(alias_entry));
+    a->redirects = make_array (p, 20, sizeof(alias_entry));
+    return a;
+}
+
+void *merge_alias_config (pool *p, void *basev, void *overridesv)
+{
+    alias_server_conf *a =
+       (alias_server_conf *)pcalloc (p, sizeof(alias_server_conf));
+    alias_server_conf *base = (alias_server_conf *)basev,
+       *overrides = (alias_server_conf *)overridesv;
+
+    a->aliases = append_arrays (p, overrides->aliases, base->aliases);
+    a->redirects = append_arrays (p, overrides->redirects, base->redirects);
+    return a;
+}
+
+char *add_alias(cmd_parms *cmd, void *dummy, char *f, char *r)
+{
+    server_rec *s = cmd->server;
+    alias_server_conf *conf =
+        (alias_server_conf *)get_module_config(s->module_config,&alias_module);
+    alias_entry *new = push_array (conf->aliases);
+
+    /* XX r can NOT be relative to DocumentRoot here... compat bug. */
+    
+    new->fake = f; new->real = r; new->handler = cmd->info;
+    return NULL;
+}
+
+char *add_redirect(cmd_parms *cmd, void *dummy, char *f, char *url)
+{
+    server_rec *s = cmd->server;
+    alias_server_conf *conf =
+        (alias_server_conf *)get_module_config(s->module_config,&alias_module);
+    alias_entry *new = push_array (conf->redirects);
+
+    if (!is_url (url)) return "Redirect to non-URL";
+    
+    new->fake = f; new->real = url;
+    return NULL;
+}
+
+command_rec alias_cmds[] = {
+{ "Alias", add_alias, NULL, RSRC_CONF, TAKE2, 
+    "a fakename and a realname"},
+{ "ScriptAlias", add_alias, "cgi-script", RSRC_CONF, TAKE2, 
+    "a fakename and a realname"},
+{ "Redirect", add_redirect, NULL, OR_FILEINFO, TAKE2, 
+    "a document to be redirected, then the destination URL" },
+{ NULL }
+};
+
+int alias_matches (char *uri, char *alias_fakename)
+{
+    char *end_fakename = alias_fakename + strlen (alias_fakename);
+    char *aliasp = alias_fakename, *urip = uri;
+
+    while (aliasp < end_fakename) {
+       if (*aliasp == '/') {
+           /* any number of '/' in the alias matches any number in
+            * the supplied URI, but there must be at least one...
+            */
+           if (*urip != '/') return 0;
+           
+           while (*aliasp == '/') ++ aliasp;
+           while (*urip == '/') ++ urip;
+       }
+       else {
+           /* Other characters are compared literally */
+           if (*urip++ != *aliasp++) return 0;
+       }
+    }
+
+    /* Check last alias path component matched all the way */
+
+    if (aliasp[-1] != '/' && *urip != '\0' && *urip != '/')
+       return 0;
+
+    /* Return number of characters from URI which matched (may be
+     * greater than length of alias, since we may have matched
+     * doubled slashes)
+     */
+
+    return urip - uri;
+}
+
+char *try_alias_list (request_rec *r, array_header *aliases, int doesc)
+{
+    alias_entry *entries = (alias_entry *)aliases->elts;
+    int i;
+    
+    for (i = 0; i < aliases->nelts; ++i) {
+        alias_entry *p = &entries[i];
+        int l = alias_matches (r->uri, p->fake);
+
+        if (l > 0) {
+           if (p->handler) { /* Set handler, and leave a note for mod_cgi */
+               r->handler = pstrdup(r->pool, p->handler);
+               table_set (r->notes, "alias-forced-type", p->handler);
+           }
+
+           if (doesc) {
+               char *escurl;
+               escurl = os_escape_path(r->pool, r->uri + l, 1);
+               return pstrcat(r->pool, p->real, escurl, NULL);
+           } else
+               return pstrcat(r->pool, p->real, r->uri + l, NULL);
+        }
+    }
+
+    return NULL;
+}
+
+int translate_alias_redir(request_rec *r)
+{
+    void *sconf = r->server->module_config;
+    alias_server_conf *conf =
+        (alias_server_conf *)get_module_config(sconf, &alias_module);
+    char *ret;
+
+#ifdef __EMX__
+    /* Add support for OS/2 drive names */
+    if ((r->uri[0] != '/' && r->uri[0] != '\0') && r->uri[1] != ':')
+#else    
+    if (r->uri[0] != '/' && r->uri[0] != '\0') 
+#endif    
+        return BAD_REQUEST;
+
+    if ((ret = try_alias_list (r, conf->redirects, 1)) != NULL) {
+        table_set (r->headers_out, "Location", ret);
+        return REDIRECT;
+    }
+    
+    if ((ret = try_alias_list (r, conf->aliases, 0)) != NULL) {
+        r->filename = ret;
+        return OK;
+    }
+    
+    return DECLINED;
+}
+
+int fixup_redir(request_rec *r)
+{
+    void *sconf = r->server->module_config;
+    alias_server_conf *conf =
+        (alias_server_conf *)get_module_config(sconf, &alias_module);
+    char *ret;
+
+    /* It may have changed since last time, so try again */
+
+    if ((ret = try_alias_list (r, conf->redirects, 1)) != NULL) {
+        table_set (r->headers_out, "Location", ret);
+        return REDIRECT;
+    }
+
+    return DECLINED;
+}
+
+module alias_module = {
+   STANDARD_MODULE_STUFF,
+   NULL,                       /* initializer */
+   NULL,                       /* dir config creater */
+   NULL,                       /* dir merger --- default is to override */
+   create_alias_config,                /* server config */
+   merge_alias_config,         /* merge server configs */
+   alias_cmds,                 /* command table */
+   NULL,                       /* handlers */
+   translate_alias_redir,      /* filename translation */
+   NULL,                       /* check_user_id */
+   NULL,                       /* check auth */
+   NULL,                       /* check access */
+   NULL,                       /* type_checker */
+   fixup_redir,                        /* fixups */
+   NULL                                /* logger */
+};
diff --git a/RELEASE_1_1_X/src/modules/standard/mod_asis.c b/RELEASE_1_1_X/src/modules/standard/mod_asis.c
new file mode 100644 (file)
index 0000000..a429cca
--- /dev/null
@@ -0,0 +1,128 @@
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_protocol.h"
+#include "http_log.h"
+#include "util_script.h"
+#include "http_main.h"
+#include "http_request.h"
+
+int asis_handler (request_rec *r)
+{
+    FILE *f;
+    char *location;
+    
+    if (r->method_number != M_GET) return DECLINED;
+    if (r->finfo.st_mode == 0) {
+       log_reason("File does not exist", r->filename, r);
+       return NOT_FOUND;
+    }
+       
+    f = fopen (r->filename, "r");
+
+    if (f == NULL) {
+        log_reason("file permissions deny server access", r->filename, r);
+        return FORBIDDEN;
+    }
+      
+    scan_script_header (r, f);
+    location = table_get (r->headers_out, "Location");
+
+    if (location && location[0] == '/' && 
+        (r->status == 200 || r->status == 301 || r->status == 302)) {
+
+        r->status = 200; /* Assume 200 status on whatever we're pointing to */
+
+       /* This redirect needs to be a GET no matter what the original
+        * method was.
+       */
+       r->method = pstrdup(r->pool, "GET");
+       r->method_number = M_GET;
+
+       internal_redirect_handler (location, r);
+       return OK;
+    }
+    
+    soft_timeout ("send", r);
+    send_http_header (r);
+    if (!r->header_only) send_fd (f, r);
+    fclose (f);
+    return OK;
+}
+
+handler_rec asis_handlers[] = {
+{ ASIS_MAGIC_TYPE, asis_handler },
+{ "send-as-is", asis_handler },
+{ NULL }
+};
+
+module asis_module = {
+   STANDARD_MODULE_STUFF,
+   NULL,                       /* initializer */
+   NULL,                       /* create per-directory config structure */
+   NULL,                       /* merge per-directory config structures */
+   NULL,                       /* create per-server config structure */
+   NULL,                       /* merge per-server config structures */
+   NULL,                       /* command table */
+   asis_handlers,              /* handlers */
+   NULL,                       /* translate_handler */
+   NULL,                       /* check_user_id */
+   NULL,                       /* check auth */
+   NULL,                       /* check access */
+   NULL,                       /* type_checker */
+   NULL,                       /* pre-run fixups */
+   NULL                                /* logger */
+};
diff --git a/RELEASE_1_1_X/src/modules/standard/mod_auth.c b/RELEASE_1_1_X/src/modules/standard/mod_auth.c
new file mode 100644 (file)
index 0000000..7c628c8
--- /dev/null
@@ -0,0 +1,267 @@
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * http_auth: authentication
+ * 
+ * Rob McCool
+ * 
+ * Adapted to Shambhala by rst.
+ */
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_core.h"
+#include "http_log.h"
+#include "http_protocol.h"
+
+typedef struct auth_config_struct {
+    char *auth_pwfile;
+    char *auth_grpfile;
+} auth_config_rec;
+
+void *create_auth_dir_config (pool *p, char *d)
+{
+    return pcalloc (p, sizeof(auth_config_rec));
+}
+
+command_rec auth_cmds[] = {
+{ "AuthUserFile", set_string_slot,
+    (void*)XtOffsetOf(auth_config_rec,auth_pwfile), OR_AUTHCFG, TAKE1, NULL },
+{ "AuthGroupFile", set_string_slot,
+    (void*)XtOffsetOf(auth_config_rec,auth_grpfile), OR_AUTHCFG, TAKE1, NULL },
+{ NULL }
+};
+
+module auth_module;
+
+char *get_pw(request_rec *r, char *user, char *auth_pwfile)
+{
+    FILE *f;
+    char l[MAX_STRING_LEN];
+    char *rpw, *w;
+
+    if(!(f=pfopen(r->pool, auth_pwfile, "r"))) {
+        log_reason ("Could not open password file", auth_pwfile, r);
+       return NULL;
+    }
+    while(!(cfg_getline(l,MAX_STRING_LEN,f))) {
+        if((l[0] == '#') || (!l[0])) continue;
+       rpw = l;
+        w = getword(r->pool, &rpw, ':');
+
+        if(!strcmp(user,w)) {
+           pfclose(r->pool, f);
+            return pstrdup (r->pool, rpw);
+       }
+    }
+    pfclose(r->pool, f);
+    return NULL;
+}
+
+table *groups_for_user (pool *p, char *user, char *grpfile) {
+    FILE *f;
+    table *grps = make_table (p, 15);
+    pool *sp;
+    char l[MAX_STRING_LEN];
+    char *group_name, *ll, *w;
+
+    if(!(f=pfopen(p, grpfile, "r")))
+        return NULL;
+
+    sp = make_sub_pool (p);
+    
+    while(!(cfg_getline(l,MAX_STRING_LEN,f))) {
+        if((l[0] == '#') || (!l[0])) continue;
+       ll = l;
+       clear_pool (sp);
+       
+        group_name = getword(sp, &ll, ':');
+
+       while(ll[0]) {
+           w = getword_conf (sp, &ll);
+           if(!strcmp(w,user)) {
+               table_set (grps, group_name, "in");
+               break;
+           }
+       }
+    }
+    pfclose(p, f);
+    destroy_pool (sp);
+    return grps;
+}
+
+/* These functions return 0 if client is OK, and proper error status
+ * if not... either AUTH_REQUIRED, if we made a check, and it failed, or
+ * SERVER_ERROR, if things are so totally confused that we couldn't
+ * figure out how to tell if the client is authorized or not.
+ *
+ * If they return DECLINED, and all other modules also decline, that's
+ * treated by the server core as a configuration error, logged and
+ * reported as such.
+ */
+
+/* Determine user ID, and check if it really is that user, for HTTP
+ * basic authentication...
+ */
+
+int authenticate_basic_user (request_rec *r)
+{
+    auth_config_rec *sec =
+      (auth_config_rec *)get_module_config (r->per_dir_config, &auth_module);
+    conn_rec *c = r->connection;
+    char *sent_pw, *real_pw;
+    char errstr[MAX_STRING_LEN];
+    int res;
+    
+    if ((res = get_basic_auth_pw (r, &sent_pw))) return res;
+    
+    if(!sec->auth_pwfile) 
+        return DECLINED;
+       
+    if (!(real_pw = get_pw(r, c->user, sec->auth_pwfile))) {
+        sprintf(errstr,"user %s not found",c->user);
+       log_reason (errstr, r->uri, r);
+       note_basic_auth_failure (r);
+       return AUTH_REQUIRED;
+    }
+    /* anyone know where the prototype for crypt is? */
+    if(strcmp(real_pw,(char *)crypt(sent_pw,real_pw))) {
+        sprintf(errstr,"user %s: password mismatch",c->user);
+       log_reason (errstr, r->uri, r);
+       note_basic_auth_failure (r);
+       return AUTH_REQUIRED;
+    }
+    return OK;
+}
+    
+/* Checking ID */
+    
+int check_user_access (request_rec *r) {
+    auth_config_rec *sec =
+      (auth_config_rec *)get_module_config (r->per_dir_config, &auth_module);
+    char *user = r->connection->user;
+    int m = r->method_number;
+    int method_restricted = 0;
+    register int x;
+    char *t, *w;
+    table *grpstatus;
+    array_header *reqs_arr = requires (r);
+    require_line *reqs;
+
+    /* BUG FIX: tadc, 11-Nov-1995.  If there is no "requires" directive, 
+     * then any user will do.
+     */
+    if (!reqs_arr)
+        return (OK);
+    reqs = (require_line *)reqs_arr->elts;
+
+    if(sec->auth_grpfile)
+        grpstatus = groups_for_user (r->pool, user, sec->auth_grpfile);
+    else
+        grpstatus = NULL;
+
+    for(x=0; x < reqs_arr->nelts; x++) {
+      
+       if (! (reqs[x].method_mask & (1 << m))) continue;
+       
+       method_restricted = 1;
+
+        t = reqs[x].requirement;
+        w = getword(r->pool, &t, ' ');
+        if(!strcmp(w,"valid-user"))
+            return OK;
+        if(!strcmp(w,"user")) {
+            while(t[0]) {
+                w = getword_conf (r->pool, &t);
+                if(!strcmp(user,w))
+                    return OK;
+            }
+        }
+        else if(!strcmp(w,"group")) {
+            if(!grpstatus) 
+               return DECLINED;        /* DBM group?  Something else? */
+           
+            while(t[0]) {
+                w = getword_conf(r->pool, &t);
+                if(table_get (grpstatus, w))
+                   return OK;
+            }
+        }
+    }
+    
+    if (!method_restricted)
+      return OK;
+
+    note_basic_auth_failure (r);
+    return AUTH_REQUIRED;
+}
+
+module auth_module = {
+   STANDARD_MODULE_STUFF,
+   NULL,                       /* initializer */
+   create_auth_dir_config,     /* dir config creater */
+   NULL,                       /* dir merger --- default is to override */
+   NULL,                       /* server config */
+   NULL,                       /* merge server config */
+   auth_cmds,                  /* command table */
+   NULL,                       /* handlers */
+   NULL,                       /* filename translation */
+   authenticate_basic_user,    /* check_user_id */
+   check_user_access,          /* check auth */
+   NULL,                       /* check access */
+   NULL,                       /* type_checker */
+   NULL,                       /* fixups */
+   NULL                                /* logger */
+};
diff --git a/RELEASE_1_1_X/src/modules/standard/mod_auth_anon.c b/RELEASE_1_1_X/src/modules/standard/mod_auth_anon.c
new file mode 100644 (file)
index 0000000..49b736a
--- /dev/null
@@ -0,0 +1,298 @@
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP OR
+ * IT'S 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * http_auth: authentication
+ * 
+ * Rob McCool & Brian Behlendorf.
+ * 
+ * Adapted to Shambhala by rst.
+ *
+ * Version 0.5 May 1996
+ *
+ * Brutally raped by Dirk.vanGulik@jrc.it to
+ * 
+ * Adapted to allow anonymous logins, just like with Anon-FTP, when
+ * one gives the magic user name 'anonymous' and ones email address
+ * as the password.
+ *
+ * Just add the following tokes to your <directory> setup:
+ * 
+ * Anonymous                   magic-user-id [magic-user-id]...
+ *
+ * Anonymous_MustGiveEmail     [ on | off ] default = off
+ * Anonymous_LogEmail          [ on | off ] default = on
+ * Anonymous_VerifyEmail       [ on | off ] default = off
+ * Anonymous_NoUserId          [ on | off ] default = off
+ * Anonymous_Authorative        [ on | off ] default = off
+ *
+ * The magic user id is something like 'anonymous', it is NOT case sensitive. 
+ * 
+ * The MustGiveEmail flag can be used to force users to enter something
+ * in the password field (like an email address). Default is off.
+ *
+ * Furthermore the 'NoUserID' flag can be set to allow completely empty
+ * usernames in as well; this can be is convenient as a single return
+ * in broken GUIs like W95 is often given by the user. The Default is off.
+ *
+ * Dirk.vanGulik@jrc.it; http://ewse.ceo.org; http://me-www.jrc.it/~dirkx
+ * 
+ */
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_core.h"
+#include "http_log.h"
+#include "http_protocol.h"
+
+typedef struct auth_anon {
+    char *password;
+    struct auth_anon * next;
+    } auth_anon;
+
+typedef struct  {
+
+    auth_anon *auth_anon_passwords;
+    int   auth_anon_nouserid;
+    int   auth_anon_logemail;
+    int   auth_anon_verifyemail;
+    int   auth_anon_mustemail;
+    int   auth_anon_authorative;
+
+} anon_auth_config_rec;
+
+void *create_anon_auth_dir_config (pool *p, char *d)
+{
+    anon_auth_config_rec * sec = (anon_auth_config_rec *) 
+       pcalloc (p, sizeof(anon_auth_config_rec));
+
+    if (!sec) return NULL; /* no memory... */
+
+    /* just to illustrate the defaults really. */
+    sec -> auth_anon_passwords                 =NULL;
+
+    sec -> auth_anon_nouserid          =0;
+    sec -> auth_anon_logemail          =1;
+    sec -> auth_anon_verifyemail       =0;
+    sec -> auth_anon_mustemail         =1;
+    sec -> auth_anon_authorative        =0;
+    return sec;
+}
+
+char *anon_set_passwd_flag (cmd_parms *cmd, 
+       anon_auth_config_rec *sec, int arg) {
+    sec->auth_anon_mustemail=arg;
+    return NULL;
+}
+
+char *anon_set_userid_flag (cmd_parms *cmd, 
+       anon_auth_config_rec *sec, int arg) {
+    sec->auth_anon_nouserid=arg;
+    return NULL;
+}
+char *anon_set_logemail_flag (cmd_parms *cmd, 
+       anon_auth_config_rec *sec, int arg) {
+    sec->auth_anon_logemail=arg;
+    return NULL;
+}
+char *anon_set_verifyemail_flag (cmd_parms *cmd, 
+       anon_auth_config_rec *sec, int arg) {
+    sec->auth_anon_verifyemail=arg;
+    return NULL;
+}
+char *anon_set_authorative_flag (cmd_parms *cmd, 
+       anon_auth_config_rec *sec, int arg) {
+    sec->auth_anon_authorative=arg;
+    return NULL;
+}
+
+char *anon_set_string_slots (cmd_parms *cmd, 
+       anon_auth_config_rec *sec, char *arg) {
+  
+    auth_anon  * first;
+
+    if (!(*arg))
+      return "Anonymous string cannot be empty, use Anonymous_NoUserId instead";
+
+    /* squeeze in a record */
+    first = sec->auth_anon_passwords;
+       
+    if (
+       (!(sec->auth_anon_passwords=(auth_anon *) palloc(cmd -> pool, sizeof(auth_anon)))) ||
+       (!(sec->auth_anon_passwords->password = pstrdup(cmd -> pool, arg)))
+       ) return "Failed to claim memory for an anonymous password...";
+
+    /* and repair the next */
+    sec->auth_anon_passwords->next = first;
+
+    return NULL;
+}
+
+command_rec anon_auth_cmds[] = {
+{ "Anonymous", anon_set_string_slots,
+    NULL,OR_AUTHCFG, ITERATE, NULL },
+{ "Anonymous_MustGiveEmail", anon_set_passwd_flag, NULL, OR_AUTHCFG, FLAG, 
+       "Limited to 'on' or 'off'" },
+{ "Anonymous_NoUserId", anon_set_userid_flag, NULL, OR_AUTHCFG, FLAG, 
+       "Limited to 'on' or 'off'" },
+{ "Anonymous_VerifyEmail", anon_set_verifyemail_flag, NULL, OR_AUTHCFG, FLAG, 
+       "Limited to 'on' or 'off'" },
+{ "Anonymous_LogEmail", anon_set_logemail_flag, NULL, OR_AUTHCFG, FLAG, 
+       "Limited to 'on' or 'off'" },
+{ "Anonymous_Authorative", anon_set_authorative_flag, NULL, OR_AUTHCFG, FLAG, 
+       "Limited to 'on' or 'off'" },
+
+{ NULL }
+};
+
+module anon_auth_module;
+
+int anon_authenticate_basic_user (request_rec *r)
+{
+    anon_auth_config_rec *sec =
+      (anon_auth_config_rec *)get_module_config (r->per_dir_config,
+                                               &anon_auth_module);
+    conn_rec *c = r->connection;
+    char *send_pw;
+    char errstr[MAX_STRING_LEN];
+    int res=DECLINED;
+    
+
+    if ((res=get_basic_auth_pw (r,&send_pw)))
+       return res;
+
+    /* Ignore if we are not configured */
+    if (!sec->auth_anon_passwords) return DECLINED;
+
+    /* Do we allow an empty userID and/or is it the magic one
+     */
+    
+    if ( (!(c->user[0])) && (sec->auth_anon_nouserid) ) {
+      res=OK;
+    } else {
+      auth_anon *p=sec->auth_anon_passwords;
+      res=DECLINED;
+      while ((res == DECLINED) && (p !=NULL)) {
+       if (!(strcasecmp(c->user,p->password)))
+         res=OK;
+       p=p->next;
+      }
+    }
+    if (
+       /* username is OK */
+       (res == OK) &&
+       /* password been filled out ? */ 
+       ( (!sec->auth_anon_mustemail) || strlen(send_pw)  ) &&
+       /* does the password look like an email address ? */
+       ( (!sec->auth_anon_verifyemail) || 
+            (strpbrk("@",send_pw) != NULL) || 
+            (strpbrk(".",send_pw) != NULL) 
+         ) 
+       ) {
+      if (sec->auth_anon_logemail) {
+       sprintf(errstr,"Anonymous: Passwd <%s> Accepted", 
+                       send_pw ? send_pw : "\'none\'");
+       log_error (errstr, r->server );
+      }
+      return OK;
+    } else {
+        if (sec->auth_anon_authorative) {
+       sprintf(errstr,"Anonymous: Authorative, Passwd <%s> not accepted",
+               send_pw ? send_pw : "\'none\'");
+       log_error(errstr,r->server);
+       return AUTH_REQUIRED;
+       }
+       /* Drop out the bottom to return DECLINED */
+    }
+     
+
+   return DECLINED;
+}
+    
+int check_anon_access (request_rec *r) {
+
+#ifdef NOTYET
+    conn_rec *c = r->connection;
+    anon_auth_config_rec *sec =
+      (anon_auth_config_rec *)get_module_config (r->per_dir_config,
+                                               &anon_auth_module);
+       
+    if (!sec->auth_anon) return DECLINED;
+
+    if ( strcasecmp(r->connection->user,sec->auth_anon ))
+       return DECLINED;
+
+   return OK;
+#endif
+   return DECLINED;
+}
+
+module anon_auth_module = {
+   STANDARD_MODULE_STUFF,
+   NULL,                       /* initializer */
+   create_anon_auth_dir_config,        /* dir config creater */
+   NULL,                       /* dir merger ensure strictness */
+   NULL,                       /* server config */
+   NULL,                       /* merge server config */
+   anon_auth_cmds,             /* command table */
+   NULL,                       /* handlers */
+   NULL,                       /* filename translation */
+   anon_authenticate_basic_user,/* check_user_id */
+   check_anon_access,          /* check auth */
+   NULL,                       /* check access */
+   NULL,                       /* type_checker */
+   NULL,                       /* fixups */
+   NULL                                /* logger */
+};
diff --git a/RELEASE_1_1_X/src/modules/standard/mod_auth_db.c b/RELEASE_1_1_X/src/modules/standard/mod_auth_db.c
new file mode 100644 (file)
index 0000000..34dd2fe
--- /dev/null
@@ -0,0 +1,267 @@
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP OR
+ * IT'S 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * mod_auth_db: authentication
+ * 
+ * Original work by Rob McCool & Brian Behlendorf.
+ * 
+ * Adapted to Apache by rst (mod_auth_dbm)
+ *
+ * Adapted for Berkeley DB by Andrew Cohen 
+ *
+ * mod_auth_db was based on mod_auth_dbm.
+ * 
+ * Warning, this is not a drop in replacement for mod_auth_dbm, 
+ * for people wanting to switch from dbm to Berkeley DB.
+ * It requires the use of AuthDBUserFile and AuthDBGroupFile
+ *           instead of   AuthDBMUserFile    AuthDBMGroupFile
+ *
+ * Also, in the configuration file you need to specify
+ *  db_auth_module rather than dbm_auth_module
+ *
+ * On some BSD systems (e.g. FreeBSD and NetBSD) dbm is automatically
+ * mapped to Berkeley DB. You can use either mod_auth_dbm or
+ * mod_auth_db. The latter makes it more obvious that it's Berkeley.
+ */
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_core.h"
+#include "http_log.h"
+#include "http_protocol.h"
+#include <db.h>
+
+typedef struct  {
+
+    char *auth_dbpwfile;
+    char *auth_dbgrpfile;
+
+} db_auth_config_rec;
+
+void *create_db_auth_dir_config (pool *p, char *d)
+{
+    return pcalloc (p, sizeof(db_auth_config_rec));
+}
+
+command_rec db_auth_cmds[] = {
+{ "AuthDBUserFile", set_string_slot,
+    (void*)XtOffsetOf(db_auth_config_rec, auth_dbpwfile),
+    OR_AUTHCFG, TAKE1, NULL },
+{ "AuthDBGroupFile", set_string_slot,
+    (void*)XtOffsetOf(db_auth_config_rec, auth_dbgrpfile),
+    OR_AUTHCFG, TAKE1, NULL },
+{ NULL }
+};
+
+module db_auth_module;
+
+char *get_db_pw(request_rec *r, char *user, const char *auth_dbpwfile) {
+    DB *f; 
+    DBT d, q; 
+    char *pw = NULL;
+
+    q.data = user; 
+    q.size = strlen(q.data); 
+    
+    if(!(f=dbopen(auth_dbpwfile,O_RDONLY,0664,DB_HASH,NULL))) {
+        log_reason ("could not open db auth file", (char *) auth_dbpwfile, r);
+       return NULL;
+    }
+
+    if (!((f->get)(f,&q,&d,0))) {
+        pw = palloc (r->pool, d.size + 1);
+       strncpy(pw,d.data,d.size);
+       pw[d.size] = '\0';         /* Terminate the string */
+    }
+
+    (f->close)(f);
+    return pw; 
+}
+
+/* We do something strange with the group file.  If the group file
+ * contains any : we assume the format is
+ *      key=username value=":"groupname [":"anything here is ignored]
+ * otherwise we now (0.8.14+) assume that the format is
+ *      key=username value=groupname
+ * The first allows the password and group files to be the same 
+ * physical DB file;   key=username value=password":"groupname[":"anything]
+ *
+ * mark@telescope.org, 22Sep95
+ */
+
+char  *get_db_grp(request_rec *r, char *user, const char *auth_dbgrpfile) {
+    char *grp_data = get_db_pw (r, user, auth_dbgrpfile);
+    char *grp_colon; char *grp_colon2;
+
+    if (grp_data == NULL) return NULL;
+    
+    if ((grp_colon = strchr(grp_data, ':'))!=NULL) {
+        grp_colon2 = strchr(++grp_colon, ':');
+        if (grp_colon2) *grp_colon2='\0';
+        return grp_colon;
+    }
+    return grp_data;
+}
+
+int db_authenticate_basic_user (request_rec *r)
+{
+    db_auth_config_rec *sec =
+      (db_auth_config_rec *)get_module_config (r->per_dir_config,
+                                               &db_auth_module);
+    conn_rec *c = r->connection;
+    char *sent_pw, *real_pw, *colon_pw;
+    char errstr[MAX_STRING_LEN];
+    int res;
+    
+    if ((res = get_basic_auth_pw (r, &sent_pw)))
+        return res;
+    
+    if(!sec->auth_dbpwfile)
+        return DECLINED;
+       
+    if(!(real_pw = get_db_pw(r, c->user, sec->auth_dbpwfile))) {
+        sprintf(errstr,"DB user %s not found", c->user);
+       log_reason (errstr, r->filename, r);
+       note_basic_auth_failure (r);
+       return AUTH_REQUIRED;
+    }    
+    /* Password is up to first : if exists */
+    colon_pw = strchr(real_pw,':');
+    if (colon_pw) *colon_pw='\0';   
+    /* anyone know where the prototype for crypt is? */
+    if(strcmp(real_pw,(char *)crypt(sent_pw,real_pw))) {
+        sprintf(errstr,"user %s: password mismatch",c->user);
+       log_reason (errstr, r->uri, r);
+       note_basic_auth_failure (r);
+       return AUTH_REQUIRED;
+    }
+    return OK;
+}
+    
+/* Checking ID */
+    
+int db_check_auth(request_rec *r) {
+    db_auth_config_rec *sec =
+      (db_auth_config_rec *)get_module_config (r->per_dir_config,
+                                               &db_auth_module);
+    char *user = r->connection->user;
+    int m = r->method_number;
+    char errstr[MAX_STRING_LEN];
+    
+    array_header *reqs_arr = requires (r);
+    require_line *reqs = reqs_arr ? (require_line *)reqs_arr->elts : NULL;
+
+    register int x;
+    char *t, *w;
+
+    if (!sec->auth_dbgrpfile) return DECLINED;
+    if (!reqs_arr) return DECLINED;
+    
+    for(x=0; x < reqs_arr->nelts; x++) {
+      
+       if (! (reqs[x].method_mask & (1 << m))) continue;
+       
+        t = reqs[x].requirement;
+        w = getword(r->pool, &t, ' ');
+       
+        if(!strcmp(w,"group") && sec->auth_dbgrpfile) {
+           char *orig_groups,*groups,*v;
+
+           if (!(groups = get_db_grp(r, user, sec->auth_dbgrpfile))) {
+               sprintf(errstr,"user %s not in DB group file %s",
+                      user, sec->auth_dbgrpfile);
+              log_reason (errstr, r->filename, r);
+              note_basic_auth_failure (r);
+              return AUTH_REQUIRED;
+           }
+           orig_groups = groups;
+           while(t[0]) {
+               w = getword(r->pool, &t, ' ');
+               groups = orig_groups;
+               while(groups[0]) {
+                   v = getword(r->pool, &groups,',');
+                   if(!strcmp(v,w))
+                       return OK;
+               }
+           }
+           sprintf(errstr,"user %s not in right group",user);
+          log_reason (errstr, r->filename, r);
+           note_basic_auth_failure(r);
+          return AUTH_REQUIRED;
+       }
+    }
+    
+    return DECLINED;
+}
+
+
+module db_auth_module = {
+   STANDARD_MODULE_STUFF,
+   NULL,                       /* initializer */
+   create_db_auth_dir_config,  /* dir config creater */
+   NULL,                       /* dir merger --- default is to override */
+   NULL,                       /* server config */
+   NULL,                       /* merge server config */
+   db_auth_cmds,               /* command table */
+   NULL,                       /* handlers */
+   NULL,                       /* filename translation */
+   db_authenticate_basic_user, /* check_user_id */
+   db_check_auth,              /* check auth */
+   NULL,                       /* check access */
+   NULL,                       /* type_checker */
+   NULL,                       /* fixups */
+   NULL                                /* logger */
+};
+
+
diff --git a/RELEASE_1_1_X/src/modules/standard/mod_auth_dbm.c b/RELEASE_1_1_X/src/modules/standard/mod_auth_dbm.c
new file mode 100644 (file)
index 0000000..4a2a618
--- /dev/null
@@ -0,0 +1,252 @@
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * http_auth: authentication
+ * 
+ * Rob McCool & Brian Behlendorf.
+ * 
+ * Adapted to Shambhala by rst.
+ */
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_core.h"
+#include "http_log.h"
+#include "http_protocol.h"
+#include <ndbm.h>
+
+typedef struct  {
+
+    char *auth_dbmpwfile;
+    char *auth_dbmgrpfile;
+
+} dbm_auth_config_rec;
+
+void *create_dbm_auth_dir_config (pool *p, char *d)
+{
+    return pcalloc (p, sizeof(dbm_auth_config_rec));
+}
+
+command_rec dbm_auth_cmds[] = {
+{ "AuthDBMUserFile", set_string_slot,
+    (void*)XtOffsetOf(dbm_auth_config_rec, auth_dbmpwfile),
+    OR_AUTHCFG, TAKE1, NULL },
+{ "AuthDBMGroupFile", set_string_slot,
+    (void*)XtOffsetOf(dbm_auth_config_rec, auth_dbmgrpfile),
+    OR_AUTHCFG, TAKE1, NULL },
+{ NULL }
+};
+
+module dbm_auth_module;
+
+char *get_dbm_pw(request_rec *r, char *user, char *auth_dbmpwfile) {
+    DBM *f; 
+    datum d, q; 
+    char *pw = NULL;
+
+    q.dptr = user; 
+    q.dsize = strlen(q.dptr); 
+    
+    if(!(f=dbm_open(auth_dbmpwfile,O_RDONLY,0664))) {
+        log_reason ("could not open dbm auth file", auth_dbmpwfile, r);
+       return NULL;
+    }
+
+    d = dbm_fetch(f, q);
+
+    if (d.dptr) {
+        pw = palloc (r->pool, d.dsize + 1);
+       strncpy(pw,d.dptr,d.dsize);
+       pw[d.dsize] = '\0';         /* Terminate the string */
+    }
+
+    dbm_close(f);
+    return pw; 
+}
+
+/* We do something strange with the group file.  If the group file
+ * contains any : we assume the format is
+ *      key=username value=":"groupname [":"anything here is ignored]
+ * otherwise we now (0.8.14+) assume that the format is
+ *      key=username value=groupname
+ * The first allows the password and group files to be the same 
+ * physical DBM file;   key=username value=password":"groupname[":"anything]
+ *
+ * mark@telescope.org, 22Sep95
+ */
+
+char  *get_dbm_grp(request_rec *r, char *user, char *auth_dbmgrpfile) {
+    char *grp_data = get_dbm_pw (r, user, auth_dbmgrpfile);
+    char *grp_colon; char *grp_colon2;
+
+    if (grp_data == NULL) return NULL;
+    
+    if ((grp_colon = strchr(grp_data, ':'))!=NULL) {
+        grp_colon2 = strchr(++grp_colon, ':');
+        if (grp_colon2) *grp_colon2='\0';
+        return grp_colon;
+    }
+    return grp_data;
+}
+
+int dbm_authenticate_basic_user (request_rec *r)
+{
+    dbm_auth_config_rec *sec =
+      (dbm_auth_config_rec *)get_module_config (r->per_dir_config,
+                                               &dbm_auth_module);
+    conn_rec *c = r->connection;
+    char *sent_pw, *real_pw, *colon_pw;
+    char errstr[MAX_STRING_LEN];
+    int res;
+    
+    if ((res = get_basic_auth_pw (r, &sent_pw)))
+        return res;
+    
+    if(!sec->auth_dbmpwfile)
+        return DECLINED;
+       
+    if(!(real_pw = get_dbm_pw(r, c->user, sec->auth_dbmpwfile))) {
+        sprintf(errstr,"DBM user %s not found", c->user);
+       log_reason (errstr, r->filename, r);
+       note_basic_auth_failure (r);
+       return AUTH_REQUIRED;
+    }    
+    /* Password is up to first : if exists */
+    colon_pw = strchr(real_pw,':');
+    if (colon_pw) *colon_pw='\0';   
+    /* anyone know where the prototype for crypt is? */
+    if(strcmp(real_pw,(char *)crypt(sent_pw,real_pw))) {
+        sprintf(errstr,"user %s: password mismatch",c->user);
+       log_reason (errstr, r->uri, r);
+       note_basic_auth_failure (r);
+       return AUTH_REQUIRED;
+    }
+    return OK;
+}
+    
+/* Checking ID */
+    
+int dbm_check_auth(request_rec *r) {
+    dbm_auth_config_rec *sec =
+      (dbm_auth_config_rec *)get_module_config (r->per_dir_config,
+                                               &dbm_auth_module);
+    char *user = r->connection->user;
+    int m = r->method_number;
+    char errstr[MAX_STRING_LEN];
+    
+    array_header *reqs_arr = requires (r);
+    require_line *reqs = reqs_arr ? (require_line *)reqs_arr->elts : NULL;
+
+    register int x;
+    char *t, *w;
+
+    if (!sec->auth_dbmgrpfile) return DECLINED;
+    if (!reqs_arr) return DECLINED;
+    
+    for(x=0; x < reqs_arr->nelts; x++) {
+      
+       if (! (reqs[x].method_mask & (1 << m))) continue;
+       
+        t = reqs[x].requirement;
+        w = getword(r->pool, &t, ' ');
+       
+        if(!strcmp(w,"group") && sec->auth_dbmgrpfile) {
+           char *orig_groups,*groups,*v;
+
+           if (!(groups = get_dbm_grp(r, user, sec->auth_dbmgrpfile))) {
+               sprintf(errstr,"user %s not in DBM group file %s",
+                      user, sec->auth_dbmgrpfile);
+              log_reason (errstr, r->filename, r);
+              note_basic_auth_failure (r);
+              return AUTH_REQUIRED;
+           }
+           orig_groups = groups;
+           while(t[0]) {
+               w = getword(r->pool, &t, ' ');
+               groups = orig_groups;
+               while(groups[0]) {
+                   v = getword(r->pool, &groups,',');
+                   if(!strcmp(v,w))
+                       return OK;
+               }
+           }
+           sprintf(errstr,"user %s not in right group",user);
+          log_reason (errstr, r->filename, r);
+           note_basic_auth_failure(r);
+          return AUTH_REQUIRED;
+       }
+    }
+    
+    return DECLINED;
+}
+
+
+module dbm_auth_module = {
+   STANDARD_MODULE_STUFF,
+   NULL,                       /* initializer */
+   create_dbm_auth_dir_config, /* dir config creater */
+   NULL,                       /* dir merger --- default is to override */
+   NULL,                       /* server config */
+   NULL,                       /* merge server config */
+   dbm_auth_cmds,              /* command table */
+   NULL,                       /* handlers */
+   NULL,                       /* filename translation */
+   dbm_authenticate_basic_user,        /* check_user_id */
+   dbm_check_auth,             /* check auth */
+   NULL,                       /* check access */
+   NULL,                       /* type_checker */
+   NULL,                       /* fixups */
+   NULL                                /* logger */
+};
diff --git a/RELEASE_1_1_X/src/modules/standard/mod_auth_msql.c b/RELEASE_1_1_X/src/modules/standard/mod_auth_msql.c
new file mode 100644 (file)
index 0000000..b8d0e21
--- /dev/null
@@ -0,0 +1,971 @@
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP OR
+ * IT'S 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * mod_auth_msql: authentication
+ *
+ * Rob McCool & Brian Behlendorf.
+ *
+ * Adapted to Shambhala by rst.
+ *
+ * Addapted for use with the mSQL database
+ * (see ftp:/ftp.bond.edu.au/pub/Minerva/mSQL)
+ *
+ * Version 1.0 May 1996 - Blame: Dirk.vanGulik@jrc.it.
+ *
+ * A (sometimes more up to date) version of the documentation
+ * can be found at the http://www.apache.org site or at 
+ * http://me-www.jrc.it/~dirkx/mod_auth_msql.html.
+ * 
+ * Outline:
+ *
+ * This module allows access control using the public domain
+ * mSQL database; a fast but limted SQL engine which can be
+ * contacted over an internal unix domain protocol as well as
+ * over normal inter-machine tcp/ip socket communication.
+ *
+ * An example table could be:
+ *
+ * create table user_records (
+ *       User_id  char(32) primary key,
+ *       Cpasswd  char(32),
+ *     [ Xgroup   char(32) ]
+ *       ) \g
+ *
+ * The user_id can be as long as desired; however some of the
+ * popular web browsers truncate, or stop the user from entering
+ * names longer than 32 characters. Furthermore the 'crypt' function
+ * on your platform might impose further limits. Also use of
+ * the 'require users uid [uid..]' directive in the access.conf file,
+ * where the user ids are separated by spaces can possibly prohibit the
+ * use of spaces in your user-names. Also, not the MAX_FIELD_LEN define
+ * somewhere below.
+ *
+ * To use the above, the following example could be in your access.conf
+ * file. Also there is a more elaborate description afther this example.
+ *
+ * <directory /web/docs/private>
+ *
+ *  Auth_MSQLhost localhost
+ * or
+ *  Auth_MSQLhost datab.machine.your.org
+ *
+ *                     If this directive is ommited, or set to
+ *                     localhost, the machine on which apache
+ *                     runs is assumed, and the faster /dev/msql
+ *                     communication channel will be used. Otherwise
+ *                     it is the machine to contact by tcp/ip.
+ *
+ * Auth_MSQLdatabase    www
+ *
+ *                      The name of the database on the above machine,
+ *                     which contains *both* the tables for group and
+ *                     for user/passwords. Currently it is not possible
+ *                     to have these split over two databases. Make
+ *                     sure that the msql.acl (access control file) of
+ *                     mSQL does indeed allow the effective uid of the
+ *                     web server read access to this database. Check the
+ *                     httpd.conf file for this uid.
+ *
+ * Auth_MSQLpwd_table   user_records
+ *
+ *                      Here the table which contain the uid/password combination
+ *                     is specified.
+ *
+ * Auth_MSQLuid_field  User_id
+ * Auth_MSQLpwd_field   Cpasswd
+ *
+ *                     These two directive specify the field names in the 'user_record'
+ *                     table. If this module is compiled with the BACKWARD_VITEK
+ *                     compatibility switch, the defaults 'user' and 'password' are
+ *                     assumed if you do not specify them. Currently the user_id field
+ *                     *MUST* be a primary key or one must ensure that each user only
+ *                     occurs *once* in the table. If a UID occurs twice access is
+ *                     denied by default.
+ *
+ * Auth_MSQLgrp_table   user_records
+ * Auth_MSQLgrp_field  Xgroup
+ *
+ *                      Optionaly one can also specify a table which contains the
+ *                     user/group combinations. This can be the same table which
+ *                     also contains the username/password combinations. However
+ *                     if a user belongs to two or more groups, one will have to
+ *                     use a differt table with multiple entries.
+ *
+ * Auth_MSQL_nopasswd          off
+ * Auth_MSQL_Authorative        on
+ * Auth_MSQL_EncryptedPasswords on
+ *
+ *                      These three optional fields (all set to the sensible defaults,
+ *                     so you really do not have to enter them) are described in more
+ *                     detail below. If you choose to set these to any other values than
+ *                     the above be very sure you understand the security implications and
+ *                     do verify that apache does what you exect it to do.
+ *
+ * AuthName            example mSQL realm
+ * AuthType            basic
+ *
+ *                      Normal apache/ncsa tokens for access control
+ *
+ * <limit get post head>
+ *   order deny,allow
+ *   allow from all
+ *
+ *   require valid-user
+ *                    'valid-user'; allow in any user which has a valid uid/passwd
+ *                    pair in the above pwd_table.
+ * or
+ *   require user smith jones
+ *                   Limit access to users who have a valid uid/passwd pair in the
+ *                   above pwd_table AND whose uid is 'smith' or 'jones'. Do note that
+ *                   the uid's are separated by 'spaces' for historic (ncsa) reasons.
+ *                   So allowing uids with spaces might cause problems.
+ *
+ *   require group has_paid
+ *                   Optionally also ensure that the uid has the value 'has_paid' in the group
+ *                   field in the group table.
+ *   </limit>
+ * </directory>
+ *
+ * End of the example
+ *
+ * - full description of all tokens: -
+ *
+ * Directives:
+ *
+ * Auth_MSQLhost       Hostname of the machine running
+ *                     the mSQL demon. The effective uid
+ *                     of the server should be allowed
+ *                     access. If not given, or if it is
+ *                     the magic name 'localhost', it is
+ *                     passed to the mSQL libary as a null
+ *                     pointer. This effectively forces it
+ *                     to use /dev/msql rather than the
+ *                     (slower) socket communication.
+ *
+ * Auth_MSQLdatabase   Name of the database in which the following
+ *                     table(s) are contained.
+ *
+ * Auth_MSQLpwd_table  Contains at least the fields with the
+ *                     username and the (encrypted) password. Each
+ *                     uid should only occur once in this table and
+ *                     for performance reasons should be a primary key.
+ *                     Normally this table is compulsory, but it is
+ *                     possible to use a fall-through to other methods
+ *                     and use the mSQL module for group control only;
+ *                     see the Authorative directive below.
+ *
+ * Auth_MSQLgrp_table  Contains at least the fields with the
+ *                     username and the groupname. A user which
+ *                     is in multiple groups has therefore
+ *                     multiple entries; this might be some per-
+ *                     formance problems associated with this; and one
+ *                     might consider to have separate tables for each
+ *                     group (rather than all groups in one table) if
+ *                     your directory structure allows for it.
+ *                     One only needs to specify this table when doing
+ *                     group control.
+ *
+ * Auth_MSQLuid_field  Name of the field containing the username
+ * Auth_MSQLpwd_field   Fieldname for the passwords
+ * Auth_MSQLgrp_field  Fieldname for the groupname
+ *
+ *                      Only the fields used need to be specified. When this
+ *                     module is compiled with the BACKWARD_VITEK option the
+ *                     uid and pwd field names default to 'user' and 'password'.
+ *
+ *
+ * Auth_MSQL_nopasswd  <on|off>
+ *                     skip password comparison if passwd field is
+ *                     empty; i.e. allow 'any' password. This is off
+ *                     by default; thus to ensure that an empty field
+ *                     in the mSQL table does not allow people in by
+ *                     default with a random password.
+ *
+ * Auth_MSQL_Authorative <on|off>
+ *                     default is 'on'. When set on, there is no
+ *                     fall through to other authorization methods. So if a
+ *                     user is not in the mSQL dbase table (and perhaps
+ *                     not in the right group) or has the password wrong, then
+ *                      he or she is denied access. When this directive is set to
+ *                     'off' control is passed on to any other authorization
+ *                     modules, such as the basic auth module wih the htpasswd
+ *                     file and or the unix-(g)dbm modules.
+ *                     The default is 'ON' to avoid nasty 'fall-through' sur-
+ *                     prizes. Do be sure you know what you decide to switch
+ *                     it off.
+ *
+ * Auth_MSQL_EncryptedPasswords <on|off>
+ *                     default is on. When set on, the values in the
+ *                     pwd_field are assumed to be crypted using *your*
+ *                     machines 'crypt' function; and the incoming password
+ *                     is 'crypt'ed before comparison. When this function is
+ *                     off, the comparison is done directly with the plaintext
+ *                     entered password. (Yes; http-basic-auth does send the
+ *                     password as plaintext over the wire :-( ). The default
+ *                     is a sensible 'on', and I personally thing that it is
+ *                     a *very-bad-idea* to change this. However a multi
+ *                     vendor or international environment (which sometimes
+ *                     leads to different crypts functions) might force you to.
+ *
+ * Dirk.vanGulik@jrc.it; http://ewse.ceo.org; http://me-www.jrc.it/~dirkx
+ * 23 Nov 1995, 24 Feb 1996, 16 May 1996.
+ *
+ * Version 0.0  First release
+ *         0.1  Update to apache 1.00
+ *         0.2  added lines which got missing god knows when
+ *              and which did the valid-user authentification
+ *              no good at all !
+ *        0.3  Added 'Auth_MSQL_nopasswd' option
+ *        0.4  Cleaned out the error messages mess.
+ *        0.6  Inconsistency with gid/grp in comment/token/source
+ *             Make sure you really use 'Auth_MSQLgrp_field' as
+ *             indicated above.
+ *        0.7  *host to host fixed. Credits go to Rob Stout,
+ *             <stout@lava.et.tudelft.nl> for spotting this one.
+ *        0.8  Authorative directive added. See above.
+ *        0.9  palloc return code check(s), should be backward compatible with
+ *             1.11 version of Vivek Khera <khera@kciLink.com> msql module,
+ *             fixed broken err msg in group control, changed command table
+ *             messages to make more sense when displayed in that new module
+ *             management tool. Added EncryptedPassword on/off functionality.
+ *             msqlClose() statements added upon error. Support for persistent
+ *             connections with the mSQL database (riscy). Escaping of ' and \.
+ *             Replaced some MAX_STRING_LENGTH claims. 
+ *        1.0  removed some error check as they where already done elsehwere
+ *             NumFields -> NumRows (Thanks Vitek). More stack memory.
+ */
+
+
+#define ONLY_ONCE 1
+/*
+ * If the mSQL table containing the uid/passwd combination does
+ * not have the uid field as a primary key, it is possible for the
+ * uid to occur more than once in the table with possibly different
+ * passwords. When this module is compiled with the ONLY_ONCE directive
+ * set, access is denied if the uid occures more than once in the
+ * uid/passwd table. If you choose not to set it, the software takes
+ * the first pair returned and ignores any further pairs. The SQL
+ * statement used for this is
+ *
+ *       "select password form pwd_table where user='uid'"
+ *
+ * this might lead to unpredictable results. For this reason as well
+ * as for performance reasons you are strongly adviced to make the
+ * uid field a primary key. Use at your own peril :-)
+ */
+
+#undef KEEP_MSQL_CONNECTION_OPEN
+/*
+ * Normally the (tcp/ip) connection with the database is opened and
+ * closed for each SQL query. When the httpd-server and the database
+ * are on the same machine, and /dev/msql is used this does not
+ * cause a serious overhead. However when your platform does not
+ * support this (see the mSQL documentation) or when the web server
+ * and the database are on different machines the overhead can be
+ * considerable. When the above is set defined the server leaves the
+ * connection open; i.e. no call to msqlClose(). If an error occures
+ * an attempt is made to re-open the connection for the next http-rq.
+ *
+ * This has a number of very serious drawbacks
+ *  - It costs 2 already rare filedescriptors for each child.
+ *  - It costs msql-connections, typically one per child. The (compiled in)
+ *    number of connections mSQL can handle is low, typically 6 or 12.
+ *    which might prohibit access to the mSQL database for later
+ *    processes.
+ *  - when a child dies, it might not free that connection properly
+ *    or quick enough.
+ *  - When errors start to occur, connection/file-descr resources might
+ *    become exausted very quickly.
+ *
+ * In short; use this at your own peril and only in a highly controled and
+ * monitored environment
+ */
+
+#define BACKWARD_VITEK
+#define VITEX_uid_name "user"
+#define VITEX_gid_name "passwd"
+/* A second mSQL auth module for apache has also been developed by
+ * Vivek Khera <khera@kciLink.com> and was subsequently distributed
+ * with some early versions of Apache. It can be optained from
+ * ftp://ftp.kcilink.com/pub/mod_auth_msql.c*. Older 'vitek' versions had
+ * the field/table names compiled in; newer versions, v.1.11 have
+ * more access.conf configuration options; however these where
+ * choosen not to be in line the 'ewse' version of this module. Also,
+ * the 'vitek' module does not give group control or 'empty' password
+ * control.
+ *
+ * To get things slightly more in line this version (0.9) should
+ * be backward compatible with the vitek module by:
+ *
+ *   - adding support for the EncryptedPassword on/off functionality
+ *
+ *   - adding support for the different spelling fo the 4 configuration
+ *     tokens for user-table-name, user/password-field-name and dbase-name.
+ *
+ *   - setting some field names to a default which used to be hard
+ *     coded in in older vitek modules.
+ *
+ * If this troubles you; remove the 'BACKWARD_VITEX' define.
+ */
+
+/* get some sensible values; rather than that big MAX_STRING_LEN,
+ */
+
+/* Max field value length limit; well above the limit of some browsers :-)
+ */
+#define MAX_FIELD_LEN (64)
+/* the next two values can be pulled from msql_priv.c, which is *NOT* copied to your
+ * /usr/local/include as part of the normal install procedure which comes with
+ * mSQL.
+ */
+#define MSQL_FIELD_NAME_LEN (19)
+#define MSQL_TABLE_NAME_LEN (19)
+/* We only do the following two queries:
+ *
+ * - for the user/passwd combination
+ *      select PWDFIELD from PWDTABEL where USERFIELD='UID'
+ *
+ * - optionally for the user/group combination:
+ *     select GROUPFIELD from GROUPTABLE where USERFIELD='UID' and GROUPFIELD='GID'
+ *
+ * This leads to the following limits: (we are ignoring escaping a wee bit bit here
+ * assuming not more than 24 escapes.)
+ */
+
+#define MAX_QUERY_LEN (32+24+MAX_FIELD_LEN*2+3*MSQL_FIELD_NAME_LEN+1*MSQL_TABLE_NAME_LEN)
+
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_core.h"
+#include "http_log.h"
+#include "http_protocol.h"
+#include <msql.h>
+#ifdef HAVE_CRYPT_H
+#include <crypt.h>
+#endif
+
+typedef struct  {
+
+    char *auth_msql_host;
+    char *auth_msql_database;
+
+    char *auth_msql_pwd_table;
+    char *auth_msql_grp_table;
+
+    char *auth_msql_pwd_field;
+    char *auth_msql_uname_field;
+    char *auth_msql_grp_field;
+
+    int auth_msql_nopasswd;
+    int auth_msql_authorative;
+    int auth_msql_encrypted;
+
+} msql_auth_config_rec;
+
+void *create_msql_auth_dir_config (pool *p, char *d)
+{
+    msql_auth_config_rec * sec= (msql_auth_config_rec *) pcalloc (p, sizeof(msql_auth_config_rec));
+
+    sec->auth_msql_host        = NULL; /* just to enforce the default 'localhost' behaviour */
+
+    /* just in case, to be nice... */
+    sec->auth_msql_database    = NULL;
+    sec->auth_msql_pwd_table   = NULL;
+    sec->auth_msql_grp_table   = NULL;
+    sec->auth_msql_pwd_field   = NULL;
+    sec->auth_msql_uname_field = NULL;
+    sec->auth_msql_grp_field   = NULL;
+
+
+    sec->auth_msql_authorative = 1; /* set some defaults, just in case... */
+    sec->auth_msql_encrypted   = 1;
+    sec->auth_msql_nopasswd    = 0;
+
+#ifdef BACKWARD_VITEK
+    /* these are for backward compatibility with the Vivek
+     * msql module, as it used to have compile-time defaults.
+     */
+    sec->auth_msql_uname_field = VITEX_uid_name;
+    sec->auth_msql_pwd_field   = VITEX_gid_name;
+#endif
+
+    return sec;
+}
+
+char *set_passwd_flag (cmd_parms *cmd, msql_auth_config_rec *sec, int arg) {
+    sec->auth_msql_nopasswd=arg;
+    return NULL;
+}
+
+char *set_authorative_flag (cmd_parms *cmd, msql_auth_config_rec *sec, int arg) {
+    sec->auth_msql_authorative=arg;
+    return NULL;
+}
+
+char *set_crypted_password_flag (cmd_parms *cmd, msql_auth_config_rec *sec , int arg) {
+    sec->auth_msql_encrypted = arg;
+    return NULL;
+}
+
+char *msql_set_string_slot (cmd_parms *cmd, char *struct_ptr, char *arg) {
+    int offset = (int)cmd->info;
+    *(char **)(struct_ptr + offset) = pstrdup (cmd->pool, arg);
+    return NULL;
+}
+
+
+command_rec msql_auth_cmds[] = {
+{ "Auth_MSQLhost", msql_set_string_slot,
+    (void*)XtOffsetOf(msql_auth_config_rec, auth_msql_host),
+    OR_AUTHCFG, TAKE1, "Host on which the mSQL database engine resides (defaults to localhost)" },
+
+{ "Auth_MSQLdatabase", msql_set_string_slot,
+    (void*)XtOffsetOf(msql_auth_config_rec, auth_msql_database),
+    OR_AUTHCFG, TAKE1, "Name of the mSQL database which contains the password (and possibly the group) tables. " },
+
+{ "Auth_MSQLpwd_table", msql_set_string_slot,
+    (void*)XtOffsetOf(msql_auth_config_rec, auth_msql_pwd_table),
+    OR_AUTHCFG, TAKE1, "Name of the mSQL table containing the password/user-name combination" },
+
+{ "Auth_MSQLgrp_table", msql_set_string_slot,
+    (void*)XtOffsetOf(msql_auth_config_rec, auth_msql_grp_table),
+    OR_AUTHCFG, TAKE1, "Name of the mSQL table containing the group-name/user-name combination; can be the same as the password-table." },
+
+{ "Auth_MSQLpwd_field", msql_set_string_slot,
+    (void*)XtOffsetOf(msql_auth_config_rec, auth_msql_pwd_field),
+    OR_AUTHCFG, TAKE1, "The name of the field in the mSQL password table" },
+
+{ "Auth_MSQLuid_field", msql_set_string_slot,
+    (void*)XtOffsetOf(msql_auth_config_rec, auth_msql_uname_field),
+    OR_AUTHCFG, TAKE1, "The name of the user-name field in the mSQL password (and possibly group) table(s)." },
+
+{ "Auth_MSQLgrp_field", msql_set_string_slot,
+    (void*)XtOffsetOf(msql_auth_config_rec, auth_msql_grp_field),
+    OR_AUTHCFG, TAKE1,
+       "The name of the group field in the mSQL group table; must be set if you want to use groups." },
+
+{ "Auth_MSQL_nopasswd", set_passwd_flag, NULL, OR_AUTHCFG, FLAG,
+       "Enable (on) or disable (off) empty password strings; in which case any user password is accepted." },
+
+{ "Auth_MSQL_Authorative", set_authorative_flag, NULL, OR_AUTHCFG, FLAG,
+       "When 'on' the mSQL database is taken to be authorative and access control is not passed along to other db or access modules." },
+
+{ "Auth_MSQL_EncryptedPasswords", set_crypted_password_flag, NULL, OR_AUTHCFG, FLAG,
+       "When 'on' the password in the password table are taken to be crypt()ed using your machines crypt() function." },
+
+#ifdef BACKWARD_VITEK
+/* These 'altenative' tokens should ensure backward compatibility
+ * with viteks mSQL module. The only difference is the spelling.
+ * Note that these tokens do not allow group configuration.
+ */
+{ "AuthMSQLHost", set_string_slot,
+    (void*)XtOffsetOf(msql_auth_config_rec, auth_msql_host),
+    OR_AUTHCFG, TAKE1, "mSQL server hostname" },
+{ "AuthMSQLDB", set_string_slot,
+    (void*)XtOffsetOf(msql_auth_config_rec, auth_msql_database),
+    OR_AUTHCFG, TAKE1, "mSQL database name" },
+{ "AuthMSQLUserTable", set_string_slot,
+    (void*)XtOffsetOf(msql_auth_config_rec, auth_msql_pwd_table),
+    OR_AUTHCFG, TAKE1, "mSQL user table name" },
+{ "AuthMSQLGroupTable", set_string_slot,
+    (void*)XtOffsetOf(msql_auth_config_rec, auth_msql_grp_table),
+    OR_AUTHCFG, TAKE1, "mSQL group table name" },
+{ "AuthMSQLNameField", set_string_slot,
+    (void*)XtOffsetOf(msql_auth_config_rec, auth_msql_uname_field),
+    OR_AUTHCFG, TAKE1, "mSQL User ID field name within table" },
+{ "AuthMSQLGroupField", set_string_slot,
+    (void*)XtOffsetOf(msql_auth_config_rec, auth_msql_grp_field),
+    OR_AUTHCFG, TAKE1, "mSQL Group field name within table" },
+{ "AuthMSQLPasswordField", set_string_slot,
+    (void*)XtOffsetOf(msql_auth_config_rec, auth_msql_pwd_field),
+    OR_AUTHCFG, TAKE1, "mSQL Password field name within table" },
+{ "AuthMSQLCryptedPasswords", set_crypted_password_flag, NULL,
+    OR_AUTHCFG, FLAG, "mSQL passwords are stored encrypted if On" },
+
+#endif
+
+{ NULL }
+};
+
+module msql_auth_module;
+
+/* boring little routine which escapes the ' and \ in the
+ * SQL query. See the mSQL FAQ for more information :-) on
+ * this very popular subject in the msql-mailing list.
+ */
+char *msql_escape(char *out, char *in, char *msql_errstr) {
+
+  register int i=0,j=0;
+
+  do {
+    /* do we need to escape */
+    if ( (in[i] == '\'') || (in[i] == '\\')) {
+
+      /* does this fit ? */
+      if (j >= (MAX_FIELD_LEN-1)) {
+       sprintf(msql_errstr,"Could not escape '%s', longer than %d",in,MAX_FIELD_LEN);
+       return NULL;
+       };
+
+      out[j++] = '\\'; /* insert that escaping slash for good measure */
+    };
+
+    /* Do things still fit ? */
+    if (j >= MAX_FIELD_LEN) return NULL;
+
+  } while ( ( out[j++] = in[i++]) != '\0' );
+
+  return out;
+}
+
+/* get the password for uname=user, and copy it
+ * into r. Assume that user is a string and stored
+ * as such in the mSQL database
+ */
+char *do_msql_query(request_rec *r, char *query, msql_auth_config_rec *sec, int once , char *msql_errstr) {
+
+       static int      sock=-1;
+       int             hit;
+       m_result        *results;
+       m_row           currow;
+
+       char            *result=NULL;
+       char            *host=sec->auth_msql_host;
+
+#ifndef KEEP_MSQL_CONNECTION_OPEN
+        sock=-1;
+#endif
+
+       /* force fast access over /dev/msql */
+
+       if ((host) && (!(strcasecmp(host,"localhost"))))
+               host=NULL;
+
+       /* (re) open if nessecary
+        */
+       if (sock==-1) if ((sock=msqlConnect(host)) == -1) {
+               sprintf (msql_errstr,
+                       "mSQL: Could not connect to Msql DB %s (%s)",
+                       (sec->auth_msql_host ? sec->auth_msql_host : "\'unset, assuming localhost!\'"),
+                       msqlErrMsg);
+               return NULL;
+               }
+
+       /* we always do this, as it avoids book-keeping
+        * and is quite cheap anyway
+        */
+       if (msqlSelectDB(sock,sec->auth_msql_database) == -1 ) {
+               sprintf (msql_errstr,"mSQL: Could not select Msql Table \'%s\' on host \'%s\'(%s)",
+                       (sec->auth_msql_database ? sec->auth_msql_database : "\'unset!\'"),
+                       (sec->auth_msql_host ? sec->auth_msql_host : "\'unset, assuming localhost!\'"),
+                       msqlErrMsg);
+               msqlClose(sock);
+               sock=-1;
+               return NULL;
+               }
+
+       if (msqlQuery(sock,query) == -1 ) {
+               sprintf (msql_errstr,"mSQL: Could not Query database '%s' on host '%s' (%s) with query [%s]",
+                       (sec->auth_msql_database ? sec->auth_msql_database : "\'unset!\'"),
+                       (sec->auth_msql_host ? sec->auth_msql_host : "\'unset, assuming localhost!\'"),
+                       msqlErrMsg,
+                       ( query ? query : "\'unset!\'") );
+               msqlClose(sock);
+               sock=-1;
+               return NULL;
+               }
+
+       if (!(results=msqlStoreResult())) {
+               sprintf (msql_errstr,"mSQL: Could not get the results from mSQL database \'%s\' on \'%s\' (%s) with query [%s]",
+                       (sec->auth_msql_database ? sec->auth_msql_database : "\'unset!\'"),
+                       (sec->auth_msql_host ? sec->auth_msql_host : "\'unset, assuming localhost!\'"),
+                       msqlErrMsg,
+                       ( query ? query : "\'unset!\'") );
+               msqlClose(sock);
+               sock=-1;
+               return NULL;
+               };
+
+       hit=msqlNumRows(results);
+
+       if (( once ) && ( hit >1 )) {
+          /* complain if there are to many
+           * matches.
+           */
+          sprintf (msql_errstr,"mSQL: More than %d matches (%d) whith query [%s]",
+                  once,hit,( query ? query : "\'unset!\'") );
+       } else
+       /* if we have a it, try to get it
+       */
+        if ( hit )  {
+               if ( (currow=msqlFetchRow(results)) != NULL) {
+                       /* copy the first matching field value */
+                       if (!(result=palloc(r->pool,strlen(currow[0])+1))) {
+                               sprintf (msql_errstr,"mSQL: Could not get memory for mSQL %s (%s) with [%s]",
+                                       (sec->auth_msql_database ? sec->auth_msql_database : "\'unset!\'"),
+                                       msqlErrMsg,
+                                       ( query ? query : "\'unset!\'") );
+                               /* do not return right away, to ensure Free/Close.
+                                */
+                               } else {
+                               strcpy(result,currow[0]);
+                               };
+               }
+       };
+
+       /* ignore errors, functions are voids anyway. */
+       msqlFreeResult(results);
+
+#ifndef KEEP_MSQL_CONNECTION_OPEN
+       /* close the connection, unless explicitly told not to. Do note that
+        * we do not have a decent closing option of child termination due
+        * the lack of hooks in the API (or my understanding thereof)
+        */
+       msqlClose(sock);
+       sock=-1;
+#endif
+
+       return result;
+}
+
+char *get_msql_pw(request_rec *r, char *user, msql_auth_config_rec *sec ,char *msql_errstr) {
+       char            query[MAX_QUERY_LEN];
+       char            esc_user[MAX_FIELD_LEN];
+
+       /* do we have enough information to build a query */
+       if (
+           (!sec->auth_msql_pwd_table) ||
+           (!sec->auth_msql_pwd_field) ||
+           (!sec->auth_msql_uname_field)
+          ) {
+               sprintf(msql_errstr,
+                       "mSQL: Missing parameters for password lookup: %s%s%s",
+                       (sec->auth_msql_pwd_table ? "" : "Password table "),
+                       (sec->auth_msql_pwd_field ? "" : "Password field name "),
+                       (sec->auth_msql_uname_field ? "" : "UserID field name ")
+                       );
+               return NULL;
+               };
+
+       if (!(msql_escape(esc_user, user, msql_errstr))) {
+               sprintf(msql_errstr,
+                       "mSQL: Could not cope/escape the '%s' user_id value; ",user);
+               return NULL;
+       };
+       sprintf(query,"select %s from %s where %s='%s'",
+               sec->auth_msql_pwd_field,
+               sec->auth_msql_pwd_table,
+               sec->auth_msql_uname_field,
+               esc_user
+               );
+
+       return do_msql_query(r,query,sec,ONLY_ONCE,msql_errstr);
+}
+
+char *get_msql_grp(request_rec *r, char *group,char *user, msql_auth_config_rec *sec, char *msql_errstr) {
+       char            query[MAX_QUERY_LEN];
+
+       char            esc_user[MAX_FIELD_LEN];
+       char            esc_group[MAX_FIELD_LEN];
+
+       /* do we have enough information to build a query */
+       if (
+           (!sec->auth_msql_grp_table) ||
+           (!sec->auth_msql_grp_field) ||
+           (!sec->auth_msql_uname_field)
+          ) {
+               sprintf(msql_errstr,
+                       "mSQL: Missing parameters for group lookup: %s%s%s",
+                       (sec->auth_msql_grp_table ? "" : "Group table "),
+                       (sec->auth_msql_grp_field ? "" : "GroupID field name "),
+                       (sec->auth_msql_uname_field ? "" : "UserID field name ")
+                       );
+               return NULL;
+               };
+
+       if (!(msql_escape(esc_user, user,msql_errstr))) {
+               sprintf(msql_errstr,
+                       "mSQL: Could not cope/escape the '%s' user_id value",user);
+
+               return NULL;
+       };
+       if (!(msql_escape(esc_group, group,msql_errstr))) {
+               sprintf(msql_errstr,
+                       "mSQL: Could not cope/escape the '%s' group_id value",group);
+
+               return NULL;
+       };
+
+       sprintf(query,"select %s from %s where %s='%s' and %s='%s'",
+               sec->auth_msql_grp_field,
+               sec->auth_msql_grp_table,
+               sec->auth_msql_uname_field,esc_user,
+               sec->auth_msql_grp_field,  esc_group
+               );
+
+       return do_msql_query(r,query,sec,0,msql_errstr);
+}
+
+
+int msql_authenticate_basic_user (request_rec *r)
+{
+    msql_auth_config_rec *sec =
+      (msql_auth_config_rec *)get_module_config (r->per_dir_config,
+                                               &msql_auth_module);
+    char msql_errstr[MAX_STRING_LEN];
+    conn_rec *c = r->connection;
+    char *sent_pw, *real_pw;
+    int res;
+    msql_errstr[0]='\0';
+
+    if ((res = get_basic_auth_pw (r, &sent_pw)))
+        return res;
+
+    /* if mSQL *password* checking is configured in any way, i.e. then
+     * handle it, if not decline and leave it to the next in line..
+     * We do not check on dbase, group, userid or host name, as it is
+     * perfectly possible to only do group control with mSQL and leave
+     * user control to the next (dbm) guy in line.
+     */
+    if (
+       (!sec->auth_msql_pwd_table) &&
+       (!sec->auth_msql_pwd_field)
+        ) return DECLINED;
+
+    if(!(real_pw = get_msql_pw(r, c->user, sec,msql_errstr ))) {
+       if ( msql_errstr[0] ) {
+               res = SERVER_ERROR;
+               } else {
+               if (sec->auth_msql_authorative) {
+                  /* insist that the user is in the database
+                   */
+                  sprintf(msql_errstr,"mSQL: Password for user %s not found", c->user);
+                  note_basic_auth_failure (r);
+                  res = AUTH_REQUIRED;
+                  } else {
+                  /* pass control on to the next authorization module.
+                   */
+                  return DECLINED;
+                  }; /* if authorative */
+               }; /* if no error */
+       log_reason (msql_errstr, r->filename, r);
+       return res;
+    }
+
+    /* allow no password, if the flag is set and the password
+     * is empty. But be sure to log this.
+     */
+
+    if ((sec->auth_msql_nopasswd) && (!strlen(real_pw))) {
+        sprintf(msql_errstr,"mSQL: user %s: Empty/'any' password accepted",c->user);
+       log_reason (msql_errstr, r->uri, r);
+       return OK;
+       };
+
+    /* if the flag is off however, keep that kind of stuff at
+     * an arms length.
+     */
+    if ((!strlen(real_pw)) || (!strlen(sent_pw))) {
+        sprintf(msql_errstr,"mSQL: user %s: Empty Password(s) Rejected",c->user);
+       log_reason (msql_errstr, r->uri, r);
+       note_basic_auth_failure (r);
+       return AUTH_REQUIRED;
+       };
+
+    if(sec->auth_msql_encrypted) {
+        /* anyone know where the prototype for crypt is?
+         *
+         * PLEASE NOTE:
+         *    The crypt function (at least under FreeBSD 2.0.5) returns
+         *    a ptr to a *static* array (max 120 chars) and does *not*
+         *    modify the string pointed at by sent_pw !
+         */
+        sent_pw=(char *)crypt(sent_pw,real_pw);
+        };
+
+    if (strcmp(real_pw,sent_pw)) {
+        sprintf(msql_errstr,"mSQL user %s: password mismatch",c->user);
+       log_reason (msql_errstr, r->uri, r);
+       note_basic_auth_failure (r);
+       return AUTH_REQUIRED;
+    }
+    return OK;
+}
+
+/* Checking ID */
+
+int msql_check_auth (request_rec *r) {
+    int user_result=DECLINED,group_result=DECLINED;
+
+    msql_auth_config_rec *sec =
+      (msql_auth_config_rec *)get_module_config (r->per_dir_config,
+                                               &msql_auth_module);
+    char msql_errstr[MAX_STRING_LEN];
+    char *user = r->connection->user;
+    int m = r->method_number;
+    array_header *reqs_arr = requires (r);
+    require_line *reqs = reqs_arr ? (require_line *)reqs_arr->elts : NULL;
+
+    register int x;
+    char *t, *w;
+    msql_errstr[0]='\0';
+
+    if (!reqs_arr) {
+       if (sec->auth_msql_authorative) {
+               sprintf(msql_errstr,"user %s denied, no access rules specified (MSQL-Authorative) ",user);
+               log_reason (msql_errstr, r->uri, r);
+               note_basic_auth_failure(r);
+               return AUTH_REQUIRED;
+               };
+       return DECLINED;
+       };
+
+    for(x=0; (x < reqs_arr->nelts) ; x++) {
+
+       if (! (reqs[x].method_mask & (1 << m))) continue;
+
+        t = reqs[x].requirement;
+        w = getword(r->pool, &t, ' ');
+
+        if ((user_result != OK) && (!strcmp(w,"user"))) {
+           user_result=AUTH_REQUIRED;
+            while(t[0]) {
+                w = getword_conf (r->pool, &t);
+                if (!strcmp(user,w)) {
+                    user_result= OK;
+                   break;
+               };
+            }
+           if ((sec->auth_msql_authorative) && ( user_result != OK)) {
+               sprintf(msql_errstr,"User %s not found (MSQL-Auhtorative)",user);
+               log_reason (msql_errstr, r->uri, r);
+               note_basic_auth_failure(r);
+               return AUTH_REQUIRED;
+               };
+        }
+
+        if ( (group_result != OK) && 
+            (!strcmp(w,"group")) &&  
+             (sec->auth_msql_grp_table) && 
+             (sec->auth_msql_grp_field)
+           ) {
+          /* look up the membership for each of the groups in the table
+            */
+          group_result=AUTH_REQUIRED;
+           while ( (t[0]) && (group_result != OK) && (!msql_errstr[0]) ) {
+                if (get_msql_grp(r,getword(r->pool, &t, ' '),user,sec,msql_errstr)) {
+                       group_result= OK;
+                       break;
+                       };
+                       };
+
+          if (msql_errstr[0]) {
+               log_reason (msql_errstr, r->filename, r);
+               return SERVER_ERROR;
+               };
+
+          if ( (sec->auth_msql_authorative) && (group_result != OK) ) {
+               sprintf(msql_errstr,"user %s not in right groups (MSQL-Authorative) ",user);
+               log_reason (msql_errstr, r->uri, r);
+               note_basic_auth_failure(r);
+               return AUTH_REQUIRED;
+               };
+           };
+
+        if(!strcmp(w,"valid-user")) {
+            user_result= OK;
+           };
+        }
+
+    /* we do not have to check the valid-ness of the group result as
+     * have not (yet) a 'valid-group' token
+     */
+    if ( (user_result != OK) && (sec->auth_msql_authorative) ) {
+        sprintf(msql_errstr,"User %s denied, no access rules applied (MSQL-Authorative) ",user);
+       log_reason (msql_errstr, r->uri, r);
+        note_basic_auth_failure(r);
+       return AUTH_REQUIRED;
+       };
+
+
+    /* if the user is DECLINED, it is up to the group_result to tip
+     * the balance. But if the group result is AUTH_REQUIRED it should
+     * always override. A SERVER_ERROR should not get here. 
+     */
+    if ( (user_result == DECLINED) || (group_result == AUTH_REQUIRED))
+       return group_result;
+
+    return user_result;
+}
+
+
+module msql_auth_module = {
+   STANDARD_MODULE_STUFF,
+   NULL,                       /* initializer */
+   create_msql_auth_dir_config,        /* dir config creater */
+   NULL,                       /* dir merger --- default is to override */
+   NULL,                       /* server config */
+   NULL,                       /* merge server config */
+   msql_auth_cmds,             /* command table */
+   NULL,                       /* handlers */
+   NULL,                       /* filename translation */
+   msql_authenticate_basic_user,/* check_user_id */
+   msql_check_auth,            /* check auth */
+   NULL,                       /* check access */
+   NULL,                       /* type_checker */
+   NULL,                       /* pre-run fixups */
+   NULL                                /* logger */
+};
+
diff --git a/RELEASE_1_1_X/src/modules/standard/mod_autoindex.c b/RELEASE_1_1_X/src/modules/standard/mod_autoindex.c
new file mode 100644 (file)
index 0000000..c30b57c
--- /dev/null
@@ -0,0 +1,846 @@
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * http_dir.c: Handles the on-the-fly html index generation
+ * 
+ * Rob McCool
+ * 3/23/93
+ * 
+ * Adapted to Shambhala by rst.
+ */
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_core.h"
+#include "http_request.h"
+#include "http_protocol.h"
+#include "http_log.h"
+#include "http_main.h"
+#include "util_script.h"
+
+module dir_module;
+
+/****************************************************************
+ *
+ * Handling configuration directives...
+ */
+
+#define FANCY_INDEXING 1       /* Indexing options */
+#define ICONS_ARE_LINKS 2
+#define SCAN_HTML_TITLES 4
+#define SUPPRESS_LAST_MOD 8
+#define SUPPRESS_SIZE 16
+#define SUPPRESS_DESC 32
+
+struct item {
+    char *type;
+    char *apply_to;
+    char *apply_path;
+    char *data;
+};
+
+typedef struct dir_config_struct {
+
+    char *default_icon;
+    char *index_names;
+  
+    array_header *icon_list, *alt_list, *desc_list, *ign_list;
+    array_header *hdr_list, *rdme_list, *opts_list;
+  
+} dir_config_rec;
+
+char c_by_encoding, c_by_type, c_by_path;
+
+#define BY_ENCODING &c_by_encoding
+#define BY_TYPE &c_by_type
+#define BY_PATH &c_by_path
+
+void push_item(array_header *arr, char *type, char *to, char *path, char *data)
+{
+    struct item *p = (struct item *)push_array(arr);
+
+    if (!to) to = "";
+    if (!path) path = "";
+    
+    p->type = type;
+    p->data = data ? pstrdup(arr->pool, data): NULL;
+    p->apply_path = pstrcat(arr->pool, path, "*", NULL);
+    
+    if((type == BY_PATH) && (!is_matchexp(to)))
+        p->apply_to = pstrcat (arr->pool, "*", to, NULL);
+    else if (to)
+        p->apply_to = pstrdup (arr->pool, to);
+    else
+        p->apply_to = NULL;
+}
+
+char *add_alt(cmd_parms *cmd, void *d, char *alt, char *to)
+{
+    if (cmd->info == BY_PATH)
+        if(!strcmp(to,"**DIRECTORY**"))
+            to = "^^DIRECTORY^^";
+
+    push_item(((dir_config_rec *)d)->alt_list, cmd->info, to, cmd->path, alt);
+    return NULL;
+}
+
+char *add_icon(cmd_parms *cmd, void *d, char *icon, char *to)
+{
+    char *iconbak = pstrdup (cmd->pool, icon);
+
+    if(icon[0] == '(') {
+        char *alt = getword (cmd->pool, &iconbak, ',');
+        iconbak[strlen(iconbak) - 1] = '\0'; /* Lose closing paren */
+        add_alt(cmd, d, &alt[1], to);
+    }
+    if(cmd->info == BY_PATH) 
+        if(!strcmp(to,"**DIRECTORY**"))
+            to = "^^DIRECTORY^^";
+
+    push_item(((dir_config_rec *)d)->icon_list, cmd->info, to, cmd->path,
+             iconbak);
+    return NULL;
+}
+
+char *add_desc(cmd_parms *cmd, void *d, char *desc, char *to)
+{
+    push_item(((dir_config_rec *)d)->desc_list, cmd->info, to, cmd->path,desc);
+    return NULL;
+}
+
+char *add_ignore(cmd_parms *cmd, void *d, char *ext) {
+    push_item(((dir_config_rec *)d)->ign_list, 0, ext, cmd->path, NULL);
+    return NULL;
+}
+
+char *add_header(cmd_parms *cmd, void *d, char *name) {
+    push_item(((dir_config_rec *)d)->hdr_list, 0, NULL, cmd->path, name);
+    return NULL;
+}
+
+char *add_readme(cmd_parms *cmd, void *d, char *name) {
+    push_item(((dir_config_rec *)d)->rdme_list, 0, NULL, cmd->path, name);
+    return NULL;
+}
+
+
+char *add_opts_int(cmd_parms *cmd, void *d, int opts) {
+    push_item(((dir_config_rec *)d)->opts_list, (char*)opts, NULL,
+             cmd->path, NULL);
+    return NULL;
+}
+
+char *fancy_indexing (cmd_parms *cmd, void *d, int arg)
+{
+    return add_opts_int (cmd, d, arg? FANCY_INDEXING : 0);
+}
+
+char *add_opts(cmd_parms *cmd, void *d, char *optstr) {
+    char *w;
+    int opts = 0;
+
+    while(optstr[0]) {
+        w = getword_conf(cmd->pool, &optstr);
+        if(!strcasecmp(w,"FancyIndexing"))
+            opts |= FANCY_INDEXING;
+        else if(!strcasecmp(w,"IconsAreLinks"))
+            opts |= ICONS_ARE_LINKS;
+        else if(!strcasecmp(w,"ScanHTMLTitles"))
+            opts |= SCAN_HTML_TITLES;
+        else if(!strcasecmp(w,"SuppressLastModified"))
+            opts |= SUPPRESS_LAST_MOD;
+        else if(!strcasecmp(w,"SuppressSize"))
+            opts |= SUPPRESS_SIZE;
+        else if(!strcasecmp(w,"SuppressDescription"))
+            opts |= SUPPRESS_DESC;
+        else if(!strcasecmp(w,"None"))
+            opts = 0;
+       else
+           return "Invalid directory indexing option";
+    }
+    return add_opts_int(cmd, d, opts);
+}
+
+#define DIR_CMD_PERMS OR_INDEXES
+
+command_rec dir_cmds[] = {
+{ "AddIcon", add_icon, BY_PATH, DIR_CMD_PERMS, ITERATE2,
+    "an icon URL followed by one or more filenames" },
+{ "AddIconByType", add_icon, BY_TYPE, DIR_CMD_PERMS, ITERATE2,
+    "an icon URL followed by one or more MIME types" },
+{ "AddIconByEncoding", add_icon, BY_ENCODING, DIR_CMD_PERMS, ITERATE2,
+    "an icon URL followed by one or more content encodings" },
+{ "AddAlt", add_alt, BY_PATH, DIR_CMD_PERMS, ITERATE2,
+    "alternate descriptive text followed by one or more filenames" },
+{ "AddAltByType", add_alt, BY_TYPE, DIR_CMD_PERMS, ITERATE2,
+    "alternate descriptive text followed by one or more MIME types" },
+{ "AddAltByEncoding", add_alt, BY_ENCODING, DIR_CMD_PERMS, ITERATE2,
+    "alternate descriptive text followed by one or more content encodings" },
+{ "IndexOptions", add_opts, NULL, DIR_CMD_PERMS, RAW_ARGS,
+    "one or more index options" },
+{ "IndexIgnore", add_ignore, NULL, DIR_CMD_PERMS, ITERATE,
+    "one or more file extensions" },
+{ "AddDescription", add_desc, BY_PATH, DIR_CMD_PERMS, ITERATE2,
+    "Descriptive text followed by one or more filenames" },
+{ "HeaderName", add_header, NULL, DIR_CMD_PERMS, TAKE1, "a filename" },
+{ "ReadmeName", add_readme, NULL, DIR_CMD_PERMS, TAKE1, "a filename" },
+{ "FancyIndexing", fancy_indexing, NULL, DIR_CMD_PERMS, FLAG, NULL },
+{ "DefaultIcon", set_string_slot,
+    (void*)XtOffsetOf(dir_config_rec, default_icon),
+    DIR_CMD_PERMS, TAKE1, "an icon URL"},
+{ "DirectoryIndex", set_string_slot,
+    (void*)XtOffsetOf(dir_config_rec, index_names),
+    DIR_CMD_PERMS, RAW_ARGS, NULL },
+{ NULL }
+};
+
+void *create_dir_config (pool *p, char *dummy)
+{
+    dir_config_rec *new =
+        (dir_config_rec *) pcalloc (p, sizeof(dir_config_rec));
+
+    new->index_names = NULL;
+    new->icon_list = make_array (p, 4, sizeof (struct item));
+    new->alt_list = make_array (p, 4, sizeof (struct item));
+    new->desc_list = make_array (p, 4, sizeof (struct item));
+    new->ign_list = make_array (p, 4, sizeof (struct item));
+    new->hdr_list = make_array (p, 4, sizeof (struct item));
+    new->rdme_list = make_array (p, 4, sizeof (struct item));
+    new->opts_list = make_array (p, 4, sizeof (struct item));
+    
+    return (void *)new;
+}
+
+void *merge_dir_configs (pool *p, void *basev, void *addv)
+{
+    dir_config_rec *new=(dir_config_rec*)pcalloc (p, sizeof(dir_config_rec));
+    dir_config_rec *base = (dir_config_rec *)basev;
+    dir_config_rec *add = (dir_config_rec *)addv;
+
+    new->default_icon = add->default_icon?add->default_icon:base->default_icon;
+    new->index_names = add->index_names? add->index_names: base->index_names;
+
+    new->alt_list = append_arrays (p, add->alt_list, base->alt_list);
+    new->ign_list = append_arrays (p, add->ign_list, base->ign_list);
+    new->hdr_list = append_arrays (p, add->hdr_list, base->hdr_list);
+    new->desc_list = append_arrays (p, add->desc_list, base->desc_list);
+    new->icon_list = append_arrays (p, add->icon_list, base->icon_list);
+    new->rdme_list = append_arrays (p, add->rdme_list, base->rdme_list);
+    new->opts_list = append_arrays (p, add->opts_list, base->opts_list);
+    
+    return new;
+}
+
+/****************************************************************
+ *
+ * Looking things up in config entries...
+ */
+
+/* Structure used to hold entries when we're actually building an index */
+
+struct ent {
+    char *name;
+    char *icon;
+    char *alt;
+    char *desc;
+    size_t size;
+    time_t lm;
+    struct ent *next;
+};
+
+char *find_item(request_rec *r, array_header *list, int path_only) {
+    char *content_type = r->content_type;
+    char *content_encoding = r->content_encoding;
+    char *path = r->filename;
+
+    struct item *items = (struct item *)list->elts;
+    int i;
+
+    for (i = 0; i < list->nelts; ++i) {
+        struct item *p = &items[i];
+      
+        /* Special cased for ^^DIRECTORY^^ and ^^BLANKICON^^ */
+        if((path[0] == '^') || (!strcmp_match(path,p->apply_path))) {
+            if(!*(p->apply_to))
+                return p->data;
+            else if(p->type == BY_PATH || path[0] == '^') {
+                if(!strcmp_match(path,p->apply_to))
+                    return p->data;
+            } else if(!path_only) {
+                if(!content_encoding) {
+                    if(p->type == BY_TYPE) {
+                        if(content_type && !strcmp_match(content_type,p->apply_to))
+                            return p->data;
+                    }
+                } else {
+                    if(p->type == BY_ENCODING) {
+                        if(!strcmp_match(content_encoding,p->apply_to))
+                            return p->data;
+                    }
+                }
+            }
+        }
+    }
+    return NULL;
+}
+
+#define find_icon(d,p,t) find_item(p,d->icon_list,t)
+#define find_alt(d,p,t) find_item(p,d->alt_list,t)
+#define find_desc(d,p) find_item(p,d->desc_list,0)
+#define find_header(d,p) find_item(p,d->hdr_list,0)
+#define find_readme(d,p) find_item(p,d->rdme_list,0)
+
+char *find_default_icon (dir_config_rec *d, char *bogus_name)
+{
+    request_rec r;
+
+    /* Bleah.  I tried to clean up find_item, and it lead to this bit
+     * of ugliness.   Note that the fields initialized are precisely
+     * those that find_item looks at...
+     */
+    
+    r.filename = bogus_name;
+    r.content_type = r.content_encoding = NULL;
+
+    return find_item (&r, d->icon_list, 1);
+}
+
+int ignore_entry(dir_config_rec *d, char *path) {
+    array_header *list = d->ign_list;
+    struct item *items = (struct item *)list->elts;
+    char *tt;
+    int i;
+
+    if((tt=strrchr(path,'/')) == NULL)
+      tt=path;
+    else {
+      tt++;
+    }
+
+    for (i = 0; i < list->nelts; ++i) {
+        struct item *p = &items[i];
+       char *ap;
+
+       if((ap=strrchr(p->apply_to,'/')) == NULL)
+         ap=p->apply_to;
+       else
+         ap++;
+
+        if(!strcmp_match(path,p->apply_path) && !strcmp_match(tt,ap))
+          return 1;
+    }
+    return 0;
+}
+
+int find_opts(dir_config_rec *d, request_rec *r) {
+    char *path = r->filename;
+    array_header *list = d->opts_list;
+    struct item *items = (struct item *)list->elts;
+    int i;
+
+    for (i = 0; i < list->nelts; ++i) {
+        struct item *p = &items[i];
+       
+        if(!strcmp_match(path,p->apply_path))
+            return (int)p->type;
+    }
+    return 0;
+}
+
+/*****************************************************************
+ *
+ * Actually generating output
+ */
+
+
+int insert_readme(char *name, char *readme_fname, int rule, request_rec *r) {
+    char *fn;
+    FILE *f;
+    struct stat finfo;
+    int plaintext=0;
+
+    fn = make_full_path(r->pool, name, readme_fname);
+    fn = pstrcat(r->pool, fn, ".html", NULL);
+    if(stat(fn,&finfo) == -1) {
+        /* A brief fake multiviews search for README.html */
+        fn[strlen(fn)-5] = '\0';
+        if(stat(fn,&finfo) == -1)
+            return 0;
+        plaintext=1;
+        if(rule) rputs("<HR>\n", r);
+        rputs("<PRE>\n", r);
+    }
+    else if (rule) rputs("<HR>\n", r);
+    if(!(f = pfopen(r->pool,fn,"r")))
+        return 0;
+    if (!plaintext)
+       send_fd(f, r);
+    else
+    {
+       char buf[IOBUFSIZE+1];
+       int i, n, c, ch;
+       while (!feof(f))
+       {
+           do n = fread(buf, sizeof(char), IOBUFSIZE, f);
+           while (n == -1 && ferror(f) && errno == EINTR);
+           if (n == -1 || n == 0) break;
+           buf[n] = '\0';
+           c = 0;
+           while (c < n)
+           {
+               for (i=c; i < n; i++)
+                   if (buf[i] == '<' || buf[i] == '>' || buf[i] == '&') break;
+               ch = buf[i];
+               buf[i] = '\0';
+               rputs(&buf[c], r);
+               if (ch == '<') rputs("&lt;", r);
+               else if (ch == '>') rputs("&gt;", r);
+               else if (ch == '&') rputs("&amp;", r);
+               c = i + 1;
+           }
+       }
+    }
+    pfclose(r->pool, f);
+    if(plaintext)
+        rputs("</PRE>\n", r);
+    return 1;
+}
+
+
+char *find_title(request_rec *r) {
+    char titlebuf[MAX_STRING_LEN], *find = "<TITLE>";
+    FILE *thefile = NULL;
+    int x,y,n,p;
+
+    if (r->content_type && !strcmp(r->content_type,"text/html") && !r->content_encoding) {
+        if(!(thefile = pfopen(r->pool, r->filename,"r")))
+            return NULL;
+        n = fread(titlebuf,sizeof(char),MAX_STRING_LEN - 1,thefile);
+        titlebuf[n] = '\0';
+        for(x=0,p=0;titlebuf[x];x++) {
+            if(toupper(titlebuf[x]) == find[p]) {
+                if(!find[++p]) {
+                    if((p = ind(&titlebuf[++x],'<')) != -1)
+                        titlebuf[x+p] = '\0';
+                    /* Scan for line breaks for Tanmoy's secretary */
+                    for(y=x;titlebuf[y];y++)
+                        if((titlebuf[y] == CR) || (titlebuf[y] == LF))
+                            titlebuf[y] = ' ';
+                   pfclose (r->pool, thefile);
+                    return pstrdup(r->pool, &titlebuf[x]);
+                }
+            } else p=0;
+        }
+       pfclose(r->pool, thefile);
+    }
+    return NULL;
+}
+
+struct ent *make_dir_entry(char *name, int dir_opts,
+                          dir_config_rec *d, request_rec *r)
+{
+    struct ent *p;
+
+    if((name[0] == '.') && (!name[1]))
+        return(NULL);
+
+    if (ignore_entry(d, make_full_path (r->pool, r->filename, name)))
+        return(NULL);
+
+    p=(struct ent *)pcalloc(r->pool, sizeof(struct ent));
+    p->name = pstrdup (r->pool, name);
+    p->size = -1;
+    p->icon = NULL;
+    p->alt = NULL;
+    p->desc = NULL;
+    p->lm = -1;
+
+    if(dir_opts & FANCY_INDEXING) {
+        request_rec *rr = sub_req_lookup_file (name, r);
+       
+       if (rr->finfo.st_mode != 0) {
+            p->lm = rr->finfo.st_mtime;
+            if(S_ISDIR(rr->finfo.st_mode)) {
+                if(!(p->icon = find_icon(d,rr,1)))
+                    p->icon = find_default_icon(d,"^^DIRECTORY^^");
+                if(!(p->alt = find_alt(d,rr,1)))
+                    p->alt = "DIR";
+                p->size = -1;
+               p->name = pstrcat (r->pool, name, "/", NULL);
+            }
+            else {
+                p->icon = find_icon(d, rr, 0);
+                p->alt = find_alt(d, rr, 0);
+                p->size = rr->finfo.st_size;
+            }
+        }
+       
+        p->desc = find_desc(d, rr);
+       
+        if((!p->desc) && (dir_opts & SCAN_HTML_TITLES))
+            p->desc = pstrdup (r->pool, find_title(rr));
+
+       destroy_sub_req (rr);
+    }
+    return(p);
+}
+
+char *terminate_description(dir_config_rec *d, char *desc, int dir_opts) {
+    int maxsize = 23;
+    register int x;
+    
+    if(dir_opts & SUPPRESS_LAST_MOD) maxsize += 17;
+    if(dir_opts & SUPPRESS_SIZE) maxsize += 7;
+
+    for(x=0;desc[x] && maxsize;x++) {
+        if(desc[x] == '<') {
+            while(desc[x] != '>') {
+                if(!desc[x]) {
+                    maxsize = 0;
+                    break;
+                }
+                ++x;
+            }
+        }
+        else --maxsize;
+    }
+    if(!maxsize) {
+        desc[x-1] = '>';       /* Grump. */
+       desc[x] = '\0';         /* Double Grump! */
+    }
+    return desc;
+}
+
+void output_directories(struct ent **ar, int n,
+                       dir_config_rec *d, request_rec *r, int dir_opts)
+{
+    int x, len;
+    char *name = r->uri;
+    char *tp;
+    pool *scratch = make_sub_pool (r->pool);
+    
+    if(name[0] == '\0') name = "/";
+
+    if(dir_opts & FANCY_INDEXING) {
+        rputs("<PRE>", r);
+        if((tp = find_default_icon(d,"^^BLANKICON^^")))
+            rvputs(r, "<IMG SRC=\"", escape_html(scratch, tp),
+                  "\" ALT=\"     \"> ", NULL);
+        rputs("Name                   ", r);
+        if(!(dir_opts & SUPPRESS_LAST_MOD))
+            rputs("Last modified     ", r);
+        if(!(dir_opts & SUPPRESS_SIZE))
+            rputs("Size  ", r);
+        if(!(dir_opts & SUPPRESS_DESC))
+            rputs("Description", r);
+        rputs("\n<HR>\n", r);
+    }
+    else {
+        rputs("<UL>", r);
+    }
+        
+    for(x=0;x<n;x++) {
+       char *anchor = NULL, *t = NULL, *t2 = NULL;
+       
+       clear_pool (scratch);
+       
+        if((!strcmp(ar[x]->name,"../")) || (!strcmp(ar[x]->name,".."))) {
+            char *t = make_full_path (scratch, name, "../");
+            getparents(t);
+            if(t[0] == '\0') t = "/";
+           anchor = pstrcat (scratch, "<A HREF=\"",
+                             escape_html(scratch, os_escape_path(scratch, t, 0)),
+                             "\">", NULL);
+           t2 = "Parent Directory</A>       ";
+        }
+        else {
+           t = ar[x]->name;
+           len = strlen(t);
+            if(len > 23) {
+               t2 = pstrdup(scratch, t);
+               t2[21] = '.';
+               t2[22] = '.';
+                t2[23] = '\0';
+               t2 = escape_html(scratch, t2);
+               t2 = pstrcat(scratch, t2, "</A>", NULL);
+            } else 
+           {
+               char buff[24]="                       ";
+               t2 = escape_html(scratch, t);
+               buff[23-len] = '\0';
+               t2 = pstrcat(scratch, t2, "</A>", buff, NULL);
+           }
+           anchor = pstrcat (scratch, "<A HREF=\"",
+                             escape_html(scratch, os_escape_path(scratch, t, 0)),
+                             "\">", NULL);
+        }
+
+        if(dir_opts & FANCY_INDEXING) {
+            if(dir_opts & ICONS_ARE_LINKS)
+                rputs(anchor, r);
+            if((ar[x]->icon) || d->default_icon) {
+                rvputs(r, "<IMG SRC=\"", 
+                      escape_html(scratch, ar[x]->icon ?
+                                  ar[x]->icon : d->default_icon),
+                      "\" ALT=\"[", (ar[x]->alt ? ar[x]->alt : "   "),
+                      "]\">", NULL);
+            }
+            if(dir_opts & ICONS_ARE_LINKS) 
+                rputs("</A>", r);
+
+            rvputs(r," ", anchor, t2, NULL);
+            if(!(dir_opts & SUPPRESS_LAST_MOD)) {
+                if(ar[x]->lm != -1) {
+                   char time[MAX_STRING_LEN];
+                    struct tm *ts = localtime(&ar[x]->lm);
+                    strftime(time,MAX_STRING_LEN,"%d-%b-%y %H:%M  ",ts);
+                   rputs(time, r);
+                }
+                else {
+                    rputs("                 ", r);
+                }
+            }
+            if(!(dir_opts & SUPPRESS_SIZE)) {
+                send_size(ar[x]->size,r);
+                rputs("  ", r);
+            }
+            if(!(dir_opts & SUPPRESS_DESC)) {
+                if(ar[x]->desc) {
+                    rputs(terminate_description(d, ar[x]->desc, dir_opts), r);
+                }
+            }
+        }
+        else
+            rvputs(r, "<LI> ", anchor," ", t2, NULL);
+        rputc('\n', r);
+    }
+    if(dir_opts & FANCY_INDEXING) {
+        rputs("</PRE>", r);
+    }
+    else {
+        rputs("</UL>", r);
+    }
+}
+
+
+int dsortf(struct ent **s1,struct ent **s2)
+{
+    return(strcmp((*s1)->name,(*s2)->name));
+}
+
+    
+int index_directory(request_rec *r, dir_config_rec *dir_conf)
+{
+    char *title_name = escape_html(r->pool, r->uri);
+    char *title_endp;
+    char *name = r->filename;
+    
+    DIR *d;
+    struct DIR_TYPE *dstruct;
+    int num_ent=0,x;
+    struct ent *head,*p;
+    struct ent **ar;
+    char *tmp;
+    int dir_opts = find_opts(dir_conf, r);
+
+    if(!(d=opendir(name))) return FORBIDDEN;
+
+    r->content_type = "text/html";
+    
+    soft_timeout ("send directory", r);
+    send_http_header(r);
+
+    if (r->header_only) {
+       closedir (d);
+       return 0;
+    }
+
+    /* Spew HTML preamble */
+    
+    title_endp = title_name + strlen(title_name) - 1;
+
+    while (title_endp > title_name && *title_endp == '/')
+       *title_endp-- = '\0';
+    
+    rvputs(r, "<HEAD><TITLE>Index of ", title_name, "</TITLE></HEAD><BODY>\n",
+          NULL);
+
+    if((!(tmp = find_header(dir_conf,r))) || (!(insert_readme(name,tmp,0,r))))
+        rvputs(r, "<H1>Index of ", title_name, "</H1>\n", NULL);
+
+    /* 
+     * Since we don't know how many dir. entries there are, put them into a 
+     * linked list and then arrayificate them so qsort can use them. 
+     */
+    head=NULL;
+    while((dstruct=readdir(d))) {
+        if((p = make_dir_entry(dstruct->d_name, dir_opts, dir_conf, r))) {
+            p->next=head;
+            head=p;
+            num_ent++;
+        }
+    }
+    ar=(struct ent **) palloc(r->pool, num_ent*sizeof(struct ent *));
+    p=head;
+    x=0;
+    while(p) {
+        ar[x++]=p;
+        p = p->next;
+    }
+    
+    qsort((void *)ar,num_ent,sizeof(struct ent *),
+#ifdef ULTRIX_BRAIN_DEATH
+          (int (*))dsortf);
+#else
+          (int (*)(const void *,const void *))dsortf);
+#endif
+     output_directories(ar, num_ent, dir_conf, r, dir_opts);
+     closedir(d);
+
+     if (dir_opts & FANCY_INDEXING)
+         if((tmp = find_readme(dir_conf, r)))
+             insert_readme(name,tmp,1,r);
+     else {
+         rputs("</UL>", r);
+     }
+
+     rputs("</BODY>", r);
+     return 0;
+}
+
+/* The formal handler... */
+
+int handle_dir (request_rec *r)
+{
+    dir_config_rec *d =
+      (dir_config_rec *)get_module_config (r->per_dir_config, &dir_module);
+    char *names_ptr = d->index_names ? d->index_names : DEFAULT_INDEX;
+    int allow_opts = allow_options (r);
+
+    if (r->uri[0] == '\0' || r->uri[strlen(r->uri)-1] != '/') {
+       char* ifile;
+       if (r->args != NULL)
+               ifile = pstrcat (r->pool, escape_uri(r->pool, r->uri),
+                       "/", "?", r->args, NULL);
+       else
+               ifile = pstrcat (r->pool, escape_uri(r->pool, r->uri),
+                        "/", NULL);
+
+       table_set (r->headers_out, "Location",
+                  construct_url(r->pool, ifile, r->server));
+       return REDIRECT;
+    }
+
+    /* KLUDGE --- make the sub_req lookups happen in the right directory.
+     * Fixing this in the sub_req_lookup functions themselves is difficult,
+     * and would probably break virtual includes...
+     */
+
+    r->filename = pstrcat (r->pool, r->filename, "/", NULL);
+    
+    while (*names_ptr) {
+          
+       char *name_ptr = getword_conf (r->pool, &names_ptr);
+       request_rec *rr = sub_req_lookup_uri (name_ptr, r);
+           
+       if (rr->status == 200 && rr->finfo.st_mode != 0) {
+           char* new_uri = escape_uri(r->pool, rr->uri);
+
+           if (rr->args != NULL)
+               new_uri = pstrcat(r->pool, new_uri, "?", rr->args, NULL);
+           else if (r->args != NULL)
+               new_uri = pstrcat(r->pool, new_uri, "?", r->args, NULL);
+       
+           destroy_sub_req (rr);
+           internal_redirect (new_uri, r);
+           return OK;
+       }
+
+        destroy_sub_req (rr);
+    }
+
+    if (r->method_number != M_GET) return NOT_IMPLEMENTED;
+    
+    /* OK, nothing easy.  Trot out the heavy artillery... */
+
+    if (allow_opts & OPT_INDEXES) 
+        return index_directory (r, d);
+    else
+        return FORBIDDEN;
+}
+
+
+handler_rec dir_handlers[] = {
+{ DIR_MAGIC_TYPE, handle_dir },
+{ NULL }
+};
+
+module dir_module = {
+   STANDARD_MODULE_STUFF,
+   NULL,                       /* initializer */
+   create_dir_config,          /* dir config creater */
+   merge_dir_configs,          /* dir merger --- default is to override */
+   NULL,                       /* server config */
+   NULL,                       /* merge server config */
+   dir_cmds,                   /* command table */
+   dir_handlers,               /* handlers */
+   NULL,                       /* filename translation */
+   NULL,                       /* check_user_id */
+   NULL,                       /* check auth */
+   NULL,                       /* check access */
+   NULL,                       /* type_checker */
+   NULL,                       /* fixups */
+   NULL                                /* logger */
+};
diff --git a/RELEASE_1_1_X/src/modules/standard/mod_cern_meta.c b/RELEASE_1_1_X/src/modules/standard/mod_cern_meta.c
new file mode 100644 (file)
index 0000000..c16bde4
--- /dev/null
@@ -0,0 +1,330 @@
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP OR
+ * IT'S 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+/*
+ * mod_cern_meta.c
+ * version 0.0.5
+ * status beta
+ * 
+ * Andrew Wilson <Andrew.Wilson@cm.cf.ac.uk> 25.Jan.96
+ *
+ * Emulate the CERN HTTPD Meta file semantics.  Meta files are HTTP
+ * headers that can be output in addition to the normal range of
+ * headers for each file accessed.  They appear rather like the Apache
+ * .asis files, and are able to provide a crude way of influencing
+ * the Expires: header, as well as providing other curiosities.
+ * There are many ways to manage meta information, this one was
+ * chosen because there is already a large number of CERN users
+ * who can exploit this module.  It should be noted that there are probably
+ * more sensitive ways of managing the Expires: header specifically.
+ *
+ * The module obeys the following directives, which can only appear 
+ * in the server's .conf files and not in any .htaccess file.
+ *
+ *  MetaDir <directory name>
+ *      
+ *    specifies the name of the directory in which Apache can find
+ *    meta information files.  The directory is usually a 'hidden'
+ *    subdirectory of the directory that contains the file being
+ *    accessed.  eg:
+ *
+ *        # .meta files are in the *same* directory as the 
+ *        # file being accessed
+ *        MetaDir .
+ *
+ *    the default is to look in a '.web' subdirectory. This is the
+ *    same as for CERN 3.+ webservers and behaviour is the same as 
+ *    for the directive:
+ *
+ *        MetaDir .web
+ *
+ *  MetaSuffix <meta file suffix>
+ *
+ *    specifies the file name suffix for the file containing the
+ *    meta information.  eg:
+ *
+ *       # our meta files are suffixed with '.cern_meta'
+ *       MetaSuffix .cern_meta
+ *
+ *    the default is to look for files with the suffix '.meta'.  This
+ *    behaviour is the same as for the directive:
+ *
+ *       MetaSuffix .meta
+ *
+ * When accessing the file
+ *
+ *   DOCUMENT_ROOT/somedir/index.html
+ *
+ * this module will look for the file
+ *
+ *   DOCUMENT_ROOT/somedir/.web/index.html.meta
+ *
+ * and will use its contents to generate additional MIME header 
+ * information.
+ *
+ * For more information on the CERN Meta file semantics see:
+ *
+ *   http://www.w3.org/hypertext/WWW/Daemon/User/Config/General.html#MetaDir
+ *
+ * Change-log:
+ * 29.Jan.96 pfopen/pfclose instead of fopen/fclose
+ *           DECLINE when real file not found, we may be checking each
+ *           of the index.html/index.shtml/index.htm variants and don't
+ *           need to report missing ones as spurious errors. 
+ * 31.Jan.96 log_error reports about a malformed .meta file, rather
+ *           than a script error.
+ *
+ */
+
+#include "httpd.h"
+#include "http_config.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "util_script.h"
+#include "http_log.h"
+
+#define DEFAULT_METADIR                ".web"
+#define DEFAULT_METASUFFIX     ".meta"
+
+module cern_meta_module;
+
+typedef struct {
+       char *metadir;
+       char *metasuffix;
+} cern_meta_config;
+
+void *create_cern_meta_config (pool *p, server_rec *dummy)
+{
+    cern_meta_config *new =
+      (cern_meta_config *) palloc (p, sizeof(cern_meta_config)); 
+    new->metadir = DEFAULT_METADIR;
+    new->metasuffix = DEFAULT_METASUFFIX;
+    
+    return new;
+}   
+
+char *set_metadir (cmd_parms *parms, void *dummy, char *arg)
+{       
+    cern_meta_config *cmc ;
+
+    cmc = get_module_config (parms->server->module_config,
+                           &cern_meta_module); 
+    cmc->metadir = arg;
+    return NULL;
+}
+
+char *set_metasuffix (cmd_parms *parms, void *dummy, char *arg)
+{       
+    cern_meta_config *cmc ;
+
+    cmc = get_module_config (parms->server->module_config,
+                           &cern_meta_module); 
+    cmc->metasuffix = arg;
+    return NULL;
+}
+
+command_rec cern_meta_cmds[] = {
+{ "MetaDir", set_metadir, NULL, RSRC_CONF, TAKE1,
+    "the name of the directory containing meta files"},
+{ "MetaSuffix", set_metasuffix, NULL, RSRC_CONF, TAKE1,
+    "the filename suffix for meta files"},
+{ NULL }
+};  
+
+int scan_meta_file(request_rec *r, FILE *f)
+{
+    char w[MAX_STRING_LEN];
+    char *l;
+    int p;
+
+    while( fgets(w, MAX_STRING_LEN-1, f) != NULL ) {
+
+       /* Delete terminal (CR?)LF */
+       
+       p = strlen(w);
+       if (p > 0 && w[p-1] == '\n')
+       {
+           if (p > 1 && w[p-2] == '\015') w[p-2] = '\0';
+           else w[p-1] = '\0';
+       }
+
+        if(w[0] == '\0') {
+           return OK;
+       }
+                                   
+       /* if we see a bogus header don't ignore it. Shout and scream */
+       
+        if(!(l = strchr(w,':'))) {
+           log_reason ("malformed header in meta file", r->filename, r);
+           return SERVER_ERROR;
+        }
+
+        *l++ = '\0';
+       while (*l && isspace (*l)) ++l;
+       
+        if(!strcasecmp(w,"Content-type")) {
+
+           /* Nuke trailing whitespace */
+           
+           char *endp = l + strlen(l) - 1;
+           while (endp > l && isspace(*endp)) *endp-- = '\0';
+           
+           r->content_type = pstrdup (r->pool, l);
+       }
+        else if(!strcasecmp(w,"Status")) {
+            sscanf(l, "%d", &r->status);
+            r->status_line = pstrdup(r->pool, l);
+        }
+        else {
+           table_set (r->headers_out, w, l);
+        }
+    }
+    return OK;
+}
+
+int add_cern_meta_data(request_rec *r)
+{
+    char *metafilename;
+    char *last_slash;
+    char *real_file;
+    char *scrap_book;
+    struct stat meta_stat;
+    FILE *f;   
+    cern_meta_config *cmc ;
+    int rv;
+
+    cmc = get_module_config (r->server->module_config,
+                           &cern_meta_module); 
+
+    /* if ./.web/$1.meta exists then output 'asis' */
+
+    if (r->finfo.st_mode == 0) {
+       return DECLINED;
+    };
+
+    /* does uri end in a trailing slash? */
+    if ( r->uri[strlen(r->uri) - 1] == '/' ) {
+       return DECLINED;
+    };
+
+    /* what directory is this file in? */
+    scrap_book = pstrdup( r->pool, r->filename );
+    /* skip leading slash, recovered in later processing */
+    scrap_book++;
+    last_slash = strrchr( scrap_book, '/' );
+    if ( last_slash != NULL ) {
+       /* skip over last slash */
+       real_file = last_slash;
+       real_file++;
+       *last_slash = '\0';
+    } else {
+       /* no last slash, buh?! */
+        log_reason("internal error in mod_cern_meta", r->filename, r);
+       /* should really barf, but hey, let's be friends... */
+       return DECLINED;
+    };
+
+    metafilename = pstrcat(r->pool, "/", scrap_book, "/", cmc->metadir, "/", real_file, cmc->metasuffix, NULL);
+
+    /*
+     * stat can legitimately fail for a bewildering number of reasons,
+     * only one of which implies the file isn't there.  A hardened
+     * version of this module should test for all conditions, but later...
+     */
+    if (stat(metafilename, &meta_stat) == -1) {
+       /* stat failed, possibly file missing */
+       return DECLINED;
+    };
+
+    /*
+     * this check is to be found in other Jan/96 Apache code, I've
+     * not been able to find any corroboration in the man pages but
+     * I've been wrong before so I'll put it in anyway.  Never
+     * admit to being clueless...
+     */
+    if ( meta_stat.st_mode == 0 ) {
+       /* stat failed, definately file missing */
+       return DECLINED;
+    };
+
+    f = pfopen (r->pool, metafilename, "r");
+    
+    if (f == NULL) {
+        log_reason("meta file permissions deny server access", metafilename, r);
+        return FORBIDDEN;
+    };
+
+    /* read the headers in */
+    rv = scan_meta_file(r, f);
+    pfclose( r->pool, f );
+
+    return rv;
+}
+
+module cern_meta_module = {
+   STANDARD_MODULE_STUFF,
+   NULL,                       /* initializer */
+   NULL,                       /* dir config creater */
+   NULL,                       /* dir merger --- default is to override */
+   create_cern_meta_config,    /* server config */
+   NULL,                       /* merge server configs */
+   cern_meta_cmds,             /* command table */
+   NULL,                       /* handlers */
+   NULL,                       /* filename translation */
+   NULL,                       /* check_user_id */
+   NULL,                       /* check auth */
+   NULL,                       /* check access */
+   NULL,                       /* type_checker */
+   add_cern_meta_data,         /* fixups */
+   NULL,                       /* logger */
+};
diff --git a/RELEASE_1_1_X/src/modules/standard/mod_cgi.c b/RELEASE_1_1_X/src/modules/standard/mod_cgi.c
new file mode 100644 (file)
index 0000000..0a86942
--- /dev/null
@@ -0,0 +1,412 @@
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * http_script: keeps all script-related ramblings together.
+ * 
+ * Compliant to CGI/1.1 spec
+ * 
+ * Adapted by rst from original NCSA code by Rob McCool
+ *
+ * Apache adds some new env vars; REDIRECT_URL and REDIRECT_QUERY_STRING for
+ * custom error responses, and DOCUMENT_ROOT because we found it useful.
+ * It also adds SERVER_ADMIN - useful for scripts to know who to mail when 
+ * they fail.
+ */
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_request.h"
+#include "http_core.h"
+#include "http_protocol.h"
+#include "http_main.h"
+#include "http_log.h"
+#include "util_script.h"
+
+/* KLUDGE --- for back-combatibility, we don't have to check ExecCGI
+ * in ScriptAliased directories, which means we need to know if this
+ * request came through ScriptAlias or not... so the Alias module
+ * leaves a note for us.
+ */
+
+int is_scriptaliased (request_rec *r)
+{
+    char *t = table_get (r->notes, "alias-forced-type");
+    return t && (!strcmp (t, "cgi-script"));
+}
+
+/****************************************************************
+ *
+ * Actual CGI handling...
+ */
+
+
+struct cgi_child_stuff {
+    request_rec *r;
+    int nph;
+    char *argv0;
+};
+
+void cgi_child (void *child_stuff)
+{
+    struct cgi_child_stuff *cld = (struct cgi_child_stuff *)child_stuff;
+    request_rec *r = cld->r;
+    char *argv0 = cld->argv0;
+    int nph = cld->nph;
+
+#ifdef DEBUG_CGI    
+#ifdef __EMX__
+    /* Under OS/2 need to use device con. */
+    FILE *dbg = fopen ("con", "w");
+#else    
+    FILE *dbg = fopen ("/dev/tty", "w");
+#endif    
+    int i;
+#endif
+    
+    char **env;
+    char err_string[HUGE_STRING_LEN];
+    
+#ifdef DEBUG_CGI    
+    fprintf (dbg, "Attempting to exec %s as %sCGI child (argv0 = %s)\n",
+           r->filename, nph ? "NPH " : "", argv0);
+#endif    
+
+    add_cgi_vars (r);
+    env = create_environment (r->pool, r->subprocess_env);
+    
+#ifdef DEBUG_CGI    
+    fprintf (dbg, "Environment: \n");
+    for (i = 0; env[i]; ++i) fprintf (dbg, "'%s'\n", env[i]);
+#endif
+    
+    chdir_file (r->filename);
+    error_log2stderr (r->server);
+
+#ifndef __EMX__
+    if (nph) client_to_stdout (r->connection);
+#endif    
+    
+    /* Transumute outselves into the script.
+     * NB only ISINDEX scripts get decoded arguments.
+     */
+    
+    cleanup_for_exec();
+    
+#ifdef __EMX__    
+    if((!r->args) || (!r->args[0]) || (ind(r->args,'=') >= 0)) {
+            int emxloop;
+            char *emxtemp;
+
+            /* For OS/2 place the variables in the current
+            enviornment then it will be inherited. This way
+            the program will also get all of OS/2's other SETs. */
+            for (emxloop=0; ((emxtemp = env[emxloop]) != NULL); emxloop++)
+                putenv(emxtemp);
+                
+            if (strstr(strupr(r->filename), ".CMD") > 0) {
+                /* Special case to allow use of REXX commands as scripts. */
+                os2pathname(r->filename);
+                execl("CMD.EXE", "CMD.EXE", "/C", r->filename, NULL);
+            } else {
+                execl(r->filename, argv0, NULL);
+            }
+    } else {
+            int emxloop;
+            char *emxtemp;
+            
+            /* For OS/2 place the variables in the current
+            enviornment then it will be inherited. This way
+            the program will also get all of OS/2's other SETs. */
+            for (emxloop=0; ((emxtemp = env[emxloop]) != NULL); emxloop++)
+                putenv(emxtemp);
+                
+            if (strstr(strupr(r->filename), ".CMD") > 0) {
+                /* Special case to allow use of REXX commands as scripts. */
+                os2pathname(r->filename);
+                execv("CMD.EXE", create_argv_cmd(r->pool, argv0, r->args, r->filename));
+            } else {
+                execv(r->filename, create_argv(r->pool, argv0, r->args));
+            }
+    }
+#else
+    if((!r->args) || (!r->args[0]) || (ind(r->args,'=') >= 0)) 
+        execle(r->filename, argv0, NULL, env);
+    else 
+        execve(r->filename, create_argv(r->pool, argv0, r->args), env);
+#endif        
+
+    /* Uh oh.  Still here.  Where's the kaboom?  There was supposed to be an
+     * EARTH-shattering kaboom!
+     *
+     * Oh, well.  Muddle through as best we can...
+     *
+     * (NB we can't use log_error, or anything like that, because we
+     * just closed the file descriptor which r->server->error_log
+     * was tied to in cleanup_for_exec().  It's only available on stderr
+     * now, so that's what we use).
+     */
+    
+    sprintf(err_string,
+           "exec of %s failed, errno is %d\n", r->filename, errno);
+    write(2, err_string, strlen(err_string));
+    exit(0);
+}
+
+int cgi_handler (request_rec *r)
+{
+    int nph;
+    char *argv0;
+    FILE *script_out, *script_in;
+    char argsbuffer[HUGE_STRING_LEN];
+    int is_included = !strcmp (r->protocol, "INCLUDED");
+    char *lenp = table_get (r->headers_in, "Content-length");
+
+    struct cgi_child_stuff cld;
+
+    if((argv0 = strrchr(r->filename,'/')) != NULL)
+        argv0++;
+    else argv0 = r->filename;
+
+    nph = !(strncmp(argv0,"nph-",4));
+    
+    if (!(allow_options (r) & OPT_EXECCGI) && !is_scriptaliased (r)) {
+        log_reason("Options ExecCGI is off in this directory", r->filename, r);
+       return FORBIDDEN;
+    }
+    if (nph && is_included) {
+        log_reason("attempt to include NPH CGI script", r->filename, r);
+       return FORBIDDEN;
+    }
+    
+    if (S_ISDIR(r->finfo.st_mode)) {
+        log_reason("attempt to invoke directory as script", r->filename, r);
+       return FORBIDDEN;
+    }
+    if (r->finfo.st_mode == 0) {
+        log_reason("script not found or unable to stat", r->filename, r);
+       return NOT_FOUND;
+    }
+    if(!can_exec(&r->finfo)) {
+        log_reason("file permissions deny server execution", r->filename, r);
+        return FORBIDDEN;
+    }
+    if ((r->method_number == M_POST || r->method_number == M_PUT)
+       && !lenp) {
+        log_reason("POST or PUT without Content-length:", r->filename, r);
+       return BAD_REQUEST;
+    }
+
+    add_common_vars (r);
+    cld.argv0 = argv0; cld.r = r; cld.nph = nph;
+    
+#ifdef __EMX__
+    if (r->method_number == M_POST || r->method_number == M_PUT) {
+        int len_to_read = atoi (lenp);
+    
+        if (len_to_read > HUGE_STRING_LEN) len_to_read = HUGE_STRING_LEN;
+        read_client_block (r, argsbuffer, len_to_read);
+
+        if (!spawn_child_os2 (r->connection->pool, cgi_child, (void *)&cld,
+                  nph ? just_wait : kill_after_timeout, 
+                  &script_out, &script_in, argsbuffer, atoi(lenp))) { 
+            log_reason ("couldn't spawn child process", r->filename, r);
+            return SERVER_ERROR;
+        }
+    } else {
+        if (!spawn_child (r->connection->pool, cgi_child, (void *)&cld,
+                  nph ? just_wait : kill_after_timeout,
+                  &script_out, &script_in)) {
+            log_reason ("couldn't spawn child process", r->filename, r);
+            return SERVER_ERROR;
+        }
+    }
+    
+#else
+     if (!spawn_child (r->connection->pool, cgi_child, (void *)&cld,
+                      nph ? just_wait : kill_after_timeout, 
+                      &script_out, nph ? NULL : &script_in)) {
+        log_reason ("couldn't spawn child process", r->filename, r);
+        return SERVER_ERROR;
+    }
+#endif
+
+    /* Transfer any put/post args, CERN style...
+     * Note that if a buggy script fails to read everything we throw
+     * at it, or a buggy client sends too much, we get a SIGPIPE, so
+     * we have to ignore SIGPIPE while doing this.  CERN does the same
+     * (and in fact, they pretty nearly guarantee themselves a SIGPIPE
+     * on every invocation by chasing the real client data with a
+     * spurious newline).
+     */
+    
+#ifndef __EMX__
+    if (r->method_number == M_POST || r->method_number == M_PUT) {
+        void (*handler)();
+       int remaining = atoi (lenp);
+       
+        hard_timeout ("copy script args", r);
+        handler = signal (SIGPIPE, SIG_IGN);
+    
+       while ((remaining > 0))
+       {
+           int len_read, len_to_read = remaining;
+
+           if (len_to_read > HUGE_STRING_LEN) len_to_read = HUGE_STRING_LEN;
+           
+           len_read = read_client_block (r, argsbuffer, len_to_read);
+           if (len_read == 0)
+               break;
+           if (fwrite (argsbuffer, 1, len_read, script_out) == 0)
+               break;
+           remaining -= len_read;
+       }
+
+       /* If script stopped reading early, soak up remaining stuff from
+        * client...
+        */
+       
+       while (remaining > 0) {
+           int len_read, len_to_read = remaining;
+           if (len_to_read > HUGE_STRING_LEN) len_to_read = HUGE_STRING_LEN;
+           
+           len_read = read_client_block (r, argsbuffer, len_to_read);
+           if (len_read == 0) break;
+       }
+    
+       fflush (script_out);
+       signal (SIGPIPE, handler);
+       
+       kill_timeout (r);
+    }
+#endif    
+    
+    pfclose (r->connection->pool, script_out);
+    
+    /* Handle script return... */
+    if (script_in && !nph) {
+        char *location;
+       int ret;
+      
+        if ((ret = scan_script_header(r, script_in)))
+           return ret;
+       
+       location = table_get (r->headers_out, "Location");
+
+        if (location && location[0] == '/' && r->status == 200) {
+         
+            /* Soak up all the script output */
+           hard_timeout ("read from script", r);
+           while (fgets(argsbuffer, HUGE_STRING_LEN-1, script_in) != NULL)
+               continue;
+           kill_timeout (r);
+
+
+          /* This redirect needs to be a GET no matter what the original
+           * method was.
+           */
+           r->method = pstrdup(r->pool, "GET");
+           r->method_number = M_GET;
+
+           internal_redirect_handler (location, r);
+           return OK;
+        }
+       else if (location && r->status == 200) {
+           /* XX Note that if a script wants to produce its own Redirect
+            * body, it now has to explicitly *say* "Status: 302"
+            */
+           return REDIRECT;
+       }
+       
+       hard_timeout ("send script output", r);
+       send_http_header(r);
+        if(!r->header_only) send_fd (script_in, r);
+       kill_timeout (r);
+       pfclose (r->connection->pool, script_in);
+    }
+
+#ifdef __EMX__
+    if (nph) {
+        while (fgets(argsbuffer, HUGE_STRING_LEN-1, script_in) != NULL) {
+            bputs(argsbuffer, r->connection->client);
+        }
+    }    
+#endif
+
+    return OK;                 /* NOT r->status, even if it has changed. */
+}
+
+handler_rec cgi_handlers[] = {
+{ CGI_MAGIC_TYPE, cgi_handler },
+{ "cgi-script", cgi_handler },
+{ NULL }
+};
+
+module cgi_module = {
+   STANDARD_MODULE_STUFF,
+   NULL,                       /* initializer */
+   NULL,                       /* dir config creater */
+   NULL,                       /* dir merger --- default is to override */
+   NULL,                       /* server config */
+   NULL,                       /* merge server config */
+   NULL,                       /* command table */
+   cgi_handlers,               /* handlers */
+   NULL,                       /* filename translation */
+   NULL,                       /* check_user_id */
+   NULL,                       /* check auth */
+   NULL,                       /* check access */
+   NULL,                       /* type_checker */
+   NULL,                       /* fixups */
+   NULL                                /* logger */
+};
diff --git a/RELEASE_1_1_X/src/modules/standard/mod_digest.c b/RELEASE_1_1_X/src/modules/standard/mod_digest.c
new file mode 100644 (file)
index 0000000..3ac81be
--- /dev/null
@@ -0,0 +1,356 @@
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * mod_digest: MD5 digest authentication
+ * 
+ * by Alexei Kosut <akosut@nueva.pvt.k12.ca.us>
+ * based on mod_auth, by Rob McCool and Robert S. Thau
+ *
+ */
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_core.h"
+#include "http_log.h"
+#include "http_protocol.h"
+#include "util_md5.h"
+
+typedef struct digest_config_struct {
+    char *pwfile;
+} digest_config_rec;
+
+typedef struct digest_header_struct {
+    char *username;
+    char *realm;
+    char *nonce;
+    char *requested_uri;
+    char *digest;
+} digest_header_rec;
+
+void *create_digest_dir_config (pool *p, char *d)
+{
+    return pcalloc (p, sizeof(digest_config_rec));
+}
+
+command_rec digest_cmds[] = {
+{ "AuthDigestFile", set_string_slot,
+    (void*)XtOffsetOf(digest_config_rec,pwfile), OR_AUTHCFG, TAKE1, NULL },
+{ NULL }
+};
+
+module digest_module;
+
+char *get_hash(request_rec *r, char *user, char *auth_pwfile)
+{
+    FILE *f;
+    char l[MAX_STRING_LEN];
+    char *rpw, *w, *x;
+
+    if(!(f=pfopen(r->pool, auth_pwfile, "r"))) {
+        log_reason ("Could not open password file", auth_pwfile, r);
+       return NULL;
+    }
+    while(!(cfg_getline(l,MAX_STRING_LEN,f))) {
+        if((l[0] == '#') || (!l[0])) continue;
+       rpw = l;
+        w = getword(r->pool, &rpw, ':');
+       x = getword(r->pool, &rpw, ':');
+
+        if(x && w && !strcmp(user,w) && !strcmp(auth_name(r), x)) {
+           pfclose(r->pool, f);
+            return pstrdup (r->pool, rpw);
+       }
+    }
+    pfclose(r->pool, f);
+    return NULL;
+}
+
+/* Parse the Authorization header, if it exists */
+
+int get_digest_rec(request_rec *r, digest_header_rec *response) {
+  char *auth_line = table_get(r->headers_in, "Authorization");
+  int l;
+  int s = 0, vk = 0, vv = 0;
+  char *t, *key, *value;
+
+  if (!(t = auth_type(r)) || strcasecmp(t, "Digest"))
+    return DECLINED;
+
+  if (!auth_name (r)) {
+    log_reason ("need AuthName", r->uri, r);
+    return SERVER_ERROR;
+  }
+
+  if (!auth_line) {
+    note_digest_auth_failure (r);
+    return AUTH_REQUIRED;
+  }
+
+  if (strcmp(getword (r->pool, &auth_line, ' '), "Digest")) {
+    /* Client tried to authenticate using wrong auth scheme */
+    log_reason ("client used wrong authentication scheme", r->uri, r);
+    note_digest_auth_failure (r);
+    return AUTH_REQUIRED;
+  }
+
+  l = strlen(auth_line);
+
+  key=palloc(r->pool,l);
+  value=palloc(r->pool,l);
+
+  /* There's probably a better way to do this, but for the time being... */
+
+#define D_KEY 0
+#define D_VALUE 1
+#define D_STRING 2
+#define D_EXIT -1
+
+  while (s != D_EXIT) {
+    switch (s) {
+    case D_STRING:
+      if (auth_line[0] == '\"') {
+       s = D_VALUE;
+      }
+      else {
+       value[vv] = auth_line[0];
+       vv++;
+      }
+      auth_line++;
+      break;
+
+    case D_VALUE:
+      if (isalnum(auth_line[0])) {
+       value[vv] = auth_line[0];
+       vv++;
+      }
+      else if (auth_line[0] == '\"') {
+       s = D_STRING;
+      }
+      else {
+       value[vv] = '\0';
+
+       if (!strcasecmp(key, "username"))
+         response->username = pstrdup(r->pool, value);
+       else if (!strcasecmp(key, "realm"))
+         response->realm = pstrdup(r->pool, value);
+       else if (!strcasecmp(key, "nonce"))
+         response->nonce = pstrdup(r->pool, value);
+       else if (!strcasecmp(key, "uri"))
+         response->requested_uri = pstrdup(r->pool, value);
+       else if (!strcasecmp(key, "response"))
+         response->digest = pstrdup(r->pool, value);
+
+       vv = 0;
+       s = D_KEY;
+      }
+      auth_line++;
+      break;
+
+    case D_KEY:
+      if (isalnum(auth_line[0])) {
+       key[vk] = auth_line[0];
+       vk++;
+      }
+      else if (auth_line[0] == '=') {
+       key[vk] = '\0';
+       vk = 0;
+       s = D_VALUE;
+      }
+      auth_line++;
+      break;
+    }
+
+    if (auth_line[-1] == '\0')
+      s = D_EXIT;
+  }
+
+  if (!response->username || !response->realm || !response->nonce ||
+      !response->requested_uri || !response->digest) {
+    note_digest_auth_failure (r);
+    return AUTH_REQUIRED;
+  }
+
+  r->connection->user = response->username;
+  r->connection->auth_type = "Digest";
+
+  return OK;
+}
+
+/* The actual MD5 code... whee */
+
+char *find_digest(request_rec *r, digest_header_rec *h, char *a1) {
+  return md5(r->pool,
+            (unsigned char *)pstrcat(r->pool, a1, ":", h->nonce, ":", 
+                         md5(r->pool,
+                             (unsigned char *)pstrcat(r->pool,r->method,":",
+                                                      h->requested_uri,NULL)),
+                                     NULL));
+}
+
+/* These functions return 0 if client is OK, and proper error status
+ * if not... either AUTH_REQUIRED, if we made a check, and it failed, or
+ * SERVER_ERROR, if things are so totally confused that we couldn't
+ * figure out how to tell if the client is authorized or not.
+ *
+ * If they return DECLINED, and all other modules also decline, that's
+ * treated by the server core as a configuration error, logged and
+ * reported as such.
+ */
+
+/* Determine user ID, and check if it really is that user, for HTTP
+ * basic authentication...
+ */
+
+int authenticate_digest_user (request_rec *r)
+{
+    digest_config_rec *sec =
+      (digest_config_rec *)get_module_config (r->per_dir_config,
+                                             &digest_module);
+    digest_header_rec *response = pcalloc (r->pool, sizeof(digest_header_rec));
+    conn_rec *c = r->connection;
+    char *a1;
+    char errstr[MAX_STRING_LEN];
+    int res;
+    
+    if ((res = get_digest_rec (r, response))) return res;
+    
+    if(!sec->pwfile) 
+        return DECLINED;
+       
+    if (!(a1 = get_hash(r, c->user, sec->pwfile))) {
+        sprintf(errstr,"user %s not found",c->user);
+       log_reason (errstr, r->uri, r);
+       note_digest_auth_failure (r);
+       return AUTH_REQUIRED;
+    }
+    /* anyone know where the prototype for crypt is? */
+    if(strcmp(response->digest, find_digest(r, response, a1))) {
+        sprintf(errstr,"user %s: password mismatch",c->user);
+       log_reason (errstr, r->uri, r);
+       note_digest_auth_failure (r);
+       return AUTH_REQUIRED;
+    }
+    return OK;
+}
+    
+/* Checking ID */
+    
+int digest_check_auth (request_rec *r) {
+    char *user = r->connection->user;
+    int m = r->method_number;
+    int method_restricted = 0;    
+    register int x;
+    char *t, *w;
+    array_header *reqs_arr;
+    require_line *reqs;
+
+    if (!(t = auth_type(r)) || strcasecmp(t, "Digest"))
+      return DECLINED;
+
+    reqs_arr = requires (r);
+    /* If there is no "requires" directive, 
+     * then any user will do.
+     */
+    if (!reqs_arr)
+        return OK;
+    reqs = (require_line *)reqs_arr->elts;
+
+    for(x=0; x < reqs_arr->nelts; x++) {
+      
+       if (! (reqs[x].method_mask & (1 << m))) continue;
+       
+        method_restricted = 1;
+
+       t = reqs[x].requirement;
+        w = getword(r->pool, &t, ' ');
+        if(!strcmp(w,"valid-user"))
+            return OK;
+        else if(!strcmp(w,"user")) {
+            while(t[0]) {
+                w = getword_conf (r->pool, &t);
+                if(!strcmp(user,w))
+                    return OK;
+            }
+         }
+       else
+         return DECLINED;
+    }
+    
+    if (!method_restricted)
+      return OK;
+
+    note_digest_auth_failure(r);
+    return AUTH_REQUIRED;
+}
+
+module digest_module = {
+   STANDARD_MODULE_STUFF,
+   NULL,                       /* initializer */
+   create_digest_dir_config,   /* dir config creater */
+   NULL,                       /* dir merger --- default is to override */
+   NULL,                       /* server config */
+   NULL,                       /* merge server config */
+   digest_cmds,                        /* command table */
+   NULL,                       /* handlers */
+   NULL,                       /* filename translation */
+   authenticate_digest_user,   /* check_user_id */
+   digest_check_auth,          /* check auth */
+   NULL,                       /* check access */
+   NULL,                       /* type_checker */
+   NULL,                       /* fixups */
+   NULL                                /* logger */
+};
+
+
diff --git a/RELEASE_1_1_X/src/modules/standard/mod_dir.c b/RELEASE_1_1_X/src/modules/standard/mod_dir.c
new file mode 100644 (file)
index 0000000..c30b57c
--- /dev/null
@@ -0,0 +1,846 @@
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * http_dir.c: Handles the on-the-fly html index generation
+ * 
+ * Rob McCool
+ * 3/23/93
+ * 
+ * Adapted to Shambhala by rst.
+ */
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_core.h"
+#include "http_request.h"
+#include "http_protocol.h"
+#include "http_log.h"
+#include "http_main.h"
+#include "util_script.h"
+
+module dir_module;
+
+/****************************************************************
+ *
+ * Handling configuration directives...
+ */
+
+#define FANCY_INDEXING 1       /* Indexing options */
+#define ICONS_ARE_LINKS 2
+#define SCAN_HTML_TITLES 4
+#define SUPPRESS_LAST_MOD 8
+#define SUPPRESS_SIZE 16
+#define SUPPRESS_DESC 32
+
+struct item {
+    char *type;
+    char *apply_to;
+    char *apply_path;
+    char *data;
+};
+
+typedef struct dir_config_struct {
+
+    char *default_icon;
+    char *index_names;
+  
+    array_header *icon_list, *alt_list, *desc_list, *ign_list;
+    array_header *hdr_list, *rdme_list, *opts_list;
+  
+} dir_config_rec;
+
+char c_by_encoding, c_by_type, c_by_path;
+
+#define BY_ENCODING &c_by_encoding
+#define BY_TYPE &c_by_type
+#define BY_PATH &c_by_path
+
+void push_item(array_header *arr, char *type, char *to, char *path, char *data)
+{
+    struct item *p = (struct item *)push_array(arr);
+
+    if (!to) to = "";
+    if (!path) path = "";
+    
+    p->type = type;
+    p->data = data ? pstrdup(arr->pool, data): NULL;
+    p->apply_path = pstrcat(arr->pool, path, "*", NULL);
+    
+    if((type == BY_PATH) && (!is_matchexp(to)))
+        p->apply_to = pstrcat (arr->pool, "*", to, NULL);
+    else if (to)
+        p->apply_to = pstrdup (arr->pool, to);
+    else
+        p->apply_to = NULL;
+}
+
+char *add_alt(cmd_parms *cmd, void *d, char *alt, char *to)
+{
+    if (cmd->info == BY_PATH)
+        if(!strcmp(to,"**DIRECTORY**"))
+            to = "^^DIRECTORY^^";
+
+    push_item(((dir_config_rec *)d)->alt_list, cmd->info, to, cmd->path, alt);
+    return NULL;
+}
+
+char *add_icon(cmd_parms *cmd, void *d, char *icon, char *to)
+{
+    char *iconbak = pstrdup (cmd->pool, icon);
+
+    if(icon[0] == '(') {
+        char *alt = getword (cmd->pool, &iconbak, ',');
+        iconbak[strlen(iconbak) - 1] = '\0'; /* Lose closing paren */
+        add_alt(cmd, d, &alt[1], to);
+    }
+    if(cmd->info == BY_PATH) 
+        if(!strcmp(to,"**DIRECTORY**"))
+            to = "^^DIRECTORY^^";
+
+    push_item(((dir_config_rec *)d)->icon_list, cmd->info, to, cmd->path,
+             iconbak);
+    return NULL;
+}
+
+char *add_desc(cmd_parms *cmd, void *d, char *desc, char *to)
+{
+    push_item(((dir_config_rec *)d)->desc_list, cmd->info, to, cmd->path,desc);
+    return NULL;
+}
+
+char *add_ignore(cmd_parms *cmd, void *d, char *ext) {
+    push_item(((dir_config_rec *)d)->ign_list, 0, ext, cmd->path, NULL);
+    return NULL;
+}
+
+char *add_header(cmd_parms *cmd, void *d, char *name) {
+    push_item(((dir_config_rec *)d)->hdr_list, 0, NULL, cmd->path, name);
+    return NULL;
+}
+
+char *add_readme(cmd_parms *cmd, void *d, char *name) {
+    push_item(((dir_config_rec *)d)->rdme_list, 0, NULL, cmd->path, name);
+    return NULL;
+}
+
+
+char *add_opts_int(cmd_parms *cmd, void *d, int opts) {
+    push_item(((dir_config_rec *)d)->opts_list, (char*)opts, NULL,
+             cmd->path, NULL);
+    return NULL;
+}
+
+char *fancy_indexing (cmd_parms *cmd, void *d, int arg)
+{
+    return add_opts_int (cmd, d, arg? FANCY_INDEXING : 0);
+}
+
+char *add_opts(cmd_parms *cmd, void *d, char *optstr) {
+    char *w;
+    int opts = 0;
+
+    while(optstr[0]) {
+        w = getword_conf(cmd->pool, &optstr);
+        if(!strcasecmp(w,"FancyIndexing"))
+            opts |= FANCY_INDEXING;
+        else if(!strcasecmp(w,"IconsAreLinks"))
+            opts |= ICONS_ARE_LINKS;
+        else if(!strcasecmp(w,"ScanHTMLTitles"))
+            opts |= SCAN_HTML_TITLES;
+        else if(!strcasecmp(w,"SuppressLastModified"))
+            opts |= SUPPRESS_LAST_MOD;
+        else if(!strcasecmp(w,"SuppressSize"))
+            opts |= SUPPRESS_SIZE;
+        else if(!strcasecmp(w,"SuppressDescription"))
+            opts |= SUPPRESS_DESC;
+        else if(!strcasecmp(w,"None"))
+            opts = 0;
+       else
+           return "Invalid directory indexing option";
+    }
+    return add_opts_int(cmd, d, opts);
+}
+
+#define DIR_CMD_PERMS OR_INDEXES
+
+command_rec dir_cmds[] = {
+{ "AddIcon", add_icon, BY_PATH, DIR_CMD_PERMS, ITERATE2,
+    "an icon URL followed by one or more filenames" },
+{ "AddIconByType", add_icon, BY_TYPE, DIR_CMD_PERMS, ITERATE2,
+    "an icon URL followed by one or more MIME types" },
+{ "AddIconByEncoding", add_icon, BY_ENCODING, DIR_CMD_PERMS, ITERATE2,
+    "an icon URL followed by one or more content encodings" },
+{ "AddAlt", add_alt, BY_PATH, DIR_CMD_PERMS, ITERATE2,
+    "alternate descriptive text followed by one or more filenames" },
+{ "AddAltByType", add_alt, BY_TYPE, DIR_CMD_PERMS, ITERATE2,
+    "alternate descriptive text followed by one or more MIME types" },
+{ "AddAltByEncoding", add_alt, BY_ENCODING, DIR_CMD_PERMS, ITERATE2,
+    "alternate descriptive text followed by one or more content encodings" },
+{ "IndexOptions", add_opts, NULL, DIR_CMD_PERMS, RAW_ARGS,
+    "one or more index options" },
+{ "IndexIgnore", add_ignore, NULL, DIR_CMD_PERMS, ITERATE,
+    "one or more file extensions" },
+{ "AddDescription", add_desc, BY_PATH, DIR_CMD_PERMS, ITERATE2,
+    "Descriptive text followed by one or more filenames" },
+{ "HeaderName", add_header, NULL, DIR_CMD_PERMS, TAKE1, "a filename" },
+{ "ReadmeName", add_readme, NULL, DIR_CMD_PERMS, TAKE1, "a filename" },
+{ "FancyIndexing", fancy_indexing, NULL, DIR_CMD_PERMS, FLAG, NULL },
+{ "DefaultIcon", set_string_slot,
+    (void*)XtOffsetOf(dir_config_rec, default_icon),
+    DIR_CMD_PERMS, TAKE1, "an icon URL"},
+{ "DirectoryIndex", set_string_slot,
+    (void*)XtOffsetOf(dir_config_rec, index_names),
+    DIR_CMD_PERMS, RAW_ARGS, NULL },
+{ NULL }
+};
+
+void *create_dir_config (pool *p, char *dummy)
+{
+    dir_config_rec *new =
+        (dir_config_rec *) pcalloc (p, sizeof(dir_config_rec));
+
+    new->index_names = NULL;
+    new->icon_list = make_array (p, 4, sizeof (struct item));
+    new->alt_list = make_array (p, 4, sizeof (struct item));
+    new->desc_list = make_array (p, 4, sizeof (struct item));
+    new->ign_list = make_array (p, 4, sizeof (struct item));
+    new->hdr_list = make_array (p, 4, sizeof (struct item));
+    new->rdme_list = make_array (p, 4, sizeof (struct item));
+    new->opts_list = make_array (p, 4, sizeof (struct item));
+    
+    return (void *)new;
+}
+
+void *merge_dir_configs (pool *p, void *basev, void *addv)
+{
+    dir_config_rec *new=(dir_config_rec*)pcalloc (p, sizeof(dir_config_rec));
+    dir_config_rec *base = (dir_config_rec *)basev;
+    dir_config_rec *add = (dir_config_rec *)addv;
+
+    new->default_icon = add->default_icon?add->default_icon:base->default_icon;
+    new->index_names = add->index_names? add->index_names: base->index_names;
+
+    new->alt_list = append_arrays (p, add->alt_list, base->alt_list);
+    new->ign_list = append_arrays (p, add->ign_list, base->ign_list);
+    new->hdr_list = append_arrays (p, add->hdr_list, base->hdr_list);
+    new->desc_list = append_arrays (p, add->desc_list, base->desc_list);
+    new->icon_list = append_arrays (p, add->icon_list, base->icon_list);
+    new->rdme_list = append_arrays (p, add->rdme_list, base->rdme_list);
+    new->opts_list = append_arrays (p, add->opts_list, base->opts_list);
+    
+    return new;
+}
+
+/****************************************************************
+ *
+ * Looking things up in config entries...
+ */
+
+/* Structure used to hold entries when we're actually building an index */
+
+struct ent {
+    char *name;
+    char *icon;
+    char *alt;
+    char *desc;
+    size_t size;
+    time_t lm;
+    struct ent *next;
+};
+
+char *find_item(request_rec *r, array_header *list, int path_only) {
+    char *content_type = r->content_type;
+    char *content_encoding = r->content_encoding;
+    char *path = r->filename;
+
+    struct item *items = (struct item *)list->elts;
+    int i;
+
+    for (i = 0; i < list->nelts; ++i) {
+        struct item *p = &items[i];
+      
+        /* Special cased for ^^DIRECTORY^^ and ^^BLANKICON^^ */
+        if((path[0] == '^') || (!strcmp_match(path,p->apply_path))) {
+            if(!*(p->apply_to))
+                return p->data;
+            else if(p->type == BY_PATH || path[0] == '^') {
+                if(!strcmp_match(path,p->apply_to))
+                    return p->data;
+            } else if(!path_only) {
+                if(!content_encoding) {
+                    if(p->type == BY_TYPE) {
+                        if(content_type && !strcmp_match(content_type,p->apply_to))
+                            return p->data;
+                    }
+                } else {
+                    if(p->type == BY_ENCODING) {
+                        if(!strcmp_match(content_encoding,p->apply_to))
+                            return p->data;
+                    }
+                }
+            }
+        }
+    }
+    return NULL;
+}
+
+#define find_icon(d,p,t) find_item(p,d->icon_list,t)
+#define find_alt(d,p,t) find_item(p,d->alt_list,t)
+#define find_desc(d,p) find_item(p,d->desc_list,0)
+#define find_header(d,p) find_item(p,d->hdr_list,0)
+#define find_readme(d,p) find_item(p,d->rdme_list,0)
+
+char *find_default_icon (dir_config_rec *d, char *bogus_name)
+{
+    request_rec r;
+
+    /* Bleah.  I tried to clean up find_item, and it lead to this bit
+     * of ugliness.   Note that the fields initialized are precisely
+     * those that find_item looks at...
+     */
+    
+    r.filename = bogus_name;
+    r.content_type = r.content_encoding = NULL;
+
+    return find_item (&r, d->icon_list, 1);
+}
+
+int ignore_entry(dir_config_rec *d, char *path) {
+    array_header *list = d->ign_list;
+    struct item *items = (struct item *)list->elts;
+    char *tt;
+    int i;
+
+    if((tt=strrchr(path,'/')) == NULL)
+      tt=path;
+    else {
+      tt++;
+    }
+
+    for (i = 0; i < list->nelts; ++i) {
+        struct item *p = &items[i];
+       char *ap;
+
+       if((ap=strrchr(p->apply_to,'/')) == NULL)
+         ap=p->apply_to;
+       else
+         ap++;
+
+        if(!strcmp_match(path,p->apply_path) && !strcmp_match(tt,ap))
+          return 1;
+    }
+    return 0;
+}
+
+int find_opts(dir_config_rec *d, request_rec *r) {
+    char *path = r->filename;
+    array_header *list = d->opts_list;
+    struct item *items = (struct item *)list->elts;
+    int i;
+
+    for (i = 0; i < list->nelts; ++i) {
+        struct item *p = &items[i];
+       
+        if(!strcmp_match(path,p->apply_path))
+            return (int)p->type;
+    }
+    return 0;
+}
+
+/*****************************************************************
+ *
+ * Actually generating output
+ */
+
+
+int insert_readme(char *name, char *readme_fname, int rule, request_rec *r) {
+    char *fn;
+    FILE *f;
+    struct stat finfo;
+    int plaintext=0;
+
+    fn = make_full_path(r->pool, name, readme_fname);
+    fn = pstrcat(r->pool, fn, ".html", NULL);
+    if(stat(fn,&finfo) == -1) {
+        /* A brief fake multiviews search for README.html */
+        fn[strlen(fn)-5] = '\0';
+        if(stat(fn,&finfo) == -1)
+            return 0;
+        plaintext=1;
+        if(rule) rputs("<HR>\n", r);
+        rputs("<PRE>\n", r);
+    }
+    else if (rule) rputs("<HR>\n", r);
+    if(!(f = pfopen(r->pool,fn,"r")))
+        return 0;
+    if (!plaintext)
+       send_fd(f, r);
+    else
+    {
+       char buf[IOBUFSIZE+1];
+       int i, n, c, ch;
+       while (!feof(f))
+       {
+           do n = fread(buf, sizeof(char), IOBUFSIZE, f);
+           while (n == -1 && ferror(f) && errno == EINTR);
+           if (n == -1 || n == 0) break;
+           buf[n] = '\0';
+           c = 0;
+           while (c < n)
+           {
+               for (i=c; i < n; i++)
+                   if (buf[i] == '<' || buf[i] == '>' || buf[i] == '&') break;
+               ch = buf[i];
+               buf[i] = '\0';
+               rputs(&buf[c], r);
+               if (ch == '<') rputs("&lt;", r);
+               else if (ch == '>') rputs("&gt;", r);
+               else if (ch == '&') rputs("&amp;", r);
+               c = i + 1;
+           }
+       }
+    }
+    pfclose(r->pool, f);
+    if(plaintext)
+        rputs("</PRE>\n", r);
+    return 1;
+}
+
+
+char *find_title(request_rec *r) {
+    char titlebuf[MAX_STRING_LEN], *find = "<TITLE>";
+    FILE *thefile = NULL;
+    int x,y,n,p;
+
+    if (r->content_type && !strcmp(r->content_type,"text/html") && !r->content_encoding) {
+        if(!(thefile = pfopen(r->pool, r->filename,"r")))
+            return NULL;
+        n = fread(titlebuf,sizeof(char),MAX_STRING_LEN - 1,thefile);
+        titlebuf[n] = '\0';
+        for(x=0,p=0;titlebuf[x];x++) {
+            if(toupper(titlebuf[x]) == find[p]) {
+                if(!find[++p]) {
+                    if((p = ind(&titlebuf[++x],'<')) != -1)
+                        titlebuf[x+p] = '\0';
+                    /* Scan for line breaks for Tanmoy's secretary */
+                    for(y=x;titlebuf[y];y++)
+                        if((titlebuf[y] == CR) || (titlebuf[y] == LF))
+                            titlebuf[y] = ' ';
+                   pfclose (r->pool, thefile);
+                    return pstrdup(r->pool, &titlebuf[x]);
+                }
+            } else p=0;
+        }
+       pfclose(r->pool, thefile);
+    }
+    return NULL;
+}
+
+struct ent *make_dir_entry(char *name, int dir_opts,
+                          dir_config_rec *d, request_rec *r)
+{
+    struct ent *p;
+
+    if((name[0] == '.') && (!name[1]))
+        return(NULL);
+
+    if (ignore_entry(d, make_full_path (r->pool, r->filename, name)))
+        return(NULL);
+
+    p=(struct ent *)pcalloc(r->pool, sizeof(struct ent));
+    p->name = pstrdup (r->pool, name);
+    p->size = -1;
+    p->icon = NULL;
+    p->alt = NULL;
+    p->desc = NULL;
+    p->lm = -1;
+
+    if(dir_opts & FANCY_INDEXING) {
+        request_rec *rr = sub_req_lookup_file (name, r);
+       
+       if (rr->finfo.st_mode != 0) {
+            p->lm = rr->finfo.st_mtime;
+            if(S_ISDIR(rr->finfo.st_mode)) {
+                if(!(p->icon = find_icon(d,rr,1)))
+                    p->icon = find_default_icon(d,"^^DIRECTORY^^");
+                if(!(p->alt = find_alt(d,rr,1)))
+                    p->alt = "DIR";
+                p->size = -1;
+               p->name = pstrcat (r->pool, name, "/", NULL);
+            }
+            else {
+                p->icon = find_icon(d, rr, 0);
+                p->alt = find_alt(d, rr, 0);
+                p->size = rr->finfo.st_size;
+            }
+        }
+       
+        p->desc = find_desc(d, rr);
+       
+        if((!p->desc) && (dir_opts & SCAN_HTML_TITLES))
+            p->desc = pstrdup (r->pool, find_title(rr));
+
+       destroy_sub_req (rr);
+    }
+    return(p);
+}
+
+char *terminate_description(dir_config_rec *d, char *desc, int dir_opts) {
+    int maxsize = 23;
+    register int x;
+    
+    if(dir_opts & SUPPRESS_LAST_MOD) maxsize += 17;
+    if(dir_opts & SUPPRESS_SIZE) maxsize += 7;
+
+    for(x=0;desc[x] && maxsize;x++) {
+        if(desc[x] == '<') {
+            while(desc[x] != '>') {
+                if(!desc[x]) {
+                    maxsize = 0;
+                    break;
+                }
+                ++x;
+            }
+        }
+        else --maxsize;
+    }
+    if(!maxsize) {
+        desc[x-1] = '>';       /* Grump. */
+       desc[x] = '\0';         /* Double Grump! */
+    }
+    return desc;
+}
+
+void output_directories(struct ent **ar, int n,
+                       dir_config_rec *d, request_rec *r, int dir_opts)
+{
+    int x, len;
+    char *name = r->uri;
+    char *tp;
+    pool *scratch = make_sub_pool (r->pool);
+    
+    if(name[0] == '\0') name = "/";
+
+    if(dir_opts & FANCY_INDEXING) {
+        rputs("<PRE>", r);
+        if((tp = find_default_icon(d,"^^BLANKICON^^")))
+            rvputs(r, "<IMG SRC=\"", escape_html(scratch, tp),
+                  "\" ALT=\"     \"> ", NULL);
+        rputs("Name                   ", r);
+        if(!(dir_opts & SUPPRESS_LAST_MOD))
+            rputs("Last modified     ", r);
+        if(!(dir_opts & SUPPRESS_SIZE))
+            rputs("Size  ", r);
+        if(!(dir_opts & SUPPRESS_DESC))
+            rputs("Description", r);
+        rputs("\n<HR>\n", r);
+    }
+    else {
+        rputs("<UL>", r);
+    }
+        
+    for(x=0;x<n;x++) {
+       char *anchor = NULL, *t = NULL, *t2 = NULL;
+       
+       clear_pool (scratch);
+       
+        if((!strcmp(ar[x]->name,"../")) || (!strcmp(ar[x]->name,".."))) {
+            char *t = make_full_path (scratch, name, "../");
+            getparents(t);
+            if(t[0] == '\0') t = "/";
+           anchor = pstrcat (scratch, "<A HREF=\"",
+                             escape_html(scratch, os_escape_path(scratch, t, 0)),
+                             "\">", NULL);
+           t2 = "Parent Directory</A>       ";
+        }
+        else {
+           t = ar[x]->name;
+           len = strlen(t);
+            if(len > 23) {
+               t2 = pstrdup(scratch, t);
+               t2[21] = '.';
+               t2[22] = '.';
+                t2[23] = '\0';
+               t2 = escape_html(scratch, t2);
+               t2 = pstrcat(scratch, t2, "</A>", NULL);
+            } else 
+           {
+               char buff[24]="                       ";
+               t2 = escape_html(scratch, t);
+               buff[23-len] = '\0';
+               t2 = pstrcat(scratch, t2, "</A>", buff, NULL);
+           }
+           anchor = pstrcat (scratch, "<A HREF=\"",
+                             escape_html(scratch, os_escape_path(scratch, t, 0)),
+                             "\">", NULL);
+        }
+
+        if(dir_opts & FANCY_INDEXING) {
+            if(dir_opts & ICONS_ARE_LINKS)
+                rputs(anchor, r);
+            if((ar[x]->icon) || d->default_icon) {
+                rvputs(r, "<IMG SRC=\"", 
+                      escape_html(scratch, ar[x]->icon ?
+                                  ar[x]->icon : d->default_icon),
+                      "\" ALT=\"[", (ar[x]->alt ? ar[x]->alt : "   "),
+                      "]\">", NULL);
+            }
+            if(dir_opts & ICONS_ARE_LINKS) 
+                rputs("</A>", r);
+
+            rvputs(r," ", anchor, t2, NULL);
+            if(!(dir_opts & SUPPRESS_LAST_MOD)) {
+                if(ar[x]->lm != -1) {
+                   char time[MAX_STRING_LEN];
+                    struct tm *ts = localtime(&ar[x]->lm);
+                    strftime(time,MAX_STRING_LEN,"%d-%b-%y %H:%M  ",ts);
+                   rputs(time, r);
+                }
+                else {
+                    rputs("                 ", r);
+                }
+            }
+            if(!(dir_opts & SUPPRESS_SIZE)) {
+                send_size(ar[x]->size,r);
+                rputs("  ", r);
+            }
+            if(!(dir_opts & SUPPRESS_DESC)) {
+                if(ar[x]->desc) {
+                    rputs(terminate_description(d, ar[x]->desc, dir_opts), r);
+                }
+            }
+        }
+        else
+            rvputs(r, "<LI> ", anchor," ", t2, NULL);
+        rputc('\n', r);
+    }
+    if(dir_opts & FANCY_INDEXING) {
+        rputs("</PRE>", r);
+    }
+    else {
+        rputs("</UL>", r);
+    }
+}
+
+
+int dsortf(struct ent **s1,struct ent **s2)
+{
+    return(strcmp((*s1)->name,(*s2)->name));
+}
+
+    
+int index_directory(request_rec *r, dir_config_rec *dir_conf)
+{
+    char *title_name = escape_html(r->pool, r->uri);
+    char *title_endp;
+    char *name = r->filename;
+    
+    DIR *d;
+    struct DIR_TYPE *dstruct;
+    int num_ent=0,x;
+    struct ent *head,*p;
+    struct ent **ar;
+    char *tmp;
+    int dir_opts = find_opts(dir_conf, r);
+
+    if(!(d=opendir(name))) return FORBIDDEN;
+
+    r->content_type = "text/html";
+    
+    soft_timeout ("send directory", r);
+    send_http_header(r);
+
+    if (r->header_only) {
+       closedir (d);
+       return 0;
+    }
+
+    /* Spew HTML preamble */
+    
+    title_endp = title_name + strlen(title_name) - 1;
+
+    while (title_endp > title_name && *title_endp == '/')
+       *title_endp-- = '\0';
+    
+    rvputs(r, "<HEAD><TITLE>Index of ", title_name, "</TITLE></HEAD><BODY>\n",
+          NULL);
+
+    if((!(tmp = find_header(dir_conf,r))) || (!(insert_readme(name,tmp,0,r))))
+        rvputs(r, "<H1>Index of ", title_name, "</H1>\n", NULL);
+
+    /* 
+     * Since we don't know how many dir. entries there are, put them into a 
+     * linked list and then arrayificate them so qsort can use them. 
+     */
+    head=NULL;
+    while((dstruct=readdir(d))) {
+        if((p = make_dir_entry(dstruct->d_name, dir_opts, dir_conf, r))) {
+            p->next=head;
+            head=p;
+            num_ent++;
+        }
+    }
+    ar=(struct ent **) palloc(r->pool, num_ent*sizeof(struct ent *));
+    p=head;
+    x=0;
+    while(p) {
+        ar[x++]=p;
+        p = p->next;
+    }
+    
+    qsort((void *)ar,num_ent,sizeof(struct ent *),
+#ifdef ULTRIX_BRAIN_DEATH
+          (int (*))dsortf);
+#else
+          (int (*)(const void *,const void *))dsortf);
+#endif
+     output_directories(ar, num_ent, dir_conf, r, dir_opts);
+     closedir(d);
+
+     if (dir_opts & FANCY_INDEXING)
+         if((tmp = find_readme(dir_conf, r)))
+             insert_readme(name,tmp,1,r);
+     else {
+         rputs("</UL>", r);
+     }
+
+     rputs("</BODY>", r);
+     return 0;
+}
+
+/* The formal handler... */
+
+int handle_dir (request_rec *r)
+{
+    dir_config_rec *d =
+      (dir_config_rec *)get_module_config (r->per_dir_config, &dir_module);
+    char *names_ptr = d->index_names ? d->index_names : DEFAULT_INDEX;
+    int allow_opts = allow_options (r);
+
+    if (r->uri[0] == '\0' || r->uri[strlen(r->uri)-1] != '/') {
+       char* ifile;
+       if (r->args != NULL)
+               ifile = pstrcat (r->pool, escape_uri(r->pool, r->uri),
+                       "/", "?", r->args, NULL);
+       else
+               ifile = pstrcat (r->pool, escape_uri(r->pool, r->uri),
+                        "/", NULL);
+
+       table_set (r->headers_out, "Location",
+                  construct_url(r->pool, ifile, r->server));
+       return REDIRECT;
+    }
+
+    /* KLUDGE --- make the sub_req lookups happen in the right directory.
+     * Fixing this in the sub_req_lookup functions themselves is difficult,
+     * and would probably break virtual includes...
+     */
+
+    r->filename = pstrcat (r->pool, r->filename, "/", NULL);
+    
+    while (*names_ptr) {
+          
+       char *name_ptr = getword_conf (r->pool, &names_ptr);
+       request_rec *rr = sub_req_lookup_uri (name_ptr, r);
+           
+       if (rr->status == 200 && rr->finfo.st_mode != 0) {
+           char* new_uri = escape_uri(r->pool, rr->uri);
+
+           if (rr->args != NULL)
+               new_uri = pstrcat(r->pool, new_uri, "?", rr->args, NULL);
+           else if (r->args != NULL)
+               new_uri = pstrcat(r->pool, new_uri, "?", r->args, NULL);
+       
+           destroy_sub_req (rr);
+           internal_redirect (new_uri, r);
+           return OK;
+       }
+
+        destroy_sub_req (rr);
+    }
+
+    if (r->method_number != M_GET) return NOT_IMPLEMENTED;
+    
+    /* OK, nothing easy.  Trot out the heavy artillery... */
+
+    if (allow_opts & OPT_INDEXES) 
+        return index_directory (r, d);
+    else
+        return FORBIDDEN;
+}
+
+
+handler_rec dir_handlers[] = {
+{ DIR_MAGIC_TYPE, handle_dir },
+{ NULL }
+};
+
+module dir_module = {
+   STANDARD_MODULE_STUFF,
+   NULL,                       /* initializer */
+   create_dir_config,          /* dir config creater */
+   merge_dir_configs,          /* dir merger --- default is to override */
+   NULL,                       /* server config */
+   NULL,                       /* merge server config */
+   dir_cmds,                   /* command table */
+   dir_handlers,               /* handlers */
+   NULL,                       /* filename translation */
+   NULL,                       /* check_user_id */
+   NULL,                       /* check auth */
+   NULL,                       /* check access */
+   NULL,                       /* type_checker */
+   NULL,                       /* fixups */
+   NULL                                /* logger */
+};
diff --git a/RELEASE_1_1_X/src/modules/standard/mod_dld.c b/RELEASE_1_1_X/src/modules/standard/mod_dld.c
new file mode 100644 (file)
index 0000000..a0bc13c
--- /dev/null
@@ -0,0 +1,191 @@
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * A first stab at dynamic loading, using the GNU dld library
+ * (or at least, an embarassingly old version of it...).
+ */
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_conf_globals.h" /* server_argv0.  Sigh... */
+#include <dld.h>
+
+/*
+ * The hard part of implementing LoadModule is deciding what to do about
+ * rereading the config files.  This proof-of-concept implementation takes the 
+ * cheap way out:  we only actually load the modules the first time through.
+ */
+
+static int been_there_done_that = 0; /* Loaded the modules yet? */
+static int have_symbol_table = 0;
+
+char *insure_dld_sane()
+{
+    int errcode;
+    char *bin_name;
+    
+    if (have_symbol_table) return NULL;
+
+    bin_name = dld_find_executable (server_argv0);
+    
+    if ((errcode = dld_init (bin_name))) {
+       dld_perror (server_argv0);
+       return "Cannot find server binary (needed for dynamic linking).";
+    }
+
+    have_symbol_table = 1;
+    return NULL;
+}
+
+char *link_file (pool *p, char *filename)
+{
+    int errcode;
+    
+    filename = server_root_relative (p, filename);
+    if ((errcode = dld_link (filename))) {
+       dld_perror (server_argv0);
+       return pstrcat (p, "Cannot load ", filename, " into server", NULL);
+    }
+    return NULL;
+}
+
+char *load_module (cmd_parms *cmd, void *dummy, char *modname, char *filename)
+{
+    char *errname;
+    module *modp;
+
+    if (been_there_done_that) return NULL;
+    
+    if ((errname = insure_dld_sane())) return errname;
+    if ((errname = link_file (cmd->pool, filename))) return errname;
+    if (!(modp = (module *)dld_get_symbol (modname))) {
+       return pstrcat (cmd->pool, "Can't find module ", modname,
+                                  " in file ", filename, NULL);
+    }
+
+    add_module (modp);
+
+    /* Alethea Patch (rws,djw2) - need to run configuration functions
+       in new modules */
+
+    if (modp->create_server_config)
+      ((void**)cmd->server->module_config)[modp->module_index]=
+       (*modp->create_server_config)(cmd->pool, cmd->server);
+
+    if (modp->create_dir_config)
+      ((void**)cmd->server->lookup_defaults)[modp->module_index]=
+       (*modp->create_dir_config)(cmd->pool, NULL);
+
+
+    return NULL;
+}
+
+char *load_file (cmd_parms *cmd, void *dummy, char *filename)
+{
+    char *errname;
+    
+    if (been_there_done_that) return NULL;
+    
+    if ((errname = insure_dld_sane())) return errname;
+    if ((errname = link_file (cmd->pool, filename))) return errname;
+    return NULL;
+}
+
+void check_loaded_modules (server_rec *dummy, pool *p)
+{
+    if (been_there_done_that) return;
+
+    if (dld_undefined_sym_count > 0) {
+       /* Screwup.  Do the best we can to inform the user, and exit */
+       char **bad_syms = dld_list_undefined_sym();
+       int i;
+
+       fprintf(stderr, "Dynamic linking error --- symbols left undefined.\n");
+       fprintf(stderr, "(It may help to relink libraries).\n");
+       fprintf(stderr, "Undefined symbols follow:\n");
+       
+       for (i = 0; i < dld_undefined_sym_count; ++i)
+           fprintf (stderr, "%s\n", bad_syms[i]);
+
+       exit (1);
+    }
+    
+    been_there_done_that = 1;
+}
+
+command_rec dld_cmds[] = {
+{ "LoadModule", load_module, NULL, RSRC_CONF, TAKE2,
+  "a module name, and the name of a file to load it from"},
+{ "LoadFile", load_file, NULL, RSRC_CONF, ITERATE,
+  "files or libraries to link into the server at runtime"},
+{ NULL }
+};
+
+module dld_module = {
+   STANDARD_MODULE_STUFF,
+   check_loaded_modules,       /* initializer */
+   NULL,                       /* create per-dir config */
+   NULL,                       /* merge per-dir config */
+   NULL,                       /* server config */
+   NULL,                       /* merge server config */
+   dld_cmds,                   /* command table */
+   NULL,                       /* handlers */
+   NULL,                       /* filename translation */
+   NULL,                       /* check_user_id */
+   NULL,                       /* check auth */
+   NULL,                       /* check access */
+   NULL,                       /* type_checker */
+   NULL                                /* logger */
+};
diff --git a/RELEASE_1_1_X/src/modules/standard/mod_env.c b/RELEASE_1_1_X/src/modules/standard/mod_env.c
new file mode 100644 (file)
index 0000000..d16accc
--- /dev/null
@@ -0,0 +1,257 @@
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP OR
+ * IT'S 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+/*
+ * mod_env.c
+ * version 0.0.5
+ * status beta
+ * Pass environment variables to CGI/SSI scripts.
+ * 
+ * Andrew Wilson <Andrew.Wilson@cm.cf.ac.uk> 06.Dec.95
+ *
+ * Change log:
+ * 08.Dec.95 Now allows PassEnv directive to appear more than once in
+ *           conf files.
+ * 10.Dec.95 optimisation.  getenv() only called at startup and used 
+ *           to build a fast-to-access table.  table used to build 
+ *           per-server environment for each request.
+ *           robustness.  better able to handle errors in configuration
+ *           files:
+ *           1)  PassEnv directive present, but no environment variable listed
+ *           2)  PassEnv FOO present, but $FOO not present in environment
+ *           3)  no PassEnv directive present
+ * 23.Dec.95 Now allows SetEnv directive with same semantics as 'sh' setenv:
+ *             SetEnv Var      sets Var to the empty string
+ *             SetEnv Var Val  sets Var to the value Val
+ *          Values containing whitespace should be quoted, eg:
+ *             SetEnv Var "this is some text"
+ *          Environment variables take their value from the last instance
+ *          of PassEnv / SetEnv to be reached in the configuration file.
+ *          For example, the sequence:
+ *             PassEnv PATH
+ *             SetEnv PATH /special/path
+ *          Causes PATH to take the value '/special/path'.
+ * 23.Feb.96 Added UnsetEnv directive to allow environment variables
+ *           to be removed.
+ *           Virtual hosts now 'inherit' parent server environment which
+ *          they're able to overwrite with their own directives or
+ *          selectively ignore with UnsetEnv.
+ *       *** IMPORTANT - the way that virtual hosts inherit their ***
+ *       *** environment variables from the default server's      ***
+ *      *** configuration has changed.  You should test your     ***
+ *       *** configuration carefully before accepting this        ***
+ *       *** version of the module in a live webserver which used ***
+ *      *** older versions of the module.                        ***
+ */
+
+#include "httpd.h"
+#include "http_config.h"
+
+typedef struct {
+    table *vars;
+    char *unsetenv;
+    int vars_present;
+} env_server_config_rec;
+
+module env_module;
+
+void *create_env_server_config (pool *p, server_rec *dummy)
+{
+    env_server_config_rec *new =
+      (env_server_config_rec *) palloc (p, sizeof(env_server_config_rec));
+    new->vars = make_table (p, 50);
+    new->unsetenv = "";
+    new->vars_present = 0;
+    return (void *) new;
+}
+
+void *merge_env_server_configs (pool *p, void *basev, void *addv)
+{
+    env_server_config_rec *base = (env_server_config_rec *)basev;
+    env_server_config_rec *add = (env_server_config_rec *)addv;
+    env_server_config_rec *new =
+      (env_server_config_rec *)palloc (p, sizeof(env_server_config_rec));
+
+    table *new_table;
+    table_entry *elts;
+
+    int i;
+    char *uenv, *copy;
+
+      /* 
+       * new_table = copy_table( p, base->vars );
+       * foreach $element ( @add->vars ) {
+       *     table_set( new_table, $element.key, $element.val );
+       * };
+       * foreach $unsetenv ( @UNSETENV ) {
+       *     table_unset( new_table, $unsetenv );
+       * }
+       */
+
+    new_table = copy_table( p, base->vars );
+
+    elts = (table_entry *) add->vars->elts;
+
+    for ( i = 0; i < add->vars->nelts; ++i ) {
+       table_set( new_table, elts[i].key, elts[i].val ); 
+    };
+
+    copy = pstrdup( p, add->unsetenv );
+    uenv = getword_conf( p, &copy );
+    while ( uenv[0] != '\0' ) {
+       table_unset( new_table, uenv );
+       uenv = getword_conf( p, &copy );
+    };
+
+    new->vars = new_table;
+
+    new->vars_present = base->vars_present || add->vars_present;
+
+    return new;
+}
+
+char *add_env_module_vars_passed (cmd_parms *cmd, char *struct_ptr, char *arg)
+{
+    env_server_config_rec *sconf =
+      get_module_config (cmd->server->module_config, &env_module);
+    table *vars = sconf->vars;
+    char *env_var;
+    char *name_ptr;
+
+    while (*arg) {
+        name_ptr = getword_conf (cmd->pool, &arg);
+        env_var = getenv(name_ptr);
+        if ( env_var != NULL ) { 
+            sconf->vars_present = 1;
+            table_set (vars, name_ptr, env_var);
+        };
+    }
+    return NULL;
+}
+
+char *add_env_module_vars_set (cmd_parms *cmd, char *struct_ptr, char *arg)
+{
+    env_server_config_rec *sconf =
+      get_module_config (cmd->server->module_config, &env_module);
+    table *vars = sconf->vars;
+    char *name, *value;
+
+    name = getword_conf( cmd->pool, &arg );
+    value = getword_conf( cmd->pool, &arg );
+
+    /* name is mandatory, value is optional.  no value means
+     * set the variable to an empty string
+     */
+
+
+    if ( (*name == '\0') || (*arg != '\0')) {
+       return "SetEnv takes one or two arguments.  An environment variable name and an optional value to pass to CGI." ;
+    };
+
+    sconf->vars_present = 1;
+    table_set (vars, name, value);
+
+    return NULL;
+}
+
+char *add_env_module_vars_unset (cmd_parms *cmd, char *struct_ptr, char *arg)
+{
+    env_server_config_rec *sconf =
+      get_module_config (cmd->server->module_config, &env_module);
+    sconf->unsetenv = sconf->unsetenv ? 
+       pstrcat( cmd->pool, sconf->unsetenv, " ", arg, NULL ) : 
+       pstrdup( cmd->pool, arg );
+    return NULL;
+}
+
+command_rec env_module_cmds[] = {
+{ "PassEnv", add_env_module_vars_passed, NULL,
+    RSRC_CONF, RAW_ARGS, "a list of environment variables to pass to CGI." },
+{ "SetEnv", add_env_module_vars_set, NULL,
+    RSRC_CONF, RAW_ARGS, "an environment variable name and a value to pass to CGI." },
+{ "UnsetEnv", add_env_module_vars_unset, NULL,
+    RSRC_CONF, RAW_ARGS, "a list of variables to remove from the CGI environment." },
+{ NULL },
+};
+
+int fixup_env_module(request_rec *r)
+{
+    table *e = r->subprocess_env;
+    server_rec *s = r->server;
+    env_server_config_rec *sconf = get_module_config (s->module_config,
+                                                  &env_module);
+    table *vars = sconf->vars;
+
+    if ( !sconf->vars_present ) return DECLINED;
+
+    r->subprocess_env = overlay_tables( r->pool, e, vars );
+
+    return OK;  
+}
+
+module env_module = {
+   STANDARD_MODULE_STUFF,
+   NULL,                       /* initializer */
+   NULL,                       /* dir config creater */
+   NULL,                       /* dir merger --- default is to override */
+   create_env_server_config,   /* server config */
+   merge_env_server_configs,   /* merge server configs */
+   env_module_cmds,            /* command table */
+   NULL,                       /* handlers */
+   NULL,                       /* filename translation */
+   NULL,                       /* check_user_id */
+   NULL,                       /* check auth */
+   NULL,                       /* check access */
+   NULL,                       /* type_checker */
+   fixup_env_module,           /* fixups */
+   NULL,                       /* logger */
+};
diff --git a/RELEASE_1_1_X/src/modules/standard/mod_imap.c b/RELEASE_1_1_X/src/modules/standard/mod_imap.c
new file mode 100644 (file)
index 0000000..2eddcf1
--- /dev/null
@@ -0,0 +1,829 @@
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP OR
+ * IT'S 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+/*
+ * This imagemap module started as a port of the original imagemap.c
+ * written by Rob McCool (11/13/93 robm@ncsa.uiuc.edu).
+ * This version includes the mapping algorithms found in version 1.3
+ * of imagemap.c.
+ *
+ * Contributors to this code include:
+ *
+ * Kevin Hughes, kevinh@pulua.hcc.hawaii.edu
+ *
+ * Eric Haines, erich@eye.com
+ * "macmartinized" polygon code copyright 1992 by Eric Haines, erich@eye.com
+ *
+ * Randy Terbush, randy@zyzzyva.com
+ * port to Apache module format, "base_uri" and support for relative URLs
+ * 
+ * James H. Cloos, Jr., cloos@jhcloos.com
+ * Added point datatype, using code in NCSA's version 1.8 imagemap.c
+ * program, as distributed with version 1.4.1 of their server.
+ * The point code is originally added by Craig Milo Rogers, Rogers@ISI.Edu
+ *
+ * Nathan Kurz, nate@tripod.com
+ * Rewrite/reorganization.  New handling of default, base and relative URLs.  
+ * New Configuration directives:
+ *    ImapMenu {none, formatted, semiformatted, unformatted}
+ *    ImapDefault {error, nocontent, referer, menu, URL}
+ *    ImapBase {map, referer, URL}
+ * Support for creating non-graphical menu added.  (backwards compatible):
+ *    Old:  directive URL [x,y ...]
+ *    New:  directive URL "Menu text" [x,y ...]
+ *     or:  directive URL x,y ... "Menu text"
+ * Map format and menu concept courtesy Joshua Bell, jsbell@acs.ucalgary.ca.
+ *
+ * Mark Cox, mark@ukweb.com, Allow relative URLs even when no base specified
+ */
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_request.h"
+#include "http_core.h"
+#include "http_protocol.h"
+#include "http_main.h"
+#include "http_log.h"
+#include "util_script.h"
+
+#define IMAP_MAGIC_TYPE "application/x-httpd-imap"
+#define LARGEBUF 500
+#define SMALLBUF 100
+#define MAXVERTS 100
+#define X 0
+#define Y 1
+
+#define IMAP_MENU_DEFAULT "formatted"
+#define IMAP_DEFAULT_DEFAULT "nocontent"
+#define IMAP_BASE_DEFAULT "map"
+
+#ifdef SUNOS4
+double strtod();   /* SunOS needed this */
+#endif
+
+module imap_module;
+
+typedef struct { 
+  char *imap_menu;
+  char *imap_default;
+  char *imap_base;
+} imap_conf_rec;
+
+void *create_imap_dir_config (pool *p, char *dummy) { 
+  imap_conf_rec *icr = 
+    (imap_conf_rec *)palloc(p, sizeof(imap_conf_rec));
+
+  icr->imap_menu = NULL;
+  icr->imap_default = NULL;
+  icr->imap_base = NULL;
+
+  return icr;
+}
+
+void *merge_imap_dir_configs (pool *p, void *basev, void *addv)
+{
+  imap_conf_rec *new=(imap_conf_rec *)pcalloc (p, sizeof(imap_conf_rec));
+  imap_conf_rec *base = (imap_conf_rec *)basev;
+  imap_conf_rec *add = (imap_conf_rec *)addv;
+  new->imap_menu = add->imap_menu ? add->imap_menu : base->imap_menu;
+  new->imap_default=add->imap_default ? add->imap_default : base->imap_default;
+  new->imap_base =add-> imap_base ? add->imap_base : base->imap_base;
+
+  return new;
+}
+
+
+command_rec imap_cmds[] = {
+{ "ImapMenu", set_string_slot, 
+    (void*)XtOffsetOf(imap_conf_rec, imap_menu), OR_INDEXES, TAKE1,
+    "the type of menu generated: none, formatted, semiformatted, unformatted"},
+{ "ImapDefault", set_string_slot, 
+    (void*)XtOffsetOf(imap_conf_rec, imap_default), OR_INDEXES, TAKE1,
+    "the action taken if no match: error, nocontent, referer, menu, URL" },
+{ "ImapBase", set_string_slot, 
+    (void*)XtOffsetOf(imap_conf_rec, imap_base), OR_INDEXES, TAKE1,
+    "the base for all URL's: map, referer, URL (or start of)" },
+{ NULL }
+};
+
+int pointinrect(double point[2], double coords[MAXVERTS][2])
+{
+    double max[2], min[2];
+    if (coords[0][X] > coords[1][X]) {
+        max[0] = coords[0][X];
+        min[0] = coords[1][X];
+    } else {
+        max[0] = coords[1][X];
+        min[0] = coords[0][X];
+    }
+
+    if (coords[0][Y] > coords[1][Y]) {
+        max[1] = coords[0][Y];
+        min[1] = coords[1][Y];
+    } else {
+        max[1] = coords[1][Y];
+        min[1] = coords[0][Y];
+    }
+
+    return ((point[X] >= min[0] && point[X] <= max[0]) &&
+           (point[Y] >= min[1] && point[Y] <= max[1]));
+}
+
+int pointincircle(double point[2], double coords[MAXVERTS][2])
+{
+    int radius1, radius2;
+
+    radius1 = ((coords[0][Y] - coords[1][Y]) * (coords[0][Y] - coords[1][Y]))
+       + ((coords[0][X] - coords[1][X]) * (coords[0][X] - coords[1][X]));
+    
+    radius2 = ((coords[0][Y] - point[Y]) * (coords[0][Y] - point[Y]))
+       + ((coords[0][X] - point[X]) * (coords[0][X] - point[X]));
+
+    return (radius2 <= radius1);
+}
+
+int pointinpoly(double point[2], double pgon[MAXVERTS][2])
+{
+    int i, numverts, inside_flag, xflag0;
+    int crossings;
+    double *p, *stop;
+    double tx, ty, y;
+
+    for (i = 0; pgon[i][X] != -1 && i < MAXVERTS; i++);
+
+    numverts = i;
+    crossings = 0;
+
+    tx = point[X];
+    ty = point[Y];
+    y = pgon[numverts - 1][Y];
+
+    p = (double *) pgon + 1;
+    if ((y >= ty) != (*p >= ty)) {
+
+       if ((xflag0 = (pgon[numverts - 1][X] >= tx)) == (*(double *) pgon >= tx)) {
+           if (xflag0)
+               crossings++;
+       }
+       else {
+           crossings += (pgon[numverts - 1][X] - (y - ty) *
+                         (*(double *) pgon - pgon[numverts - 1][X]) /
+                         (*p - y)) >= tx;
+       }
+    }
+
+    stop = pgon[numverts];
+
+    for (y = *p, p += 2; p < stop; y = *p, p += 2) {
+       
+       if (y >= ty) {
+        
+           while ((p < stop) && (*p >= ty))
+               p += 2;
+           
+           if (p >= stop)
+               break;
+           if ((xflag0 = (*(p - 3) >= tx)) == (*(p - 1) >= tx)) {
+               
+               if (xflag0)
+                   crossings++;
+           }
+           else {
+               crossings += (*(p - 3) - (*(p - 2) - ty) *
+                             (*(p - 1) - *(p - 3)) / (*p - *(p - 2))) >= tx;
+           }
+       }
+       else {
+           while ((p < stop) && (*p < ty))
+               p += 2;
+
+           if (p >= stop)
+               break;
+
+           if ((xflag0 = (*(p - 3) >= tx)) == (*(p - 1) >= tx)) {
+               if (xflag0)
+                   crossings++;
+           }
+           else {
+               crossings += (*(p - 3) - (*(p - 2) - ty) *
+                             (*(p - 1) - *(p - 3)) / (*p - *(p - 2))) >= tx;
+           }
+       }
+    }
+
+    inside_flag = crossings & 0x01;
+    return (inside_flag);
+}
+
+
+int is_closer(double point[2], double coords[MAXVERTS][2], double *closest)
+{
+  double dist_squared =((point[X] - coords[0][X]) * (point[X] - coords[0][X]))
+            + ((point[Y] - coords[0][Y]) * (point[Y] - coords[0][Y]));
+
+  if (point[X] < 0 || point[Y] < 0 ) 
+    return(0);          /* don't mess around with negative coordinates */
+
+  if ( *closest < 0 || dist_squared < *closest ) {
+    *closest = dist_squared;
+    return(1);         /* if this is the first point or is the closest yet
+                         set 'closest' equal to this distance^2 */
+  }
+  
+  return(0);           /* if it's not the first or closest */
+
+}
+
+double get_x_coord(char *args) 
+{
+  char *endptr;           /* we want it non-null */
+  double x_coord = -1;    /* -1 is returned if no coordinate is given */
+
+  if (args == NULL)
+    return(-1);           /* in case we aren't passed anything */
+
+  while( *args && !isdigit(*args) && *args != ',') 
+    args++;   /* jump to the first digit, but not past a comma or end */
+
+  x_coord = strtod(args, &endptr);
+
+  if (endptr > args)   /* if a conversion was made */
+    return(x_coord); 
+
+  return(-1);  /* else if no conversion was made, or if no args was given */
+}
+
+double get_y_coord(char *args) 
+{
+  char *endptr;        /* we want it non-null */
+  char *start_of_y = NULL;
+  double y_coord = -1;    /* -1 is returned on error */
+
+  if (args == NULL)
+    return(-1);           /* in case we aren't passed anything */
+
+  start_of_y = strchr(args, ',');  /* the comma */
+
+  if (start_of_y) {
+    
+    start_of_y++;    /* start looking at the character after the comma */
+
+    while( *start_of_y && !isdigit(*start_of_y))  
+      start_of_y++;  /* jump to the first digit, but not past the end */
+
+    y_coord = strtod(start_of_y, &endptr);
+
+    if (endptr > start_of_y) 
+      return(y_coord); 
+  }
+  
+  return(-1);   /* if no conversion was made, or no comma was found in args */
+}
+  
+
+int read_quoted(char *string, char *quoted_part)
+{ 
+  char *starting_pos = string;
+  
+  while ( isspace(*string) )
+    string++;    /* go along string until non-whitespace */
+
+  if ( *string == '"' ) { /* if that character is a double quote */
+
+    string++;  /* step over it */
+
+    while ( *string && *string != '"' ) {
+      *quoted_part++ = *string++;  /* copy the quoted portion */
+    }
+
+    *quoted_part = '\0';  /* end the string with a SNUL */
+       
+    string++;  /* step over the last double quote */
+  }
+
+  return(string - starting_pos); /* return the total characters read */
+}
+
+
+void imap_url(request_rec *r, char *base, char *value, char *url) 
+{
+/* translates a value into a URL. */
+  int slen, clen;
+  char *string_pos = NULL;
+  char *directory = NULL;
+  char *referer = NULL;
+  char my_base[SMALLBUF] = {'\0'};
+
+  if ( ! strcasecmp(value, "map" ) || ! strcasecmp(value, "menu") ) {
+    if (r->server->port == 80 ) { 
+      sprintf(url, "http://%s%s", r->server->server_hostname, r->uri);
+    }
+    else {
+      sprintf(url, "http://%s:%d%s", r->server->server_hostname,
+             r->server->port, r->uri);      
+    }
+    return;  
+  }
+
+  if ( ! strcasecmp(value, "nocontent") || ! strcasecmp(value, "error") ) {
+    strcpy(url, value);
+    return;    /* these are handled elsewhere, so just copy them */
+  }
+
+  if ( ! strcasecmp(value, "referer" ) ) {
+    referer = table_get(r->headers_in, "Referer");
+    if ( referer && *referer ) {
+      strcpy(url, referer);
+      return;
+    }
+    else {
+      *value = '\0';  /* if 'referer' but no referring page, null the value */
+    }                 
+  }         
+
+  string_pos = value;
+  while ( isalpha(*string_pos) )
+    string_pos++;    /* go along the URL from the map until a non-letter */
+  if ( *string_pos == ':' ) { 
+    strcpy(url, value);        /* if letters and then a colon (like http:) */
+    return;                    /* it's an absolute URL, so use it! */
+  }
+
+  if ( ! base || ! *base ) {
+    if ( value && *value ) {  
+      strcpy(url, value);   /* no base: use what is given */
+    }         
+    else {                  
+      if (r->server->port == 80 ) {  
+       sprintf(url, "http://%s/", r->server->server_hostname);
+      }            
+      if (r->server->port != 80 ) {
+       sprintf(url, "http://%s:%d/", r->server->server_hostname, 
+               r->server->port);
+      }                     /* no base, no value: pick a simple default */
+    }
+    return;  
+  }
+
+  strcpy(my_base, base);  /* must be a relative URL to be combined with base */
+  string_pos = my_base; 
+  while (*string_pos) {  
+    if (*string_pos == '/' && *(string_pos+1) == '/') {
+      string_pos += 2;  /* if there are two slashes, jump over them */
+      continue;
+    }
+    if (*string_pos == '/') {  /* the first single slash */
+       if ( value[0] == '/' ) {
+         *string_pos = '\0';  
+       }              /* if the URL from the map starts from root, end the
+                         base URL string at the first single slash */
+       else {
+         directory = string_pos; /* save the start of the directory portion */
+
+         string_pos = strrchr(string_pos, '/');  /* now reuse string_pos */
+         string_pos++;  /* step over that last slash */
+         *string_pos = '\0';
+       }              /* but if the map url is relative, leave the
+                       slash on the base (if there is one) */
+       break;
+      }
+    string_pos++;   /* until we get to the end of my_base without finding
+                      a slash by itself */
+  }
+
+  while ( ! strncmp(value, "../", 3) || ! strcmp(value, "..") ) { 
+
+      if (directory && (slen = strlen (directory))) {
+
+         /* for each '..',  knock a directory off the end 
+            by ending the string right at the last slash.
+            But only consider the directory portion: don't eat
+            into the server name.  And only try if a directory
+            portion was found */    
+         
+         clen = slen - 1;
+       
+         while ((slen - clen) == 1) {
+       
+             if ((string_pos = strrchr(directory, '/')))
+                 *string_pos = '\0';
+             clen = strlen (directory);
+             if (clen == 0) break;
+         }
+
+         value += 2;      /* jump over the '..' that we found in the value */
+      }
+      
+      if (! strncmp(value, "/../", 4) || ! strcmp(value, "/..") )
+
+         value++;       /* step over the '/' if there are more '..' to do.
+                          this way, we leave the starting '/' on value after
+                          the last '..', but get rid of it otherwise */ 
+     
+  }                   /* by this point, value does not start with '..' */
+
+  if ( value && *value ) {
+    sprintf(url, "%s%s", my_base, value);   
+  }
+  else {
+    sprintf(url, "%s", my_base);   
+  }
+  return;
+}
+
+int imap_reply(request_rec *r, char *redirect)
+{ 
+  if ( ! strcasecmp(redirect, "error") ) {
+    return SERVER_ERROR;  /* they actually requested an error! */
+  }
+  if ( ! strcasecmp(redirect, "nocontent") ) {
+    r->status_line = pstrdup(r->pool, "204 No Content");
+    soft_timeout ("send no content", r);
+    send_http_header(r);
+    return OK;            /* tell the client to keep the page it has */
+  }
+  if (redirect && *redirect ) { 
+    table_set(r->headers_out, "Location", redirect);
+    return REDIRECT;      /* must be a URL, so redirect to it */
+  }    
+  return SERVER_ERROR;
+}
+
+void menu_header(request_rec *r, char *menu)
+{
+  if (! strcasecmp(menu, "formatted")) {
+    r->content_type = "text/html";
+    soft_timeout ("send menu", r);
+    send_http_header(r);
+    rvputs(r, "<html>\n<head><title>Menu for ", r->uri,
+          "</title></head>\n\n<body>\n", NULL);
+    rvputs(r, "<h1>Menu for ", r->uri, "</h1>\n<hr>\n\n", NULL);
+  } 
+  if (! strcasecmp(menu, "semiformatted")) {
+    r->content_type = "text/html";
+    soft_timeout ("send menu", r);
+    send_http_header(r);
+    rvputs(r, "<html>\n<head><title>Menu for ", r->uri,
+          "</title></head>\n\n<body>\n", NULL);
+  } 
+  if (! strcasecmp(menu, "unformatted")) {
+    r->content_type = "text/html";
+    soft_timeout ("send menu", r);
+    send_http_header(r);
+    rvputs(r, "<html>\n<head><title>Menu for ", r->uri,
+          "</title></head>\n\n<body>\n", NULL);
+  }
+  return;
+}
+
+void menu_blank(request_rec *r, char *menu)
+{
+  if (! strcasecmp(menu, "formatted") ) {
+    rputs("\n", r);
+  }
+  if (! strcasecmp(menu, "semiformatted") ) {
+    rputs("<br>\n", r);
+  }
+  if (! strcasecmp(menu, "unformatted") ) {
+    rputs("\n", r);  
+  }
+  return;  
+}
+
+void menu_comment(request_rec *r, char *menu, char *comment)
+{
+  if (! strcasecmp(menu, "formatted") ) {
+    rputs("\n", r);  /* print just a newline if 'formatted' */
+  }
+  if (! strcasecmp(menu, "semiformatted") && *comment ) {
+    rvputs(r, comment, "\n", NULL);
+  }             
+  if (! strcasecmp(menu, "unformatted") && *comment ) {
+    rvputs(r, comment, "\n", NULL);
+  }             
+  return;    /* comments are ignored in the 'formatted' form */
+}
+
+void menu_default(request_rec *r, char *menu, char *href, char *text)
+{
+  if ( ! strcasecmp(href, "error") || ! strcasecmp(href, "nocontent") ) {
+    return;   /* don't print such lines, these aren'te really href's */
+  }
+  if ( ! strcasecmp(menu, "formatted" ) ) {
+    rvputs(r, "<pre>(Default) <a href=\"", href, "\">", text, "</a></pre>\n",
+          NULL);
+  }
+  if ( ! strcasecmp(menu, "semiformatted" ) ) {
+    rvputs(r, "<pre>(Default) <a href=\"", href, "\">", text, "</a></pre>\n",
+          NULL);
+  }
+  if ( ! strcasecmp(menu, "unformatted" ) ) {
+    rvputs(r, "<a href=\"", href, "\">", text, "</a>", NULL);
+  }
+  return;
+}
+
+void menu_directive(request_rec *r, char *menu, char *href, char *text)
+{
+  if ( ! strcasecmp(href, "error") || ! strcasecmp(href, "nocontent") ) {
+    return;   /* don't print such lines, as this isn't really an href */
+  }
+  if ( ! strcasecmp(menu, "formatted" ) ) {
+    rvputs(r, "<pre>          <a href=\"", href, "\">", text, "</a></pre>\n",
+          NULL);
+  }
+  if ( ! strcasecmp(menu, "semiformatted" ) ) {
+    rvputs(r, "<pre>          <a href=\"", href, "\">", text, "</a></pre>\n",
+          NULL);
+  }
+  if ( ! strcasecmp(menu, "unformatted" ) ) {
+    rvputs(r, "<a href=\"", href, "\">", text, "</a>", NULL);
+  }
+  return;
+}
+
+void menu_footer(request_rec *r)
+{
+  rputs("\n\n</body>\n</html>\n", r);  /* finish the menu */
+}
+
+int imap_handler(request_rec *r)
+{
+  char input[LARGEBUF] = {'\0'};
+  char href_text[SMALLBUF] = {'\0'};
+  char base[SMALLBUF] = {'\0'};
+  char redirect[SMALLBUF] = {'\0'};
+  char directive[SMALLBUF] = {'\0'};
+  char value[SMALLBUF] = {'\0'};
+  char mapdflt[SMALLBUF] = {'\0'};
+  char closest[SMALLBUF] = {'\0'};
+  double closest_yet = -1;
+
+  double testpoint[2] = { -1,-1 }; 
+  double pointarray[MAXVERTS + 1][2] = { {-1,-1} };
+  int vertex = 0;
+
+  char *string_pos = NULL;
+  int chars_read = 0;
+  int showmenu = 0;
+
+  imap_conf_rec *icr = get_module_config(r->per_dir_config, &imap_module);
+
+  char *imap_menu = icr->imap_menu ? 
+    icr->imap_menu : IMAP_MENU_DEFAULT;
+  char *imap_default = icr->imap_default ? 
+    icr->imap_default : IMAP_DEFAULT_DEFAULT;
+  char *imap_base = icr->imap_base ?
+    icr->imap_base : IMAP_BASE_DEFAULT;
+
+  FILE *imap = pfopen(r->pool, r->filename, "r"); 
+
+  if ( ! imap ) 
+    return NOT_FOUND;
+
+  imap_url(r, NULL, imap_base, base);       /* set base according to default */
+  imap_url(r, NULL, imap_default, mapdflt); /* and default to global default */
+
+  testpoint[X] = get_x_coord(r->args);
+  testpoint[Y] = get_y_coord(r->args);
+
+  if ((testpoint[X] == -1 || testpoint[Y] == -1) ||
+      (testpoint[X] == 0  && testpoint[Y] == 0) ) {
+              /* if either is -1 or if both are zero (new Lynx) */
+              /* we don't have valid coordinates */
+    testpoint[X] = -1;
+    testpoint[Y] = -1;
+    if ( strncasecmp(imap_menu, "none", 2) )
+      showmenu = 1;    /* show the menu _unless_ ImapMenu is 'none' or 'no' */
+  }
+
+  if (showmenu) {        /* send start of imagemap menu if we're going to */
+    menu_header(r, imap_menu);
+  }
+
+  while (!cfg_getline(input, LARGEBUF, imap)) {
+    string_pos = input;   /* always start at the beginning of line */
+
+    directive[0] = '\0';
+    value[0] = '\0';  
+    href_text[0] = '\0';
+    redirect[0] = '\0';
+    chars_read = 0; /* clear these before using */
+
+    if ( ! input[0] ) {     
+      if (showmenu) {
+       menu_blank(r, imap_menu);
+      }
+      continue;                           
+    }
+
+    if ( input[0] == '#' ) {
+      if (showmenu) {
+       menu_comment(r, imap_menu, input + 1); 
+      }           
+      continue;
+    } /* blank lines and comments are ignored if we aren't printing a menu */
+
+
+    if (sscanf(input, "%s %s", directive, value) != 2) {
+      continue;                           /* make sure we read two fields */
+    }
+    /* Now skip what we just read... we can't use ANSIism %n */
+    while (!(isspace(*string_pos)))    /* past directive */
+       string_pos++;
+    while (isspace(*string_pos))       /* and whitespace */
+       string_pos++;
+    while (!(isspace(*string_pos)))    /* and value... have to watch it */
+       string_pos++;                   /* can have punctuation and stuff */
+    
+    if ( ! strncasecmp(directive, "base", 4 ) ) {       /* base, base_uri */
+      imap_url(r, NULL, value, base);
+      continue; /* base is never printed to a menu */
+    }  
+
+    chars_read = read_quoted(string_pos, href_text);
+    string_pos += chars_read;      /* read the quoted href text if present */
+
+    if ( ! strcasecmp(directive, "default" ) ) {        /* default */
+      imap_url(r, NULL, value, mapdflt);
+      if (showmenu) {              /* print the default if there's a menu */
+       if (! *href_text) {           /* if we didn't find a "href text" */
+         strcpy(href_text, mapdflt); /* use the href itself as text */
+       }
+       imap_url(r, base, mapdflt, redirect); 
+       menu_default(r, imap_menu, redirect, href_text);
+      }
+      continue;
+    }
+
+    vertex = 0;
+    while ( vertex < MAXVERTS &&  
+     sscanf(string_pos, "%lf,%lf",
+     &pointarray[vertex][X], &pointarray[vertex][Y])   == 2)
+    {
+       /* Now skip what we just read... we can't use ANSIism %n */
+       while(isspace(*string_pos))     /* past whitespace */
+           string_pos++;
+       while(isdigit(*string_pos))     /* and the 1st number */
+           string_pos++;
+       string_pos++;                   /* skip the ',' */
+       while(isdigit(*string_pos))     /* 2nd number */
+           string_pos++;
+       vertex++;
+    }                /* so long as there are more vertices to read, and
+                       we have room, read them in.  We start where we left
+                       off of the last sscanf, not at the beginning.*/
+                  
+    pointarray[vertex][X] = -1;  /* signals the end of vertices */
+
+    if (showmenu) {
+      read_quoted(string_pos, href_text); /* href text could be here instead */
+      if (! *href_text) {           /* if we didn't find a "href text" */
+       strcpy(href_text, value);  /* use the href itself in the menu */
+      }
+      imap_url(r, base, value, redirect); 
+      menu_directive(r, imap_menu, redirect, href_text);
+      continue;
+    }
+    /* note that we don't make it past here if we are making a menu */
+
+    if (testpoint[X] == -1 || pointarray[0][X] == -1 )
+      continue;    /* don't try the following tests if testpoints
+                   are invalid, or if there are no coordinates */
+
+    if ( ! strcasecmp(directive, "poly" ) ) {        /* poly */
+
+      if (pointinpoly (testpoint, pointarray) ) {
+       pfclose(r->pool, imap); 
+       imap_url(r, base, value, redirect);     
+       return (imap_reply(r, redirect));
+      }
+      continue;
+    }
+
+    if ( ! strcasecmp(directive, "circle" ) ) {        /* circle */
+       
+      if (pointincircle (testpoint, pointarray) ) {
+       pfclose(r->pool, imap); 
+       imap_url(r, base, value, redirect);     
+       return (imap_reply(r, redirect));
+      }
+      continue;
+    }
+    
+    if ( ! strcasecmp(directive, "rect" ) ) {        /* rect */
+      
+      if (pointinrect (testpoint, pointarray) ) {
+       pfclose(r->pool, imap); 
+       imap_url(r, base, value, redirect);     
+       return (imap_reply(r, redirect));
+      }
+      continue;
+    }
+    
+    if ( ! strcasecmp(directive, "point" ) ) {         /* point */
+      
+      if (is_closer(testpoint, pointarray, &closest_yet) ) {
+       strcpy(closest, value);  /* if the closest point yet save it */
+      }
+      
+      continue;    
+    }     /* move on to next line whether it's closest or not */
+    
+  }       /* nothing matched, so we get another line! */
+
+  pfclose(r->pool, imap);   /* we are done with the map file, so close it */
+
+  if (showmenu) {
+    menu_footer(r);   /* finish the menu and we are done */
+    return OK;                
+  }
+
+  if (*closest) {    /* if a 'point' directive has been seen */
+    imap_url(r, base, closest, redirect);     
+    return (imap_reply(r, redirect));
+  }    
+
+  if (*mapdflt ) {   /* a default should be defined, even if only 'nocontent'*/
+    imap_url(r, base, mapdflt, redirect);
+    return(imap_reply(r, redirect));
+  }    
+
+  return SERVER_ERROR;   /* If we make it this far, we failed. They lose! */
+}
+
+
+handler_rec imap_handlers[] = {
+{ IMAP_MAGIC_TYPE, imap_handler },
+{ "imap-file", imap_handler },
+{ NULL }
+};
+
+module imap_module = {
+   STANDARD_MODULE_STUFF,
+   NULL,                       /* initializer */
+   create_imap_dir_config,     /* dir config creater */
+   merge_imap_dir_configs,     /* dir merger --- default is to override */
+   NULL,                       /* server config */
+   NULL,                       /* merge server config */
+   imap_cmds,                  /* command table */
+   imap_handlers,              /* handlers */
+   NULL,                       /* filename translation */
+   NULL,                       /* check_user_id */
+   NULL,                       /* check auth */
+   NULL,                       /* check access */
+   NULL,                       /* type_checker */
+   NULL,                       /* fixups */
+   NULL                                /* logger */
+};
diff --git a/RELEASE_1_1_X/src/modules/standard/mod_include.c b/RELEASE_1_1_X/src/modules/standard/mod_include.c
new file mode 100644 (file)
index 0000000..dcd5b0f
--- /dev/null
@@ -0,0 +1,908 @@
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * http_include.c: Handles the server-parsed HTML documents
+ * 
+ * Original by Rob McCool; substantial fixups by David Robinson;
+ * incorporated into the Shambhala module framework by rst.
+ * 
+ */
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_request.h"
+#include "http_core.h"
+#include "http_protocol.h"
+#include "http_log.h"
+#include "http_main.h"
+#include "util_script.h"
+
+#define STARTING_SEQUENCE "<!--#"
+#define ENDING_SEQUENCE "-->"
+#define DEFAULT_ERROR_MSG "[an error occurred while processing this directive]"
+#define DEFAULT_TIME_FORMAT "%A, %d-%b-%y %T %Z"
+#define SIZEFMT_BYTES 0
+#define SIZEFMT_KMG 1
+
+static void decodehtml(char *s);
+static char *get_tag(pool *p, FILE *in, char *tag, int tag_len, int dodecode);
+static int get_directive(FILE *in, char *d, pool *p);
+
+/* ------------------------ Environment function -------------------------- */
+
+void add_include_vars(request_rec *r, char *timefmt)
+{
+    struct passwd *pw;
+    table *e = r->subprocess_env;
+    char *t;
+    time_t date = time(NULL);
+
+    table_set(e, "DATE_LOCAL", ht_time(r->pool, date, timefmt, 0));
+    table_set(e, "DATE_GMT", ht_time(r->pool, date, timefmt, 1));
+    table_set(e, "LAST_MODIFIED",ht_time(r->pool,r->finfo.st_mtime,timefmt,0));
+    table_set(e, "DOCUMENT_URI", r->uri);
+    table_set(e, "DOCUMENT_PATH_INFO", r->path_info);
+    pw = getpwuid(r->finfo.st_uid);
+    if (pw) {
+      table_set(e, "USER_NAME", pw->pw_name);
+    } else {
+      char uid[16];
+      sprintf(uid, "user#%ld", (unsigned long)r->finfo.st_uid);
+      table_set(e, "USER_NAME", uid);
+    }
+
+    if((t = strrchr(r->filename, '/')))
+        table_set (e, "DOCUMENT_NAME", ++t);
+    else
+        table_set (e, "DOCUMENT_NAME", r->uri);
+    if (r->args) {
+        unescape_url (r->args);
+         table_set (e, "QUERY_STRING_UNESCAPED",
+                  escape_shell_cmd (r->pool, r->args));
+    }
+}
+
+#define GET_CHAR(f,c,r,p) \
+ { \
+   int i = getc(f); \
+   if(feof(f) || ferror(f) || (i == -1)) { \
+        pfclose(p, f); \
+        return r; \
+   } \
+   c = (char)i; \
+ }
+
+/* --------------------------- Parser functions --------------------------- */
+
+/* Grrrr... rputc makes this slow as all-get-out.  Elsewhere, it doesn't
+ * matter much, but this is an inner loop...
+ */
+
+int find_string(FILE *in,char *str, request_rec *r) {
+    int x,l=strlen(str),p;
+    char c;
+
+    p=0;
+    while(1) {
+        GET_CHAR(in,c,1,r->pool);
+        if(c == str[p]) {
+            if((++p) == l)
+                return 0;
+        }
+        else {
+            if(r) {
+                if(p) {
+                    for(x=0;x<p;x++) {
+                        rputc(str[x],r);
+                    }
+                }
+                rputc(c,r);
+            }
+            p=0;
+        }
+    }
+}
+
+/*
+ * decodes a string containing html entities or numeric character references.
+ * 's' is overwritten with the decoded string.
+ * If 's' is syntatically incorrect, then the followed fixups will be made:
+ *   unknown entities will be left undecoded;
+ *   references to unused numeric characters will be deleted.
+ *   In particular, &#00; will not be decoded, but will be deleted.
+ *
+ * drtr
+ */
+
+/* maximum length of any ISO-LATIN-1 HTML entity name. */
+#define MAXENTLEN (6)
+
+/* The following is a shrinking transformation, therefore safe. */
+
+static void
+decodehtml(char *s)
+{
+    int val, i, j;
+    char *p=s;
+    char *ents;
+    static char *entlist[MAXENTLEN+1]={
+       NULL,  /* 0 */
+       NULL,  /* 1 */
+       "lt\074gt\076", /* 2 */
+       "amp\046ETH\320eth\360", /* 3 */
+       "quot\042Auml\304Euml\313Iuml\317Ouml\326Uuml\334auml\344euml\353\
+iuml\357ouml\366uuml\374yuml\377", /* 4 */
+       "Acirc\302Aring\305AElig\306Ecirc\312Icirc\316Ocirc\324Ucirc\333\
+THORN\336szlig\337acirc\342aring\345aelig\346ecirc\352icirc\356ocirc\364\
+ucirc\373thorn\376", /* 5 */
+       "Agrave\300Aacute\301Atilde\303Ccedil\307Egrave\310Eacute\311\
+Igrave\314Iacute\315Ntilde\321Ograve\322Oacute\323Otilde\325Oslash\330\
+Ugrave\331Uacute\332Yacute\335agrave\340aacute\341atilde\343ccedil\347\
+egrave\350eacute\351igrave\354iacute\355ntilde\361ograve\362oacute\363\
+otilde\365oslash\370ugrave\371uacute\372yacute\375" /* 6 */
+    };
+
+    for (; *s != '\0'; s++, p++) {
+       if (*s != '&') {
+           *p = *s;
+           continue;
+       }
+       /* find end of entity */
+       for (i=1; s[i] != ';' && s[i] != '\0'; i++)
+           continue;
+
+       if (s[i] == '\0') {     /* treat as normal data */
+           *p = *s;
+           continue;
+       }
+
+       /* is it numeric ? */
+       if (s[1] == '#') {
+           for (j=2, val=0; j < i && isdigit(s[j]); j++)
+               val = val * 10 + s[j] - '0';
+           s += i;
+           if (j < i || val <= 8 || (val >= 11 && val <= 31) ||
+               (val >= 127 && val <= 160) || val >= 256)
+               p--;  /* no data to output */
+           else
+               *p = val;
+       } else{
+           j = i-1;
+           if (i-1 > MAXENTLEN || entlist[i-1] == NULL) { /* wrong length */
+               *p = '&';
+               continue;  /* skip it */
+           }
+           for (ents=entlist[i-1]; *ents != '\0'; ents += i)
+               if (strncmp(s+1, ents, i-1) == 0) break;
+
+           if (*ents == '\0')
+               *p = '&';  /* unknown */
+           else {
+               *p = ((const unsigned char *)ents)[i-1];
+               s += i;
+           }
+       }
+    }
+
+    *p = '\0';
+}
+
+/*
+ * extract the next tag name and value.
+ * if there are no more tags, set the tag name to 'done'
+ * the tag value is html decoded if dodecode is non-zero
+ */
+
+static char *
+get_tag(pool *p, FILE *in, char *tag, int tagbuf_len, int dodecode) {
+    char *t = tag, *tag_val, c, term;
+    int n;
+
+    n = 0;
+
+    do { /* skip whitespace */
+       GET_CHAR(in,c,NULL,p);
+    } while (isspace(c));
+
+    /* tags can't start with - */
+    if(c == '-') {
+        GET_CHAR(in,c,NULL,p);
+        if(c == '-') {
+            do {
+               GET_CHAR(in,c,NULL,p);
+           } while (isspace(c));
+            if(c == '>') {
+                strcpy(tag,"done");
+                return tag;
+            }
+        }
+       return NULL; /* failed */
+    }
+
+    /* find end of tag name */
+    while(1) {
+        if(++n == tagbuf_len) {
+            t[tagbuf_len - 1] = '\0';
+            return NULL;
+        }
+       if(c == '=' || isspace(c)) break;
+       *(t++) = tolower(c);
+        GET_CHAR(in,c,NULL,p);
+    }
+
+    *t++ = '\0';
+    tag_val = t;
+
+    while (isspace(c)) GET_CHAR(in, c, NULL,p); /* space before = */
+    if (c != '=') return NULL;
+
+    do {
+       GET_CHAR(in,c,NULL,p);  /* space after = */
+    } while (isspace(c));
+
+    /* we should allow a 'name' as a value */
+    
+    if (c != '"' && c != '\'') return NULL;
+    term = c;
+    while(1) {
+       GET_CHAR(in,c,NULL,p);
+       if(++n == tagbuf_len) {
+           t[tagbuf_len - 1] = '\0';
+           return NULL;
+       }
+       if (c == term) break;
+       *(t++) = c;
+    }
+    *t = '\0';
+    if (dodecode) decodehtml(tag_val);
+    return pstrdup (p, tag_val);
+}
+
+/* the pool is required to allow GET_CHAR to call pfclose */
+static int
+get_directive(FILE *in, char *d, pool *p) {
+    char c;
+
+    /* skip initial whitespace */
+    while(1) {
+        GET_CHAR(in,c,1,p);
+        if(!isspace(c))
+            break;
+    }
+    /* now get directive */
+    while(1) {
+        *d++ = tolower(c);
+        GET_CHAR(in,c,1,p);
+        if(isspace(c))
+            break;
+    }
+    *d = '\0';
+    return 0;
+}
+
+/* --------------------------- Action handlers ---------------------------- */
+
+int include_cgi(char *s, request_rec *r)
+{
+    request_rec *rr = sub_req_lookup_uri (s, r);
+    
+    if (rr->status != 200) return -1;
+    
+    /* No hardwired path info or query allowed */
+    
+    if ((rr->path_info && rr->path_info[0]) || rr->args) return -1;
+    if (rr->finfo.st_mode == 0) return -1;
+
+    /* Script gets parameters of the *document*, for back compatibility */
+    
+    rr->path_info = r->path_info; /* painful to get right; see mod_cgi.c */
+    rr->args = r->args;
+    
+    /* Force sub_req to be treated as a CGI request, even if ordinary
+     * typing rules would have called it something else.
+     */
+
+    rr->content_type = CGI_MAGIC_TYPE;
+
+    /* Run it. */
+    
+    if (run_sub_req (rr) == REDIRECT) {
+        char *location = table_get (rr->headers_out, "Location");
+       location = escape_html(rr->pool, location);
+       rvputs(r,"<A HREF=\"", location, "\">", location, "</A>", NULL);
+    }
+    
+    destroy_sub_req (rr);
+    
+    return 0;
+}
+
+int handle_include(FILE *in, request_rec *r, char *error, int noexec) {
+    char tag[MAX_STRING_LEN];
+    char *tag_val;
+
+    while(1) {
+        if(!(tag_val = get_tag(r->pool, in, tag, MAX_STRING_LEN, 1)))
+            return 1;
+        if(!strcmp(tag,"file") || !strcmp (tag, "virtual")) {
+           request_rec *rr=NULL;
+           char *error_fmt = NULL;
+
+           if (tag[0] == 'f')
+           { /* be safe; only files in this directory or below allowed */
+               char tmp[MAX_STRING_LEN+2];
+               sprintf(tmp, "/%s/", tag_val);
+               if (tag_val[0] == '/' || strstr(tmp, "/../") != NULL)
+                   error_fmt = "unable to include file %s in parsed file %s";
+               else
+                   rr = sub_req_lookup_file (tag_val, r);
+           } else
+               rr = sub_req_lookup_uri (tag_val, r);
+           
+           if (!error_fmt && rr->status != 200)
+               error_fmt = "unable to include %s in parsed file %s";
+
+           if (!error_fmt && noexec && rr->content_type
+               && (strncmp (rr->content_type, "text/", 5)))
+               error_fmt =
+                 "unable to include potential exec %s in parsed file %s";
+
+           if (error_fmt == NULL)
+           {
+               request_rec *p;
+
+               for (p=r; p != NULL; p=p->main)
+                   if (strcmp(p->filename, rr->filename) == 0) break;
+               if (p != NULL)
+                   error_fmt = "Recursive include of %s in parsed file %s";
+           }
+           
+           if (!error_fmt && run_sub_req (rr))
+               error_fmt = "unable to include %s in parsed file %s";
+                   
+            if (error_fmt) {
+                log_printf(r->server, error_fmt, tag_val, r->filename);
+                rputs(error, r);
+            }            
+
+           if (rr != NULL) destroy_sub_req (rr);
+        } 
+        else if(!strcmp(tag,"done"))
+            return 0;
+        else {
+            log_printf(r->server, "unknown parameter %s to tag include in %s",
+                      tag, r->filename);
+            rputs(error, r);
+        }
+    }
+}
+
+typedef struct {
+    request_rec *r;
+    char *s;
+} include_cmd_arg;
+
+void include_cmd_child (void *arg)
+{
+    request_rec *r =  ((include_cmd_arg *)arg)->r;
+    char *s = ((include_cmd_arg *)arg)->s;
+    table *env = r->subprocess_env;
+#ifdef DEBUG_INCLUDE_CMD    
+#ifdef __EMX__
+    /* under OS/2 /dev/tty is referenced as con */
+    FILE *dbg = fopen ("con", "w");
+#else
+        FILE *dbg = fopen ("/dev/tty", "w");
+#endif    
+#endif    
+    char err_string [MAX_STRING_LEN];
+
+#ifdef DEBUG_INCLUDE_CMD    
+    fprintf (dbg, "Attempting to include command '%s'\n", s);
+#endif    
+
+    if (r->path_info && r->path_info[0] != '\0')
+    {
+       request_rec *pa_req;
+
+       table_set (env, "PATH_INFO", escape_shell_cmd (r->pool, r->path_info));
+       
+       pa_req = sub_req_lookup_uri(escape_uri(r->pool, r->path_info), r);
+       if (pa_req->filename)
+           table_set(env, "PATH_TRANSLATED",
+                     pstrcat(r->pool, pa_req->filename, pa_req->path_info,
+                             NULL));
+    }
+
+    if (r->args) {
+        table_set (env, "QUERY_STRING", r->args);
+       unescape_url (r->args);
+       table_set (env, "QUERY_STRING_UNESCAPED",
+                  escape_shell_cmd (r->pool, r->args));
+    }
+    
+    error_log2stderr (r->server);
+    
+#ifdef DEBUG_INCLUDE_CMD    
+    fprintf (dbg, "Attempting to exec '%s'\n", s);
+#endif    
+    cleanup_for_exec();
+    execle(SHELL_PATH, SHELL_PATH, "-c", s, NULL,
+          create_environment (r->pool, env));
+    
+    /* Oh, drat.  We're still here.  The log file descriptors are closed,
+     * so we have to whimper a complaint onto stderr...
+     */
+    
+#ifdef DEBUG_INCLUDE_CMD    
+    fprintf (dbg, "Exec failed\n");
+#endif    
+    sprintf(err_string, "httpd: exec of %s failed, errno is %d\n",
+           SHELL_PATH,errno);
+    write (2, err_string, strlen(err_string));
+    exit(0);
+}
+
+int include_cmd(char *s, request_rec *r) {
+    include_cmd_arg arg;
+    FILE *f;
+
+    arg.r = r; arg.s = s;
+
+    if (!spawn_child (r->connection->pool, include_cmd_child, &arg,
+                     kill_after_timeout, NULL, &f))
+        return -1;
+    
+    send_fd(f,r);
+    pfclose(r->pool, f);       /* will wait for zombie when
+                                * r->pool is cleared
+                                */
+    return 0;
+}
+
+
+int handle_exec(FILE *in, request_rec *r, char *error)
+{
+    char tag[MAX_STRING_LEN];
+    char *tag_val;
+    char *file = r->filename;
+
+    while(1) {
+        if(!(tag_val = get_tag (r->pool, in, tag, MAX_STRING_LEN, 1)))
+            return 1;
+        if(!strcmp(tag,"cmd")) {
+            if(include_cmd(tag_val, r) == -1) {
+                log_printf(r->server, "failed command exec %s in %s",
+                          tag_val, file);
+                rputs(error, r);
+            }
+            /* just in case some stooge changed directories */
+            chdir_file(r->filename);
+        } 
+        else if(!strcmp(tag,"cgi")) {
+            if(include_cgi(tag_val, r) == -1) {
+                log_printf(r->server, "invalid CGI ref %s in %s",tag_val,file);
+                rputs(error, r);
+            }
+            /* grumble groan */
+            chdir_file(r->filename);
+        }
+        else if(!strcmp(tag,"done"))
+            return 0;
+        else {
+            log_printf(r->server, "unknown parameter %s to tag exec in %s",
+                      tag, file);
+            rputs(error, r);
+        }
+    }
+
+}
+
+int handle_echo (FILE *in, request_rec *r, char *error) {
+    char tag[MAX_STRING_LEN];
+    char *tag_val;
+
+    while(1) {
+        if(!(tag_val = get_tag (r->pool, in, tag, MAX_STRING_LEN, 1)))
+            return 1;
+        if(!strcmp(tag,"var")) {
+           char *val = table_get (r->subprocess_env, tag_val);
+
+           if (val) rputs(val, r);
+           else rputs("(none)", r);
+        } else if(!strcmp(tag,"done"))
+            return 0;
+        else {
+            log_printf(r->server, "unknown parameter %s to tag echo in %s",
+                   tag, r->filename);
+            rputs(error, r);
+        }
+    }
+}
+
+int handle_config(FILE *in, request_rec *r, char *error, char *tf,
+                  int *sizefmt) {
+    char tag[MAX_STRING_LEN];
+    char *tag_val;
+    table *env = r->subprocess_env;
+
+    while(1) {
+        if(!(tag_val = get_tag(r->pool, in, tag, MAX_STRING_LEN, 0)))
+            return 1;
+        if(!strcmp(tag,"errmsg"))
+            strcpy(error,tag_val);
+        else if(!strcmp(tag,"timefmt")) {
+           time_t date = time(NULL);
+            strcpy(tf,tag_val);
+            table_set (env, "DATE_LOCAL", ht_time(r->pool,date,tf,0));
+            table_set (env, "DATE_GMT", ht_time(r->pool,date,tf,1));
+            table_set (env, "LAST_MODIFIED", ht_time(r->pool,r->finfo.st_mtime,tf,0));
+        }
+        else if(!strcmp(tag,"sizefmt")) {
+           decodehtml(tag_val);
+            if(!strcmp(tag_val,"bytes"))
+                *sizefmt = SIZEFMT_BYTES;
+            else if(!strcmp(tag_val,"abbrev"))
+                *sizefmt = SIZEFMT_KMG;
+        } 
+        else if(!strcmp(tag,"done"))
+            return 0;
+        else {
+            log_printf(r->server, "unknown parameter %s to tag config in %s",
+                    tag, r->filename);
+            rputs(error, r);
+        }
+    }
+}
+
+
+
+int find_file(request_rec *r, char *directive, char *tag, 
+              char *tag_val, struct stat *finfo, char *error)
+{
+    char dir[MAX_STRING_LEN];
+    char *to_send;
+
+    if(!strcmp(tag,"file")) {
+        getparents(tag_val); /* get rid of any nasties */
+        getwd(dir);
+        to_send = make_full_path (r->pool, dir, tag_val);
+        if(stat(to_send,finfo) == -1) {
+            log_printf(r->server,
+                    "unable to get information about %s in parsed file %s",
+                    to_send, r->filename);
+            rputs(error, r);
+            return -1;
+        }
+        return 0;
+    }
+    else if(!strcmp(tag,"virtual")) {
+       request_rec *rr = sub_req_lookup_uri (tag_val, r);
+       
+       if (rr->status == 200 && rr->finfo.st_mode != 0) {
+           memcpy ((char*)finfo, (const char *)&rr->finfo, sizeof (struct stat));
+           destroy_sub_req (rr);
+           return 0;
+        } else {
+            log_printf(r->server,
+                    "unable to get information about %s in parsed file %s",
+                    tag_val, r->filename);
+            rputs(error, r);
+           destroy_sub_req (rr);
+            return -1;
+        }
+    }
+    else {
+        log_printf(r->server, "unknown parameter %s to tag %s in %s",
+                tag, directive, r->filename);
+       rputs(error, r);
+        return -1;
+    }
+}
+
+
+int handle_fsize(FILE *in, request_rec *r, char *error, int sizefmt) 
+{
+    char tag[MAX_STRING_LEN];
+    char *tag_val;
+    struct stat finfo;
+
+    while(1) {
+        if(!(tag_val = get_tag(r->pool, in, tag, MAX_STRING_LEN, 1)))
+            return 1;
+        else if(!strcmp(tag,"done"))
+            return 0;
+        else if(!find_file(r,"fsize",tag,tag_val,&finfo,error)) {
+            if(sizefmt == SIZEFMT_KMG) {
+                send_size(finfo.st_size, r);
+            }
+            else {
+                int l,x;
+#if defined(BSD) && BSD > 199305
+                sprintf(tag,"%qd",finfo.st_size);
+#else
+                sprintf(tag,"%ld",finfo.st_size);
+#endif
+                l = strlen(tag); /* grrr */
+                for(x=0;x<l;x++) {
+                    if(x && (!((l-x) % 3))) {
+                        rputc(',', r);
+                    }
+                    rputc (tag[x],r);
+                }
+            }
+        }
+    }
+}
+
+int handle_flastmod(FILE *in, request_rec *r, char *error, char *tf) 
+{
+    char tag[MAX_STRING_LEN];
+    char *tag_val;
+    struct stat finfo;
+
+    while(1) {
+        if(!(tag_val = get_tag(r->pool, in, tag, MAX_STRING_LEN, 1)))
+            return 1;
+        else if(!strcmp(tag,"done"))
+            return 0;
+        else if(!find_file(r,"flastmod",tag,tag_val,&finfo,error))
+            rputs(ht_time(r->pool, finfo.st_mtime, tf, 0), r);
+    }
+}    
+
+
+
+/* -------------------------- The main function --------------------------- */
+
+/* This is a stub which parses a file descriptor. */
+
+void send_parsed_content(FILE *f, request_rec *r)
+{
+    char directive[MAX_STRING_LEN], error[MAX_STRING_LEN];
+    char timefmt[MAX_STRING_LEN];
+    int noexec = allow_options (r) & OPT_INCNOEXEC;
+    int ret, sizefmt;
+
+    strcpy(error,DEFAULT_ERROR_MSG);
+    strcpy(timefmt,DEFAULT_TIME_FORMAT);
+    sizefmt = SIZEFMT_KMG;
+
+    chdir_file (r->filename);
+
+    while(1) {
+        if(!find_string(f,STARTING_SEQUENCE,r)) {
+            if(get_directive(f,directive,r->pool))
+                return;
+            if(!strcmp(directive,"exec")) {
+                if(noexec) {
+                    log_printf(r->server,
+                              "httpd: exec used but not allowed in %s",
+                              r->filename);
+                    rputs(error, r);
+                    ret = find_string(f,ENDING_SEQUENCE,NULL);
+                } else 
+                    ret=handle_exec(f, r, error);
+            } 
+            else if(!strcmp(directive,"config"))
+                ret=handle_config(f, r, error, timefmt, &sizefmt);
+            else if(!strcmp(directive,"include"))
+                ret=handle_include(f, r, error, noexec);
+            else if(!strcmp(directive,"echo"))
+                ret=handle_echo(f, r, error);
+            else if(!strcmp(directive,"fsize"))
+                ret=handle_fsize(f, r, error, sizefmt);
+            else if(!strcmp(directive,"flastmod"))
+                ret=handle_flastmod(f, r, error, timefmt);
+            else {
+                log_printf(r->server, 
+                          "httpd: unknown directive %s in parsed doc %s",
+                          directive, r->filename);
+                rputs(error, r);
+                ret=find_string(f,ENDING_SEQUENCE,NULL);
+            }
+            if(ret) {
+                log_printf(r->server, "httpd: premature EOF in parsed file %s",
+                          r->filename);
+                return;
+            }
+        } else 
+            return;
+    }
+}
+
+/*****************************************************************
+ *
+ * XBITHACK.  Sigh...  NB it's configurable per-directory; the compile-time
+ * option only changes the default.
+ */
+
+module includes_module;
+enum xbithack { xbithack_off, xbithack_on, xbithack_full };
+
+#ifdef XBITHACK        
+#define DEFAULT_XBITHACK xbithack_full
+#else
+#define DEFAULT_XBITHACK xbithack_off
+#endif
+
+void *create_includes_dir_config (pool *p, char *dummy)
+{
+    enum xbithack *result = (enum xbithack*)palloc(p, sizeof (enum xbithack));
+    *result = DEFAULT_XBITHACK;
+    return result;
+}
+
+char *set_xbithack (cmd_parms *cmd, void *xbp, char *arg)
+{
+   enum xbithack *state = (enum xbithack *)xbp;
+
+   if (!strcasecmp (arg, "off")) *state = xbithack_off;
+   else if (!strcasecmp (arg, "on")) *state = xbithack_on;
+   else if (!strcasecmp (arg, "full")) *state = xbithack_full;
+   else return "XBitHack must be set to Off, On, or Full";
+
+   return NULL;
+}
+
+int send_parsed_file(request_rec *r)
+{
+    FILE *f;
+    enum xbithack *state =
+       (enum xbithack *)get_module_config(r->per_dir_config,&includes_module);
+    int errstatus;
+
+    if (!(allow_options (r) & OPT_INCLUDES)) return DECLINED;
+    if (r->method_number != M_GET) return DECLINED;
+    if (r->finfo.st_mode == 0) return NOT_FOUND;
+       
+    if (*state == xbithack_full
+#ifndef __EMX__    
+    /*  OS/2 dosen't support Groups. */
+       && (r->finfo.st_mode & S_IXGRP)
+#endif
+       && (errstatus = set_last_modified (r, r->finfo.st_mtime)))
+        return errstatus;
+    
+    if(!(f=pfopen(r->pool, r->filename, "r"))) {
+        log_reason("file permissions deny server access", r->filename, r);
+       return FORBIDDEN;
+    }
+    
+    hard_timeout ("send", r);
+    send_http_header(r);
+
+    if (r->header_only) {
+        kill_timeout (r);
+       pfclose (r->pool, f);
+       return OK;
+    }
+   
+    if (r->main) {
+       /* Kludge --- for nested includes, we want to keep the
+        * subprocess environment of the base document (for compatibility);
+        * that means torquing our own last_modified date as well so that
+        * the LAST_MODIFIED variable gets reset to the proper value if
+        * the nested document resets <!--#config timefmt-->
+        */
+       r->subprocess_env = r->main->subprocess_env;
+       r->finfo.st_mtime= r->main->finfo.st_mtime;
+    } else { 
+       add_common_vars (r);
+       add_cgi_vars(r);
+       add_include_vars (r, DEFAULT_TIME_FORMAT);
+    }
+    
+    send_parsed_content (f, r);
+    
+    kill_timeout (r);
+    return OK;
+}
+
+int send_shtml_file (request_rec *r)
+{
+    r->content_type = "text/html";
+    return send_parsed_file(r);
+}
+
+int xbithack_handler (request_rec *r)
+{
+    enum xbithack *state;
+       
+#ifdef __EMX__
+    /* OS/2 dosen't currently support the xbithack. This is being worked on. */
+    return DECLINED;
+#else
+
+    if (!(r->finfo.st_mode & S_IXUSR)) return DECLINED;
+
+    state = (enum xbithack *)get_module_config(r->per_dir_config,
+                                              &includes_module);
+    
+    if (*state == xbithack_off) return DECLINED;
+    return send_parsed_file (r);
+#endif    
+}
+
+command_rec includes_cmds[] = {
+{ "XBitHack", set_xbithack, NULL, OR_OPTIONS, TAKE1, "Off, On, or Full" },
+{ NULL }    
+};
+
+handler_rec includes_handlers[] = {
+{ INCLUDES_MAGIC_TYPE, send_shtml_file },
+{ INCLUDES_MAGIC_TYPE3, send_shtml_file },
+{ "server-parsed", send_parsed_file },
+{ "text/html", xbithack_handler },
+{ NULL }
+};
+
+module includes_module = {
+   STANDARD_MODULE_STUFF,
+   NULL,                       /* initializer */
+   create_includes_dir_config, /* dir config creater */
+   NULL,                       /* dir merger --- default is to override */
+   NULL,                       /* server config */
+   NULL,                       /* merge server config */
+   includes_cmds,              /* command table */
+   includes_handlers,          /* handlers */
+   NULL,                       /* filename translation */
+   NULL,                       /* check_user_id */
+   NULL,                       /* check auth */
+   NULL,                       /* check access */
+   NULL,                       /* type_checker */
+   NULL,                       /* fixups */
+   NULL                                /* logger */
+};
diff --git a/RELEASE_1_1_X/src/modules/standard/mod_info.c b/RELEASE_1_1_X/src/modules/standard/mod_info.c
new file mode 100644 (file)
index 0000000..644d519
--- /dev/null
@@ -0,0 +1,426 @@
+/* ====================================================================
+ * Copyright (c) 1995, 1996 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+/* 
+ * Info Module.  Display configuration information for the server and
+ * all included modules.
+ *
+ * <Location /info>
+ * SetHandler server-info
+ * </Location>
+ *
+ * GET /info - Returns full configuration page for server and all modules
+ * GET /info?server - Returns server configuration only
+ * GET /info?module_name - Returns configuration for a single module
+ * GET /info?list - Returns quick list of included modules
+ *
+ * Rasmus Lerdorf <rasmus@vex.net>, May 1996
+ *
+ * 05.01.96 Initial Version
+ * 
+ */
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_core.h"
+#include "http_log.h"
+#include "http_main.h"
+#include "http_protocol.h"
+#include "util_script.h"
+
+typedef struct mod_info_config_lines {
+       char *cmd;
+       char *line;
+       struct mod_info_config_lines *next;
+} mod_info_config_lines;
+
+module info_module;
+extern module *top_module;
+
+char *mod_info_html_cmd_string(char *string) {
+       char *s,*t;
+       static char ret[64];  /* What is the max size of a command? */
+
+       ret[0]='\0';
+       s = string;
+       t=ret;  
+       while(*s) {
+               if(*s=='<') { strcat(t,"&lt;"); t+=4*sizeof(char); }
+               else if(*s=='>') { strcat(t,"&gt;"); t+=4*sizeof(char); }
+               else *t++=*s;
+               s++;
+               *t='\0';
+       }
+       return(ret);
+}
+
+mod_info_config_lines *mod_info_load_config(pool *p, char *filename) {
+       char s[MAX_STRING_LEN];
+       FILE *fp;
+       mod_info_config_lines *new, *ret=NULL, *prev=NULL;
+       char *t,*tt,o;
+       
+       fp = pfopen(p,filename,"r");
+       if(!fp) return NULL;
+       while(!cfg_getline(s,MAX_STRING_LEN,fp)) {
+               if(*s=='#') continue; /* skip comments */
+               new = palloc(p,sizeof(struct mod_info_config_lines));
+               new->next = NULL;
+               if(!ret) ret=new;
+               if(prev) prev->next=new;
+               t=strchr(s,' ');        
+               tt=strchr(s,'\t');
+               if(t && tt) t = (t<tt)?t:tt;
+               else if(tt) t=tt;
+               if(t) {
+                       o=*t;
+                       *t='\0';
+                       new->cmd = pstrdup(p,s);
+                       new->line = pstrdup(p,t+1);
+                       *t=o;
+               } else {
+                       new->cmd = pstrdup(p,s);
+                       new->line = NULL;
+               }
+               prev=new;       
+       }
+       pfclose(p,fp);
+       return(ret);
+}
+
+void mod_info_module_cmds(request_rec *r, mod_info_config_lines *cfg, command_rec *cmds,char *label) {
+       command_rec *cmd=cmds;
+       mod_info_config_lines *li=cfg,*li_st=NULL,*li_se=NULL,*block_start=NULL;
+       int lab=0, nest=0;
+
+       while(li) {
+               if(!strncasecmp(li->cmd,"<directory",10) || !strncasecmp(li->cmd,"<location",9) ||
+                 !strncasecmp(li->cmd,"<limit",6)) { 
+                       if(nest) li_se=li;
+                       else li_st=li; 
+                       li=li->next; 
+                       nest++;
+                       continue; 
+               } else if(nest && (!strncasecmp(li->cmd,"</limit",7) ||
+                 !strncasecmp(li->cmd,"</location",10) || !strncasecmp(li->cmd,"</directory",11))) { 
+                       if(block_start) {
+                               if((nest==1 && block_start==li_st) || (nest==2 && block_start==li_se)) {
+                                       rputs("<dd><tt>",r);
+                                       if(nest==2) rputs("&nbsp;&nbsp;",r);
+                                       rputs(mod_info_html_cmd_string(li->cmd),r);
+                                       rputs(" ",r);
+                                       if(li->line) rputs(mod_info_html_cmd_string(li->line),r);
+                                       rputs("</tt>\n",r);
+                                       nest--;
+                                       if(!nest) {
+                                               block_start=NULL;
+                                               li_st=NULL;
+                                       } else {
+                                               block_start=li_st;
+                                       }
+                                       li_se=NULL; 
+                               } else {
+                                       nest--; 
+                                       if(!nest) {
+                                               li_st=NULL;
+                                       }
+                                       li_se=NULL; 
+                               }
+                       } else {
+                               nest--; 
+                               if(!nest) {
+                                       li_st=NULL;
+                               }
+                               li_se=NULL; 
+                       }
+                       li=li->next;
+                       continue;
+               }
+               cmd = cmds;
+               while(cmd) {
+                       if(cmd->name) {
+                               if(!strcasecmp(cmd->name,li->cmd)) {
+                                       if(!lab) {
+                                               rputs("<dt><strong>",r);
+                                               rputs(label,r);
+                                               rputs("</strong>\n",r);
+                                               lab=1;
+                                       }
+                                       if(((nest && block_start==NULL) || (nest==2 && block_start==li_st))
+                                         && (strncasecmp(li->cmd,"<directory",10) &&
+                                         strncasecmp(li->cmd,"<location",9) && strncasecmp(li->cmd,"<limit",6) &&
+                                         strncasecmp(li->cmd,"</limit",7) && strncasecmp(li->cmd,"</location",10) &&
+                                         strncasecmp(li->cmd,"</directory",11))) {
+                                               rputs("<dd><tt>",r);
+                                               rputs(mod_info_html_cmd_string(li_st->cmd),r);
+                                               rputs(" ",r);
+                                               if(li_st->line) rputs(mod_info_html_cmd_string(li_st->line),r);
+                                               rputs("</tt>\n",r);
+                                               block_start=li_st;
+                                               if(li_se) {
+                                                       rputs("<dd><tt>&nbsp;&nbsp;",r);
+                                                       rputs(mod_info_html_cmd_string(li_se->cmd),r);
+                                                       rputs(" ",r);
+                                                       if(li_se->line) rputs(mod_info_html_cmd_string(li_se->line),r);
+                                                       rputs("</tt>\n",r);
+                                                       block_start=li_se;
+                                               }
+                                       }       
+                                       rputs("<dd><tt>",r);
+                                       if(nest) rputs("&nbsp;&nbsp;",r);
+                                       if(nest==2) rputs("&nbsp;&nbsp;",r);
+                                       rputs(mod_info_html_cmd_string(li->cmd),r);
+                                       if(li->line) {
+                                               rputs(" <i>",r);
+                                               rputs(mod_info_html_cmd_string(li->line),r);
+                                               rputs("</i></tt>",r);
+                                       }
+                               }
+                       } else break;
+                       cmd++;
+               }
+               li = li->next;
+       }
+}
+
+int display_info(request_rec *r) {
+       module *modp = NULL;
+       char buf[256];
+    extern char *module_names[];
+    char **names = module_names;
+       command_rec *cmd=NULL;
+       handler_rec *hand=NULL;
+       server_rec *serv = r->server;
+       int comma=0;
+       mod_info_config_lines *mod_info_cfg_httpd=NULL;
+       mod_info_config_lines *mod_info_cfg_srm=NULL;
+       mod_info_config_lines *mod_info_cfg_access=NULL;
+       extern int standalone;
+       extern uid_t user_id;
+       extern char *user_name;
+       extern gid_t group_id;
+       extern int max_requests_per_child;
+       extern char *pid_fname;
+       extern char *scoreboard_fname;
+       extern int daemons_to_start;
+       extern int daemons_min_free;
+       extern int daemons_max_free;
+       extern int daemons_limit;
+       extern char server_root[MAX_STRING_LEN];
+       extern char server_confname[MAX_STRING_LEN];
+
+       /* Init timeout */
+       soft_timeout ("send server info", r);
+       r->content_type = "text/html";          
+       send_http_header(r);
+       if(r->header_only) {
+               return 0;
+    }
+       
+       rputs("<html><head><title>Server Information</title></head>\n",r);
+       rputs("<body><h1 align=center>Apache Server Information</h1>\n",r);
+       if(!r->args || strcasecmp(r->args,"list")) {
+               sprintf(buf,"%s/%s",server_root,server_confname);
+               mod_info_cfg_httpd = mod_info_load_config(r->pool,buf);
+               sprintf(buf,"%s/%s",server_root,serv->srm_confname);
+               mod_info_cfg_srm = mod_info_load_config(r->pool,buf);
+               sprintf(buf,"%s/%s",server_root,serv->access_confname);
+               mod_info_cfg_access = mod_info_load_config(r->pool,buf);
+               if(!r->args) {
+                       rputs("<tt><a href=\"#server\">Server Settings</a>, ",r);
+                       for(modp = top_module, names=module_names; modp; modp = modp->next, names++) {
+                               sprintf(buf,"<a href=\"#%s\">%s</a>",*names,*names);
+                               rputs(buf, r);
+                               if(modp->next) rputs(", ",r);
+                       }
+                       rputs("</tt><hr>",r);
+
+               }
+               if(!r->args || !strcasecmp(r->args,"server")) { 
+                       sprintf(buf,"<a name=\"server\"><strong>Server Version:</strong> <font size=+1><tt>%s</tt></a></font><br>\n",SERVER_VERSION);
+                       rputs(buf,r);
+                       sprintf(buf,"<strong>API Version:</strong> <tt>%d</tt><br>\n",MODULE_MAGIC_NUMBER);
+                       rputs(buf,r);
+                       sprintf(buf,"<strong>Run Mode:</strong> <tt>%s</tt><br>\n",standalone?"standalone":"inetd");
+                       rputs(buf,r);
+                       sprintf(buf,"<strong>User/Group:</strong> <tt>%s(%d)/%d</tt><br>\n",user_name,(int)user_id,(int)group_id);
+                       rputs(buf,r);
+                       sprintf(buf,"<strong>Hostname/port:</strong> <tt>%s:%d</tt><br>\n",serv->server_hostname,serv->port);
+                       rputs(buf,r);
+                       sprintf(buf,"<strong>Daemons:</strong> <tt>start: %d &nbsp;&nbsp; min idle: %d &nbsp;&nbsp; max idle: %d &nbsp;&nbsp; max: %d</tt><br>\n",daemons_to_start,daemons_min_free,daemons_max_free,daemons_limit);
+                       rputs(buf,r);
+                       sprintf(buf,"<strong>Max Requests:</strong> <tt>per child: %d &nbsp;&nbsp; per connection: %d</tt><br>\n",max_requests_per_child,serv->keep_alive);
+                       rputs(buf,r);
+                       sprintf(buf,"<strong>Timeouts:</strong> <tt>connection: %d &nbsp;&nbsp; keep-alive: %d</tt><br>",serv->timeout,serv->keep_alive_timeout);
+                       rputs(buf,r);
+                       sprintf(buf,"<strong>Server Root:</strong> <tt>%s</tt><br>\n",server_root);
+                       rputs(buf,r);
+                       sprintf(buf,"<strong>Config File:</strong> <tt>%s</tt><br>\n",server_confname);
+                       rputs(buf,r);
+                       sprintf(buf,"<strong>PID File:</strong> <tt>%s</tt><br>\n",pid_fname);
+                       rputs(buf,r);
+                       sprintf(buf,"<strong>Scoreboard File:</strong> <tt>%s</tt><br>\n",scoreboard_fname);
+                       rputs(buf,r);
+               }
+               rputs("<hr><dl>",r);
+               for(modp = top_module, names=module_names; modp; modp = modp->next, names++) {
+                       if(!r->args || !strcasecmp(*names,r->args)) {   
+                               sprintf(buf,"<dt><a name=\"%s\"><strong>Module Name:</strong> <font size=+1><tt>%s</tt></a></font>\n",*names,*names);
+                               rputs(buf,r);
+                               rputs("<dt><strong>Content-types affected:</strong>",r);        
+                               hand = modp->handlers;
+                               if(hand) {
+                                       while(hand) {
+                                               if(hand->content_type) {
+                                                       sprintf(buf," <tt>%s</tt>\n",hand->content_type);       
+                                                       rputs(buf,r);
+                                               } else break;
+                                               hand++;
+                                               if(hand && hand->content_type) rputs(",",r);
+                                       }
+                               } else {
+                                       rputs("<tt> none</tt>",r);
+                               }
+                               rputs("<dt><strong>Module Groups:</strong> \n",r);
+                               if(modp->translate_handler) {
+                                       rputs("<tt>Translate Handler</tt>\n",r);
+                                       comma=1;
+                               }
+                               if(modp->check_user_id) {
+                                       if(comma) rputs(", ",r);
+                                       rputs("<tt>User ID Checking</tt>\n",r);
+                                       comma=1;
+                               }
+                               if(modp->auth_checker) {
+                                       if(comma) rputs(", ",r);
+                                       rputs("<tt>Authentication Checking</tt>\n",r);
+                                       comma=1;
+                               }
+                               if(modp->access_checker) {
+                                       if(comma) rputs(", ",r);
+                                       rputs("<tt>Access Checking</tt>\n",r);
+                                       comma=1;
+                               }
+                               if(modp->type_checker) {
+                                       if(comma) rputs(", ",r);
+                                       rputs("<tt>Type Checking</tt>\n",r);
+                                       comma=1;
+                               }
+                               if(modp->fixer_upper) {
+                                       if(comma) rputs(", ",r);
+                                       rputs("<tt>Header Fixer</tt>\n",r);
+                                       comma=1;
+                               }
+                               if(modp->logger) {
+                                       if(comma) rputs(", ",r);
+                                       rputs("<tt>Logging</tt>\n",r);
+                                       comma=1;
+                               }
+                               if(!comma) rputs("<tt> none</tt>",r);
+                               comma=0;
+                               rputs("<dt><strong>Module Configuration Commands:</strong> ",r);
+                               cmd = modp->cmds;
+                               if(cmd) {
+                                       while(cmd) {
+                                               if(cmd->name) {
+                                                       sprintf(buf,"<dd><tt>%s - <i>",mod_info_html_cmd_string(cmd->name));    
+                                                       rputs(buf,r);
+                                                       if(cmd->errmsg) rputs(cmd->errmsg,r);
+                                                       rputs("</i></tt>\n",r);
+                                               } else break;
+                                               cmd++;
+                                       }
+                                       rputs("<dt><strong>Current Configuration:</strong>\n",r);
+                                       mod_info_module_cmds(r,mod_info_cfg_httpd,modp->cmds,"httpd.conf");     
+                                       mod_info_module_cmds(r,mod_info_cfg_srm,modp->cmds,"srm.conf");
+                                       mod_info_module_cmds(r,mod_info_cfg_access,modp->cmds,"access.conf");
+                               } else {
+                                       rputs("<tt> none</tt>\n",r);
+                               }
+                               rputs("<dt><hr>\n",r);
+                               if(r->args) break;
+                       }
+               }
+               if(!modp && r->args && strcasecmp(r->args,"server")) rputs("<b>No such module</b>\n",r);
+       } else {
+               for(modp = top_module; modp; modp = modp->next, names++) {
+                       rputs(*names,r);
+                       if(modp->next) rputs("<br>",r);
+               }       
+       }       
+       rputs("</dl></body></html>\n",r);
+       /* Done, turn off timeout, close file and return */
+       return 0;
+}
+
+handler_rec info_handlers[] = {
+       { "server-info", display_info },
+       { NULL }
+};
+
+module info_module = {
+       STANDARD_MODULE_STUFF,
+       NULL,                           /* initializer */
+       NULL,                           /* dir config creater */
+       NULL,                           /* dir merger --- default is to override */
+       NULL,                           /* server config */
+       NULL,                           /* merge server config */
+       NULL,                           /* command table */
+       info_handlers,          /* handlers */
+       NULL,                           /* filename translation */
+       NULL,                           /* check_user_id */
+       NULL,                           /* check auth */
+       NULL,                           /* check access */
+       NULL,                           /* type_checker */
+       NULL,                           /* fixups */
+       NULL                            /* logger */
+};
diff --git a/RELEASE_1_1_X/src/modules/standard/mod_log_agent.c b/RELEASE_1_1_X/src/modules/standard/mod_log_agent.c
new file mode 100644 (file)
index 0000000..14c185b
--- /dev/null
@@ -0,0 +1,193 @@
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+
+#include "httpd.h"
+#include "http_config.h"
+
+module agent_log_module;
+
+static int xfer_flags = ( O_WRONLY | O_APPEND | O_CREAT );
+#ifdef __EMX__
+/* OS/2 dosen't support users and groups */
+static mode_t xfer_mode = ( S_IREAD | S_IWRITE );
+#else
+static mode_t xfer_mode = ( S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH );
+#endif
+
+typedef struct {
+    char *fname;
+    int agent_fd;
+} agent_log_state;
+
+void *make_agent_log_state (pool *p, server_rec *s)
+{
+    agent_log_state *cls =
+      (agent_log_state *)palloc (p, sizeof (agent_log_state));
+
+    cls->fname = "";
+    cls->agent_fd = -1;
+
+
+    return (void *)cls;
+}
+
+char *set_agent_log (cmd_parms *parms, void *dummy, char *arg)
+{
+    agent_log_state *cls = get_module_config (parms->server->module_config,
+                                              &agent_log_module);
+  
+    cls->fname = arg;
+    return NULL;
+}
+
+command_rec agent_log_cmds[] = {
+{ "AgentLog", set_agent_log, NULL, RSRC_CONF, TAKE1,
+    "the filename of the agent log" },
+{ NULL }
+};
+
+void agent_log_child (void *cmd)
+{
+    /* Child process code for 'AgentLog "|..."';
+     * may want a common framework for this, since I expect it will
+     * be common for other foo-loggers to want this sort of thing...
+     */
+    
+    cleanup_for_exec();
+    signal (SIGHUP, SIG_IGN);
+    execl (SHELL_PATH, SHELL_PATH, "-c", (char *)cmd, NULL);
+    exit (1);
+}
+
+void open_agent_log (server_rec *s, pool *p)
+{
+    agent_log_state *cls = get_module_config (s->module_config,
+                                              &agent_log_module);
+  
+    char *fname = server_root_relative (p, cls->fname);
+    
+    if (cls->agent_fd > 0) return; /* virtual log shared w/main server */
+    
+    if (*cls->fname == '|') {
+       FILE *dummy;
+       
+       spawn_child(p, agent_log_child, (void *)(cls->fname+1),
+                   kill_after_timeout, &dummy, NULL);
+
+       if (dummy == NULL) {
+           fprintf (stderr, "Couldn't fork child for AgentLog process\n");
+           exit (1);
+       }
+
+       cls->agent_fd = fileno (dummy);
+    }
+    else if(*cls->fname != '\0') {
+      if((cls->agent_fd = popenf(p, fname, xfer_flags, xfer_mode)) < 0) {
+        fprintf(stderr,"httpd: could not open agent log file %s.\n", fname);
+        perror("open");
+        exit(1);
+      }
+    }
+}
+
+void init_agent_log (server_rec *s, pool *p)
+{
+    for (; s; s = s->next) open_agent_log (s, p);
+}
+
+int agent_log_transaction(request_rec *orig)
+{
+    agent_log_state *cls = get_module_config (orig->server->module_config,
+                                              &agent_log_module);
+  
+    char str[HUGE_STRING_LEN];
+    char *agent;
+    request_rec *r;
+
+    if(cls->agent_fd <0)
+      return OK;
+
+    for (r = orig; r->next; r = r->next)
+        continue;
+    if (*cls->fname == '\0')   /* Don't log agent */
+       return DECLINED;
+
+    agent = table_get(orig->headers_in, "User-Agent");
+    if(agent != NULL) 
+      {
+       sprintf(str, "%s\n", agent);
+       write(cls->agent_fd, str, strlen(str));
+      }
+    
+    return OK;
+}
+
+module agent_log_module = {
+   STANDARD_MODULE_STUFF,
+   init_agent_log,             /* initializer */
+   NULL,                       /* create per-dir config */
+   NULL,                       /* merge per-dir config */
+   make_agent_log_state,       /* server config */
+   NULL,                       /* merge server config */
+   agent_log_cmds,             /* command table */
+   NULL,                       /* handlers */
+   NULL,                       /* filename translation */
+   NULL,                       /* check_user_id */
+   NULL,                       /* check auth */
+   NULL,                       /* check access */
+   NULL,                       /* type_checker */
+   NULL,                       /* fixups */
+   agent_log_transaction       /* logger */
+};
diff --git a/RELEASE_1_1_X/src/modules/standard/mod_log_config.c b/RELEASE_1_1_X/src/modules/standard/mod_log_config.c
new file mode 100644 (file)
index 0000000..3084ccc
--- /dev/null
@@ -0,0 +1,573 @@
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * This is module implements the TransferLog directive (same as the
+ * common log module), and an additional directive, LogFormat.
+ *
+ * The argument to LogFormat is a string, which can include literal
+ * characters copied into the log files, and '%' directives as follows:
+ *
+ * %...h:  remote host
+ * %...l:  remote logname (from identd, if supplied)
+ * %...u:  remote user (from auth; may be bogus if return status (%s) is 401)
+ * %...t:  time, in common log format time format
+ * %...r:  first line of request
+ * %...s:  status.  For requests that got internally redirected, this
+ *         is status of the *original* request --- %...>s for the last.
+ * %...b:  bytes sent.
+ * %...{Foobar}i:  The contents of Foobar: header line(s) in the request
+ *                 sent to the client.
+ * %...{Foobar}o:  The contents of Foobar: header line(s) in the reply.
+ *
+ * The '...' can be nothing at all (e.g. "%h %u %r %s %b"), or it can
+ * indicate conditions for inclusion of the item (which will cause it
+ * to be replaced with '-' if the condition is not met).  Note that
+ * there is no escaping performed on the strings from %r, %...i and
+ * %...o; some with long memories may remember that I thought this was
+ * a bad idea, once upon a time, and I'm still not comfortable with
+ * it, but it is difficult to see how to "do the right thing" with all
+ * of '%..i', unless we URL-escape everything and break with CLF.
+ *
+ * The forms of condition are a list of HTTP status codes, which may
+ * or may not be preceded by '!'.  Thus, '%400,501{User-agent}i' logs
+ * User-agent: on 400 errors and 501 errors (Bad Request, Not
+ * Implemented) only; '%!200,304,302{Referer}i' logs Referer: on all
+ * requests which did *not* return some sort of normal status.
+ *
+ * The default LogFormat reproduces CLF; see below.
+ *
+ * The way this is supposed to work with virtual hosts is as follows:
+ * a virtual host can have its own LogFormat, or its own TransferLog.
+ * If it doesn't have its own LogFormat, it inherits from the main
+ * server.  If it doesn't have its own TransferLog, it writes to the
+ * same descriptor (meaning the same process for "| ...").
+ *
+ * That means that you can do things like:
+ *
+ * <VirtualHost hosta.com>
+ * LogFormat "hosta ..."
+ * ...
+ * </VirtualHost>
+ *
+ * <VirtualHost hosta.com>
+ * LogFormat "hostb ..."
+ * ...
+ * </VirtualHost>
+ *
+ * ... to have different virtual servers write into the same log file,
+ * but have some indication which host they came from, though a %v
+ * directive may well be a better way to handle this.
+ *
+ * --- rst */
+
+#define DEFAULT_LOG_FORMAT "%h %l %u %t \"%r\" %s %b"
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_core.h" /* For REMOTE_NAME */
+
+module config_log_module;
+
+static int xfer_flags = ( O_WRONLY | O_APPEND | O_CREAT );
+#ifdef __EMX__
+/* OS/2 dosen't support users and groups */
+static mode_t xfer_mode = ( S_IREAD | S_IWRITE );
+#else
+static mode_t xfer_mode = ( S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH );
+#endif
+
+typedef struct {
+    char *fname;
+    array_header *format;
+    int log_fd;
+} config_log_state;
+
+/*
+ * Format items...
+ */
+
+typedef char *(*item_key_func)(request_rec *, char *);
+
+typedef struct {
+    item_key_func func;
+    char *arg;
+    int condition_sense;
+    int want_orig;
+    array_header *conditions;
+} log_format_item;
+
+char *format_integer(pool *p, int i)
+{
+    char dummy[40];
+    sprintf (dummy, "%d", i);
+    return pstrdup (p, dummy);
+}
+
+static char *pfmt(pool *p, int i)
+{
+    if (i <= 0) return "-";
+    else return format_integer (p, i);
+}
+
+char *constant_item (request_rec *dummy, char *stuff) { return stuff; }
+
+char *log_remote_host (request_rec *r, char *a)
+{ return (char *)get_remote_host(r->connection, r->per_dir_config, REMOTE_NAME); }
+
+char *log_remote_logname(request_rec *r, char *a)
+{return (char *)get_remote_logname(r);}
+
+char *log_remote_user (request_rec *r, char *a)
+{ return r->connection->user; }
+
+char *log_request_line (request_rec *r, char *a)
+{ return r->the_request; }
+
+char *log_status (request_rec *r, char *a)
+{ return pfmt(r->pool, r->status); }
+
+char *log_bytes_sent (request_rec *r, char *a)
+{
+    if (!r->sent_bodyct) return "-";
+    else
+    {
+       long int bs;
+       char dummy[40];
+       bgetopt(r->connection->client, BO_BYTECT, &bs);
+       sprintf(dummy, "%ld", bs);
+       return pstrdup(r->pool, dummy);
+    }
+}
+
+char *log_header_in (request_rec *r, char *a)
+{ return table_get (r->headers_in, a); }
+
+char *log_header_out (request_rec *r, char *a)
+{
+    char *cp = table_get (r->headers_out, a);
+    if (cp) return cp;
+    return table_get (r->err_headers_out, a);
+}
+
+char *log_env_var (request_rec *r, char *a)
+{ return table_get (r->subprocess_env, a); }
+
+char *log_request_time (request_rec *r, char *a)
+{
+    long timz;
+    struct tm *t;
+    char tstr[MAX_STRING_LEN],sign;
+    
+    t = get_gmtoff(&timz);
+    sign = (timz < 0 ? '-' : '+');
+    if(timz < 0) 
+        timz = -timz;
+
+    strftime(tstr,MAX_STRING_LEN,"[%d/%b/%Y:%H:%M:%S ",t);
+
+    sprintf (tstr + strlen(tstr), "%c%02ld%02ld]",
+            sign, timz/3600, timz%3600);
+
+    return pstrdup (r->pool, tstr);
+}
+
+/*****************************************************************
+ *
+ * Parsing the log format string
+ */
+
+struct log_item_list {
+    char ch;
+    item_key_func func;
+    int want_orig_default;
+} log_item_keys[] = {
+    { 'h', log_remote_host, 0 },
+    { 'l', log_remote_logname, 0 },
+    { 'u', log_remote_user, 0 },
+    { 't', log_request_time, 0 },
+    { 'r', log_request_line, 1 },
+    { 's', log_status, 1 },
+    { 'b', log_bytes_sent, 0 },
+    { 'i', log_header_in, 0 },
+    { 'o', log_header_out, 0 },
+    { 'e', log_env_var, 0 },
+    { '\0' }
+};
+
+struct log_item_list  *find_log_func (char k)
+{
+    int i;
+
+    for (i = 0; log_item_keys[i].ch; ++i)
+       if (k == log_item_keys[i].ch)
+           return &log_item_keys[i];
+
+    return NULL;
+}
+
+char *log_format_substring (pool *p, char *start, char *end)
+{
+    char *res = palloc (p, end - start + 1);
+    strncpy (res, start, end - start);
+    res[end - start] = '\0';
+    return res;
+}
+
+char *parse_log_misc_string (pool *p, log_format_item *it, char **sa)
+{
+    char *s = *sa;
+    
+    it->func = constant_item;
+    it->conditions = NULL;
+
+    while (*s && *s != '%') ++s;
+    it->arg = log_format_substring (p, *sa, s);
+    *sa = s;
+    
+    return NULL;
+}
+
+char *parse_log_item (pool *p, log_format_item *it, char **sa)
+{
+    char *s = *sa;
+    if (*s != '%') return parse_log_misc_string (p, it, sa);
+
+    ++s;
+    it->condition_sense = 0;
+    it->conditions = NULL;
+    it->want_orig = -1;
+    it->arg = "";              /* For safety's sake... */
+
+    while (*s) {
+       int i;
+       struct log_item_list *l;
+       
+       switch (*s) {
+       case '!':
+           ++s;
+           it->condition_sense = !it->condition_sense;
+           break;
+
+       case '<':
+           ++s;
+           it->want_orig = 1;
+           break;
+
+       case '>':
+           ++s;
+           it->want_orig = 0;
+           break;
+           
+       case ',':
+           ++s;
+           break;
+
+       case '{':
+           ++s;
+           it->arg = getword (p, &s, '}');
+           break;
+           
+       case '0': case '1': case '2': case '3': case '4': 
+       case '5': case '6': case '7': case '8': case '9':
+           i = *s - '0';
+           while (isdigit (*++s)) i = i * 10 + (*s) - '0';
+           if (!it->conditions)
+               it->conditions = make_array (p, 4, sizeof(int));
+           *(int *)push_array(it->conditions) = i;
+           break;
+
+       default:
+           l = find_log_func (*s++);
+           if (!l) {
+               char dummy[] = { '\0', '\0'};
+               dummy[0] = s[-1];
+               return pstrcat (p, "Unrecognized LogFormat directive %",
+                               dummy, NULL);
+           }
+           it->func = l->func;
+           if (it->want_orig == -1) it->want_orig = l->want_orig_default;
+           *sa = s;
+           return NULL;
+       }
+    }
+
+    return "Ran off end of LogFormat parsing args to some directive";
+}
+
+array_header *parse_log_string (pool *p, char *s, char **err)
+{
+    array_header *a = make_array (p, 30, sizeof (log_format_item));
+    char *res;
+
+    while (*s) {
+       if ((res = parse_log_item (p, (log_format_item *)push_array(a), &s))) {
+           *err = res;
+           return NULL;
+       }
+    }
+
+    s = "\n";
+    parse_log_item (p, (log_format_item *)push_array(a), &s);
+    return a;
+}
+
+/*****************************************************************
+ *
+ * Actually logging.
+ */
+
+char *process_item(request_rec *r, request_rec *orig, log_format_item *item)
+{
+    char *cp;
+    
+    /* First, see if we need to process this thing at all... */
+
+    if (item->conditions && item->conditions->nelts != 0) {
+       int i;
+       int *conds = (int *)item->conditions->elts;
+       int in_list = 0;
+
+       for (i = 0; i < item->conditions->nelts; ++i)
+           if (r->status == conds[i]) {
+               in_list = 1;
+               break;
+           }
+
+       if ((item->condition_sense && in_list)
+           || (!item->condition_sense && !in_list))
+       {
+           return "-";
+       }
+    }
+
+    /* We do.  Do it... */
+
+    cp = (*item->func)(item->want_orig ? orig : r, item->arg);
+    return cp ? cp : "-";
+}
+
+int config_log_transaction(request_rec *r)
+{
+    config_log_state *cls = get_module_config (r->server->module_config,
+                                              &config_log_module);
+  
+    array_header *strsa= make_array(r->pool, cls->format->nelts,sizeof(char*));
+    log_format_item *items = (log_format_item *)cls->format->elts;
+    char *str, **strs, *s;
+    request_rec *orig;
+    int i;
+    int len = 0;
+
+    orig = r;
+    while (orig->prev) orig = orig->prev;
+    while (r->next) r = r->next;
+
+    for (i = 0; i < cls->format->nelts; ++i)
+       *((char**)push_array (strsa)) = process_item (r, orig, &items[i]);
+
+    strs = (char **)strsa->elts;
+    
+    for (i = 0; i < cls->format->nelts; ++i)
+       len += strlen (strs[i]);
+
+    str = palloc (r->pool, len + 1);
+
+    for (i = 0, s = str; i < cls->format->nelts; ++i) {
+       strcpy (s, strs[i]);
+       s += strlen (strs[i]);
+    }
+    
+    write(cls->log_fd, str, strlen(str));
+
+    return OK;
+}
+
+/*****************************************************************
+ *
+ * Module glue...
+ */
+
+void *make_config_log_state (pool *p, server_rec *s)
+{
+    config_log_state *cls =
+      (config_log_state *)palloc (p, sizeof (config_log_state));
+
+    cls->fname = NULL;
+    cls->format = NULL;
+    cls->log_fd = -1;
+
+    return (void *)cls;
+}
+
+char *set_config_log (cmd_parms *parms, void *dummy, char *arg)
+{
+    config_log_state *cls = get_module_config (parms->server->module_config,
+                                              &config_log_module);
+  
+    cls->fname = arg;
+    return NULL;
+}
+
+char *log_format (cmd_parms *cmd, void *dummy, char *arg)
+{
+    char *err_string = NULL;
+    config_log_state *cls = get_module_config (cmd->server->module_config,
+                                              &config_log_module);
+  
+    cls->format = parse_log_string (cmd->pool, arg, &err_string);
+    return err_string;
+}
+
+command_rec config_log_cmds[] = {
+{ "TransferLog", set_config_log, NULL, RSRC_CONF, TAKE1,
+    "the filename of the access log" },
+{ "LogFormat", log_format, NULL, RSRC_CONF, TAKE1,
+      "a log format string (see docs)" },
+{ NULL }
+};
+
+void config_log_child (void *cmd)
+{
+    /* Child process code for 'TransferLog "|..."';
+     * may want a common framework for this, since I expect it will
+     * be common for other foo-loggers to want this sort of thing...
+     */
+    
+    cleanup_for_exec();
+    signal (SIGHUP, SIG_IGN);
+    execl (SHELL_PATH, SHELL_PATH, "-c", (char *)cmd, NULL);
+    fprintf (stderr, "Exec of shell for logging failed!!!\n");
+    exit (1);
+}
+
+config_log_state *open_config_log (server_rec *s, pool *p,
+                                  config_log_state *defaults)
+{
+    config_log_state *cls = get_module_config (s->module_config,
+                                              &config_log_module);
+  
+    if (cls->log_fd > 0) return cls; /* virtual config shared w/main server */
+    
+    if (cls->format == NULL) {
+       char *dummy;
+       
+       if (defaults) cls->format = defaults->format;
+       else cls->format = parse_log_string (p, DEFAULT_LOG_FORMAT, &dummy);
+    }
+
+    if (cls->fname == NULL) {
+       if (defaults) {
+           cls->log_fd = defaults->log_fd;
+           return cls;
+       }
+       else cls->fname = DEFAULT_XFERLOG;
+    }
+    
+    if (*cls->fname == '|') {
+       FILE *dummy;
+       
+       spawn_child(p, config_log_child, (void *)(cls->fname+1),
+                   kill_after_timeout, &dummy, NULL);
+
+       if (dummy == NULL) {
+           fprintf (stderr, "Couldn't fork child for TransferLog process\n");
+           exit (1);
+       }
+
+       cls->log_fd = fileno (dummy);
+    }
+    else {
+       char *fname = server_root_relative (p, cls->fname);
+       if((cls->log_fd = popenf(p, fname, xfer_flags, xfer_mode)) < 0) {
+           fprintf (stderr,
+                    "httpd: could not open transfer log file %s.\n", fname);
+           perror("open");
+           exit(1);
+       }
+    }
+
+    return cls;
+}
+
+void init_config_log (server_rec *s, pool *p)
+{
+    /* First, do "physical" server, which gets default log fd and format
+     * for the virtual servers, if they don't override...
+     */
+    
+    config_log_state *default_conf = open_config_log (s, p, NULL);
+    
+    /* Then, virtual servers */
+    
+    for (s = s->next; s; s = s->next) open_config_log (s, p, default_conf);
+}
+
+module config_log_module = {
+   STANDARD_MODULE_STUFF,
+   init_config_log,            /* initializer */
+   NULL,                       /* create per-dir config */
+   NULL,                       /* merge per-dir config */
+   make_config_log_state,      /* server config */
+   NULL,                       /* merge server config */
+   config_log_cmds,            /* command table */
+   NULL,                       /* handlers */
+   NULL,                       /* filename translation */
+   NULL,                       /* check_user_id */
+   NULL,                       /* check auth */
+   NULL,                       /* check access */
+   NULL,                       /* type_checker */
+   NULL,                       /* fixups */
+   config_log_transaction      /* logger */
+};
diff --git a/RELEASE_1_1_X/src/modules/standard/mod_log_referer.c b/RELEASE_1_1_X/src/modules/standard/mod_log_referer.c
new file mode 100644 (file)
index 0000000..26ac28d
--- /dev/null
@@ -0,0 +1,231 @@
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+
+#include "httpd.h"
+#include "http_config.h"
+
+module referer_log_module;
+
+static int xfer_flags = ( O_WRONLY | O_APPEND | O_CREAT );
+
+#ifdef __EMX__
+/* OS/2 lacks support for users and groups */
+static mode_t xfer_mode = ( S_IREAD | S_IWRITE );
+#else
+static mode_t xfer_mode = ( S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH );
+#endif
+
+typedef struct {
+    char *fname;
+    int referer_fd;
+    array_header *referer_ignore_list;
+} referer_log_state;
+
+void *make_referer_log_state (pool *p, server_rec *s)
+{
+    referer_log_state *cls =
+      (referer_log_state *)palloc (p, sizeof (referer_log_state));
+
+    cls->fname = "";
+    cls->referer_fd = -1;
+    cls->referer_ignore_list = make_array(p, 1, sizeof(char *));
+    return (void *)cls;
+}
+
+char *set_referer_log (cmd_parms *parms, void *dummy, char *arg)
+{
+    referer_log_state *cls = get_module_config (parms->server->module_config,
+                                              &referer_log_module);
+  
+    cls->fname = arg;
+    return NULL;
+}
+
+char *add_referer_ignore (cmd_parms *parms, void *dummy, char *arg)
+{
+  char **addme;
+  referer_log_state *cls = get_module_config (parms->server->module_config,
+                                             &referer_log_module);
+
+  addme = push_array(cls->referer_ignore_list);
+  *addme = pstrdup(cls->referer_ignore_list->pool, arg);
+  return NULL;
+}
+
+command_rec referer_log_cmds[] = {
+{ "RefererLog", set_referer_log, NULL, RSRC_CONF, TAKE1,
+    "the filename of the referer log" },
+{ "RefererIgnore", add_referer_ignore, NULL, RSRC_CONF, ITERATE,
+    "referer hostnames to ignore" },
+{ NULL }
+};
+
+void referer_log_child (void *cmd)
+{
+    /* Child process code for 'RefererLog "|..."';
+     * may want a common framework for this, since I expect it will
+     * be common for other foo-loggers to want this sort of thing...
+     */
+    
+    cleanup_for_exec();
+    signal (SIGHUP, SIG_IGN);
+    execl (SHELL_PATH, SHELL_PATH, "-c", (char *)cmd, NULL);
+    fprintf (stderr, "Exec of shell for logging failed!!!\n");
+    exit (1);
+}
+
+void open_referer_log (server_rec *s, pool *p)
+{
+    referer_log_state *cls = get_module_config (s->module_config,
+                                              &referer_log_module);
+  
+    char *fname = server_root_relative (p, cls->fname);
+    
+    if (cls->referer_fd > 0) return; /* virtual log shared w/main server */
+    
+    if (*cls->fname == '|') {
+       FILE *dummy;
+       
+       spawn_child(p, referer_log_child, (void *)(cls->fname+1),
+                   kill_after_timeout, &dummy, NULL);
+
+       if (dummy == NULL) {
+           fprintf (stderr, "Couldn't fork child for RefererLog process\n");
+           exit (1);
+       }
+
+       cls->referer_fd = fileno (dummy);
+    }
+    else if(*cls->fname != '\0') {
+      if((cls->referer_fd = popenf(p, fname, xfer_flags, xfer_mode)) < 0) {
+        fprintf(stderr,"httpd: could not open referer log file %s.\n", fname);
+        perror("open");
+        exit(1);
+      }
+    }
+}
+
+void init_referer_log (server_rec *s, pool *p)
+{
+    for (; s; s = s->next) open_referer_log (s, p);
+}
+
+int referer_log_transaction(request_rec *orig)
+{
+    char **ptrptr, **ptrptr2;
+    referer_log_state *cls = get_module_config (orig->server->module_config,
+                                              &referer_log_module);
+  
+    char *str;
+    char *referer;
+    request_rec *r;
+
+    if(cls->referer_fd <0)
+      return OK;
+
+    for (r = orig; r->next; r = r->next)
+        continue;
+    if (*cls->fname == '\0')   /* Don't log referer */
+       return DECLINED;
+    
+    referer = table_get(orig->headers_in, "Referer");
+    if(referer != NULL)
+      {
+
+
+         /* The following is an upsetting mess of pointers, I'm sorry
+            Anyone with the motiviation and/or the time should feel free
+            to make this cleaner... */
+
+         ptrptr2 = (char **) (cls->referer_ignore_list->elts + 
+                    (cls->referer_ignore_list->nelts *
+                     cls->referer_ignore_list->elt_size));
+         
+         /* Go through each element of the ignore list and compare it to the
+            referer_host.  If we get a match, return without logging */
+
+         for(ptrptr = (char **) cls->referer_ignore_list->elts;
+             ptrptr < ptrptr2;
+             ptrptr = (char **)((char *)ptrptr + cls->referer_ignore_list->elt_size)) 
+           {
+               if(strstr(referer, *ptrptr))
+                 return OK;
+           }
+         
+         
+         str = pstrcat(orig->pool, referer, " -> ", r->uri, "\n", NULL);
+         write(cls->referer_fd, str, strlen(str));
+      }
+
+    return OK;
+}
+
+module referer_log_module = {
+   STANDARD_MODULE_STUFF,
+   init_referer_log,           /* initializer */
+   NULL,                       /* create per-dir config */
+   NULL,                       /* merge per-dir config */
+   make_referer_log_state,     /* server config */
+   NULL,                       /* merge server config */
+   referer_log_cmds,           /* command table */
+   NULL,                       /* handlers */
+   NULL,                       /* filename translation */
+   NULL,                       /* check_user_id */
+   NULL,                       /* check auth */
+   NULL,                       /* check access */
+   NULL,                       /* type_checker */
+   NULL,                       /* fixups */
+   referer_log_transaction     /* logger */
+};
diff --git a/RELEASE_1_1_X/src/modules/standard/mod_mime.c b/RELEASE_1_1_X/src/modules/standard/mod_mime.c
new file mode 100644 (file)
index 0000000..74393f4
--- /dev/null
@@ -0,0 +1,315 @@
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * http_mime.c: Sends/gets MIME headers for requests
+ * 
+ * Rob McCool
+ * 
+ */
+
+#define MIME_PRIVATE
+
+#include "httpd.h"
+#include "http_config.h"
+
+typedef struct {
+    table *forced_types;       /* Additional AddTyped stuff */
+    table *encoding_types;     /* Added with AddEncoding... */
+    table *language_types;     /* Added with AddLanguage... */
+    table *handlers;           /* Added with AddHandler...  */
+
+    char *type;                        /* Type forced with ForceType  */
+    char *handler;             /* Handler forced with SetHandler */
+} mime_dir_config;
+
+module mime_module;
+
+void *create_mime_dir_config (pool *p, char *dummy)
+{
+    mime_dir_config *new =
+      (mime_dir_config *) palloc (p, sizeof(mime_dir_config));
+
+    new->forced_types = make_table (p, 4);
+    new->encoding_types = make_table (p, 4);
+    new->language_types = make_table (p, 4);
+    new->handlers = make_table (p, 4);
+
+    new->type = NULL;
+    new->handler = NULL;
+    
+    return new;
+}
+
+void *merge_mime_dir_configs (pool *p, void *basev, void *addv)
+{
+    mime_dir_config *base = (mime_dir_config *)basev;
+    mime_dir_config *add = (mime_dir_config *)addv;
+    mime_dir_config *new =
+      (mime_dir_config *)palloc (p, sizeof(mime_dir_config));
+
+    new->forced_types = overlay_tables (p, add->forced_types,
+                                       base->forced_types);
+    new->encoding_types = overlay_tables (p, add->encoding_types,
+                                         base->encoding_types);
+    new->language_types = overlay_tables (p, add->language_types,
+                                         base->language_types);
+    new->handlers = overlay_tables (p, add->handlers,
+                                         base->handlers);
+
+    new->type = add->type ? add->type : base->type;
+    new->handler = add->handler ? add->handler : base->handler;
+
+    return new;
+}
+
+char *add_type(cmd_parms *cmd, mime_dir_config *m, char *ct, char *ext)
+{
+    if (*ext == '.') ++ext;
+    table_set (m->forced_types, ext, ct);
+    return NULL;
+}
+
+char *add_encoding(cmd_parms *cmd, mime_dir_config *m, char *enc, char *ext)
+{
+    if (*ext == '.') ++ext;
+    table_set (m->encoding_types, ext, enc);
+    return NULL;
+}
+
+char *add_language(cmd_parms *cmd, mime_dir_config *m, char *lang, char *ext)
+{
+    if (*ext == '.') ++ext;
+    table_set (m->language_types, ext, lang);
+    return NULL;
+}
+
+char *add_handler(cmd_parms *cmd, mime_dir_config *m, char *hdlr, char *ext)
+{
+    if (*ext == '.') ++ext;
+    table_set (m->handlers, ext, hdlr);
+    return NULL;
+}
+
+/* The sole bit of server configuration that the MIME module has is
+ * the name of its config file, so...
+ */
+
+char *set_types_config (cmd_parms *cmd, void *dummy, char *arg)
+{
+    set_module_config (cmd->server->module_config, &mime_module,
+                      pstrdup (cmd->pool, arg));
+    return NULL;
+}
+
+command_rec mime_cmds[] = {
+{ "AddType", add_type, NULL, OR_FILEINFO, ITERATE2,
+    "a mime type followed by one or more file extensions" },
+{ "AddEncoding", add_encoding, NULL, OR_FILEINFO, ITERATE2,
+    "an encoding (e.g., gzip), followed by one or more file extensions" },
+{ "AddLanguage", add_language, NULL, OR_FILEINFO, ITERATE2,
+    "a language (e.g., fr), followed by one or more file extensions" },
+{ "AddHandler", add_handler, NULL, OR_FILEINFO, ITERATE2,
+    "a handler name followed by one or more file extensions" },
+{ "ForceType", set_string_slot, (void*)XtOffsetOf(mime_dir_config, type),
+    OR_FILEINFO, TAKE1, "a media type" },
+{ "SetHandler", set_string_slot, (void*)XtOffsetOf(mime_dir_config, handler),
+    OR_FILEINFO, TAKE1, "a handler name" },
+{ "TypesConfig", set_types_config, NULL, RSRC_CONF, TAKE1,
+    "the MIME types config file" },
+{ NULL }
+};
+
+/* Hash table  --- only one of these per daemon; virtual hosts can
+ * get private versions through AddType...
+ */
+
+#define MIME_HASHSIZE 27
+#define hash(i) (isalpha(i) ? (tolower(i)) - 'a' : 26)
+
+static table *hash_buckets[MIME_HASHSIZE];
+
+void init_mime (server_rec *s, pool *p)
+{
+    FILE *f;
+    char l[MAX_STRING_LEN];
+    int x;
+    char *types_confname = get_module_config (s->module_config, &mime_module);
+
+    if (!types_confname) types_confname = TYPES_CONFIG_FILE;
+
+    types_confname = server_root_relative (p, types_confname);
+
+    if(!(f = fopen(types_confname,"r"))) {
+        fprintf(stderr,"httpd: could not open mime types file %s\n",
+                types_confname);
+        perror("fopen");
+        exit(1);
+    }
+
+    for(x=0;x<27;x++) 
+        hash_buckets[x] = make_table (p, 10);
+
+    while(!(cfg_getline(l,MAX_STRING_LEN,f))) {
+        char *ll = l, *ct;
+      
+        if(l[0] == '#') continue;
+        ct = getword_conf (p, &ll);
+
+        while(ll[0]) {
+            char *ext = getword_conf (p, &ll);
+           str_tolower (ext);  /* ??? */
+           table_set (hash_buckets[hash(ext[0])], ext, ct);
+        }
+    }
+    fclose(f);
+}
+
+int find_ct(request_rec *r)
+{
+    char *fn = strrchr(r->filename, '/');
+    mime_dir_config *conf =
+      (mime_dir_config *)get_module_config(r->per_dir_config, &mime_module);
+    char *ext, *type, *orighandler = r->handler;
+
+    if (S_ISDIR(r->finfo.st_mode)) {
+        r->content_type = DIR_MAGIC_TYPE;
+       return OK;
+    }
+
+    /* TM -- FIXME
+     * 
+     * if r->filename does not contain a '/', the following passes a null
+     * pointer to getword, causing a SEGV ..
+     */
+
+    if(fn == NULL) fn = r->filename;
+
+    /* Parse filename extensions, which can be in any order */
+    while ((ext = getword(r->pool, &fn, '.')) && *ext) {
+      int found = 0;
+
+      /* Check for Content-Type */
+      if ((type = table_get (conf->forced_types, ext))
+         || (type = table_get (hash_buckets[hash(*ext)], ext))) {
+          r->content_type = type;
+         found = 1;
+      }
+
+      /* Check for Content-Language */
+      if ((type = table_get (conf->language_types, ext))) {
+         r->content_language = type;
+         found = 1;
+      }
+       
+      /* Check for Content-Encoding */
+      if ((type = table_get (conf->encoding_types, ext))) {
+         if (!r->content_encoding)
+             r->content_encoding = type;
+         else
+             r->content_encoding = pstrcat(r->pool, r->content_encoding,
+                                           ", ", type, NULL);
+         found = 1;
+      }
+
+      /* Check for a special handler, but not for proxy request */
+      if ((type = table_get (conf->handlers, ext)) && !r->proxyreq) {
+         r->handler = type;
+         found = 1;
+      }
+
+      /* This is to deal with cases such as foo.gif.bak, which we want
+       * to not have a type. So if we find an unknown extension, we
+       * zap the type/language/encoding and reset the handler
+       */
+
+      if (!found) {
+       r->content_type = NULL;
+       r->content_language = NULL;
+       r->content_encoding = NULL;
+       r->handler = orighandler;
+      }
+
+    }
+
+    /* Check for overrides with ForceType/SetHandler */
+
+    if (conf->type && strcmp(conf->type, "none"))
+        r->content_type = pstrdup(r->pool, conf->type);
+    if (conf->handler && strcmp(conf->handler, "none"))
+        r->handler = pstrdup(r->pool, conf->handler);
+
+    if (!r->content_type) return DECLINED;
+
+    return OK;
+}
+
+
+module mime_module = {
+   STANDARD_MODULE_STUFF,
+   init_mime,                  /* initializer */
+   create_mime_dir_config,
+   merge_mime_dir_configs,
+   NULL,                       /* server config */
+   NULL,                       /* merge server config */
+   mime_cmds,
+   NULL,                       /* handlers */
+   NULL,                       /* filename translation */
+   NULL,                       /* check_user_id */
+   NULL,                       /* check auth */
+   NULL,                       /* check access */
+   find_ct,                    /* type_checker */
+   NULL,                       /* fixups */
+   NULL                                /* logger */
+};
diff --git a/RELEASE_1_1_X/src/modules/standard/mod_negotiation.c b/RELEASE_1_1_X/src/modules/standard/mod_negotiation.c
new file mode 100644 (file)
index 0000000..77f1cbd
--- /dev/null
@@ -0,0 +1,1122 @@
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * mod_negotiation.c: keeps track of MIME types the client is willing to
+ * accept, and contains code to handle type arbitration.
+ *
+ * rst
+ */
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_request.h"
+#include "http_core.h"
+#include "http_log.h"
+
+/* Commands --- configuring document caching on a per (virtual?)
+ * server basis...
+ */
+
+typedef struct {
+    array_header *language_priority;
+} neg_dir_config;
+
+module negotiation_module;
+
+void *create_neg_dir_config (pool *p, char *dummy)
+{
+    neg_dir_config *new =
+      (neg_dir_config *) palloc (p, sizeof (neg_dir_config));
+
+    new->language_priority = make_array (p, 4, sizeof (char *));
+    return new;
+}
+
+void *merge_neg_dir_configs (pool *p, void *basev, void *addv)
+{
+    neg_dir_config *base = (neg_dir_config *)basev;
+    neg_dir_config *add = (neg_dir_config *)addv;
+    neg_dir_config *new =
+      (neg_dir_config *) palloc (p, sizeof (neg_dir_config));
+
+    /* give priority to the config in the subdirectory */
+    new->language_priority = append_arrays (p, add->language_priority,
+                                           base->language_priority);
+    return new;
+}
+
+char *set_language_priority (cmd_parms *cmd, void *n, char *lang)
+{
+    array_header *arr = ((neg_dir_config *) n)->language_priority;
+    char **langp = (char **) push_array (arr);
+
+    *langp = pstrdup (arr->pool, lang);
+    return NULL;
+}
+
+char *cache_negotiated_docs (cmd_parms *cmd, void *dummy, char *dummy2)
+{
+    void *server_conf = cmd->server->module_config;
+    
+    set_module_config (server_conf, &negotiation_module, "Cache");
+    return NULL;
+}
+
+int do_cache_negotiated_docs (server_rec *s)
+{
+    return (get_module_config (s->module_config, &negotiation_module) != NULL);
+}
+
+command_rec negotiation_cmds[] = {
+{ "CacheNegotiatedDocs", cache_negotiated_docs, NULL, RSRC_CONF, RAW_ARGS,
+    NULL },
+{ "LanguagePriority", set_language_priority, NULL, OR_FILEINFO, ITERATE,
+    NULL },
+{ NULL }
+};
+
+/*
+ * TO DO --- error code 406.  Unfortunately, the specification for
+ *           a 406 reply in the current draft standard is unworkable;
+ *           we return 404 for these pending a workable spec. 
+ */
+
+/* Record of available info on a media type specified by the client
+ * (we also use 'em for encodings and languages)
+ */
+
+typedef struct accept_rec {
+    char *type_name;
+    float quality;
+    float max_bytes;
+    float level;
+} accept_rec;
+
+/* Record of available info on a particular variant
+ *
+ * Note that a few of these fields are updated by the actual negotiation
+ * code.  These are:
+ *
+ * quality --- initialized to the value of qs, and subsequently jiggered
+ *             to reflect the client's preferences.  In particular, it
+ *             gets zeroed out if the variant has an unacceptable content
+ *             encoding, or if it is in a language which the client
+ *             doesn't accept and some other variant *is* in a language
+ *             the client accepts.
+ *
+ * level_matched --- initialized to zero.  Set to the value of level
+ *             if the client actually accepts this media type at that
+ *             level (and *not* if it got in on a wildcard).  See level_cmp
+ *             below.
+ */
+
+typedef struct var_rec {
+    request_rec *sub_req;      /* May be NULL (is, for map files) */
+    char *type_name;
+    char *file_name;
+    char *content_encoding;
+    char *content_language;
+    float level;               /* Auxiliary to content-type... */
+    float qs;
+    float bytes;
+    int lang_index;
+    int is_pseudo_html;                /* text/html, *or* the INCLUDES_MAGIC_TYPEs */
+
+    /* Above are all written-once properties of the variant.  The
+     * three fields below are changed during negotiation:
+     */
+    
+    float quality;     
+    float level_matched;
+    int mime_stars;
+} var_rec;
+
+/* Something to carry around the state of negotiation (and to keep
+ * all of this thread-safe)...
+ */
+
+typedef struct {
+    pool *pool;
+    request_rec *r;
+    char *dir_name;
+    
+    array_header *accepts;     /* accept_recs */
+    array_header *accept_encodings;    /* accept_recs */
+    array_header *accept_langs;        /* accept_recs */
+    array_header *avail_vars;  /* available variants */
+} negotiation_state;
+
+/* A few functions to manipulate var_recs.
+ * Cleaning out the fields...
+ */
+
+void clean_var_rec (var_rec *mime_info)
+{
+    mime_info->sub_req = NULL;
+    mime_info->type_name = "";
+    mime_info->file_name = "";
+    mime_info->content_encoding = "";
+    mime_info->content_language = "";
+
+    mime_info->is_pseudo_html = 0;
+    mime_info->level = 0.0;
+    mime_info->level_matched = 0.0;
+    mime_info->qs = 0.0;
+    mime_info->quality = 0.0;
+    mime_info->bytes = 0;
+    mime_info->lang_index = -1;
+    mime_info->mime_stars = 0;
+}
+
+/* Initializing the relevant fields of a variant record from the
+ * accept_info read out of its content-type, one way or another.
+ */
+
+void set_mime_fields (var_rec *var, accept_rec *mime_info)
+{
+    var->type_name = mime_info->type_name;
+    var->qs = mime_info->quality;
+    var->quality = mime_info->quality; /* Initial quality is just qs */
+    var->level = mime_info->level;
+
+    var->is_pseudo_html = 
+       (!strcmp (var->type_name, "text/html")
+        || !strcmp (var->type_name, INCLUDES_MAGIC_TYPE)
+        || !strcmp (var->type_name, INCLUDES_MAGIC_TYPE3));
+}
+
+/*****************************************************************
+ *
+ * Parsing (lists of) media types and their parameters, as seen in
+ * HTTPD header lines and elsewhere.
+ */
+
+/*
+ * Get a single mime type entry --- one media type and parameters;
+ * enter the values we recognize into the argument accept_rec
+ */
+
+char *get_entry (pool *p, accept_rec *result, char *accept_line)
+{
+    result->quality = 1.0;
+    result->max_bytes = 0.0;
+    result->level = 0.0;
+    
+    /* Note that this handles what I gather is the "old format",
+     *
+     *    Accept: text/html text/plain moo/zot
+     *
+     * without any compatibility kludges --- if the token after the
+     * MIME type begins with a semicolon, we know we're looking at parms,
+     * otherwise, we know we aren't.  (So why all the pissing and moaning
+     * in the CERN server code?  I must be missing something).
+     */
+    
+    result->type_name = get_token (p, &accept_line, 0);
+    str_tolower (result->type_name); /* You want case-insensitive,
+                                     * you'll *get* case-insensitive.
+                                     */
+    
+
+    /* KLUDGE!!! Default HTML to level 2.0 unless the browser
+     * *explicitly* says something else.
+     */
+       
+    if (!strcmp (result->type_name, "text/html")
+       && result->level == 0.0)
+       result->level = 2.0;
+    else if (!strcmp (result->type_name, INCLUDES_MAGIC_TYPE))
+       result->level = 2.0;
+    else if (!strcmp (result->type_name, INCLUDES_MAGIC_TYPE3))
+       result->level = 3.0;
+
+    while (*accept_line == ';') {
+       /* Parameters ... */
+
+       char *parm;
+       char *cp;
+           
+       ++accept_line;
+       parm = get_token (p, &accept_line, 1);
+
+       /* Look for 'var = value' --- and make sure the var is in lcase. */
+       
+       for (cp = parm; *cp && !isspace(*cp) && *cp != '='; ++cp)
+           *cp = tolower(*cp);
+
+       if (!*cp) continue;     /* No '='; just ignore it. */
+           
+       *cp++ = '\0';           /* Delimit var */
+       while (*cp && (isspace(*cp) || *cp == '='))
+           ++cp;
+
+       if (*cp == '"') ++cp;
+       
+       if (parm[0] == 'q'
+           && (parm[1] == '\0' || (parm[1] == 's' && parm[2] == '\0')))
+           result->quality = atof(cp);
+       else if (parm[0] == 'm' && parm[1] == 'x' &&
+                parm[2] == 'b' && parm[3] == '\0')
+           result->max_bytes = atof(cp);
+       else if (parm[0] == 'l' && !strcmp (&parm[1], "evel"))
+           result->level = atof(cp);
+    }
+
+    if (*accept_line == ',') ++accept_line;
+
+    return accept_line;
+}
+                
+
+/*****************************************************************
+ *
+ * Dealing with header lines ...
+ */
+
+array_header *do_header_line (pool *p, char *accept_line)
+{
+    array_header *accept_recs = make_array (p, 40, sizeof (accept_rec));
+  
+    if (!accept_line) return accept_recs;
+    
+    while (*accept_line) {
+        accept_rec *new = (accept_rec *)push_array (accept_recs);
+       accept_line = get_entry (p, new, accept_line);
+    }
+
+    return accept_recs;
+}
+
+/*****************************************************************
+ *
+ * Handling header lines from clients...
+ */
+
+negotiation_state *parse_accept_headers (request_rec *r)
+{
+    negotiation_state *new =
+        (negotiation_state *)palloc (r->pool, sizeof (negotiation_state));
+    table *hdrs = r->headers_in;
+
+    new->pool = r->pool;
+    new->r = r;
+    new->dir_name = make_dirstr(r->pool, r->filename, count_dirs(r->filename));
+    
+    new->accepts = do_header_line (r->pool, table_get (hdrs, "Accept"));
+    new->accept_encodings =
+      do_header_line (r->pool, table_get (hdrs, "Accept-encoding"));
+    new->accept_langs =
+      do_header_line (r->pool, table_get (hdrs, "Accept-language"));
+    new->avail_vars = make_array (r->pool, 40, sizeof (var_rec));
+
+    return new;
+}
+
+/* Sometimes clients will give us no Accept info at all; this routine sets
+ * up the standard default for that case, and also arranges for us to be
+ * willing to run a CGI script if we find one.  (In fact, we set up to
+ * dramatically prefer CGI scripts in cases where that's appropriate,
+ * e.g., POST).
+ */
+
+void maybe_add_default_encodings(negotiation_state *neg, int prefer_scripts)
+{
+    accept_rec *new_accept = (accept_rec *)push_array (neg->accepts); 
+  
+    new_accept->type_name = CGI_MAGIC_TYPE;
+    new_accept->quality = prefer_scripts ? 1e-20 : 1e20;
+    new_accept->level = 0.0;
+    new_accept->max_bytes = 0.0;
+
+    if (neg->accepts->nelts > 1) return;
+    
+    new_accept = (accept_rec *)push_array (neg->accepts); 
+    
+    new_accept->type_name = "*/*";
+    new_accept->quality = 1.0;
+    new_accept->level = 0.0;
+    new_accept->max_bytes = 0.0;
+}
+
+/*****************************************************************
+ *
+ * Parsing type-map files, in Roy's meta/http format augmented with
+ * #-comments.
+ */
+
+/* Reading RFC822-style header lines, ignoring #-comments and
+ * handling continuations.
+ */
+
+enum header_state { header_eof, header_seen, header_sep };
+
+enum header_state get_header_line (char *buffer, int len, FILE *map)
+{
+    char *buf_end = buffer + len;
+    char *cp;
+    int c;
+    
+    /* Get a noncommented line */
+    
+    do {
+       if (fgets(buffer, MAX_STRING_LEN, map) == NULL)
+           return header_eof;
+    } while (buffer[0] == '#');
+    
+    /* If blank, just return it --- this ends information on this variant */
+    
+    for (cp = buffer; *cp && isspace (*cp); ++cp)
+      continue;
+
+    if (*cp == '\0') return header_sep;
+
+    /* If non-blank, go looking for header lines, but note that we still
+     * have to treat comments specially...
+     */
+
+    cp += strlen(cp);
+    
+    while ((c = getc(map)) != EOF)
+    {
+       if (c == '#') {
+           /* Comment line */
+           while ((c = getc(map)) != EOF && c != '\n')
+              continue;
+       } else if (isspace(c)) {
+           /* Leading whitespace.  POSSIBLE continuation line
+            * Also, possibly blank --- if so, we ungetc() the final newline
+            * so that we will pick up the blank line the next time 'round.
+            */
+           
+           while (c != EOF && c != '\n' && isspace(c))
+               c = getc(map);
+
+           ungetc (c, map);
+           
+           if (c == '\n') return header_seen; /* Blank line */
+
+           /* Continuation */
+
+           while (cp < buf_end - 2 && (c = getc(map)) != EOF && c != '\n')
+               *cp++ = c;
+
+           *cp++ = '\n';
+           *cp = '\0';
+       } else {
+
+           /* Line beginning with something other than whitespace */
+           
+           ungetc (c, map);
+           return header_seen;
+       }
+    }
+
+    return header_seen;
+}
+
+/* Stripping out RFC822 comments */
+
+void strip_paren_comments (char *hdr)
+{
+    /* Hmmm... is this correct?  In Roy's latest draft, (comments) can nest! */
+  
+    while (*hdr) {
+       if (*hdr == '"') {
+           while (*++hdr && *hdr != '"')
+               continue;
+           ++hdr;
+       }
+       else if (*hdr == '(') {
+           while (*hdr && *hdr != ')') *hdr++ = ' ';
+           
+           if (*hdr) *hdr++ = ' ';
+       }
+       else ++hdr;
+    }
+}
+
+/* Getting to a header body from the header */
+
+char *lcase_header_name_return_body (char *header, request_rec *r)
+{
+    char *cp = header;
+    
+    while (*cp && *cp != ':')
+        *cp++ = tolower(*cp);
+    
+    if (!*cp) {
+       log_reason ("Syntax error in type map --- no ':'", r->filename, r);
+       return NULL;
+    }
+
+    do ++cp; while (*cp && isspace (*cp));
+
+    if (!*cp) {
+       log_reason ("Syntax error in type map --- no header body",
+                   r->filename, r);
+       return NULL;
+    }
+
+    return cp;
+}
+
+int read_type_map (negotiation_state *neg, char *map_name)
+{
+    request_rec *r = neg->r;
+    FILE *map = pfopen (neg->pool, map_name, "r");
+
+    char buffer[MAX_STRING_LEN];
+    enum header_state hstate;
+    struct var_rec mime_info;
+    
+    if (map == NULL) {
+        log_reason("cannot access type map file", map_name, r);
+       return FORBIDDEN;
+    }
+
+    clean_var_rec (&mime_info);
+    
+    do {
+       hstate = get_header_line (buffer, MAX_STRING_LEN, map);
+       
+       if (hstate == header_seen) {
+           char *body = lcase_header_name_return_body (buffer, neg->r);
+           
+           if (body == NULL) return SERVER_ERROR;
+           
+           strip_paren_comments (body);
+           
+           if (!strncmp (buffer, "uri:", 4)) {
+               mime_info.file_name = get_token (neg->pool, &body, 0);
+           }
+           else if (!strncmp (buffer, "content-type:", 13)) {
+               struct accept_rec accept_info;
+               
+               get_entry (neg->pool, &accept_info, body);
+               set_mime_fields (&mime_info, &accept_info);
+           }
+           else if (!strncmp (buffer, "content-length:", 15)) {
+               mime_info.bytes = atoi(body);
+           }
+           else if (!strncmp (buffer, "content-language:", 17)) {
+               mime_info.content_language = get_token (neg->pool, &body, 0);
+               str_tolower (mime_info.content_language);
+           }
+           else if (!strncmp (buffer, "content-encoding:", 17)) {
+               mime_info.content_encoding = get_token (neg->pool, &body, 0);
+               str_tolower (mime_info.content_encoding);
+           }
+       } else {
+           if (mime_info.quality > 0) {
+               void *new_var = push_array (neg->avail_vars);
+               memcpy (new_var, (void *)&mime_info, sizeof (var_rec));
+           }
+           
+           clean_var_rec(&mime_info);
+       }
+    } while (hstate != header_eof);
+    
+    pfclose (neg->pool, map);
+    return OK;
+}
+
+/*****************************************************************
+ *
+ * Same, except we use a filtered directory listing as the map...
+ */
+
+int read_types_multi (negotiation_state *neg)
+{
+    request_rec *r = neg->r;
+    
+    char *filp;
+    int prefix_len;
+    DIR *dirp;
+    struct DIR_TYPE *dir_entry;
+    struct var_rec mime_info;
+    struct accept_rec accept_info;
+    void *new_var;
+
+    clean_var_rec (&mime_info);
+
+    if (!(filp = strrchr (r->filename, '/'))) return DECLINED; /* Weird... */
+
+    ++filp;
+    prefix_len = strlen (filp);
+
+    dirp = opendir (neg->dir_name); /* Not pool protected; sigh... */
+
+    if (dirp == NULL) {
+        log_reason("cannot read directory for multi", neg->dir_name, r);
+       return FORBIDDEN;
+    }
+
+    while ((dir_entry = readdir (dirp))) {
+       
+        request_rec *sub_req;
+      
+       /* Do we have a match? */
+       
+       if (strncmp (dir_entry->d_name, filp, prefix_len)) continue;
+       if (dir_entry->d_name[prefix_len] != '.') continue;
+       
+       /* Yep.  See if it's something which we have access to, and 
+        * which has a known type and encoding (as opposed to something
+        * which we'll be slapping default_type on later).
+        */
+       
+       sub_req = sub_req_lookup_file (dir_entry->d_name, r);
+
+       /* If it has a handler, we'll pretend it's a CGI script,
+        * since that's a good indication of the sort of thing it
+        * might be doing.
+        */
+       if (sub_req->handler && !sub_req->content_type)
+         sub_req->content_type = CGI_MAGIC_TYPE;
+
+       if (sub_req->status != 200 || !sub_req->content_type) continue;
+       
+       /* If it's a map file, we use that instead of the map
+        * we're building...
+        */
+
+       if (((sub_req->content_type) &&
+            !strcmp (sub_req->content_type, MAP_FILE_MAGIC_TYPE)) || 
+           ((sub_req->handler) && 
+           !strcmp (sub_req->handler, "type-map"))) {
+           closedir(dirp);
+           
+           neg->avail_vars->nelts = 0;
+           return read_type_map (neg, sub_req->filename);
+       }
+       
+       /* Have reasonable variant --- gather notes.
+        */
+       
+       mime_info.sub_req = sub_req;
+       mime_info.file_name = pstrdup(neg->pool, dir_entry->d_name);
+       mime_info.content_encoding = sub_req->content_encoding;
+       mime_info.content_language = sub_req->content_language;
+       
+       get_entry (neg->pool, &accept_info, sub_req->content_type);
+       set_mime_fields (&mime_info, &accept_info);
+       
+       new_var = push_array (neg->avail_vars);
+       memcpy (new_var, (void *)&mime_info, sizeof (var_rec));
+           
+       clean_var_rec(&mime_info);
+    }
+
+    closedir(dirp);
+    return OK;
+}
+
+
+/*****************************************************************
+ * And now for the code you've been waiting for... actually
+ * finding a match to the client's requirements.
+ */
+
+/* Matching MIME types ... the star/star and foo/star commenting conventions
+ * are implemented here.  (You know what I mean by star/star, but just
+ * try mentioning those three characters in a C comment).  Using strcmp()
+ * is legit, because everything has already been smashed to lowercase.
+ *
+ * Note also that if we get an exact match on the media type, we update
+ * level_matched for use in level_cmp below...
+ * 
+ * We also give a value for mime_stars, which is used later. It should
+ * be 1 for star/star, 2 for type/star and 3 for type/subtype.
+ */
+
+int mime_match (accept_rec *accept, var_rec *avail)
+{
+    char *accept_type = accept->type_name;
+    char *avail_type = avail->type_name;
+    int len = strlen(accept_type);
+  
+    if (accept_type[0] == '*') { /* Anything matches star/star */
+        if (avail->mime_stars < 1)
+         avail->mime_stars = 1;
+       return 1; 
+    }
+    else if ((accept_type[len - 1] == '*') &&
+            !strncmp (accept_type, avail_type, len - 2)) {
+        if (avail->mime_stars < 2)
+         avail->mime_stars = 2;
+       return 1;
+    }
+    else if (!strcmp (accept_type, avail_type)
+            || (!strcmp (accept_type, "text/html")
+                && (!strcmp(avail_type, INCLUDES_MAGIC_TYPE)
+                    || !strcmp(avail_type, INCLUDES_MAGIC_TYPE3)))) {
+       if (accept->level >= avail->level) {
+           avail->level_matched = avail->level;
+           avail->mime_stars = 3;
+           return 1;
+       }
+    }
+
+    return OK;
+}
+
+/* This code implements a piece of the tie-breaking algorithm between
+ * variants of equal quality.  This piece is the treatment of variants
+ * of the same base media type, but different levels.  What we want to
+ * return is the variant at the highest level that the client explicitly
+ * claimed to accept.
+ *
+ * If all the variants available are at a higher level than that, or if
+ * the client didn't say anything specific about this media type at all
+ * and these variants just got in on a wildcard, we prefer the lowest
+ * level, on grounds that that's the one that the client is least likely
+ * to choke on.
+ *
+ * (This is all motivated by treatment of levels in HTML --- we only
+ * want to give level 3 to browsers that explicitly ask for it; browsers
+ * that don't, including HTTP/0.9 browsers that only get the implicit
+ * "Accept: * / *" [space added to avoid confusing cpp --- no, that
+ * syntax doesn't really work] should get HTML2 if available).
+ *
+ * (Note that this code only comes into play when we are choosing among
+ * variants of equal quality, where the draft standard gives us a fair
+ * bit of leeway about what to do.  It ain't specified by the standard;
+ * rather, it is a choice made by this server about what to do in cases
+ * where the standard does not specify a unique course of action).
+ */
+
+int level_cmp (var_rec *var1, var_rec *var2)
+{
+    /* Levels are only comparable between matching media types */
+
+    if (var1->is_pseudo_html && !var2->is_pseudo_html)
+       return 0;
+    
+    if (!var1->is_pseudo_html && strcmp (var1->type_name, var2->type_name))
+       return 0;
+    
+    /* Take highest level that matched, if either did match. */
+    
+    if (var1->level_matched > var2->level_matched) return 1;
+    if (var1->level_matched < var2->level_matched) return -1;
+
+    /* Neither matched.  Take lowest level, if there's a difference. */
+
+    if (var1->level < var2->level) return 1;
+    if (var1->level > var2->level) return -1;
+
+    /* Tied */
+
+    return 0;
+}
+
+/* Finding languages.  Note that we only match the substring specified
+ * by the Accept: line --- this is to allow "en" to match all subvariants
+ * of English.
+ *
+ * Again, strcmp() is legit because we've ditched case already.
+ */
+
+int find_lang_index (array_header *accept_langs, char *lang)
+{
+    accept_rec *accs;
+    int i;
+
+    if (!lang)
+       return -1;
+
+    accs = (accept_rec *)accept_langs->elts;
+
+    for (i = 0; i < accept_langs->nelts; ++i)
+       if (!strncmp (lang, accs[i].type_name, strlen(accs[i].type_name)))
+           return i;
+           
+    return -1;         
+}
+
+/* This function returns the priority of a given language
+ * according to LanguagePriority.  It is used in case of a tie
+ * between several languages.
+ */
+
+int find_default_index (neg_dir_config *conf, char *lang)
+{
+    array_header *arr;
+    int nelts;
+    char **elts;
+    int i;
+
+    if (!lang)
+       return -1;
+
+    arr = conf->language_priority;
+    nelts = arr->nelts;
+    elts = (char **) arr->elts;
+
+    for (i = 0; i < nelts; ++i)
+        if (!strcasecmp (elts[i], lang))
+           return i;
+
+    return -1;
+}
+
+void find_lang_indexes (negotiation_state *neg)
+{
+    var_rec *var_recs = (var_rec*)neg->avail_vars->elts;
+    int i;
+    int found_any = 0;
+    neg_dir_config *conf = NULL;
+    int naccept = neg->accept_langs->nelts;
+
+    if (naccept == 0)
+       conf = (neg_dir_config *) get_module_config (neg->r->per_dir_config,
+                                                    &negotiation_module);
+
+    for (i = 0; i < neg->avail_vars->nelts; ++i)
+       if (var_recs[i].quality > 0) {
+           int index;
+           if (naccept == 0)           /* Client doesn't care */
+               index = find_default_index (conf,
+                                           var_recs[i].content_language);
+           else                        /* Client has Accept-Language */
+               index = find_lang_index (neg->accept_langs,
+                                        var_recs[i].content_language);
+
+           var_recs[i].lang_index = index;
+           if (index >= 0) found_any = 1;
+       }
+
+    /* If we have any variants in a language acceptable to the client,
+     * blow away everything that isn't.
+     */
+    
+    if (found_any)
+       for (i = 0; i < neg->avail_vars->nelts; ++i) 
+           if (var_recs[i].lang_index < 0)
+               var_recs[i].quality = 0;
+}
+
+/* Finding content encodings.  Note that we assume that the client
+ * accepts the trivial encodings.  Strcmp() is legit because... aw, hell.
+ */
+
+int is_identity_encoding (char *enc)
+{
+    return (!enc || !enc[0] || !strcmp (enc, "7bit") || !strcmp (enc, "8bit")
+           || !strcmp (enc, "binary"));
+}
+
+int find_encoding (array_header *accept_encodings, char *enc)
+{
+    accept_rec *accs = (accept_rec *)accept_encodings->elts;
+    int i;
+
+    if (is_identity_encoding(enc)) return 1;
+
+    for (i = 0; i < accept_encodings->nelts; ++i)
+       if (!strcmp (enc, accs[i].type_name))
+           return 1;
+
+    return 0;
+}
+
+void do_encodings (negotiation_state *neg)
+{
+    var_rec *var_recs = (var_rec*)neg->avail_vars->elts;
+    int i;
+
+    /* If no Accept-Encoding is present, everything is acceptable */
+
+    if (!neg->accept_encodings->nelts)
+       return;
+
+    /* Lose any variant with an unacceptable content encoding */
+    
+    for (i = 0; i < neg->avail_vars->nelts; ++i)
+       if (var_recs[i].quality > 0
+           && !find_encoding (neg->accept_encodings,
+                              var_recs[i].content_encoding))
+           
+           var_recs[i].quality = 0;
+}
+
+/* Determining the content length --- if the map didn't tell us,
+ * we have to do a stat() and remember for next time.
+ *
+ * Grump.  For shambhala, even the first stat here may well be
+ * redundant (for multiviews) with a stat() done by the sub_req
+ * machinery.  At some point, that ought to be fixed.
+ */
+
+int find_content_length(negotiation_state *neg, var_rec *variant)
+{
+    struct stat statb;
+
+    if (variant->bytes == 0) {
+        char *fullname = make_full_path (neg->pool, neg->dir_name,
+                                        variant->file_name);
+       
+       if (stat (fullname, &statb) >= 0) variant->bytes = statb.st_size;
+    }
+
+    return variant->bytes;
+}
+
+/* The main event. */
+
+var_rec *best_match(negotiation_state *neg)
+{
+    int i, j;
+    var_rec *best = NULL;
+    float best_quality = 0.0;
+    int levcmp;
+    
+    accept_rec *accept_recs = (accept_rec *)neg->accepts->elts;
+    var_rec *avail_recs = (var_rec *)neg->avail_vars->elts;
+
+    /* Nuke variants which are unsuitable due to a content encoding,
+     * or possibly a language, which the client doesn't accept.
+     * (If we haven't *got* a variant in a language the client accepts,
+     * find_lang_indexes keeps 'em all, so we still wind up serving
+     * something...).
+     */
+    
+    do_encodings (neg);
+    find_lang_indexes (neg);
+    
+    for (i = 0; i < neg->accepts->nelts; ++i) {
+
+       accept_rec *type = &accept_recs[i];
+       
+       for (j = 0; j < neg->avail_vars->nelts; ++j) {
+           
+           var_rec *variant = &avail_recs[j];
+           float q = type->quality * variant->quality;
+               
+           /* If we've already rejected this variant, don't waste time */
+           
+           if (q == 0.0) continue;     
+           
+           /* If media types don't match, forget it.
+            * (This includes the level check).
+            */
+           
+           if (!mime_match(type, variant)) continue;
+
+           /* Check maxbytes */
+               
+           if (type->max_bytes > 0
+               && (find_content_length(neg, variant)
+                   > type->max_bytes))
+               continue;
+               
+           /* If it lasted this far, consider it ---
+            * If better quality than our current best, take it.
+            * If equal quality, *maybe* take it.
+            *
+            * Note that the current http draft specifies no particular
+            * behavior for variants which tie in quality; the server
+            * can, at its option, return a 300 response listing all
+            * of them (and perhaps the others), or choose one of the
+            * tied variants by whatever means it likes.  This server
+            * breaks ties as follows, in order:
+            *
+            * By perferring non-wildcard entries to those with
+            * wildcards. The spec specifically says we should
+            * do this, and it makes a lot of sense.
+            *
+            * By order of languages in Accept-language, to give the
+            * client a way to specify a language preference.  I'd prefer
+            * to give this precedence over media type, but the standard
+            * doesn't allow for that.
+            *
+            * By level preference, as defined by level_cmp above.
+            *
+            * By order of Accept: header matched, so that the order in
+            * which media types are named by the client functions as a
+            * preference order, if the client didn't give us explicit
+            * quality values.
+            *
+            * Finally, by content_length, so that among variants which
+            * have the same quality, language and content_type (including
+            * level) we ship the one that saps the least bandwidth.
+            */
+               
+           if (q > best_quality
+               || (q == best_quality
+                   && ((variant->mime_stars > best->mime_stars)
+                       || (variant->lang_index < best->lang_index
+                           || (variant->lang_index == best->lang_index
+                               && ((levcmp = level_cmp (variant, best)) == 1
+                                   || (levcmp == 0
+                                       && !strcmp (variant->type_name,
+                                                   best->type_name)
+                                       && (find_content_length(neg, variant)
+                                           <
+                               find_content_length(neg, best)))))))))
+           {
+               best = variant;
+               best_quality = q;
+           }
+       }
+    }
+
+    return best;
+}
+
+/****************************************************************
+ *
+ * Executive...
+ */
+
+int handle_map_file (request_rec *r)
+{
+    negotiation_state *neg = parse_accept_headers (r);
+    var_rec *best;
+    int res;
+    
+    char *udir;
+    
+    if ((res = read_type_map (neg, r->filename))) return res;
+    
+    maybe_add_default_encodings(neg, 0);
+    
+    if (!(best = best_match(neg))) {
+      /* Should be a 406 */
+      log_reason ("no acceptable variant", r->filename, r);
+      return NOT_FOUND;
+    }
+
+    if (!do_cache_negotiated_docs(r->server)) r->no_cache = 1;
+    udir = make_dirstr (r->pool, r->uri, count_dirs (r->uri));
+    udir = escape_uri(r->pool, udir);
+    internal_redirect (make_full_path (r->pool, udir, best->file_name), r);
+    return OK;
+}
+
+int handle_multi (request_rec *r)
+{
+    negotiation_state *neg;
+    var_rec *best;
+    request_rec *sub_req;
+    int res;
+    
+    if (r->finfo.st_mode != 0 || !(allow_options (r) & OPT_MULTI))
+        return DECLINED;
+    
+    neg = parse_accept_headers (r);
+    
+    if ((res = read_types_multi (neg))) return res;
+    
+    maybe_add_default_encodings(neg,
+                               r->method_number != M_GET
+                                 || r->args || r->path_info);
+    
+    if (neg->avail_vars->nelts == 0) return DECLINED;
+    
+    if (!(best = best_match(neg))) {
+      /* Should be a 406 */
+      log_reason ("no acceptable variant", r->filename, r);
+      return NOT_FOUND;
+    }
+
+    if (! (sub_req = best->sub_req)) {
+        /* We got this out of a map file, so we don't actually have
+        * a sub_req structure yet.  Get one now.
+        */
+      
+        sub_req = sub_req_lookup_file (best->file_name, r);
+       if (sub_req->status != 200) return sub_req->status;
+    }
+      
+    /* BLETCH --- don't multi-resolve non-ordinary files */
+
+    if (!S_ISREG(sub_req->finfo.st_mode)) return NOT_FOUND;
+    
+    /* Otherwise, use it. */
+    
+    if (!do_cache_negotiated_docs(r->server)) r->no_cache = 1;
+    r->filename = sub_req->filename;
+    r->content_type = sub_req->content_type;
+    r->content_encoding = sub_req->content_encoding;
+    r->content_language = sub_req->content_language;
+    r->finfo = sub_req->finfo;
+    
+    return OK;
+}
+
+handler_rec negotiation_handlers[] = {
+{ MAP_FILE_MAGIC_TYPE, handle_map_file },
+{ "type-map", handle_map_file },
+{ NULL }
+};
+
+module negotiation_module = {
+   STANDARD_MODULE_STUFF,
+   NULL,                       /* initializer */
+   create_neg_dir_config,      /* dir config creater */
+   merge_neg_dir_configs,      /* dir merger --- default is to override */
+   NULL,                       /* server config */
+   NULL,                       /* merge server config */
+   negotiation_cmds,           /* command table */
+   negotiation_handlers,       /* handlers */
+   NULL,                       /* filename translation */
+   NULL,                       /* check_user_id */
+   NULL,                       /* check auth */
+   NULL,                       /* check access */
+   handle_multi,               /* type_checker */
+   NULL,                       /* fixups */
+   NULL                                /* logger */
+};
diff --git a/RELEASE_1_1_X/src/modules/standard/mod_status.c b/RELEASE_1_1_X/src/modules/standard/mod_status.c
new file mode 100644 (file)
index 0000000..5a324fa
--- /dev/null
@@ -0,0 +1,591 @@
+/* ====================================================================
+ * Copyright (c) 1995, 1996 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+/* Status Module.  Provide a way of getting at the internal Apache
+ * status information without having to worry where the scoreboard is
+ * held.
+ *
+ * AddType application/x-httpd-status .status
+ * You might like to do this in a .htaccess in a protected directory only
+ *
+ * GET /.status - Returns pretty page for system admin user
+ * GET /.status?refresh - Returns page with 1 second refresh
+ * GET /.status?refresh=6 - Returns page with refresh every 6 seconds
+ * GET /.status?auto - Returns page with data for automatic parsing
+ * GET /.status?notable - Returns page with no table niceties
+ *
+ * Mark Cox, mark@ukweb.com, November 1995
+ *
+ * 12.11.95 Initial version for telescope.org
+ * 13.3.96  Updated to remove rprintf's [Mark]
+ * 18.3.96  Added CPU usage, process information, and tidied [Ben Laurie]
+ * 18.3.96  Make extra Scoreboard variables #definable
+ * 25.3.96  Make short report have full precision [Ben Laurie suggested]
+ * 25.3.96  Show uptime better [Mark/Ben Laurie]
+ * 29.3.96  Better HTML and explanation [Mark/Rob Hartill suggested]
+ * 09.4.96  Added message for non-STATUS compiled version
+ * 18.4.96  Added per child and per slot counters [Jim Jagielski]
+ * 01.5.96  Table format, cleanup, even more spiffy data [Chuck Murcko/Jim J.]
+ * 18.5.96  Adapted to use new rprintf() routine, incidentally fixing a missing
+ *          piece in short reports [Ben Laurie]
+ * 21.5.96  Additional Status codes (DNS and LOGGING only enabled if
+             extended STATUS is enabled) [George Burgyan/Jim J.]
+ */
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_core.h"
+#include "http_protocol.h"
+#include "http_main.h"
+#include "util_script.h"
+#include <time.h>
+#include "scoreboard.h"
+
+#ifdef NEXT
+#include <machine/param.h>
+#endif
+
+#define STATUS_MAXLINE         50
+
+#define KBYTE                  1024
+#define        MBYTE                   1048576L
+#define        GBYTE                   1073741824L
+
+module status_module;
+
+/* Format the number of bytes nicely */
+
+void format_byte_out(request_rec *r,unsigned long bytes)
+{
+    if (bytes < (5 * KBYTE))
+       rprintf(r,"%d B",(int)bytes);
+    else if (bytes < (MBYTE / 2))
+       rprintf(r,"%.1f kB",(float)bytes/KBYTE);
+    else if (bytes < (GBYTE / 2))
+       rprintf(r,"%.1f MB",(float)bytes/MBYTE);
+    else
+       rprintf(r,"%.1f GB",(float)bytes/GBYTE);
+}
+
+void show_time(request_rec *r,time_t tsecs)
+{
+    long days,hrs,mins,secs;
+    char buf[100];
+    char *s;
+
+    secs=tsecs%60;
+    tsecs/=60;
+    mins=tsecs%60;
+    tsecs/=60;
+    hrs=tsecs%24;
+    days=tsecs/24;
+    s=buf;
+    *s='\0';
+    if(days)
+       rprintf(r," %ld day%s",days,days==1?"":"s");
+    if(hrs)
+       rprintf(r," %ld hour%s",hrs,hrs==1?"":"s");
+    if(mins)
+       rprintf(r," %ld minute%s",mins,mins==1?"":"s");
+    if(secs)
+       rprintf(r," %ld second%s",secs,secs==1?"":"s");
+}
+
+#if defined(SUNOS4)
+double
+difftime(time1, time0)
+        time_t time1, time0;
+{   
+        return(time1 - time0);
+}   
+#endif
+    
+/* Main handler for x-httpd-status requests */
+
+/* ID values for command table */
+
+#define STAT_OPT_END           -1
+#define STAT_OPT_REFRESH       0
+#define STAT_OPT_NOTABLE       1
+#define STAT_OPT_AUTO          2
+
+struct stat_opt
+{
+    int id;
+    char *form_data_str;
+    char *hdr_out_str;
+};
+
+int status_handler (request_rec *r)
+{
+    struct stat_opt options[] =        /* see #defines above */
+    {
+       { STAT_OPT_REFRESH, "refresh", "Refresh" },
+        { STAT_OPT_NOTABLE, "notable", NULL },
+        { STAT_OPT_AUTO, "auto", NULL },
+       { STAT_OPT_END, NULL, NULL }
+    };
+    char *loc;
+    time_t nowtime=time(NULL);
+    time_t up_time;
+    int i,res;
+    int ready=0;
+    int busy=0;
+#if defined(STATUS)
+    unsigned long count=0;
+    unsigned long lres,bytes;
+    unsigned long my_lres,my_bytes,conn_bytes;
+    unsigned short conn_lres;
+    unsigned long bcount=0;
+#ifdef NEXT
+    float tick=HZ;
+#else
+    float tick=sysconf(_SC_CLK_TCK);
+#endif
+#endif /* STATUS */
+    int short_report=0;
+    int no_table_report=0;
+    server_rec *server = r->server;
+    short_score score_record;
+    char status[]="??????????";
+    char stat_buffer[HARD_SERVER_LIMIT];
+    clock_t tu,ts,tcu,tcs;
+
+    tu=ts=tcu=tcs=0;
+
+    status[SERVER_DEAD]='.';  /* We don't want to assume these are in */
+    status[SERVER_READY]='_'; /* any particular order in scoreboard.h */
+    status[SERVER_STARTING]='S';
+    status[SERVER_BUSY_READ]='R';
+    status[SERVER_BUSY_WRITE]='W';
+    status[SERVER_BUSY_KEEPALIVE]='K';
+    status[SERVER_BUSY_LOG]='L';
+    status[SERVER_BUSY_DNS]='D';
+
+    if (r->method_number != M_GET) return NOT_IMPLEMENTED;
+    r->content_type = "text/html";
+
+    /*
+     * Simple table-driven form data set parser that lets you alter the header
+     */
+
+    if (r->args)
+    {
+       i = 0;
+        while (options[i].id != STAT_OPT_END)
+        {
+            if ((loc = strstr(r->args,options[i].form_data_str)) != NULL)
+           {
+                switch (options[i].id)
+                {
+                  case STAT_OPT_REFRESH:
+                      if(*(loc + strlen(options[i].form_data_str)) == '=')
+                          table_set(r->headers_out,options[i].hdr_out_str,
+                           loc+strlen(options[i].hdr_out_str)+1);
+                      else
+                          table_set(r->headers_out,options[i].hdr_out_str,"1");
+                      break;
+                  case STAT_OPT_NOTABLE:
+                      no_table_report = 1;
+                      break;
+                  case STAT_OPT_AUTO:
+                      r->content_type = "text/plain";
+                      short_report = 1;
+                      break;
+                }
+           }
+           i++;
+        }
+    }
+
+    soft_timeout ("send status info", r);
+    send_http_header(r);
+
+    if (r->header_only) 
+       return 0;
+
+    sync_scoreboard_image();
+    for (i = 0; i<HARD_SERVER_LIMIT; ++i)
+    {
+        score_record = get_scoreboard_info(i);
+        res = score_record.status;
+       stat_buffer[i] = status[res];
+        if (res == SERVER_READY)
+           ready++;
+        else if (res == SERVER_BUSY_READ || res==SERVER_BUSY_WRITE || 
+                res == SERVER_STARTING || res==SERVER_BUSY_KEEPALIVE ||
+                res == SERVER_BUSY_LOG || res==SERVER_BUSY_DNS)
+           busy++;
+#if defined(STATUS)
+        lres = score_record.access_count;
+       bytes= score_record.bytes_served;
+        if (lres!=0 || (score_record.status != SERVER_READY
+         && score_record.status != SERVER_DEAD))
+       {
+           tu+=score_record.times.tms_utime;
+           ts+=score_record.times.tms_stime;
+           tcu+=score_record.times.tms_cutime;
+           tcs+=score_record.times.tms_cstime;
+            count+=lres;
+           bcount+=bytes;
+       }
+#endif /* STATUS */
+    }
+
+    up_time=nowtime-restart_time;
+
+    if (!short_report)
+    {
+        rputs("<html><head><title>Apache Status</title></head><body>\n",r);
+        rputs("<h1>Apache Server Status for ",r);
+       rvputs(r,server->server_hostname,"</h1>\n\n",NULL);
+       rvputs(r,"Current Time: ",asctime(localtime(&nowtime)),"<br>\n",NULL);
+       rvputs(r,"Restart Time: ",asctime(localtime(&restart_time)),"<br>\n",
+              NULL);
+       rputs("Server uptime: ",r);
+       show_time(r,up_time);
+       rputs("<br>\n",r);
+    }
+
+#if defined(STATUS)
+    if (short_report)
+    {
+        rprintf(r,"Total Accesses: %lu\nTotal Bytes: %lu\n",count,bcount);
+
+       if(ts || tu || tcu || tcs)
+           rprintf(r,"CPULoad: %g\n",(tu+ts+tcu+tcs)/tick/up_time*100.);
+
+       rprintf(r,"Uptime: %ld\n",(long)(up_time));
+       if (up_time>0)
+           rprintf(r,"ReqPerSec: %g\n",(float)count/(float)up_time);
+
+       if (up_time>0)
+           rprintf(r,"BytesPerSec: %g\n",(float)bcount/(float)up_time);
+
+       if (count>0)
+           rprintf(r,"BytesPerReq: %g\n",(float)bcount/(float)count);
+    } else /* !short_report */
+    {
+       rprintf(r,"Total accesses: %lu - Total Traffic: ", count);
+       format_byte_out(r,bcount);
+       rputs("<br>\n",r);
+        rprintf(r,"CPU Usage: u%g s%g cu%g cs%g",
+               tu/tick,ts/tick,tcu/tick,tcs/tick);
+
+       if(ts || tu || tcu || tcs)
+           rprintf(r," - %.3g%% CPU load",(tu+ts+tcu+tcs)/tick/up_time*100.);
+
+       rputs("<br>\n",r);
+
+       if (up_time>0)
+           rprintf(r,"%.3g requests/sec - ",
+                   (float)count/(float)up_time);
+
+       if (up_time>0)
+       {
+           format_byte_out(r,(float)bcount/(float)up_time);
+           rputs("/second - ",r);
+       }
+
+       if (count>0)
+       {
+           format_byte_out(r,(float)bcount/(float)count);
+           rputs("/request",r);
+       }
+
+       rputs("<p>\n",r);
+    } /* short_report */
+#endif /* STATUS */
+
+    /* send the scoreboard 'table' out */
+
+    rputs("Scoreboard: \n",r);
+
+    if(!short_report)
+       rputs("<PRE>",r);
+
+    rputs("\n",r);
+
+    for (i = 0; i<HARD_SERVER_LIMIT; ++i)
+    {
+       rputc(stat_buffer[i], r);
+       if(i%STATUS_MAXLINE == (STATUS_MAXLINE - 1))
+           rputs("\n",r);
+    }
+
+    if (short_report)
+    {
+        rprintf(r,"\nBusyServers: %d\nIdleServers: %d\n",busy,ready);
+    }
+    else 
+    {
+       rputs("</PRE>\n",r);
+       rputs("Key:<br> \n",r);
+       rputs("\"<code>_</code>\" Waiting for Connection, \n",r);
+       rputs("\"<code>S</code>\" Starting up,<br> \n",r);
+       rputs("\"<code>R</code>\" Reading Request, \n",r);
+       rputs("\"<code>W</code>\" Sending Reply,<br> \n",r);
+       rputs("\"<code>K</code>\" Keepalive (read), \n",r);
+       rputs("\"<code>D</code>\" DNS Lookup, \n",r);
+       rputs("\"<code>L</code>\" Logging<p>\n",r);
+        rprintf(r,"\n%d requests currently being processed, %d idle servers\n"
+               ,busy,ready);
+    }
+
+#if defined(STATUS)
+    if (!short_report)
+       if(no_table_report)
+            rputs("<p><hr><h2>Server Details</h2>\n\n",r);
+       else
+            rputs("<p>\n\n<table border=0><tr><th>Srv<th>PID<th>Acc<th>M<th>CPU\n<th>SS<th>Conn<th>Child<th>Slot<th>Host<th>Request</tr>\n\n",r);
+
+
+    for (i = 0; i<HARD_SERVER_LIMIT; ++i)
+    {
+        score_record=get_scoreboard_info(i);
+        lres = score_record.access_count;
+        my_lres = score_record.my_access_count;
+       conn_lres = score_record.conn_count;
+       bytes= score_record.bytes_served;
+       my_bytes = score_record.my_bytes_served;
+       conn_bytes = score_record.conn_bytes;
+        if (lres!=0 || (score_record.status != SERVER_READY
+               && score_record.status != SERVER_DEAD))
+       {
+           if (!short_report)
+           {
+               if (no_table_report)
+               {
+                   rprintf(r,"<b>Server %d</b> (%d): %d|%lu|%lu [",
+                    i,(int)score_record.pid,(int)conn_lres,my_lres,lres);
+
+                   switch (score_record.status)
+                   {
+                       case SERVER_READY:
+                           rputs("Ready",r);
+                           break;
+                       case SERVER_STARTING:
+                           rputs("Starting",r);
+                           break;
+                       case SERVER_BUSY_READ:
+                           rputs("<b>Read</b>",r);
+                           break;
+                       case SERVER_BUSY_WRITE:
+                           rputs("<b>Write</b>",r);
+                           break;
+                       case SERVER_BUSY_KEEPALIVE:
+                           rputs("<b>Keepalive</b>",r);
+                           break;
+                       case SERVER_BUSY_LOG:
+                           rputs("<b>Logging</b>",r);
+                           break;
+                       case SERVER_BUSY_DNS:
+                           rputs("<b>DNS lookup</b>",r);
+                           break;
+                       case SERVER_DEAD:
+                           rputs("Dead",r);
+                           break;
+                   }
+                   rprintf(r,"] u%g s%g cu%g cs%g\n %s (",
+                           score_record.times.tms_utime/tick,
+                           score_record.times.tms_stime/tick,
+                           score_record.times.tms_cutime/tick,
+                           score_record.times.tms_cstime/tick,
+                           asctime(localtime(&score_record.last_used)));
+                   format_byte_out(r,conn_bytes);
+                   rputs("|",r);
+                   format_byte_out(r,my_bytes);
+                   rputs("|",r);
+                   format_byte_out(r,bytes);
+                   rputs(")\n",r);
+                   rprintf(r," <i>%s {%s}</i><br>\n\n",
+                           score_record.client, score_record.request);
+               }
+               else /* !no_table_report */
+               {
+                   rprintf(r,"<tr><td><b>%d</b><td>%d<td>%d/%lu/%lu",
+                    i,(int)score_record.pid,(int)conn_lres,my_lres,lres);
+
+                   switch (score_record.status)
+                   {
+                       case SERVER_READY:
+                           rputs("<td>_",r);
+                           break;
+                       case SERVER_STARTING:
+                           rputs("<td><b>S</b>",r);
+                           break;
+                       case SERVER_BUSY_READ:
+                           rputs("<td><b>R</b>",r);
+                           break;
+                       case SERVER_BUSY_WRITE:
+                           rputs("<td><b>W</b>",r);
+                           break;
+                       case SERVER_BUSY_KEEPALIVE:
+                           rputs("<td><b>K</b>",r);
+                           break;
+                       case SERVER_BUSY_LOG:
+                           rputs("<td><b>L</b>",r);
+                           break;
+                       case SERVER_BUSY_DNS:
+                           rputs("<td><b>D</b>",r);
+                           break;
+                       case SERVER_DEAD:
+                           rputs("<td>.",r);
+                           break;
+                   }
+                   rprintf(r,"\n<td>%.2f<td>%.0f",
+                           (score_record.times.tms_utime +
+                           score_record.times.tms_stime +
+                           score_record.times.tms_cutime +
+                           score_record.times.tms_cstime)/tick,
+                           difftime(nowtime, score_record.last_used));
+                   rprintf(r,"<td>%-1.1f<td>%-2.2f<td>%-2.2f\n",
+                       (float)conn_bytes/KBYTE, (float)my_bytes/MBYTE,
+                       (float)bytes/MBYTE);
+                   rprintf(r,"<td>%s<td nowrap>%s</tr>\n\n",
+                       score_record.client, score_record.request);
+               }       /* no_table_report */
+           }           /* !short_report */
+       }               /* if (<active child>) */
+    }                  /* for () */
+
+    if (!(short_report || no_table_report))
+    {
+       rputs("</table>\n \
+<hr> \
+<table>\n \
+<tr><th>Srv<td>Server number\n \
+<tr><th>PID<td>OS process ID\n \
+<tr><th>Acc<td>Number of accesses this connection / this child / this slot\n \
+<tr><th>M<td>Mode of operation\n \
+<tr><th>CPU<td>CPU usage, number of seconds\n \
+<tr><th>SS<td>Seconds since beginning of most recent request\n \
+<tr><th>Conn<td>Kilobytes transferred this connection\n \
+<tr><th>Child<td>Megabytes transferred this child\n \
+<tr><th>Slot<td>Total megabytes transferred this slot\n \
+</table>\n",r);
+    }
+
+#else /* !defined(STATUS) */
+
+    rputs("<hr>To obtain a full report with current status information \n",r);
+    rputs("you need to recompile Apache adding the <code>-DSTATUS</code> \n",r);
+    rputs("directive on the <code>CFLAGS</code> line in the \n",r);
+    rputs("<code>Configuration</code> file.\n",r);
+    rputs("<code>DNS</code> and <code>LOGGING</code> status \n",r);
+    rputs("also requires the <code>-DSTATUS</code> directive. \n",r);
+
+#endif /* STATUS */
+
+    if (!short_report)
+        rputs("</body></html>",r);
+    return 0;
+}
+
+handler_rec status_handlers[] =
+{
+{ STATUS_MAGIC_TYPE, status_handler },
+{ "server-status", status_handler },
+{ NULL }
+};
+
+module status_module =
+{
+   STANDARD_MODULE_STUFF,
+   NULL,                       /* initializer */
+   NULL,                       /* dir config creater */
+   NULL,                       /* dir merger --- default is to override */
+   NULL,                       /* server config */
+   NULL,                       /* merge server config */
+   NULL,                       /* command table */
+   status_handlers,            /* handlers */
+   NULL,                       /* filename translation */
+   NULL,                       /* check_user_id */
+   NULL,                       /* check auth */
+   NULL,                       /* check access */
+   NULL,                       /* type_checker */
+   NULL,                       /* fixups */
+   NULL                                /* logger */
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/RELEASE_1_1_X/src/modules/standard/mod_userdir.c b/RELEASE_1_1_X/src/modules/standard/mod_userdir.c
new file mode 100644 (file)
index 0000000..320f869
--- /dev/null
@@ -0,0 +1,206 @@
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * mod_userdir... implement the UserDir command.  Broken away from the
+ * Alias stuff for a couple of good and not-so-good reasons:
+ *
+ * 1) It shows a real minimal working example of how to do something like
+ *    this.
+ * 2) I know people who are actually interested in changing this *particular*
+ *    aspect of server functionality without changing the rest of it.  That's
+ *    what this whole modular arrangement is supposed to be good at...
+ *
+ * Modified by Alexei Kosut to support the following constructs
+ * (server running at www.foo.com, request for /~bar/one/two.html)
+ *
+ * UserDir public_html      -> ~bar/public_html/one/two.html
+ * UserDir /usr/web         -> /usr/web/bar/one/two.html
+ * UserDir /home/ * /www     -> /home/bar/www/one/two.html
+ *  NOTE: theses ^ ^ space only added allow it to work in a comment, ignore
+ * UserDir http://x/users   -> (302) http://x/users/bar/one/two.html
+ * UserDir http://x/ * /y     -> (302) http://x/bar/y/one/two.html
+ *  NOTE: here also ^ ^
+ *
+ * In addition, you can use multiple entries, to specify alternate
+ * user directories (a la Directory Index). For example:
+ *
+ * UserDir public_html /usr/web http://www.xyz.com/users
+ *
+ */
+
+#include "httpd.h"
+#include "http_config.h"
+
+module userdir_module;
+
+/*
+ * Sever config for this module is a little unconventional...
+ * It's just one string anyway, so why pretend?
+ */
+
+void *create_userdir_config (pool *dummy, server_rec *s) { 
+    return (void*)DEFAULT_USER_DIR; 
+}
+
+char *set_user_dir (cmd_parms *cmd, void *dummy, char *arg)
+{
+    void *server_conf = cmd->server->module_config;
+    
+    set_module_config (server_conf, &userdir_module, pstrdup (cmd->pool, arg));
+    return NULL;
+}
+
+command_rec userdir_cmds[] = {
+{ "UserDir", set_user_dir, NULL, RSRC_CONF, RAW_ARGS,
+    "the public subdirectory in users' home directories, or 'disabled'" },
+{ NULL }
+};
+
+int translate_userdir (request_rec *r)
+{
+    void *server_conf = r->server->module_config;
+    char *userdirs = (char *)get_module_config(server_conf, &userdir_module);
+    char *name = r->uri;
+    char *w, *dname, *redirect;
+    char *x = NULL;
+
+    if (userdirs == NULL || !strcasecmp(userdirs, "disabled") ||
+        (name[0] != '/') || (name[1] != '~')) {
+      return DECLINED;
+    }
+
+    while (*userdirs) {
+      char *userdir = getword_conf (r->pool, &userdirs);
+      char *filename = NULL;
+
+      dname = name + 2;
+      w = getword(r->pool, &dname, '/');
+
+      if (!strcmp(w, ""))
+       return DECLINED;
+
+      /* The 'dname' funny business involves backing it up to capture
+       * the '/' delimiting the "/~user" part from the rest of the URL,
+       * in case there was one (the case where there wasn't being just
+       * "GET /~user HTTP/1.0", for which we don't want to tack on a
+       * '/' onto the filename).
+       */
+       
+      if (dname[-1] == '/') --dname;
+
+      if (strchr(userdir, '*'))
+       x = getword(r->pool, &userdir, '*');
+
+      if (userdir[0] == '/') {
+       if (x) {
+         if (strchr(x, ':')) {
+           redirect = pstrcat(r->pool, x, w, userdir, dname, NULL);
+           table_set (r->headers_out, "Location", redirect);
+           return REDIRECT;
+         }
+         else
+           filename = pstrcat (r->pool, x, w, userdir, NULL);
+       }
+       else
+         filename = pstrcat (r->pool, userdir, "/", w, NULL);
+      }
+      else if (strchr(userdir, ':')) {
+       redirect = pstrcat(r->pool, userdir, "/", w, dname, NULL);
+       table_set (r->headers_out, "Location", redirect);
+       return REDIRECT;
+      }
+      else {
+       struct passwd *pw;
+       if((pw=getpwnam(w)))
+#ifdef __EMX__
+         /* Need to manually add user name for OS/2 */
+         filename = pstrcat (r->pool, pw->pw_dir, w, "/", userdir, NULL);
+#else
+         filename = pstrcat (r->pool, pw->pw_dir, "/", userdir, NULL);
+#endif
+
+      }
+
+      /* Now see if it exists, or we're at the last entry. If we are at the
+       last entry, then use the filename generated (if there is one) anyway,
+       in the hope that some handler might handle it. This can be used, for
+       example, to run a CGI script for the user. 
+       */
+      if (filename && (!*userdirs || stat(filename, &r->finfo) != -1)) {
+       r->filename = pstrcat(r->pool, filename, dname, NULL);
+       return OK;
+      }
+    }
+
+  return DECLINED;    
+}
+    
+module userdir_module = {
+   STANDARD_MODULE_STUFF,
+   NULL,                       /* initializer */
+   NULL,                       /* dir config creater */
+   NULL,                       /* dir merger --- default is to override */
+   create_userdir_config,      /* server config */
+   NULL,                       /* merge server config */
+   userdir_cmds,               /* command table */
+   NULL,                       /* handlers */
+   translate_userdir,          /*filename translation */
+   NULL,                       /* check_user_id */
+   NULL,                       /* check auth */
+   NULL,                       /* check access */
+   NULL,                       /* type_checker */
+   NULL,                       /* fixups */
+   NULL                                /* logger */
+};
diff --git a/RELEASE_1_1_X/src/support/.cvsignore b/RELEASE_1_1_X/src/support/.cvsignore
new file mode 100644 (file)
index 0000000..0eada2a
--- /dev/null
@@ -0,0 +1,6 @@
+rotatelogs
+htpasswd
+htdigest
+unescape
+inc2shtml
+httpd_monitor
diff --git a/RELEASE_1_1_X/src/support/Makefile b/RELEASE_1_1_X/src/support/Makefile
new file mode 100755 (executable)
index 0000000..5234181
--- /dev/null
@@ -0,0 +1,76 @@
+# For gcc
+CC= gcc
+# For ANSI compilers
+#CC= cc
+
+#For Optimization
+#CFLAGS= -O2
+#For debugging
+CFLAGS= -g
+# For SCO ODT
+#EXTRA_LIBS= -lcrypt_i
+# For OS/2 port
+#EXTRA_LIBS= -llibufc
+
+
+INCLUDES= -I../src
+
+RM= /bin/rm -f
+#--- You shouldn't have to edit anything else. ---
+
+.c.o: 
+       $(CC) -c $(CFLAGS) $(INCLUDES) $<
+
+TARGETS=htpasswd htdigest httpd_monitor rotatelogs logresolve
+
+all: $(TARGETS)
+
+aux:
+       make all CC=gcc CFLAGS=-O2
+
+ibm:
+       make all CC=gcc
+
+sun:
+       make all CC=gcc
+
+hp:
+       make all CC=gcc
+
+sgi:
+       make all CC=cc
+
+decmips:
+       make all CC=cc
+
+decaxp:
+       make all CC=cc
+
+sco5:
+       make all CC=cc
+
+sco3:
+       make all CC=cc EXTRA_LIBS=-lcrypt_i
+
+
+tar: htpasswd 
+       $(RM) htpasswd
+
+htpasswd: htpasswd.c
+       $(CC) $(CFLAGS) htpasswd.c -o htpasswd $(EXTRA_LIBS)
+
+htdigest: htdigest.c
+       $(CC) $(CFLAGS) htdigest.c -o htdigest
+
+httpd_monitor: httpd_monitor.c
+       $(CC) $(INCLUDES) $(CFLAGS) httpd_monitor.c -o httpd_monitor
+
+rotatelogs: rotatelogs.c
+       $(CC) $(INCLUDES) $(CFLAGS) rotatelogs.c -o rotatelogs
+
+logresolve: logresolve.c
+       $(CC) $(INCLUDES) $(CFLAGS) logresolve.c -o logresolve
+
+clean:
+       rm -f $(TARGETS)
+
diff --git a/RELEASE_1_1_X/src/support/cls.c b/RELEASE_1_1_X/src/support/cls.c
new file mode 100644 (file)
index 0000000..2c553ce
--- /dev/null
@@ -0,0 +1,165 @@
+#include <ctype.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+/*
+ * Compare a string to a mask
+ * Mask characters:
+ *   @ - uppercase letter
+ *   # - lowercase letter
+ *   & - hex digit
+ *   # - digit
+ *   * - swallow remaining characters 
+ *  <x> - exact match for any other character
+ */
+static int
+checkmask(const char *data, const char *mask)
+{
+    int i, ch, d;
+
+    for (i=0; mask[i] != '\0' && mask[i] != '*'; i++)
+    {
+       ch = mask[i];
+       d = data[i];
+       if (ch == '@')
+       {
+           if (!isupper(d)) return 0;
+       } else if (ch == '$')
+       {
+           if (!islower(d)) return 0;
+       } else if (ch == '#')
+       {
+           if (!isdigit(d)) return 0;
+       } else if (ch == '&')
+       {
+           if (!isxdigit(d)) return 0;
+       } else if (ch != d) return 0;
+    }
+
+    if (mask[i] == '*') return 1;
+    else return (data[i] == '\0');
+}
+
+/*
+ * Converts 8 hex digits to a time integer
+ */
+static int
+hex2sec(const char *x)
+{
+    int i, ch;
+    unsigned int j;
+
+    for (i=0, j=0; i < 8; i++)
+    {
+       ch = x[i];
+       j <<= 4;
+       if (isdigit(ch)) j |= ch - '0';
+       else if (isupper(ch)) j |= ch - ('A' - 10);
+       else j |= ch - ('a' - 10);
+    }
+    if (j == 0xffffffff) return -1;  /* so that it works with 8-byte ints */
+    else return j;
+}
+
+int
+main(int argc, char **argv)
+{
+    int i, ver;
+    DIR *d;
+    struct dirent *e;
+    const char *s;
+    FILE *fp;
+    char path[FILENAME_MAX+1];
+    char line[1035];
+    time_t date, lmod, expire;
+    unsigned int len;
+    struct tm ts;
+    char sdate[30], slmod[30], sexpire[30];
+    const char time_format[]="%e %b %Y %R";
+
+    if (argc != 2)
+    {
+       printf("Usage: cls directory\n");
+       exit(0);
+    }
+
+    d = opendir(argv[1]);
+    if (d == NULL)
+    {
+       perror("opendir");
+       exit(1);
+    }
+
+    for (;;)
+    {
+       e = readdir(d);
+       if (e == NULL) break;
+       s = e->d_name;
+       if (s[0] == '.' || s[0] == '#') continue;
+       sprintf(path, "%s/%s", argv[1], s);
+       fp = fopen(path, "r");
+       if (fp == NULL)
+       {
+           perror("fopen");
+           continue;
+       }
+       if (fgets(line, 1034, fp) == NULL)
+       {
+           perror("fgets");
+           fclose(fp);
+           continue;
+       }
+       if (!checkmask(line, "&&&&&&&& &&&&&&&& &&&&&&&& &&&&&&&& &&&&&&&&\n"))
+       {
+           fprintf(stderr, "Bad cache file\n");
+           fclose(fp);
+           continue;
+       }
+       date = hex2sec(line);
+       lmod = hex2sec(line+9);
+       expire = hex2sec(line+18);
+       ver = hex2sec(line+27);
+       len = hex2sec(line+35);
+       if (fgets(line, 1034, fp) == NULL)
+       {
+           perror("fgets");
+           fclose(fp);
+           continue;
+       }
+       fclose(fp);
+       i = strlen(line);
+       if (strncmp(line, "X-URL: ", 7) != 0 || line[i-1] != '\n')
+       {
+           fprintf(stderr, "Bad cache file\n");
+           continue;
+       }
+       line[i-1] = '\0';
+       if (date != -1)
+       {
+           ts = *gmtime(&date);
+           strftime(sdate, 30, time_format, &ts);
+       } else
+           strcpy(sdate, "-");
+
+       if (lmod != -1)
+       {       
+           ts = *gmtime(&lmod);
+           strftime(slmod, 30, time_format, &ts);
+       } else
+           strcpy(slmod, "-");
+
+       if (expire != -1)
+       {
+           ts = *gmtime(&expire);
+           strftime(sexpire, 30, time_format, &ts);
+       } else
+           strcpy(sexpire, "-");
+
+       printf("%s: %d; %s  %s  %s\n", line+7, ver, sdate, slmod, sexpire);
+    }
+
+    closedir(d);
+    return 0;
+}
diff --git a/RELEASE_1_1_X/src/support/dbmmanage b/RELEASE_1_1_X/src/support/dbmmanage
new file mode 100644 (file)
index 0000000..c337ddf
--- /dev/null
@@ -0,0 +1,123 @@
+#!/usr/local/bin/perl
+
+# ====================================================================
+# Copyright (c) 1995 The Apache Group.  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. All advertising materials mentioning features or use of this
+#    software must display the following acknowledgment:
+#    "This product includes software developed by the Apache Group
+#    for use in the Apache HTTP server project (http://www.apache.org/)."
+#
+# 4. The names "Apache Server" and "Apache Group" must not be used to
+#    endorse or promote products derived from this software without
+#    prior written permission.
+#
+# 5. Redistributions of any form whatsoever must retain the following
+#    acknowledgment:
+#    "This product includes software developed by the Apache Group
+#    for use in the Apache HTTP server project (http://www.apache.org/)."
+#
+# THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+# on public domain software written at the National Center for
+# Supercomputing Applications, University of Illinois, Urbana-Champaign.
+# For more information on the Apache Group and the Apache HTTP server
+# project, please see <http://www.apache.org/>.
+
+
+# usage: dbmmanage <DBMfile> <command> <key> <value> <group>
+#
+# commands: add, delete, view, adduser
+#
+# no values needed for delete, no keys or values needed for view.
+# to change a value, simply use "add".
+# adduser encrypts the password:
+# dbmmanage <dbm file> adduser <person> <password>
+#
+# <group> is optional, and may also be supplied to add the user
+# to a specified group:
+# dbmmanage <dbm file> adduser <person> <password> <group>
+
+if (scalar(@ARGV) < 2) {
+       print "Too few arguments.\n";
+       exit;
+}
+
+# ugly - this should be changed to be random.
+$salt="XX";
+$file=$ARGV[0];
+$command=$ARGV[1];
+$key=$ARGV[2];
+$value=$ARGV[3];
+$group=$ARGV[4];
+
+if ($command eq "add") {
+        dbmopen(%DB, $file, 0664) || die "Error: $!\n";
+        $value .= ":$group" if $group ne "";
+        $DB{$key} = $value;
+        dbmclose(%DB);
+       print "Entry $key added with value $value.\n";
+       exit;
+}
+
+if ($command eq "adduser") {
+       $hash = crypt($value, "$salt");
+        dbmopen(%DB, $file, 0664) || die "Error: $!\n";
+        $hash .= ":$group" if $group ne "";
+        $value .= ":$group" if $group ne "";
+        $DB{$key} = $hash;
+        dbmclose(%DB);
+       print "User $key added with password $value, encrypted to $hash\n";
+       exit;
+}
+
+if ($command eq "delete") {
+        dbmopen(%DB, $file, 0664) || die "Error: $!\n";
+        delete($DB{$key});
+        dbmclose(%DB);
+       exit;
+}
+
+if ($command eq "view") {
+        dbmopen(%DB, $file, undef) || die "Error: $!\n";
+        $return_status = 1;
+        unless ($key) {
+                while (($nkey,$val) = each %DB) {
+                        print "$nkey = $val\n";
+                }
+        } else {
+                $return_status = 0 if defined $DB{$key};
+                print "$key = $DB{$key}\n";
+        } 
+        dbmclose(%DB);
+       exit($return_status);
+}
+
+print "Command unrecognized - must be one of: view, add, adduser, delete.\n";
+
diff --git a/RELEASE_1_1_X/src/support/dbmmanage.new b/RELEASE_1_1_X/src/support/dbmmanage.new
new file mode 100644 (file)
index 0000000..dd07b08
--- /dev/null
@@ -0,0 +1,133 @@
+#!/usr/local/bin/perl
+
+# ====================================================================
+# Copyright (c) 1995 The Apache Group.  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. All advertising materials mentioning features or use of this
+#    software must display the following acknowledgment:
+#    "This product includes software developed by the Apache Group
+#    for use in the Apache HTTP server project (http://www.apache.org/)."
+#
+# 4. The names "Apache Server" and "Apache Group" must not be used to
+#    endorse or promote products derived from this software without
+#    prior written permission.
+#
+# 5. Redistributions of any form whatsoever must retain the following
+#    acknowledgment:
+#    "This product includes software developed by the Apache Group
+#    for use in the Apache HTTP server project (http://www.apache.org/)."
+#
+# THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+# on public domain software written at the National Center for
+# Supercomputing Applications, University of Illinois, Urbana-Champaign.
+# For more information on the Apache Group and the Apache HTTP server
+# project, please see <http://www.apache.org/>.
+
+
+# usage: dbmmanage <DBMfile> <command> <key> <value>
+#
+# commands: add, delete, view, adduser
+#
+# no values needed for delete, no keys or values needed for view.
+# to change a value, simply use "add".
+# adduser encrypts the password:
+# dbmmanage <dbm file> adduser <person> <password>
+
+die "Too few arguments.\n" if (@ARGV < 2);
+
+($file,$command,$key,$value) = @ARGV;
+
+$file =~ s/\.db.?$//;          # remove ".db" or ".dbX" extension if any
+$file =~ s/\.pag$//;           # remove ".pag" and ".dir" as well.
+$file =~ s/\.dir$//;           # these are all common DBM extensions.
+
+if ($command eq "add") {
+  dbmopen(%DB, $file, 0664) || die "Error: $!\n";
+  $DB{$key} = $value;
+  dbmclose(%DB);
+  print "Entry $key added with value $value.\n";
+} elsif ($command eq "adduser") {
+  srand;                       # needs to be done only once.
+  $salt = &compute_salt(0);    # change to compute_salt(1) for new crypt()
+  $hash = crypt($value, $salt);
+  dbmopen(%DB, $file, 0664) || die "Error: $!\n";
+  $DB{$key} = $hash;
+  dbmclose(%DB);
+  print "User $key added with password ``$value'', encrypted to $hash\n";
+} elsif ($command eq "delete") {
+  dbmopen(%DB, $file, 0664) || die "Error: $!\n";
+  delete($DB{$key});
+  dbmclose(%DB);
+} elsif ($command eq "view") {
+  dbmopen(%DB, $file, undef) || die "Error: $!\n";
+  unless ($key) {
+    while (($nkey,$val) = each %DB) {
+      print "$nkey = $val\n";
+    }
+  } else {
+    print "$key = $DB{$key}\n";
+  } 
+  dbmclose(%DB);
+} else {
+  print "Command unrecognized - must be one of: view, add, adduser, delete.\n";
+}
+
+exit(0);
+
+# if $newstyle is 1, then use new style salt (starts with '_' and contains
+# four bytes of iteration count and four bytes of salt).  Otherwise, just use
+# the traditional two-byte salt.
+# see the man page on your system to decide if you have a newer crypt() lib.
+# I believe that 4.4BSD derived systems do (at least BSD/OS 2.0 does).
+# The new style crypt() allows up to 20 characters of the password to be
+# significant rather than only 8.
+sub compute_salt {
+  local($newstyle) = @_;
+  local($salt);
+  if ($newstyle) {
+    $salt = "_" . &randchar(1) . "a.." . &randchar(4);
+  } else {
+    $salt = &randchar(2);
+  }
+  $salt;
+}
+
+# return $count random characters
+sub randchar {
+  local($count) = @_;
+  local($str) = "";
+  local($enc) =
+    "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+  while ($count--) {
+    # 64 = length($enc) in call to rand() below
+    $str .= substr($enc,int(rand(64))+1,1);
+  }
+  $str;
+}
diff --git a/RELEASE_1_1_X/src/support/dbmmanage.readme b/RELEASE_1_1_X/src/support/dbmmanage.readme
new file mode 100644 (file)
index 0000000..3862096
--- /dev/null
@@ -0,0 +1,6 @@
+Two versions of the dbmmanage script are included with this release.
+One is the old faithful version, which should continue to work if you've
+been using it; the other is a newer cut, which can be easily modified to
+support the newer extended crypt routines which are present on some
+systems (including 4.4BSD derivatives); this newer version is, for the
+nonce, experimental...
diff --git a/RELEASE_1_1_X/src/support/htdigest.c b/RELEASE_1_1_X/src/support/htdigest.c
new file mode 100644 (file)
index 0000000..ab8b712
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * htdigest.c: simple program for manipulating digest passwd file for Apache
+ *
+ * by Alexei Kosut, based on htpasswd.c, by Rob McCool
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/signal.h>
+#include <stdlib.h>
+#include <time.h>
+
+/* This is probably the easiest way to do it */
+#include "../src/md5c.c"
+
+#define LF 10
+#define CR 13
+
+#define MAX_STRING_LEN 256
+
+char *tn;
+
+char *strd(char *s) {
+    char *d;
+
+    d=(char *)malloc(strlen(s) + 1);
+    strcpy(d,s);
+    return(d);
+}
+
+void getword(char *word, char *line, char stop) {
+    int x = 0,y;
+
+    for(x=0;((line[x]) && (line[x] != stop));x++)
+        word[x] = line[x];
+
+    word[x] = '\0';
+    if(line[x]) ++x;
+    y=0;
+
+    while((line[y++] = line[x++]));
+}
+
+int getline(char *s, int n, FILE *f) {
+    register int i=0;
+
+    while(1) {
+        s[i] = (char)fgetc(f);
+
+        if(s[i] == CR)
+            s[i] = fgetc(f);
+
+        if((s[i] == 0x4) || (s[i] == LF) || (i == (n-1))) {
+            s[i] = '\0';
+            return (feof(f) ? 1 : 0);
+        }
+        ++i;
+    }
+}
+
+void putline(FILE *f,char *l) {
+    int x;
+
+    for(x=0;l[x];x++) fputc(l[x],f);
+    fputc('\n',f);
+}
+
+
+void add_password(char *user, char *realm, FILE *f) {
+    char *pw, *cpw;
+    MD5_CTX context;
+    unsigned char digest[16];
+    char string[MAX_STRING_LEN];
+    unsigned int i;
+
+    pw = strd((char *) getpass("New password:"));
+    if(strcmp(pw,(char *) getpass("Re-type new password:"))) {
+        fprintf(stderr,"They don't match, sorry.\n");
+        if(tn)
+            unlink(tn);
+        exit(1);
+    }
+    fprintf(f,"%s:%s:",user,realm);
+
+    /* Do MD5 stuff */
+    sprintf(string, "%s:%s:%s", user, realm, pw);
+
+    MD5Init (&context);
+    MD5Update (&context, string, strlen(string));
+    MD5Final (digest, &context);
+
+    for (i = 0; i < 16; i++)
+        fprintf(f, "%02x", digest[i]);
+
+    fprintf(f, "\n");
+}
+
+void usage() {
+    fprintf(stderr,"Usage: htdigest [-c] passwordfile realm username\n");
+    fprintf(stderr,"The -c flag creates a new file.\n");
+    exit(1);
+}
+
+void interrupted() {
+    fprintf(stderr,"Interrupted.\n");
+    if(tn) unlink(tn);
+    exit(1);
+}
+
+void main(int argc, char *argv[]) {
+    FILE *tfp,*f;
+    char user[MAX_STRING_LEN];
+    char realm[MAX_STRING_LEN];
+    char line[MAX_STRING_LEN];
+    char l[MAX_STRING_LEN];
+    char w[MAX_STRING_LEN];
+    char x[MAX_STRING_LEN];
+    char command[MAX_STRING_LEN];
+    int found;
+
+    tn = NULL;
+    signal(SIGINT,(void (*)())interrupted);
+    if(argc == 5) {
+        if(strcmp(argv[1],"-c"))
+            usage();
+        if(!(tfp = fopen(argv[2],"w"))) {
+            fprintf(stderr,"Could not open passwd file %s for writing.\n",
+                    argv[2]);
+            perror("fopen");
+            exit(1);
+        }
+        printf("Adding password for %s in realm %s.\n",argv[4], argv[3]);
+        add_password(argv[4],argv[3],tfp);
+        fclose(tfp);
+        exit(0);
+    } else if(argc != 4) usage();
+
+    tn = tmpnam(NULL);
+    if(!(tfp = fopen(tn,"w"))) {
+        fprintf(stderr,"Could not open temp file.\n");
+        exit(1);
+    }
+
+    if(!(f = fopen(argv[1],"r"))) {
+        fprintf(stderr,
+                "Could not open passwd file %s for reading.\n",argv[1]);
+        fprintf(stderr,"Use -c option to create new one.\n");
+        exit(1);
+    }
+    strcpy(user,argv[3]);
+    strcpy(realm,argv[2]);
+
+    found = 0;
+    while(!(getline(line,MAX_STRING_LEN,f))) {
+        if(found || (line[0] == '#') || (!line[0])) {
+            putline(tfp,line);
+            continue;
+        }
+        strcpy(l,line);
+        getword(w,l,':');
+       getword(x,l,':');
+        if(strcmp(user,w) || strcmp(realm,x)) {
+            putline(tfp,line);
+            continue;
+        }
+        else {
+            printf("Changing password for user %s in realm %s\n",user,realm);
+            add_password(user,realm,tfp);
+            found = 1;
+        }
+    }
+    if(!found) {
+        printf("Adding user %s in realm %s\n",user,realm);
+        add_password(user,realm,tfp);
+    }
+    fclose(f);
+    fclose(tfp);
+    sprintf(command,"cp %s %s",tn,argv[1]);
+    system(command);
+    unlink(tn);
+}
diff --git a/RELEASE_1_1_X/src/support/htpasswd.c b/RELEASE_1_1_X/src/support/htpasswd.c
new file mode 100644 (file)
index 0000000..2396170
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * htpasswd.c: simple program for manipulating password file for NCSA httpd
+ * 
+ * Rob McCool
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/signal.h>
+#include <stdlib.h>
+#include <time.h>
+
+#define LF 10
+#define CR 13
+
+#define MAX_STRING_LEN 256
+
+char *tn;
+
+char *strd(char *s) {
+    char *d;
+
+    d=(char *)malloc(strlen(s) + 1);
+    strcpy(d,s);
+    return(d);
+}
+
+void getword(char *word, char *line, char stop) {
+    int x = 0,y;
+
+    for(x=0;((line[x]) && (line[x] != stop));x++)
+        word[x] = line[x];
+
+    word[x] = '\0';
+    if(line[x]) ++x;
+    y=0;
+
+    while(line[y++] = line[x++]);
+}
+
+int getline(char *s, int n, FILE *f) {
+    register int i=0;
+
+    while(1) {
+        s[i] = (char)fgetc(f);
+
+        if(s[i] == CR)
+            s[i] = fgetc(f);
+
+        if((s[i] == 0x4) || (s[i] == LF) || (i == (n-1))) {
+            s[i] = '\0';
+            return (feof(f) ? 1 : 0);
+        }
+        ++i;
+    }
+}
+
+void putline(FILE *f,char *l) {
+    int x;
+
+    for(x=0;l[x];x++) fputc(l[x],f);
+    fputc('\n',f);
+}
+
+
+/* From local_passwd.c (C) Regents of Univ. of California blah blah */
+static unsigned char itoa64[] =         /* 0 ... 63 => ascii - 64 */
+        "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+to64(s, v, n)
+  register char *s;
+  register long v;
+  register int n;
+{
+    while (--n >= 0) {
+        *s++ = itoa64[v&0x3f];
+        v >>= 6;
+    }
+}
+
+char *crypt(char *pw, char *salt); /* why aren't these prototyped in include */
+
+void add_password(char *user, FILE *f) {
+    char *pw, *cpw, salt[3];
+
+    pw = strd((char *) getpass("New password:"));
+    if(strcmp(pw,(char *) getpass("Re-type new password:"))) {
+        fprintf(stderr,"They don't match, sorry.\n");
+        if(tn)
+            unlink(tn);
+        exit(1);
+    }
+    (void)srand((int)time((time_t *)NULL));
+    to64(&salt[0],rand(),2);
+    cpw = crypt(pw,salt);
+    free(pw);
+    fprintf(f,"%s:%s\n",user,cpw);
+}
+
+void usage() {
+    fprintf(stderr,"Usage: htpasswd [-c] passwordfile username\n");
+    fprintf(stderr,"The -c flag creates a new file.\n");
+    exit(1);
+}
+
+void interrupted() {
+    fprintf(stderr,"Interrupted.\n");
+    if(tn) unlink(tn);
+    exit(1);
+}
+
+main(int argc, char *argv[]) {
+    FILE *tfp,*f;
+    char user[MAX_STRING_LEN];
+    char line[MAX_STRING_LEN];
+    char l[MAX_STRING_LEN];
+    char w[MAX_STRING_LEN];
+    char command[MAX_STRING_LEN];
+    int found;
+
+    tn = NULL;
+    signal(SIGINT,(void (*)())interrupted);
+    if(argc == 4) {
+        if(strcmp(argv[1],"-c"))
+            usage();
+        if(!(tfp = fopen(argv[2],"w"))) {
+            fprintf(stderr,"Could not open passwd file %s for writing.\n",
+                    argv[2]);
+            perror("fopen");
+            exit(1);
+        }
+        printf("Adding password for %s.\n",argv[3]);
+        add_password(argv[3],tfp);
+        fclose(tfp);
+        exit(0);
+    } else if(argc != 3) usage();
+
+    tn = tmpnam(NULL);
+    if(!(tfp = fopen(tn,"w"))) {
+        fprintf(stderr,"Could not open temp file.\n");
+        exit(1);
+    }
+
+    if(!(f = fopen(argv[1],"r"))) {
+        fprintf(stderr,
+                "Could not open passwd file %s for reading.\n",argv[1]);
+        fprintf(stderr,"Use -c option to create new one.\n");
+        exit(1);
+    }
+    strcpy(user,argv[2]);
+
+    found = 0;
+    while(!(getline(line,MAX_STRING_LEN,f))) {
+        if(found || (line[0] == '#') || (!line[0])) {
+            putline(tfp,line);
+            continue;
+        }
+        strcpy(l,line);
+        getword(w,l,':');
+        if(strcmp(user,w)) {
+            putline(tfp,line);
+            continue;
+        }
+        else {
+            printf("Changing password for user %s\n",user);
+            add_password(user,tfp);
+            found = 1;
+        }
+    }
+    if(!found) {
+        printf("Adding user %s\n",user);
+        add_password(user,tfp);
+    }
+    fclose(f);
+    fclose(tfp);
+    sprintf(command,"cp %s %s",tn,argv[1]);
+    system(command);
+    unlink(tn);
+}
diff --git a/RELEASE_1_1_X/src/support/httpd.1m b/RELEASE_1_1_X/src/support/httpd.1m
new file mode 100644 (file)
index 0000000..e3db0b4
--- /dev/null
@@ -0,0 +1,108 @@
+.TH httpd 1m "October 1995"
+.\" Copyright (c) 1995 David Robinson. 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. All advertising materials mentioning features or use of this
+.\"    software must display the following acknowledgment:
+.\"    "This product includes software developed by the Apache Group
+.\"    for use in the Apache HTTP server project (http://www.apache.org/)."
+.\"
+.\" 4. The names "Apache Server" and "Apache Group" must not be used to
+.\"    endorse or promote products derived from this software without
+.\"    prior written permission.
+.\"
+.\" 5. Redistributions of any form whatsoever must retain the following
+.\"    acknowledgment:
+.\"    "This product includes software developed by the Apache Group
+.\"    for use in the Apache HTTP server project (http://www.apache.org/)."
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+.\" on public domain software written at the National Center for
+.\" Supercomputing Applications, University of Illinois, Urbana-Champaign.
+.\" For more information on the Apache Group and the Apache HTTP server
+.\" project, please see <http://www.apache.org/>.
+.SH NAME
+httpd \- Apache hypertext transfer protocol server
+.SH SYNOPSIS
+.B httpd 
+[
+.B \-vX?
+] [
+.BI \-d " serverroot"
+] [
+.BI \-f " config"
+]
+.SH DESCRIPTION
+.B httpd
+is the Apache HyperText Transfer Protocol (HTTP) server process. The server may
+be invoked by the Internet daemon inetd(1M) each time a connection to the
+HTTP service is made, or alternatively it may run as a daemon.
+.SH OPTIONS
+.TP 12
+.BI \-d " serverroot"
+Set the initial value for the ServerRoot variable to \fIserverroot\fP. This
+can be overridden by the ServerRoot command in the configuration file. The
+default is \fB/usr/local/etc/httpd\fP.
+.TP
+.BI \-f " config"
+Execute the commands in the file \fIconfig\fP on startup. If \fIconfig\fP
+does not begin with a /, then it is taken to be a path relative to
+the ServerRoot. The default is \fBconf/httpd.conf\fP.
+.TP
+.B \-X
+Run in single-process mode, for internal debugging purposes only; the daemon
+does not detach from the terminal or fork any children. Do NOT use this mode
+to provide ordinary web service.
+.TP
+.B \-v
+Print the version of httpd, and then exit.
+.TP
+.B \-?
+Print a list of the httpd options, and then exit.
+.SH FILES
+.PD 0
+.B /usr/local/etc/httpd/conf/httpd.conf
+.br
+.B /usr/local/etc/httpd/conf/srm.conf
+.br
+.B /usr/local/etc/httpd/conf/access.conf
+.br
+.B /usr/local/etc/httpd/conf/mime.types
+.br
+.B /usr/local/etc/httpd/logs/error_log
+.br
+.B /usr/local/etc/httpd/logs/access_log
+.br
+.B /usr/local/etc/httpd/logs/httpd.pid
+.PD
+.SH SEE ALSO
+.BR inetd (1m).
+.PP
+Documentation for the Apache http server is available from
+http://www.apache.org
diff --git a/RELEASE_1_1_X/src/support/httpd_monitor.c b/RELEASE_1_1_X/src/support/httpd_monitor.c
new file mode 100644 (file)
index 0000000..c9a87ee
--- /dev/null
@@ -0,0 +1,302 @@
+/*
+ * ====================================================================
+ * Copyright (c) 1995 The Apache Group.  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. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP OR
+ * IT'S 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 Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+
+
+ * simple script to monitor the child Apache processes
+ *   Usage:
+ *      httpd_monitor -p pid_file -s sleep_time
+ *                Will give you an update ever sleep_time seconds
+ *                 using pid_file as the location of the PID file.
+ *                If you choose 0, it might chew up lots of CPU time.
+ *
+ * Output explanation..
+ *
+ *  s = sleeping but "ready to go" child
+ *  R = active child
+ *  _ = dead child (no longer needed)
+ *  t = just starting
+ *
+ *
+ *  Jim Jagielski <jim@jaguNET.com>
+ *   v1.0 Notes:
+ *    This code is much more ugly and complicated than it
+ *    needs to be.
+ *
+ *   v1.1:
+ *    Minor fixes
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "scoreboard.h"
+#include "httpd.h"
+
+#define PIDFILE_OPT            "PidFile"
+#define        SCORE_OPT               "ScoreBoardFile"
+#define DEFAULT_SLEEPTIME      2
+#define ASIZE                  1024
+#define MAX_PROC               40
+
+int
+main(argc, argv)
+int argc;
+char **argv;
+{
+    short_score scoreboard_image;
+    FILE *afile;
+    char conf_name[ASIZE];
+    char pid_name[ASIZE];
+    char score_name[ASIZE];
+    char tbuf[ASIZE];
+    char *ptmp;
+    static char kid_stat[] = { '_', 's', 'R', 't' };
+    char achar;
+    long thepid;
+    int score_fd;
+    int sleep_time = DEFAULT_SLEEPTIME;
+    int last_len = 0;
+    int kiddies;
+    int running, dead, total, loop;
+    short got_config = 0;
+    struct stat statbuf;
+    time_t last_time = 0;
+    extern char *optarg;
+    extern int optind, opterr;
+    void lookfor();
+
+    int usage();
+
+    /*
+     * Handle the options. Using getopt() is most probably overkill,
+     * but let's think about the future!
+     */
+    strcpy(conf_name, HTTPD_ROOT);
+    while((achar = getopt(argc,argv,"s:d:f:")) != -1) {
+       switch(achar) {
+         case 'd':
+           strcpy(conf_name, optarg);
+           break;
+         case 'f':
+           strcpy(conf_name, optarg);
+           got_config = 1;
+           break;
+         case 's':
+           sleep_time = atoi(optarg);
+           break;
+         case '?':
+           usage(argv[0]);
+       }
+    }
+
+    /*
+     * Now build the name of the httpd.conf file
+     */
+     if (!got_config) {
+        strcat(conf_name, "/");
+        strcat(conf_name, SERVER_CONFIG_FILE);
+    }
+
+    /*
+     * Make sure we have the right file... Barf if not
+     */
+    if (!(afile = fopen(conf_name, "r"))) {
+       perror("httpd_monitor");
+       fprintf(stderr, "Can't open config file: %s\n", conf_name);
+       exit(1);
+    }
+    /*
+     * now scan thru the ConfigFile to look for the items that
+     * interest us
+     */
+    lookfor(pid_name, score_name, afile);
+    fclose(afile);
+
+    /*
+     * now open the PidFile and then the ScoreBoardFile
+     */
+    if (!(afile = fopen(pid_name, "r"))) {
+       perror("httpd_monitor");
+       fprintf(stderr, "Can't open PIDfile: %s\n", pid_name);
+       exit(1);
+    }
+    fscanf(afile, "%ld", &thepid);
+    fclose(afile);
+
+    /*
+     * Enough taters, time for the MEAT!
+     */
+    for(;;sleep(sleep_time)) {
+       if (stat(score_name, &statbuf)) {
+           perror("httpd_monitor");
+           fprintf(stderr, "Can't stat scoreboard file: %s\n", score_name);
+           exit(1);
+       }
+       if (last_time == statbuf.st_mtime)
+           continue;   /* tricky ;) */
+       last_time = statbuf.st_mtime;   /* for next time */
+       if ((score_fd = open(score_name, 0)) == -1 ) {
+           perror("httpd_monitor");
+           fprintf(stderr, "Can't open scoreboard file: %s\n", score_name);
+           exit(1);
+       }
+       /*
+        * all that for _this_
+        */
+       running = dead = total = 0;
+       ptmp = tbuf;
+       *ptmp = '\0';
+       for(kiddies=0;kiddies<MAX_PROC; kiddies++) {
+           read(score_fd, (char *)&scoreboard_image, sizeof(short_score));
+           achar = kid_stat[(int)scoreboard_image.status];
+           if (scoreboard_image.pid != 0 && scoreboard_image.pid != thepid) {
+               total++;
+               if (achar == 'R')
+                   running++;
+               *ptmp = achar;
+               *++ptmp = '\0';
+           }
+       }
+       close(score_fd);
+       sprintf(ptmp, " (%d/%d)", running, total);
+       for(loop=1;loop<=last_len;loop++)
+           putchar('\010');
+       if (last_len > strlen(tbuf)) {
+           for(loop=1;loop<=last_len;loop++)
+               putchar(' ');
+           for(loop=1;loop<=last_len;loop++)
+               putchar('\010');
+       }
+       printf("%s", tbuf);
+       fflush(stdout);
+       last_len = strlen(tbuf);
+    }  /* for */
+}
+
+int
+usage(arg)
+char *arg;
+{
+    printf("httpd_monitor: Usage\n");
+    printf("  httpd_monitor [ -d config-dir] [ -s sleep-time ]\n");
+    printf("    Defaults: config-dir = %s\n", HTTPD_ROOT);
+    printf("              sleep-time = %d seconds\n", DEFAULT_SLEEPTIME);
+    exit(0);
+}
+
+/*
+ * This function uses some hard-wired knowledge about the
+ * Apache httpd.conf file setup (basically names of the 3
+ * parameters we are interested in)
+ *
+ * We basically scan thru the file and grab the 3 values we
+ * need. This could be done better...
+ */
+void
+lookfor(pidname, scorename, thefile)
+char *pidname, *scorename;
+FILE *thefile;
+{
+    char line[ASIZE], param[ASIZE], value[ASIZE];
+    char sroot[ASIZE], pidfile[ASIZE], scorefile[ASIZE];
+
+    *sroot = *pidfile  = *scorefile = '\0';
+    while (!(feof(thefile))) {
+       fgets(line, ASIZE-1, thefile);
+       *value = '\0';  /* protect braindead sscanf() */
+       sscanf(line, "%s %s", param, value);
+       if (strcmp(param, "PidFile")==0 && *value)
+           strcpy(pidfile, value);
+       if (strcmp(param, "ScoreBoardFile")==0 && *value)
+           strcpy(scorefile, value);
+       if (strcmp(param, "ServerRoot")==0 && *value)
+           strcpy(sroot, value);
+    }
+
+    /*
+     * We've reached EOF... we should have encountered the
+     * ServerRoot line... if not, we bail out
+     */
+    if (!*sroot) {
+       perror("httpd_monitor");
+       fprintf(stderr, "Can't find ServerRoot!\n");
+       exit(1);
+    }
+
+    /*
+     * Not finding PidFile or ScoreBoardFile is OK, since
+     * we have defaults for them
+     */
+    if (!*pidfile)
+       strcpy(pidfile, DEFAULT_PIDLOG);
+    if (!*scorefile)
+       strcpy(scorefile, DEFAULT_SCOREBOARD);
+
+    /*
+     * Relative or absolute? Handle both
+     */
+    if (*pidfile == '/')
+       strcpy(pidname, pidfile);
+    else {
+       strcpy(pidname, sroot);
+       strcat(pidname, "/");
+       strcat(pidname, pidfile);
+    }
+    if (*scorefile == '/')
+       strcpy(scorename, scorefile);
+    else {
+       strcpy(scorename, sroot);
+       strcat(scorename, "/");
+       strcat(scorename, scorefile);
+    }
+}
+
diff --git a/RELEASE_1_1_X/src/support/log_server_status b/RELEASE_1_1_X/src/support/log_server_status
new file mode 100755 (executable)
index 0000000..ed75197
--- /dev/null
@@ -0,0 +1,110 @@
+#!/usr/local/bin/perl
+
+# ====================================================================
+# Copyright (c) 1995 The Apache Group.  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. All advertising materials mentioning features or use of this
+#    software must display the following acknowledgment:
+#    "This product includes software developed by the Apache Group
+#    for use in the Apache HTTP server project (http://www.apache.org/)."
+#
+# 4. The names "Apache Server" and "Apache Group" must not be used to
+#    endorse or promote products derived from this software without
+#    prior written permission.
+#
+# 5. Redistributions of any form whatsoever must retain the following
+#    acknowledgment:
+#    "This product includes software developed by the Apache Group
+#    for use in the Apache HTTP server project (http://www.apache.org/)."
+#
+# THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
+# on public domain software written at the National Center for
+# Supercomputing Applications, University of Illinois, Urbana-Champaign.
+# For more information on the Apache Group and the Apache HTTP server
+# project, please see <http://www.apache.org/>.
+
+
+# Log Server Status
+# Mark J Cox, UK Web Ltd 1996, mark@ukweb.com
+#
+# This script is designed to be run at a frequent interval by something
+# like cron.  It connects to the server and downloads the status
+# information.  It reformats the information to a single line and logs
+# it to a file.  Make sure the directory $wherelog is writable by the
+# user who runs this script.
+#
+require 'sys/socket.ph';
+
+$wherelog = "/var/log/graph/";  # Logs will be like "/var/log/graph/960312"
+$server = "localhost";          # Name of server, could be "www.foo.com"
+$port = "80";                   # Port on server
+$request = "/status/?auto";     # Request to send
+
+sub tcp_connect
+{
+       local($host,$port) =@_;
+        $sockaddr='S n a4 x8';
+        chop($hostname=`hostname`);
+        $port=(getservbyname($port, 'tcp'))[2]  unless $port =~ /^\d+$/;
+        $me=pack($sockaddr,&AF_INET,0,(gethostbyname($hostname))[4]);
+        $them=pack($sockaddr,&AF_INET,$port,(gethostbyname($host))[4]);
+        socket(S,&PF_INET,&SOCK_STREAM,(getprotobyname('tcp'))[2]) || 
+               die "socket: $!";
+        bind(S,$me) || return "bind: $!";
+        connect(S,$them) || return "connect: $!";
+        select(S); 
+       $| = 1; 
+       select(stdout);
+       return "";
+}
+
+### Main
+
+{
+       $date=`date +%y%m%d:%H%M%S`;
+       chop($date);
+       ($day,$time)=split(/:/,$date);
+       $res=&tcp_connect($server,$port);
+       open(OUT,">>$wherelog$day");
+       if ($res) {
+               print OUT "$time:-1:-1:-1:-1:$res\n";
+               exit 1;
+       }
+       print S "GET $request\n";
+       while (<S>) {
+               $requests=$1 if ( m|^BusyServers:\ (\S+)|);
+               $idle=$1 if ( m|^IdleServers:\ (\S+)|);
+               $number=$1 if ( m|sses:\ (\S+)|);
+               $cpu=$1 if (m|^CPULoad:\ (\S+)|);
+       }
+       print OUT "$time:$requests:$idle:$number:$cpu\n";
+}
+
+
diff --git a/RELEASE_1_1_X/src/support/logresolve.c b/RELEASE_1_1_X/src/support/logresolve.c
new file mode 100644 (file)
index 0000000..c66a344
--- /dev/null
@@ -0,0 +1,352 @@
+/***                                                                      ***\
+
+    logresolve 1.1
+
+    Tom Rathborne - tomr@uunet.ca - http://www.uunet.ca/~tomr/
+    UUNET Canada, April 16, 1995
+
+    Rewritten by David Robinson. (drtr@ast.cam.ac.uk)
+
+    Usage: logresolve [-s filename] [-c] < access_log > new_log
+
+    Arguments:
+       -s filename     name of a file to record statistics
+       -c              check the DNS for a matching A record for the host.
+
+    Notes:
+
+    To generate meaningful statistics from an HTTPD log file, it's good
+    to have the domain name of each machine that accessed your site, but
+    doing this on the fly can slow HTTPD down.
+
+    Compiling NCSA HTTPD with the -DMINIMAL_DNS flag turns IP#->hostname
+    resolution off. Before running your stats program, just run your log
+    file through this program (logresolve) and all of your IP numbers will
+    be resolved into hostnames (where possible).
+
+    logresolve takes an HTTPD access log (in the COMMON log file format,
+    or any other format that has the IP number/domain name as the first
+    field for that matter), and outputs the same file with all of the
+    domain names looked up. Where no domain name can be found, the IP
+    number is left in.
+
+    To minimize impact on your nameserver, logresolve has its very own
+    internal hash-table cache. This means that each IP number will only
+    be looked up the first time it is found in the log file.
+
+    The -c option causes logresolve to apply the same check as httpd
+    compiled with -DMAXIMUM_DNS; after finding the hostname from the IP
+    address, it looks up the IP addresses for the hostname and checks
+    that one of these matches the original address.
+
+\***                                                                      ***/
+
+#include <ctype.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+static void cgethost(struct in_addr ipnum, char *string, int check);
+static int getline(char *s, int n);
+static void stats(FILE *output);
+
+
+/* maximum line length */
+#define MAXLINE 1024
+
+/* maximum length of a domain name */
+#ifndef MAXDNAME
+#define MAXDNAME 256
+#endif
+
+/* number of buckets in cache hash table */
+#define BUCKETS 256
+
+/*
+ * struct nsrec - record of nameservice for cache linked list
+ * 
+ * ipnum - IP number hostname - hostname noname - nonzero if IP number has no
+ * hostname, i.e. hostname=IP number
+ */
+
+struct nsrec {
+    struct in_addr ipnum;
+    char *hostname;
+    int        noname;
+    struct nsrec *next;
+} *nscache[BUCKETS];
+
+/*
+ * statistics - obvious
+ */
+
+/* largeste value for h_errno */
+#define MAX_ERR (NO_ADDRESS)
+#define UNKNOWN_ERR (MAX_ERR+1)
+#define NO_REVERSE  (MAX_ERR+2)
+
+static int cachehits = 0;
+static int cachesize = 0;
+static int entries = 0;
+static int resolves = 0;
+static int withname = 0;
+static int errors[MAX_ERR+3];
+
+/*
+ * cgethost - gets hostname by IP address, caching, and adding unresolvable
+ * IP numbers with their IP number as hostname, setting noname flag
+ */
+
+static void
+cgethost(ipnum, string, check)
+struct in_addr ipnum;
+char *string;
+int check;
+{
+    struct nsrec **current, *new;
+    struct hostent *hostdata;
+    char *name;
+    extern int h_errno;  /* some machines don't have this in their headers */
+
+    current = &nscache[((ipnum.s_addr + (ipnum.s_addr >> 8) +
+               (ipnum.s_addr >> 16) + (ipnum.s_addr >> 24)) % BUCKETS)];
+
+    while (*current != NULL && ipnum.s_addr != (*current)->ipnum.s_addr)
+       current = & (*current)->next;
+
+    if (*current == NULL)
+    {
+       cachesize++;
+       new = (struct nsrec *) malloc(sizeof(struct nsrec));
+       if (new == NULL)
+       {
+           perror("malloc");
+           fprintf(stderr, "Insufficient memory\n");
+           exit(1);
+       }
+       *current = new;
+       new->next = NULL;
+
+       new->ipnum = ipnum;
+       
+       hostdata = gethostbyaddr((const char *) &ipnum, sizeof(struct in_addr),
+                                AF_INET);
+       if (hostdata == NULL)
+       {
+           if (h_errno > MAX_ERR) errors[UNKNOWN_ERR]++;
+           else errors[h_errno]++;
+           new->noname = h_errno;
+           name = strdup(inet_ntoa(ipnum));
+       } else
+       {
+           new->noname = 0;
+           name = strdup(hostdata->h_name);
+           if (check)
+           {
+               if (name == NULL)
+               {
+                   perror("strdup");
+                   fprintf(stderr, "Insufficient memory\n");
+                   exit(1);
+               }
+               hostdata = gethostbyname(name);
+               if (hostdata != NULL)
+               {
+                   char **hptr;
+                   
+                   for (hptr=hostdata->h_addr_list; *hptr != NULL; hptr++)
+                       if(((struct in_addr *)(*hptr))->s_addr == ipnum.s_addr)
+                           break;
+                   if (*hptr == NULL) hostdata = NULL;
+               }
+               if (hostdata == NULL)
+               {
+                   fprintf(stderr, "Bad host: %s != %s\n", name,
+                           inet_ntoa(ipnum));
+                   new->noname = NO_REVERSE;
+                   free(name);
+                   name = strdup(inet_ntoa(ipnum));
+                   errors[NO_REVERSE]++;
+               }
+           }
+       }
+       new->hostname = name;
+       if (new->hostname == NULL)
+       {
+           perror("strdup");
+           fprintf(stderr, "Insufficient memory\n");
+           exit(1);
+       }
+    } else
+       cachehits++;
+
+    strcpy(string, (*current)->hostname);
+}
+
+/*
+ * prints various statistics to output
+ */
+
+static void
+stats(output)
+FILE *output;
+{
+    int i;
+    char *ipstring;
+    struct nsrec *current;
+    char *errstring[MAX_ERR+3];
+
+    for (i=0; i < MAX_ERR+3; i++) errstring[i] = "Unknown error";
+    errstring[HOST_NOT_FOUND] = "Host not found";
+    errstring[TRY_AGAIN] = "Try again";
+    errstring[NO_RECOVERY] = "Non recoverable error";
+    errstring[NO_DATA] = "No data record";
+    errstring[NO_ADDRESS] = "No address";
+    errstring[NO_REVERSE] = "No reverse entry";
+    
+    fprintf(output, "logresolve Statistics:\n");
+
+    fprintf(output, "Entries: %d\n", entries);
+    fprintf(output, "    With name   : %d\n", withname);
+    fprintf(output, "    Resolves    : %d\n", resolves);
+    if (errors[HOST_NOT_FOUND])
+       fprintf(output, "    - Not found : %d\n", errors[HOST_NOT_FOUND]);
+    if (errors[TRY_AGAIN])
+       fprintf(output, "    - Try again : %d\n", errors[TRY_AGAIN]);
+    if (errors[NO_DATA])
+       fprintf(output, "    - No data   : %d\n", errors[NO_DATA]);
+    if (errors[NO_ADDRESS])
+       fprintf(output, "    - No address: %d\n", errors[NO_ADDRESS]);
+    if (errors[NO_REVERSE])
+       fprintf(output, "    - No reverse: %d\n", errors[NO_REVERSE]);
+    fprintf(output, "Cache hits      : %d\n", cachehits);
+    fprintf(output, "Cache size      : %d\n", cachesize);
+    fprintf(output, "Cache buckets   :     IP number * hostname\n");
+
+    for (i = 0; i < BUCKETS; i++)
+       for (current = nscache[i]; current != NULL; current = current->next)
+       {
+           ipstring = inet_ntoa(current->ipnum);
+           if (current->noname == 0)
+               fprintf(output, "  %3d  %15s - %s\n", i, ipstring,
+                       current->hostname);
+           else
+           {
+               if (current->noname > MAX_ERR+2)
+                   fprintf(output, "  %3d  %15s : Unknown error\n", i,
+                           ipstring);
+               else
+                   fprintf(output, "  %3d  %15s : %s\n", i, ipstring,
+                           errstring[current->noname]);
+           }
+       }
+}
+
+
+/*
+ * gets a line from stdin
+ */
+
+static int
+getline(s, n)
+char *s;
+int n;
+{
+    char *cp;
+    
+    if (!fgets(s, n, stdin))
+       return (0);
+    cp = strchr(s, '\n');
+    if (cp)
+       *cp = '\0';
+    return (1);
+}
+
+int
+main(argc, argv)
+int argc;
+char *argv[];
+{
+    struct in_addr ipnum;
+    char *bar, hoststring[MAXDNAME+1], line[MAXLINE], *statfile;
+    int i, check;
+
+    check = 0;
+    statfile = NULL;
+    for (i=1; i < argc; i++)
+    {
+       if (strcmp(argv[i], "-c") == 0) check = 1;
+       else if (strcmp(argv[i], "-s") == 0)
+       {
+           if (i == argc-1)
+           {
+               fprintf(stderr, "logresolve: missing filename to -s\n");
+               exit(1);
+           }
+           i++;
+           statfile = argv[i];
+       }
+       else
+       {
+           fprintf(stderr, "Usage: logresolve [-s statfile] [-c] < input > output");
+           exit(0);
+       }
+    }
+    
+
+    for (i = 0; i < BUCKETS; i++) nscache[i] = NULL;
+    for (i=0; i < MAX_ERR+2; i++) errors[i] = 0;
+
+    while (getline(line, MAXLINE))
+    {
+       if (line[0] == '\0') continue;
+       entries++;
+       if (!isdigit(line[0]))
+       { /* short cut */
+           puts(line);
+           withname++;
+           continue;
+       }
+       bar = strchr(line, ' ');
+       if (bar != NULL) *bar = '\0';
+       ipnum.s_addr = inet_addr(line);
+       if (ipnum.s_addr == 0xffffffffu)
+       {
+           if (bar != NULL) *bar = ' ';
+           puts(line);
+           withname++;
+           continue;
+       }
+
+       resolves++;
+
+       cgethost(ipnum, hoststring, check);
+       if (bar != NULL)
+           printf("%s %s\n", hoststring, bar+1);
+       else
+           puts(hoststring);
+    }
+    
+    if (statfile != NULL)
+    {
+       FILE *fp;
+       fp = fopen(statfile, "w");
+       if (fp == NULL)
+       {
+           fprintf(stderr, "logresolve: could not open statistics file '%s'\n"
+                   , statfile);
+           exit(1);
+       }
+       stats(fp);
+       fclose(fp);
+    }
+    
+    return (0);
+}
diff --git a/RELEASE_1_1_X/src/support/rotatelogs.c b/RELEASE_1_1_X/src/support/rotatelogs.c
new file mode 100644 (file)
index 0000000..e446841
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+
+Simple program to rotate Apache logs without having to kill the server.
+
+Contributed by Ben Laurie <ben@algroup.co.uk>
+
+12 Mar 1996
+
+*/
+
+#define BUFSIZE                65536
+#define MAX_PATH       1024
+
+#include <stdio.h>
+#include <time.h>
+#include <errno.h>
+#include <fcntl.h>
+
+void main(int argc,char **argv)
+    {
+    char buf[BUFSIZE],buf2[MAX_PATH];
+    time_t tLogEnd;
+    time_t tRotation;
+    int nLogFD=-1;
+    int nRead;
+    char *szLogRoot;
+
+    if(argc != 3)
+       {
+       fprintf(stderr,"%s <logfile> <rotation time in seconds>\n\n",argv[0]);
+#ifdef __EMX__
+       fprintf(stderr,"Add this:\n\nTransferLog \"|%s.exe /some/where 86400\"\n\n",argv[0]);
+#else
+               fprintf(stderr,"Add this:\n\nTransferLog \"|%s /some/where 86400\"\n\n",argv[0]);
+#endif
+       fprintf(stderr,"to httpd.conf. The generated name will be /some/where.nnnn where nnnn is the\n");
+       fprintf(stderr,"system time at which the log nominally starts (N.B. this time will always be a\n");
+       fprintf(stderr,"multiple of the rotation time, so you can synchronize cron scripts with it).\n");
+       fprintf(stderr,"At the end of each rotation time a new log is started.\n");
+       exit(1);
+       }
+
+    szLogRoot=argv[1];
+    tRotation=atoi(argv[2]);
+    if(tRotation <= 0)
+       {
+       fprintf(stderr,"Rotation time must be > 0\n");
+       exit(6);
+       }
+
+    for( ; ; )
+       {
+       nRead=read(0,buf,sizeof buf);
+       if(nRead == 0)
+           exit(3);
+       if(nRead < 0)
+           if(errno != EINTR)
+               exit(4);
+       if(nLogFD >= 0 && (time(NULL) >= tLogEnd || nRead < 0))
+           {
+           close(nLogFD);
+           nLogFD=-1;
+           }
+       if(nLogFD < 0)
+           {
+           time_t tLogStart=(time(NULL)/tRotation)*tRotation;
+           sprintf(buf2,"%s.%d",szLogRoot,tLogStart);
+           tLogEnd=tLogStart+tRotation;
+           nLogFD=open(buf2,O_WRONLY|O_CREAT|O_APPEND,0666);
+           if(nLogFD < 0)
+               {
+               perror(buf2);
+               exit(2);
+               }
+           }
+       if(write(nLogFD,buf,nRead) != nRead)
+           {
+           perror(buf2);
+           exit(5);
+           }
+       }
+    }
diff --git a/RELEASE_1_1_X/src/test/cls.c b/RELEASE_1_1_X/src/test/cls.c
new file mode 100644 (file)
index 0000000..2c553ce
--- /dev/null
@@ -0,0 +1,165 @@
+#include <ctype.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+/*
+ * Compare a string to a mask
+ * Mask characters:
+ *   @ - uppercase letter
+ *   # - lowercase letter
+ *   & - hex digit
+ *   # - digit
+ *   * - swallow remaining characters 
+ *  <x> - exact match for any other character
+ */
+static int
+checkmask(const char *data, const char *mask)
+{
+    int i, ch, d;
+
+    for (i=0; mask[i] != '\0' && mask[i] != '*'; i++)
+    {
+       ch = mask[i];
+       d = data[i];
+       if (ch == '@')
+       {
+           if (!isupper(d)) return 0;
+       } else if (ch == '$')
+       {
+           if (!islower(d)) return 0;
+       } else if (ch == '#')
+       {
+           if (!isdigit(d)) return 0;
+       } else if (ch == '&')
+       {
+           if (!isxdigit(d)) return 0;
+       } else if (ch != d) return 0;
+    }
+
+    if (mask[i] == '*') return 1;
+    else return (data[i] == '\0');
+}
+
+/*
+ * Converts 8 hex digits to a time integer
+ */
+static int
+hex2sec(const char *x)
+{
+    int i, ch;
+    unsigned int j;
+
+    for (i=0, j=0; i < 8; i++)
+    {
+       ch = x[i];
+       j <<= 4;
+       if (isdigit(ch)) j |= ch - '0';
+       else if (isupper(ch)) j |= ch - ('A' - 10);
+       else j |= ch - ('a' - 10);
+    }
+    if (j == 0xffffffff) return -1;  /* so that it works with 8-byte ints */
+    else return j;
+}
+
+int
+main(int argc, char **argv)
+{
+    int i, ver;
+    DIR *d;
+    struct dirent *e;
+    const char *s;
+    FILE *fp;
+    char path[FILENAME_MAX+1];
+    char line[1035];
+    time_t date, lmod, expire;
+    unsigned int len;
+    struct tm ts;
+    char sdate[30], slmod[30], sexpire[30];
+    const char time_format[]="%e %b %Y %R";
+
+    if (argc != 2)
+    {
+       printf("Usage: cls directory\n");
+       exit(0);
+    }
+
+    d = opendir(argv[1]);
+    if (d == NULL)
+    {
+       perror("opendir");
+       exit(1);
+    }
+
+    for (;;)
+    {
+       e = readdir(d);
+       if (e == NULL) break;
+       s = e->d_name;
+       if (s[0] == '.' || s[0] == '#') continue;
+       sprintf(path, "%s/%s", argv[1], s);
+       fp = fopen(path, "r");
+       if (fp == NULL)
+       {
+           perror("fopen");
+           continue;
+       }
+       if (fgets(line, 1034, fp) == NULL)
+       {
+           perror("fgets");
+           fclose(fp);
+           continue;
+       }
+       if (!checkmask(line, "&&&&&&&& &&&&&&&& &&&&&&&& &&&&&&&& &&&&&&&&\n"))
+       {
+           fprintf(stderr, "Bad cache file\n");
+           fclose(fp);
+           continue;
+       }
+       date = hex2sec(line);
+       lmod = hex2sec(line+9);
+       expire = hex2sec(line+18);
+       ver = hex2sec(line+27);
+       len = hex2sec(line+35);
+       if (fgets(line, 1034, fp) == NULL)
+       {
+           perror("fgets");
+           fclose(fp);
+           continue;
+       }
+       fclose(fp);
+       i = strlen(line);
+       if (strncmp(line, "X-URL: ", 7) != 0 || line[i-1] != '\n')
+       {
+           fprintf(stderr, "Bad cache file\n");
+           continue;
+       }
+       line[i-1] = '\0';
+       if (date != -1)
+       {
+           ts = *gmtime(&date);
+           strftime(sdate, 30, time_format, &ts);
+       } else
+           strcpy(sdate, "-");
+
+       if (lmod != -1)
+       {       
+           ts = *gmtime(&lmod);
+           strftime(slmod, 30, time_format, &ts);
+       } else
+           strcpy(slmod, "-");
+
+       if (expire != -1)
+       {
+           ts = *gmtime(&expire);
+           strftime(sexpire, 30, time_format, &ts);
+       } else
+           strcpy(sexpire, "-");
+
+       printf("%s: %d; %s  %s  %s\n", line+7, ver, sdate, slmod, sexpire);
+    }
+
+    closedir(d);
+    return 0;
+}