]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
This commit was manufactured by cvs2svn to create branch 'APACHE_1_2_X'.
author(no author) <(no author)@unknown>
Mon, 9 Jun 1997 14:17:28 +0000 (14:17 +0000)
committer(no author) <(no author)@unknown>
Mon, 9 Jun 1997 14:17:28 +0000 (14:17 +0000)
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/1.3@78269 13f79535-47bb-0310-9956-ffa450edef68

314 files changed:
APACHE_1_2_X/ABOUT_APACHE [new file with mode: 0644]
APACHE_1_2_X/CHANGES [new file with mode: 0644]
APACHE_1_2_X/KEYS [new file with mode: 0644]
APACHE_1_2_X/LICENSE [new file with mode: 0644]
APACHE_1_2_X/README [new file with mode: 0644]
APACHE_1_2_X/RULES.CVS [new file with mode: 0644]
APACHE_1_2_X/cgi-bin/printenv [new file with mode: 0644]
APACHE_1_2_X/cgi-bin/test-cgi [new file with mode: 0644]
APACHE_1_2_X/conf/access.conf-dist [new file with mode: 0644]
APACHE_1_2_X/conf/httpd.conf-dist [new file with mode: 0644]
APACHE_1_2_X/conf/mime.types [new file with mode: 0644]
APACHE_1_2_X/conf/srm.conf-dist [new file with mode: 0644]
APACHE_1_2_X/htdocs/apache_pb.gif [new file with mode: 0644]
APACHE_1_2_X/htdocs/index.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/LICENSE [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/TODO [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/bind.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/cgi_path.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/content-negotiation.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/custom-error.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/dns-caveats.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/env.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/expand.pl [new file with mode: 0755]
APACHE_1_2_X/htdocs/manual/footer.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/handler.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/header.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/host.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/images/home.gif [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/images/index.gif [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/images/sub.gif [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/index.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/install.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/install_1_1.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/invoking.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/keepalive.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/location.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/man-template.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/misc/API.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/misc/FAQ.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/misc/client_block_api.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/misc/compat_notes.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/misc/fin_wait_2.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/misc/footer.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/misc/header.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/misc/howto.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/misc/index.html [new file with mode: 0755]
APACHE_1_2_X/htdocs/manual/misc/known_bugs.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/misc/nopgp.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/misc/perf-bsd44.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/misc/perf-dec.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/misc/perf.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/misc/security_tips.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/misc/vif-info.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/misc/windoz_keepalive.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/mod/core.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/mod/directives.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/mod/footer.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/mod/header.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/mod/index.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/mod/mod_access.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/mod/mod_actions.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/mod/mod_alias.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/mod/mod_asis.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/mod/mod_auth.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/mod/mod_auth_anon.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/mod/mod_auth_db.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/mod/mod_auth_dbm.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/mod/mod_auth_msql.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/mod/mod_browser.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/mod/mod_cern_meta.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/mod/mod_cgi.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/mod/mod_cookies.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/mod/mod_digest.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/mod/mod_dir.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/mod/mod_dld.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/mod/mod_env.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/mod/mod_example.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/mod/mod_expires.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/mod/mod_headers.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/mod/mod_imap.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/mod/mod_include.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/mod/mod_info.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/mod/mod_log_agent.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/mod/mod_log_common.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/mod/mod_log_config.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/mod/mod_log_referer.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/mod/mod_mime.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/mod/mod_negotiation.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/mod/mod_proxy.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/mod/mod_rewrite.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/mod/mod_status.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/mod/mod_userdir.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/mod/mod_usertrack.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/multilogs.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/new_features_1_0.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/new_features_1_1.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/new_features_1_2.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/process-model.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/stopping.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/suexec.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/unixware.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/vhosts-in-depth.html [new file with mode: 0644]
APACHE_1_2_X/htdocs/manual/virtual-host.html [new file with mode: 0644]
APACHE_1_2_X/icons/README [new file with mode: 0644]
APACHE_1_2_X/icons/a.gif [new file with mode: 0644]
APACHE_1_2_X/icons/alert.black.gif [new file with mode: 0644]
APACHE_1_2_X/icons/alert.red.gif [new file with mode: 0644]
APACHE_1_2_X/icons/apache_pb.gif [new file with mode: 0644]
APACHE_1_2_X/icons/back.gif [new file with mode: 0644]
APACHE_1_2_X/icons/ball.gray.gif [new file with mode: 0644]
APACHE_1_2_X/icons/ball.red.gif [new file with mode: 0644]
APACHE_1_2_X/icons/binary.gif [new file with mode: 0644]
APACHE_1_2_X/icons/binhex.gif [new file with mode: 0644]
APACHE_1_2_X/icons/blank.gif [new file with mode: 0644]
APACHE_1_2_X/icons/bomb.gif [new file with mode: 0644]
APACHE_1_2_X/icons/box1.gif [new file with mode: 0644]
APACHE_1_2_X/icons/box2.gif [new file with mode: 0644]
APACHE_1_2_X/icons/broken.gif [new file with mode: 0644]
APACHE_1_2_X/icons/burst.gif [new file with mode: 0644]
APACHE_1_2_X/icons/c.gif [new file with mode: 0644]
APACHE_1_2_X/icons/comp.blue.gif [new file with mode: 0644]
APACHE_1_2_X/icons/comp.gray.gif [new file with mode: 0644]
APACHE_1_2_X/icons/compressed.gif [new file with mode: 0644]
APACHE_1_2_X/icons/continued.gif [new file with mode: 0644]
APACHE_1_2_X/icons/dir.gif [new file with mode: 0644]
APACHE_1_2_X/icons/down.gif [new file with mode: 0644]
APACHE_1_2_X/icons/dvi.gif [new file with mode: 0644]
APACHE_1_2_X/icons/f.gif [new file with mode: 0644]
APACHE_1_2_X/icons/folder.gif [new file with mode: 0644]
APACHE_1_2_X/icons/folder.open.gif [new file with mode: 0644]
APACHE_1_2_X/icons/folder.sec.gif [new file with mode: 0644]
APACHE_1_2_X/icons/forward.gif [new file with mode: 0644]
APACHE_1_2_X/icons/generic.gif [new file with mode: 0644]
APACHE_1_2_X/icons/generic.red.gif [new file with mode: 0644]
APACHE_1_2_X/icons/generic.sec.gif [new file with mode: 0644]
APACHE_1_2_X/icons/hand.right.gif [new file with mode: 0644]
APACHE_1_2_X/icons/hand.up.gif [new file with mode: 0644]
APACHE_1_2_X/icons/icon.sheet.gif [new file with mode: 0644]
APACHE_1_2_X/icons/image1.gif [new file with mode: 0644]
APACHE_1_2_X/icons/image2.gif [new file with mode: 0644]
APACHE_1_2_X/icons/image3.gif [new file with mode: 0644]
APACHE_1_2_X/icons/index.gif [new file with mode: 0644]
APACHE_1_2_X/icons/layout.gif [new file with mode: 0644]
APACHE_1_2_X/icons/left.gif [new file with mode: 0644]
APACHE_1_2_X/icons/link.gif [new file with mode: 0644]
APACHE_1_2_X/icons/movie.gif [new file with mode: 0644]
APACHE_1_2_X/icons/p.gif [new file with mode: 0644]
APACHE_1_2_X/icons/patch.gif [new file with mode: 0644]
APACHE_1_2_X/icons/pdf.gif [new file with mode: 0644]
APACHE_1_2_X/icons/pie0.gif [new file with mode: 0644]
APACHE_1_2_X/icons/pie1.gif [new file with mode: 0644]
APACHE_1_2_X/icons/pie2.gif [new file with mode: 0644]
APACHE_1_2_X/icons/pie3.gif [new file with mode: 0644]
APACHE_1_2_X/icons/pie4.gif [new file with mode: 0644]
APACHE_1_2_X/icons/pie5.gif [new file with mode: 0644]
APACHE_1_2_X/icons/pie6.gif [new file with mode: 0644]
APACHE_1_2_X/icons/pie7.gif [new file with mode: 0644]
APACHE_1_2_X/icons/pie8.gif [new file with mode: 0644]
APACHE_1_2_X/icons/portal.gif [new file with mode: 0644]
APACHE_1_2_X/icons/ps.gif [new file with mode: 0644]
APACHE_1_2_X/icons/quill.gif [new file with mode: 0644]
APACHE_1_2_X/icons/right.gif [new file with mode: 0644]
APACHE_1_2_X/icons/screw1.gif [new file with mode: 0644]
APACHE_1_2_X/icons/screw2.gif [new file with mode: 0644]
APACHE_1_2_X/icons/script.gif [new file with mode: 0644]
APACHE_1_2_X/icons/sound1.gif [new file with mode: 0644]
APACHE_1_2_X/icons/sound2.gif [new file with mode: 0644]
APACHE_1_2_X/icons/sphere1.gif [new file with mode: 0644]
APACHE_1_2_X/icons/sphere2.gif [new file with mode: 0644]
APACHE_1_2_X/icons/tar.gif [new file with mode: 0644]
APACHE_1_2_X/icons/tex.gif [new file with mode: 0644]
APACHE_1_2_X/icons/text.gif [new file with mode: 0644]
APACHE_1_2_X/icons/transfer.gif [new file with mode: 0644]
APACHE_1_2_X/icons/unknown.gif [new file with mode: 0644]
APACHE_1_2_X/icons/up.gif [new file with mode: 0644]
APACHE_1_2_X/icons/uu.gif [new file with mode: 0644]
APACHE_1_2_X/icons/uuencoded.gif [new file with mode: 0644]
APACHE_1_2_X/icons/world1.gif [new file with mode: 0644]
APACHE_1_2_X/icons/world2.gif [new file with mode: 0644]
APACHE_1_2_X/src/.cvsignore [new file with mode: 0644]
APACHE_1_2_X/src/.indent.pro [new file with mode: 0644]
APACHE_1_2_X/src/CHANGES [new file with mode: 0644]
APACHE_1_2_X/src/Configuration.tmpl [new file with mode: 0644]
APACHE_1_2_X/src/Configure [new file with mode: 0755]
APACHE_1_2_X/src/INSTALL [new file with mode: 0644]
APACHE_1_2_X/src/Makefile.tmpl [new file with mode: 0644]
APACHE_1_2_X/src/PORTING [new file with mode: 0644]
APACHE_1_2_X/src/README [new file with mode: 0644]
APACHE_1_2_X/src/ap/ap_md5c.c [new file with mode: 0644]
APACHE_1_2_X/src/ap/ap_snprintf.c [new file with mode: 0644]
APACHE_1_2_X/src/helpers/CutRule [new file with mode: 0755]
APACHE_1_2_X/src/helpers/GuessOS [new file with mode: 0755]
APACHE_1_2_X/src/helpers/PrintPath [new file with mode: 0755]
APACHE_1_2_X/src/include/alloc.h [new file with mode: 0644]
APACHE_1_2_X/src/include/ap_config.h [new file with mode: 0644]
APACHE_1_2_X/src/include/buff.h [new file with mode: 0644]
APACHE_1_2_X/src/include/conf.h [new file with mode: 0644]
APACHE_1_2_X/src/include/explain.h [new file with mode: 0644]
APACHE_1_2_X/src/include/hsregex.h [new file with mode: 0644]
APACHE_1_2_X/src/include/http_conf_globals.h [new file with mode: 0644]
APACHE_1_2_X/src/include/http_config.h [new file with mode: 0644]
APACHE_1_2_X/src/include/http_core.h [new file with mode: 0644]
APACHE_1_2_X/src/include/http_log.h [new file with mode: 0644]
APACHE_1_2_X/src/include/http_main.h [new file with mode: 0644]
APACHE_1_2_X/src/include/http_protocol.h [new file with mode: 0644]
APACHE_1_2_X/src/include/http_request.h [new file with mode: 0644]
APACHE_1_2_X/src/include/httpd.h [new file with mode: 0644]
APACHE_1_2_X/src/include/md5.h [new file with mode: 0644]
APACHE_1_2_X/src/include/regex.h [new file with mode: 0644]
APACHE_1_2_X/src/include/rfc1413.h [new file with mode: 0644]
APACHE_1_2_X/src/include/scoreboard.h [new file with mode: 0644]
APACHE_1_2_X/src/include/util_date.h [new file with mode: 0644]
APACHE_1_2_X/src/include/util_md5.h [new file with mode: 0644]
APACHE_1_2_X/src/include/util_script.h [new file with mode: 0644]
APACHE_1_2_X/src/main/alloc.c [new file with mode: 0644]
APACHE_1_2_X/src/main/buff.c [new file with mode: 0644]
APACHE_1_2_X/src/main/explain.c [new file with mode: 0644]
APACHE_1_2_X/src/main/http_bprintf.c [new file with mode: 0644]
APACHE_1_2_X/src/main/http_config.c [new file with mode: 0644]
APACHE_1_2_X/src/main/http_core.c [new file with mode: 0644]
APACHE_1_2_X/src/main/http_log.c [new file with mode: 0644]
APACHE_1_2_X/src/main/http_main.c [new file with mode: 0644]
APACHE_1_2_X/src/main/http_protocol.c [new file with mode: 0644]
APACHE_1_2_X/src/main/http_request.c [new file with mode: 0644]
APACHE_1_2_X/src/main/md5c.c [new file with mode: 0644]
APACHE_1_2_X/src/main/rfc1413.c [new file with mode: 0644]
APACHE_1_2_X/src/main/util.c [new file with mode: 0644]
APACHE_1_2_X/src/main/util_date.c [new file with mode: 0644]
APACHE_1_2_X/src/main/util_md5.c [new file with mode: 0644]
APACHE_1_2_X/src/main/util_script.c [new file with mode: 0644]
APACHE_1_2_X/src/main/util_snprintf.c [new file with mode: 0644]
APACHE_1_2_X/src/mod_browser.c [new file with mode: 0644]
APACHE_1_2_X/src/modules/.cvsignore [new file with mode: 0644]
APACHE_1_2_X/src/modules/example/Makefile [new file with mode: 0755]
APACHE_1_2_X/src/modules/example/README [new file with mode: 0644]
APACHE_1_2_X/src/modules/example/mod_example.c [new file with mode: 0644]
APACHE_1_2_X/src/modules/proxy/Makefile [new file with mode: 0644]
APACHE_1_2_X/src/modules/proxy/mod_proxy.c [new file with mode: 0644]
APACHE_1_2_X/src/modules/proxy/mod_proxy.h [new file with mode: 0644]
APACHE_1_2_X/src/modules/proxy/proxy_cache.c [new file with mode: 0644]
APACHE_1_2_X/src/modules/proxy/proxy_connect.c [new file with mode: 0644]
APACHE_1_2_X/src/modules/proxy/proxy_ftp.c [new file with mode: 0644]
APACHE_1_2_X/src/modules/proxy/proxy_http.c [new file with mode: 0644]
APACHE_1_2_X/src/modules/proxy/proxy_util.c [new file with mode: 0644]
APACHE_1_2_X/src/modules/standard/mod_access.c [new file with mode: 0644]
APACHE_1_2_X/src/modules/standard/mod_actions.c [new file with mode: 0644]
APACHE_1_2_X/src/modules/standard/mod_alias.c [new file with mode: 0644]
APACHE_1_2_X/src/modules/standard/mod_asis.c [new file with mode: 0644]
APACHE_1_2_X/src/modules/standard/mod_auth.c [new file with mode: 0644]
APACHE_1_2_X/src/modules/standard/mod_auth_anon.c [new file with mode: 0644]
APACHE_1_2_X/src/modules/standard/mod_auth_db.c [new file with mode: 0644]
APACHE_1_2_X/src/modules/standard/mod_auth_dbm.c [new file with mode: 0644]
APACHE_1_2_X/src/modules/standard/mod_auth_msql.c [new file with mode: 0644]
APACHE_1_2_X/src/modules/standard/mod_cern_meta.c [new file with mode: 0644]
APACHE_1_2_X/src/modules/standard/mod_cgi.c [new file with mode: 0644]
APACHE_1_2_X/src/modules/standard/mod_digest.c [new file with mode: 0644]
APACHE_1_2_X/src/modules/standard/mod_dir.c [new file with mode: 0644]
APACHE_1_2_X/src/modules/standard/mod_dld.c [new file with mode: 0644]
APACHE_1_2_X/src/modules/standard/mod_env.c [new file with mode: 0644]
APACHE_1_2_X/src/modules/standard/mod_expires.c [new file with mode: 0644]
APACHE_1_2_X/src/modules/standard/mod_headers.c [new file with mode: 0644]
APACHE_1_2_X/src/modules/standard/mod_imap.c [new file with mode: 0644]
APACHE_1_2_X/src/modules/standard/mod_include.c [new file with mode: 0644]
APACHE_1_2_X/src/modules/standard/mod_info.c [new file with mode: 0644]
APACHE_1_2_X/src/modules/standard/mod_log_agent.c [new file with mode: 0644]
APACHE_1_2_X/src/modules/standard/mod_log_config.c [new file with mode: 0644]
APACHE_1_2_X/src/modules/standard/mod_log_referer.c [new file with mode: 0644]
APACHE_1_2_X/src/modules/standard/mod_mime.c [new file with mode: 0644]
APACHE_1_2_X/src/modules/standard/mod_negotiation.c [new file with mode: 0644]
APACHE_1_2_X/src/modules/standard/mod_rewrite.c [new file with mode: 0644]
APACHE_1_2_X/src/modules/standard/mod_rewrite.h [new file with mode: 0644]
APACHE_1_2_X/src/modules/standard/mod_status.c [new file with mode: 0644]
APACHE_1_2_X/src/modules/standard/mod_userdir.c [new file with mode: 0644]
APACHE_1_2_X/src/modules/standard/mod_usertrack.c [new file with mode: 0644]
APACHE_1_2_X/src/regex/.cvsignore [new file with mode: 0644]
APACHE_1_2_X/src/regex/COPYRIGHT [new file with mode: 0644]
APACHE_1_2_X/src/regex/Makefile [new file with mode: 0644]
APACHE_1_2_X/src/regex/README [new file with mode: 0644]
APACHE_1_2_X/src/regex/WHATSNEW [new file with mode: 0644]
APACHE_1_2_X/src/regex/cclass.h [new file with mode: 0644]
APACHE_1_2_X/src/regex/cname.h [new file with mode: 0644]
APACHE_1_2_X/src/regex/debug.c [new file with mode: 0644]
APACHE_1_2_X/src/regex/engine.c [new file with mode: 0644]
APACHE_1_2_X/src/regex/main.c [new file with mode: 0644]
APACHE_1_2_X/src/regex/mkh [new file with mode: 0644]
APACHE_1_2_X/src/regex/regcomp.c [new file with mode: 0644]
APACHE_1_2_X/src/regex/regerror.c [new file with mode: 0644]
APACHE_1_2_X/src/regex/regex.3 [new file with mode: 0644]
APACHE_1_2_X/src/regex/regex.7 [new file with mode: 0644]
APACHE_1_2_X/src/regex/regex.h [new file with mode: 0644]
APACHE_1_2_X/src/regex/regex2.h [new file with mode: 0644]
APACHE_1_2_X/src/regex/regexec.c [new file with mode: 0644]
APACHE_1_2_X/src/regex/regfree.c [new file with mode: 0644]
APACHE_1_2_X/src/regex/split.c [new file with mode: 0644]
APACHE_1_2_X/src/regex/tests [new file with mode: 0644]
APACHE_1_2_X/src/regex/utils.h [new file with mode: 0644]
APACHE_1_2_X/src/support/.cvsignore [new file with mode: 0644]
APACHE_1_2_X/src/support/Makefile.tmpl [new file with mode: 0644]
APACHE_1_2_X/src/support/cls.c [new file with mode: 0644]
APACHE_1_2_X/src/support/dbmmanage [new file with mode: 0644]
APACHE_1_2_X/src/support/dbmmanage.new [new file with mode: 0644]
APACHE_1_2_X/src/support/dbmmanage.readme [new file with mode: 0644]
APACHE_1_2_X/src/support/htdigest.c [new file with mode: 0644]
APACHE_1_2_X/src/support/htpasswd.1 [new file with mode: 0644]
APACHE_1_2_X/src/support/htpasswd.c [new file with mode: 0644]
APACHE_1_2_X/src/support/httpd.8 [new file with mode: 0644]
APACHE_1_2_X/src/support/httpd_monitor.c [new file with mode: 0644]
APACHE_1_2_X/src/support/log_server_status [new file with mode: 0755]
APACHE_1_2_X/src/support/logresolve.c [new file with mode: 0644]
APACHE_1_2_X/src/support/phf_abuse_log.cgi [new file with mode: 0755]
APACHE_1_2_X/src/support/rotatelogs.c [new file with mode: 0644]
APACHE_1_2_X/src/support/suexec.c [new file with mode: 0644]
APACHE_1_2_X/src/support/suexec.h [new file with mode: 0644]
APACHE_1_2_X/src/test/cls.c [new file with mode: 0644]

diff --git a/APACHE_1_2_X/ABOUT_APACHE b/APACHE_1_2_X/ABOUT_APACHE
new file mode 100644 (file)
index 0000000..22db915
--- /dev/null
@@ -0,0 +1,222 @@
+
+                     The Apache HTTP Server Project
+
+                         http://www.apache.org/
+
+                               June 1997
+
+The Apache Project is a collaborative software development effort aimed
+at creating a robust, commercial-grade, featureful, and freely-available
+source code implementation of an HTTP (Web) server.  The project is
+jointly managed by a group of volunteers located around the world, using
+the Internet and the Web to communicate, plan, and develop the server and
+its related documentation.  These volunteers are known as the Apache Group.
+In addition, hundreds of users have contributed ideas, code, and
+documentation to the project.  This file is intended to briefly describe
+the history of the Apache Group, recognize the many contributors, and
+explain how you can join the fun too.
+
+In February of 1995, the most popular server software on the Web was the
+public domain HTTP daemon developed by Rob McCool at the National Center
+for Supercomputing Applications, University of Illinois, Urbana-Champaign.
+However, development of that httpd had stalled after Rob left NCSA in
+mid-1994, and many webmasters had developed their own extensions and bug
+fixes that were in need of a common distribution.  A small group of these
+webmasters, contacted via private e-mail, gathered together for the purpose
+of coordinating their changes (in the form of "patches").  Brian Behlendorf
+and Cliff Skolnick put together a mailing list, shared information space,
+and logins for the core developers on a machine in the California Bay Area,
+with bandwidth and diskspace donated by HotWired and Organic Online.
+By the end of February, eight core contributors formed the foundation
+of the original Apache Group:
+
+   Brian Behlendorf        Roy T. Fielding          Rob Hartill
+   David Robinson          Cliff Skolnick           Randy Terbush
+   Robert S. Thau          Andrew Wilson
+
+with additional contributions from
+
+   Eric Hagberg            Frank Peters             Nicolas Pioch
+
+Using NCSA httpd 1.3 as a base, we added all of the published bug fixes
+and worthwhile enhancements we could find, tested the result on our own
+servers, and made the first official public release (0.6.2) of the Apache
+server in April 1995.  By coincidence, NCSA restarted their own development
+during the same period, and Brandon Long and Beth Frank of the NCSA Server
+Development Team joined the list in March as honorary members so that the
+two projects could share ideas and fixes.
+
+The early Apache server was a big hit, but we all knew that the codebase
+needed a general overhaul and redesign.  During May-June 1995, while
+Rob Hartill and the rest of the group focused on implementing new features
+for 0.7.x (like pre-forked child processes) and supporting the rapidly growing
+Apache user community, Robert Thau designed a new server architecture
+(code-named Shambhala) which included a modular structure and API for better
+extensibility, pool-based memory allocation, and an adaptive pre-forking
+process model.  The group switched to this new server base in July and added
+the features from 0.7.x, resulting in Apache 0.8.8 (and its brethren)
+in August.
+
+After extensive beta testing, many ports to obscure platforms, a new set
+of documentation (by David Robinson), and the addition of many features
+in the form of our standard modules, Apache 1.0 was released on
+December 1, 1995.
+
+Less than a year after the group was formed, the Apache server passed
+NCSA's httpd as the #1 server on the Internet.
+
+ ============================================================================
+
+Current Apache Group, 1 June 1997
+
+   Brian Behlendorf       Organic Online, California 
+   Ken Coar               Process Software Corporation, New England, USA 
+   Mark J. Cox            UKWeb, UK 
+   Roy T. Fielding        UC Irvine, California 
+   Dean Gaudet            Steam Tunnel Operations, California 
+   Rob Hartill            Internet Movie DB, UK 
+   Jim Jagielski          jaguNET ISP, Maryland 
+   Alexei Kosut           Nueva High School, California 
+   Ben Laurie             Freelance Consultant, UK 
+   Chuck Murcko           The Topsail Group, Pennsylvania 
+   Aram W. Mirzadeh       Qosina Corporation, New York 
+   Sameer Parekh          C2Net, California 
+   Paul Sutton            UKWeb, UK 
+   Marc Slemko            Canada 
+   Randy Terbush          Zyzzyva ISP, Nebraska 
+   Dirk-Willem van Gulik  Freelance Consultant, Italy 
+   Andrew Wilson          Freelance Consultant, UK 
+
+Apache Emeritae (old group members now off doing other things)
+
+   Robert S. Thau         MIT, Massachusetts
+   David Robinson         Cambridge University, UK
+   
+Other major contributors
+
+   Rob McCool (original author of the NCSA httpd),
+   Brandon Long and Beth Frank (NCSA Server Development Team, post-1.3),
+   Paul Richards (convinced the group to use remote CVS after 1.0),
+   Kevin Hughes (creator of all those nifty icons),
+   Henry Spencer (author of the regex library), Garey Smiley (OS/2 port),
+   Ralf S. Engelschall (mod_rewrite), Howard Fear (mod_include),
+   Florent Guillaume (language negotiation).
+
+Many 3rd-party modules, frequently used and recommended, are also
+freely-available and linked from the related projects page:
+<http://www.zyzzyva.com/module_registry/>, and their authors frequently
+contribute ideas, patches, and testing.  In particular, Doug MacEachern
+(mod_perl) and Rasmus Lerdorf (mod_php).
+
+Hundreds of people have made individual contributions to the Apache
+project.  Patch contributors are listed in the src/CHANGES file.
+Frequent contributors have included Petr Lampa, Tom Tromey,
+James H. Cloos Jr., Ed Korthof, Nathan Neulinger, Jason S. Clary,
+Jason A. Dour, Michael Douglass, Tony Sanders, Martin Kraemer,
+Brian Tao, Michael Smith, Adam Sussman, Nathan Schrenk, Matthew Gray,
+and John Heidemann.
+
+ ============================================================================
+
+How to join the Apache Group
+
+There are several levels of contributing.  If you just want to send
+in an occasional suggestion/fix, then you can just use the bug reporting
+form at <http://www.apache.org/bugdb.cgi>.  You can also subscribe to the
+announcements mailing list (apache-announce@apache.org) which we use to
+broadcast information about new releases, bugfixes, and upcoming events.
+
+If you'd like to become an active member of the Apache Group (the group
+of volunteers who vote on changes to the distributed server), then
+you need to start by subscribing to the new-httpd@apache.org mailing list.
+One warning though: traffic is high, 1000 to 1500 messages/month.
+To subscribe to the list, send "subscribe new-httpd" in the body of
+a message to <majordomo@apache.org>.  We recommend reading the list for
+a while before trying to jump in to development.
+
+   NOTE: The developer mailing list (new-httpd@apache.org) is not
+   a user support forum; it is for people actively working on development
+   of the server code and documentation, and for planning future
+   directions.  If you have user/configuration questions, send them
+   to the USENET newsgroup "comp.infosystems.www.servers.unix".
+
+The Apache Group is a meritocracy -- the more work you have done, the more
+you are allowed to do.  The group founders set the original rules, but
+they can be changed by vote of the active members.  There is a core group
+of people who have logins on our server (hyperreal.com) and access to the
+CVS repository.  Everyone has access to the CVS snapshots.  Changes to
+the code are proposed on the mailing list and usually voted on by active
+members -- three +1 (yes votes) and no -1 (no votes, or vetoes) are needed
+to commit a code change during a release cycle; docs are usually committed
+first and then changed as needed, with conflicts resolved by majority vote.
+
+Our primary method of communication is our mailing list. Approximately 40
+messages a day flow over the list, and are typically very conversational in
+tone. We discuss new features to add, bug fixes, user problems, developments
+in the web server community, release dates, etc.  The actual code development
+takes place on the developers' local machines, with proposed changes
+communicated using a patch (output of a context "diff -c3 oldfile newfile"
+command), and committed to the source repository by one of the core
+developers using remote CVS.
+
+New members of the Apache Group are added when a frequent contributor is
+nominated by one member and unanimously approved by the voting members.
+In most cases, this "new" member has been actively contributing to the
+group's work for over six months, so it's usually an easy decision.
+Anyone on the mailing list can vote on a particular issue, but we only
+count those made by active members or people who are known to be experts
+on that part of the server.  Vetoes must be accompanied by a convincing
+explanation.
+
+The above describes our past and current (as of June 1997) guidelines,
+which will probably change over time as the membership of the group
+changes and our development/coordination tools improve.
+
+ ============================================================================
+
+Why Apache Is Free
+
+Apache exists to provide a robust and commercial-grade reference
+implementation of the HTTP protocol.  It must remain a platform upon which
+individuals and institutions can build reliable systems, both for
+experimental purposes and for mission-critical purposes.  We believe the
+tools of online publishing should be in the hands of everyone, and
+software companies should make their money providing value-added services
+such as specialized modules and support, amongst other things.  We realize
+that it is often seen as an economic advantage for one company to "own" a
+market - in the software industry that means to control tightly a
+particular conduit such that all others must pay.  This is typically done
+by "owning" the protocols through which companies conduct business, at the
+expense of all those other companies.  To the extent that the protocols of
+the World Wide Web remain "unowned" by a single company, the Web will
+remain a level playing field for companies large and small. Thus,
+"ownership" of the protocol must be prevented, and the existence of a
+robust reference implementation of the protocol, available absolutely for
+free to all companies, is a tremendously good thing.  
+
+Furthermore, Apache is an organic entity; those who benefit from it
+by using it often contribute back to it by providing feature enhancements,
+bug fixes, and support for others in public newsgroups.  The amount of
+effort expended by any particular individual is usually fairly light, but
+the resulting product is made very strong.  This kind of community can
+only happen with freeware -- when someone pays for software, they usually
+aren't willing to fix its bugs.  One can argue, then, that Apache's
+strength comes from the fact that it's free, and if it were made "not
+free" it would suffer tremendously, even if that money were spent on a
+real development team.
+
+We want to see Apache used very widely -- by large companies, small
+companies, research institutions, schools, individuals, in the intranet
+environment, everywhere -- even though this may mean that companies who
+could afford commercial software, and would pay for it without blinking,
+might get a "free ride" by using Apache.  We would even be happy if some
+commercial software companies completely dropped their own HTTP server
+development plans and used Apache as a base, with the proper attributions
+as described in the LICENSE file.
+
+Thanks for using Apache!
+
+ ============================================================================
+Roy Fielding, June 1997
+
+If you are interested in other WWW history, see <http://www.webhistory.org/>
diff --git a/APACHE_1_2_X/CHANGES b/APACHE_1_2_X/CHANGES
new file mode 100644 (file)
index 0000000..7e762e2
--- /dev/null
@@ -0,0 +1,129 @@
+                   OVERVIEW OF NEW FEATURES IN APACHE 1.2
+
+New features with this release, as extensions of the Apache functionality
+For more information, see the documentation included with this release
+(htdocs/manual/) or http://www.apache.org/docs/
+
+In addition to a number of bug fixes and internal performance
+enhancements, Apache 1.2 has the following specific new user
+features:
+
+
+  *) HTTP/1.1 Compliance
+       Aside from the optional proxy module (which operates as HTTP/1.0),
+       Apache is conditionally compliant with the HTTP/1.1 proposed standard,
+       as approved by the IESG and the IETF HTTP working group.
+       HTTP/1.1 provides a much-improved protocol, and should allow for
+       greater performance and efficiency when transferring files. Apache
+       does, however, still work great with HTTP/1.0 browsers.  We are very
+       close to being unconditionally compliant; if you note any deviance
+       from the proposed standard, please report it as a bug.
+
+  *) eXtended Server Side Includes (XSSI)
+       A new set of server-side include directives allows the user to
+       better create WWW pages. This includes number of powerful new
+       features, such as the ability to set variables and use conditional
+       HTML.
+
+  *) File-based and Regex-enabled Directive Sections
+       The new <Files> section allows directives to be enabled based on
+       full filename, not just directory and URL. In addition, <Files>
+       sections can appear in .htaccess files. <Files>, along with
+       <Directory> and <Location>, can also now be based on regular
+       expressions, not just simple prefix matching.
+
+  *) Browser-based Environment Variables
+       Environment variables can now be set based on the User-Agent
+       string of the browser. Combined with XSSI, this allows you to
+       write browser-based conditional HTML documents.
+
+  *) SetUID CGI Execution 
+       Apache now supports the execution of CGI scripts as users other
+       than the server user. A number of security checks are built in to
+       try and make this as safe as possible.
+
+  *) URL Rewriting Module
+       The optional mod_rewrite module is now included. This module can
+       provide powerful URL mapping, using regular expressions. There's
+       nothing this module can't do!
+
+  *) Enhanced, Configurable Logging
+       The optional mod_log_config included with earlier versions of
+       Apache is now standard, and has been enhanced to allow logging of
+       much more detail about the transaction, and can be used to open
+       more than one log at once (each of which can have a different log
+       format).
+
+  *) User Tracking (Cookies) Revisions
+       The mod_cookies included with previous versions of Apache has been
+       renamed mod_usertrack, to more accurately reflect its function
+       (some people inadvertently thought it enabled cookie support in
+       Apache, which is not true - Apache supports the use of cookies
+       directly). It is also now possible to disable the generation of
+       cookies, even when the cookie module is compiled in. Also, an
+       expiry time can be set on the cookies.
+
+  *) Multiple IPs in <VirtualHost>
+       The <VirtualHost> directive can now take more than one IP address
+       or hostname. This lets a single vhost handles requests for
+       multiple IPs or hostnames.
+
+  *) CGI Debugging Environment
+       ScriptLog allows you to now set up a log that records all input
+       and output to failed CGI scripts. This includes environment
+       variables, input headers, POST data, output, and more. This makes
+       CGI scripts much easier to debug.
+
+  *) Resource Limits for CGI Scripts
+       New directives allow the limiting of resources used by CGI scripts
+       (e.g. max CPU time). This is helpful in preventing 'runaway' CGI
+       processes.
+
+  *) Redirect Directive Can Return Alternate Status
+       The Redirect directive can return permanent or temporary redirects,
+       "Gone" or "See Other" HTTP status. For NCSA-compatibility,
+       RedirectTemp and RedirectPermanent are also implemented.
+
+  *) Graceful Restarts
+       Apache can re-read the config files and re-open log files without
+       terminating transactions in progress.
+
+  *) Simplified Compilation
+       The process of configuring Apache for compilation has been
+       simplified.
+
+  *) Add or Remove Options
+       The Options directive can now add or remove options from those
+       currently in force, rather than always replacing them.
+
+  *) Command-line Help
+       The -h command-line option now lists all the available directives.
+
+  *) Optional Headers Module to Set or Remove HTTP Headers
+       The optional mod_headers module can be used to set custom headers
+       in the HTTP response. It can append to existing headers, replace
+       them, or remove headers from the response.
+
+  *) Conditional Config Directives
+       A new <IfModule> section allows directives to be enabled only if a
+       given module is loaded into the server.
+
+  *) Authorization Directives Now Use NCSA-style Syntax
+       The AuthUserFile, AuthGroupFile and AuthDigestFile commands now
+       have a syntax compatible with the NCSA server.
+
+  *) Optional Proxy Module
+       An improved FTP, HTTP, and CONNECT mode SSL proxy is included with
+       Apache 1.2. Some of the changes visible to users:
+       
+              - Improved FTP proxy supporting PASV mode
+              - NoProxy directive for excluding sites to proxy
+              - CONNECT mode ports are configurable from a list
+              - NoCache * directive for disabling proxy caching
+              - Numerous bug fixes
+
+  *) Optional Example Module
+       An example module that demonstrates many of the aspects of the
+       API is now included with Apache as of version 1.2.  It can be
+       used as a base for those who wish to write their own Apache
+       modules.
diff --git a/APACHE_1_2_X/KEYS b/APACHE_1_2_X/KEYS
new file mode 100644 (file)
index 0000000..1507ca3
--- /dev/null
@@ -0,0 +1,171 @@
+This file contains the PGP keys of various Apache developers.
+Please don't use them for email unless you have to. Their main
+purpose is code signing.
+
+Apache users: pgp < KEYS
+Apache developers: pgp -kxa <your name> and append it to this file.
+
+
+Type Bits/KeyID    Date       User ID
+pub  1024/2719AF35 1995/05/13 Ben Laurie <ben@algroup.co.uk>
+                              Ben Laurie <ben@gonzo.ben.algroup.co.uk>
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: 2.6.3ia
+
+mQCNAi+0jQEAAAEEAK7oX0FeNncaHfa1v+V7SMUviAm8qB8orWG0zvja4ZtSrHVg
+/PMwppUh44t5ERA9lltRBdHu30+YSh8a1dYt1XOD83nknzj9rhtpFAPqyywlLVhN
+VY3PVLyMbULw27aEAGc+StFqrDoUQ0+j9QU/YH/IyVN9rBaJyhsIDEUnGa81AAUR
+tB5CZW4gTGF1cmllIDxiZW5AYWxncm91cC5jby51az6JARUDBRAyb2Doc3AsNzyk
+Yh0BARa6CACUBnsP9Vb+T/PvNYKVQBIODz+90tz5GozWwCVfPVSaRd8Dz+oF1sFs
+YCz/KuxqBhL5PkiCuSMfOVlPA5nirjoktMF/af5saZqhPr5rvr67Z1OzZnVDvWe4
+DhFrn8EoLrY5YNJhUwfINnZqyKaQu8TW6p4caLkTCW0KM+4ztTe74xRG9NeE+K0+
+0RMpAF3jEY36LGRjq6miazt2bVZQDTl6CuWE+gAaFlX2ojV7e1xdxVvpBIEc34MP
+g9ORJ0evx1QilMt1VyGcS/pe4IQgjdJqjU/4fzqFZkT2nntQMbV9kQyNe2+qfqP7
+giTryIanmBAfd3oOCTsRz2VKPfdhCqCRiQB1AwUQMRdzEEyr2GZv4ALJAQEuhAL6
+A8I84BR+87uNAHD0ZJkTM73WdyMEGvAKBvrZK/g0VLYj0NtgkSuRJfrXnGkuh27I
+ZrjfL952Q/mXgMtHhJHJ9YfenGFWSEDHnolNzKOzTQJpE01IZ3nWv7ezA9N1LZVC
+iQCVAgUQMROrdRsIDEUnGa81AQEUNgQAlvyjt534RDQd2AYGoZriaFzjaL7dTCRH
+4b1zxuWBNWf3pI4W0iwU02Q5rEWEmY5DLl6/ie+vcQKOWSqXVgnM/s6EARdKEN56
+d6PzkwszgfEybDYrcAxReJcTCcV8ItJer/iqpBLgtaxyUpI77NvKcDGHp6BgYpnv
+1lNkH0FISK+JAJUDBRAwtzlWdGx7qH+PTVkBARFWA/99NTCMihlOZS7LmHDVic/q
+H1K1DVdMcv0iL39+7Pq4+AA/ET8dWIgcjaIreSqAZTpjwU1pMPaWgecDD1rEMCYX
+R+JoofLJ24BLcSlpXJ/gWMifYNxqdDeMRkw/aW/kaXQJWIz+oDYNuOyi5VvB6faF
+6Lm7P5cw1mX0I5rYc3woh7QoQmVuIExhdXJpZSA8YmVuQGdvbnpvLmJlbi5hbGdy
+b3VwLmNvLnVrPokAlQIFEDEXgCUbCAxFJxmvNQEBiL8D/3MLjfHGvuByqP1VFQrF
+QeMNd2aIQuC7ys3lkDvrLkkPJQANua0/MdDaZk6F5pCGcTmmmaJOjcOcCheD7FU5
+w9zxkQGR3Swr3opFHSr/CkEl83jRy3oq1MFydWoGajQjIr/c23X8zr+XntPyO6VX
+q5He4RrTiXeAEFBzz+J+R+EQ
+=zh1u
+-----END PGP PUBLIC KEY BLOCK-----
+
+
+Type bits/keyID    Date       User ID
+pub  1024/A99F75DD 1997/01/24 Ken A L Coar <Coar@DECUS.Org>
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: 2.6.2
+
+mQCNAzLpIyUAAAEEAN9KC8CxTeozPYJjsnhFpJ14d4Hhf2M6OTgqPQFRHOswM/3j
+B7IW0s+HwVyQ5/SjIlo+8ur9X7yaj1FS2GQmKD1x9LKeHRAoosBIs33okRtoeDRy
+ufTaTyQTwLklxClWm3JEef4xZioun1mtWbpz0yVEOCSZcRvtnJrNPMCpn3XdAAUR
+tB1LZW4gQSBMIENvYXIgPENvYXJAREVDVVMuT3JnPokAlQMFEDNLrGCazTzAqZ91
+3QEBzwEEAMqamgAftJ8X39dH+slXVZhXAkUDfUNPkDyy7Yd8R+UTCdXXZMRrVSc3
+3nGsd7sycFot+TQ4RWK8g1o/eY0LzgT+hSxsI80BabdnX2hCP8Yq6aqBw9XfHRQU
++zUHA5h150dX9vEUp+Rb8UKPvkqTNz58Cv1HFAHboZ55KMJ+oeTk
+=arlJ
+-----END PGP PUBLIC KEY BLOCK-----
+
+Type Bits/KeyID    Date       User ID
+pub   768/A0BB71C1 1997/06/03 Jim Jagielski <jim@jaguNET.com>
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: 2.6.3
+
+mQBtAzOUkNMAAAEDANZdTUJQPwrFI9526Qf+DEWL8dXgfhWW8o6CzewdcCoHYEpu
+9CiOMD3f9bgo1VozOPceGzCu/9FF2hMLUvVsTAZkzC3rre5TtPo/vOf5HJ+ac9M7
+aqxW+gRu2/90oLtxwQAFEbQfSmltIEphZ2llbHNraSA8amltQGphZ3VORVQuY29t
+PokAdQMFEDOUkNRu2/90oLtxwQEB8iEC/i9Qo55TlT8bRpcqeM3lzNDqzU9cqKRf
+9X8pGJIVE5m2JPm99qPLs8RPeepLChi8ZZ+2hSfb7ldQhvVLgNqQqLpsjGtJjJOU
+C+MrKDeSk2WAicg6Uo0FWCsEHxrssw139A==
+=pwim
+-----END PGP PUBLIC KEY BLOCK-----
+
+Type Bits/KeyID    Date       User ID
+pub  2048/DD919C31 1996/12/24 sameer@c2.net
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: 2.6.3ia
+
+mQENAzK/QZIAAAEIALrsEjuGlt6wkHy8fx2wPSkH7paAqJHDCbO1W/GMVs41BsH1
+xpyBi9lOtUXHsDC8Obx/TES4/xVPSsFKPQLa9Q/OsxjXmEPBvQ5PZdOXJ5zmRMI1
+1cfUp2s8w6i+IS68IWRKdPMshGWFGar1YUPM1UpVME7U+uGD3wgdC4DrVJHzS5Eh
+gEDyQ9FPb+8CpsRO3AvUPzsZGG8Iy/9GiLzmaJG34zZ5fv5X7sr89xiWJ21ehk+X
+ePO9kvq+nzfOCCK6a3GZD4g3KJX/Pm3oKeaXeL8WSCCPzpNbtRJk3ofeN7Zm1K0L
+yChPiyui+OO063/WASv52bxUIlmzbX82a92RnDEABRG0DXNhbWVlckBjMi5uZXSJ
+ARUDBRAyv0GTbX82a92RnDEBAfqVB/9GSzADIVqY0faFOLN6+E3qqg3hPRLBvjgC
+5cvTlwT7W64zI+aiSZuN+xAXq+3lnKtmzn45F3hD7gBxRPJbSKsObn2zU4UcqW/o
+qoiYEnO9EhoBomwPUbVy8C00CWvDLfeF4L5r+2oXgilTsCojSaWJX0QoPCwRQao1
+YwZ6CqAA78vdbBNkmA0WrPsVqwd3ijgFapcX671AqiT+pDbvK646I6uGPXJzN3ZU
+vFuDim9D2uNk9CfvPhKGscr4qqP40TnNn5fjSsmrFyFxYsdwo7I4TFpnsEPOw226
+GU+TR7zdwnByP72AxPEBJ/F22LwNyreuph+fRpWCnCf+9gVW9Heh
+=jS5Z
+-----END PGP PUBLIC KEY BLOCK-----
+
+ ===========================
+Rob Hartill <robh@imdb.com>
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: 2.6.2
+
+mQCNAzG6VfMAAAEEAOvtvphFG/D02vGLENBl5OVPgEJgP9E1xhUgKTZnJstv30kD
+h1IqeIBkEAy5bpKapCbvvxukyQErhB0efTi2v5yTAlz5pVjgWM5Sa8CyTXJmXPHH
+EuOfy1DqaiQSmZ6KWX0ygw3gKDZMiNMf06UURLLYtRlGKSYY3WVj2u2UCmS9AAUR
+tB5Sb2JlcnQgSGFydGlsbCA8cm9iaEBpbWRiLmNvbT6JAJUDBRAx5eIAZWPa7ZQK
+ZL0BAU2XBACXfopMzC8kW3KEqq+N9W9fkGNgy//8XqQ77FmfPQPbO4X7Zn3cyO46
+MxvPP+92zSyN3dyj/xWZYoRLwll+ync9d4KUFwKw45DALAvz1CKHMOpQPD7dIWdE
+9poJQrcbKeOqLcGZTu/hY90gWBUZ++9umR8X8lyh/WEgcUolfgYHew==
+=upYh
+-----END PGP PUBLIC KEY BLOCK-----
+
+Type Bits/KeyID    Date       User ID
+pub  1024/631B5749 1996/06/21 Randy Terbush <randy@zyzzyva.com>
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: 2.6.3
+
+mQCNAzHLBS8AAAEEANGFXb9o0NPVfVjSLvQh1j3fN6cMeVNA5BGUJ6HZGP/NDxTE
+i8hwejJqakkU4ux/g6Kqckrx3h8WR7OXZZ+R8CsA0bg9Sr42ndEQCUISgArg+lXZ
+gRUniARPPA7tamTSq8v1mnxqy9s26Ht2rAG2D6IiK/7v0JlezKirDeBjG1dJAAUR
+tCFSYW5keSBUZXJidXNoIDxyYW5keUB6eXp6eXZhLmNvbT6JAJUDBRAxywUwqKsN
+4GMbV0kBAegnA/sH63WyfwMFmn3nWe8T/5IXO/QkMYoMGLS1i7IxMY9O8BVvKQM+
+oxEcJdFAG7zPZkpgKzTBxmExz5hMZ9hwJ42XhrslWoP7JVvADJcdthrUAYW9W+jx
+GcDYAW3qW5DpKsQchfvXq9QOBDxP+Kbbe2B8xGEyGUhLkacISFTrIhhQSg==
+=8P8s
+-----END PGP PUBLIC KEY BLOCK-----
+
+Type Bits/KeyID    Date       User ID
+pub  1024/49A563D9 1997/02/24 Mark Cox <mark@ukweb.com>
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: 2.6.3ia
+
+mQCNAzMRY/IAAAEEAOloTOU0f4w7FDRMM6kA/6XazXxJ/HH8dsmb6E7RuYfVlXsd
+kCwxUBOkyW+AYhkHbYUwnB5qBoFUyLrbLGuwKHW1KnAwgbeZLTH5nqQLpA0RLGVZ
+v3tzImKUdyyxBphZWC4IeEgUbl9cc+piOsEJ8QzF7gnqwWo/Ku6tTP1JpWPZAAUR
+tBlNYXJrIENveCA8bWFya0B1a3dlYi5jb20+iQCVAwUQMxFj8u6tTP1JpWPZAQHz
+eQP+N0nQDbPzWeqLssQLyhFkjw5zZByN60j8p25+6JEq7RXgkN1cHtAdH5LMwRAG
+fc258f7P9Syp64lH8s4XWYSX5GX8YA8MurOrJmoGFrJs/yxWng8xtxI9tFUnuoIb
+HqnD7HCS9Oj1INdyyQuCxZYGHAgxHhpfNTZt+33tMSFIZTQ=
+=uIkU
+-----END PGP PUBLIC KEY BLOCK-----
+
+Type Bits/KeyID    Date       User ID
+pub  1024/2F90A69D 1997/02/24 Paul Sutton <paul@ukweb.com>
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: 2.6.3ia
+
+mQCNAzMRsB0AAAEEAKj2XYYEGcZhT69x4gskQ3xz+KMTLn7gKSqqcyyeinJ0ZjLl
+6AJjb1/68nGsF+IIY+IJS+5smq8do1qpC3UZcmw423Sg8F71GeqDO4HZXOAOieVy
+rpVs6S5TaXlJOcrC7zZCx+iql97+xJFjUGkkS7j/jIkx1AajzMNkSr0vkKadAAUR
+tBxQYXVsIFN1dHRvbiA8cGF1bEB1a3dlYi5jb20+iQCVAwUQMxGwHcNkSr0vkKad
+AQGrigP9F43zbiOigYel+JCMiB0HK/UdqSrf3xWxHIKWKNhQNjhnyeF+jKQwFld6
+7KQYsqZIpHsWLWmSk0AmKQOUIw+DxclDxBL2dT4p+CjgTgIAcbvPpahWkBAw/E+c
+EGTiYbe+Y3sHJhhP+d0TOLmsETG9tpi7gFZ6FfNcWPxFMdxGrf4=
+=0jQW
+-----END PGP PUBLIC KEY BLOCK-----
+
+Type bits/keyID    Date       User ID
+pub  1024/BA20321D 1997/06/05 Chuck Murcko <chuck@topsail.org>
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: 2.6.2
+
+mQCNAzOW7moAAAEEAMYZlNOxWCjLR/PosadbG+xsrB2unid2LiYoakTFiDIBaZjx
+bu6hNmVZPYfKOXQcqrCu0EY3uVLP/L89bST5pfIZOzz8GTm33zrETgfzpXYyFdbX
+eZ5vc6aa3+7zmI7h/aU567P9ruB2C/RBLl1A59wmPRRVvjEIAkI4bAO6IDIdAAUR
+tCBDaHVjayBNdXJja28gPGNodWNrQHRvcHNhaWwub3JnPg==
+=vUdL
+-----END PGP PUBLIC KEY BLOCK-----
+
diff --git a/APACHE_1_2_X/LICENSE b/APACHE_1_2_X/LICENSE
new file mode 100644 (file)
index 0000000..ec09d30
--- /dev/null
@@ -0,0 +1,54 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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/APACHE_1_2_X/README b/APACHE_1_2_X/README
new file mode 100644 (file)
index 0000000..f8b53dc
--- /dev/null
@@ -0,0 +1,86 @@
+                                 Apache
+                             Version 1.2 (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
+-------------
+
+The documentation available as of the date of this release is also
+included, in HTML format, in the htdocs/manual/ directory. For the
+most up-to-date documentation, visit us on the WWW, at
+<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).
+
+Licencing
+---------
+
+Please see the file called LICENSE.
+
+Acknowledgements
+----------------
+
+We wish to acknowledge the following copyrighted works that make up
+portions of the Apache software:
+
+Portions of this software were developed at the National Center for
+Supercomputing Applications at the University of Illinois at
+Urbana-Champaign.
+
+This software contains code derived from the RSA Data Security Inc. MD5
+Message-Diest Algorithm, including various modifications by Spyglass Inc.,
+Caregie Mellon University, and Bell Communications Research, Inc. 
+(Bellcore).
+
+This package contains software written and copyrighted by Henry Spencer. 
+Please see the file called src/regex/COPYRIGHT. 
diff --git a/APACHE_1_2_X/RULES.CVS b/APACHE_1_2_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/APACHE_1_2_X/cgi-bin/printenv b/APACHE_1_2_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/APACHE_1_2_X/cgi-bin/test-cgi b/APACHE_1_2_X/cgi-bin/test-cgi
new file mode 100644 (file)
index 0000000..a85631e
--- /dev/null
@@ -0,0 +1,31 @@
+#!/bin/sh
+
+# disable filename globbing
+set -f
+
+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/APACHE_1_2_X/conf/access.conf-dist b/APACHE_1_2_X/conf/access.conf-dist
new file mode 100644 (file)
index 0000000..8e17b53
--- /dev/null
@@ -0,0 +1,70 @@
+# 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/server-status
+# Change the ".your_domain.com" to match your domain to enable.
+
+#<Location /server-status>
+#SetHandler server-status
+
+#order deny,allow
+#deny from all
+#allow from .your_domain.com
+#</Location>
+
+# There have been reports of people trying to abuse an old bug from pre-1.1
+# days.  This bug involved a CGI script distributed as a part of Apache.
+# By uncommenting these lines you can redirect these attacks to a logging 
+# script on phf.apache.org.  Or, you can record them yourself, using the script
+# support/phf_abuse_log.cgi.
+
+#<Location /cgi-bin/phf*>
+#deny from all
+#ErrorDocument 403 http://phf.apache.org/phf_abuse_log.cgi
+#</Location>
+
+# You may place any other directories or locations you wish to have
+# access information for after this one.
+
diff --git a/APACHE_1_2_X/conf/httpd.conf-dist b/APACHE_1_2_X/conf/httpd.conf-dist
new file mode 100644 (file)
index 0000000..3a783c6
--- /dev/null
@@ -0,0 +1,186 @@
+# 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
+#  On HPUX you may not be able to use shared memory as nobody, and the
+#  suggested workaround is to create a user www and use that user.
+User nobody
+Group #-1
+
+# The following directive disables keepalives and HTTP header flushes for
+# Netscape 2.x and browsers which spoof it. There are known problems with
+# these
+
+BrowserMatch Mozilla/2 nokeepalive
+
+# 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.
+# Not all architectures require this.  But if yours does (you'll know because
+# this file is created when you run Apache) then you *must* ensure that
+# no two invocations of Apache share the same scoreboard file.
+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
+
+Timeout 300
+
+# KeepAlive: Whether or not to allow persistent connections (more than
+# one request per connection). Set to "Off" to deactivate.
+
+KeepAlive On
+
+# MaxKeepAliveRequests: The maximum number of requests to allow
+# during a persistent connection. Set to 0 to allow an unlimited amount.
+# We reccomend you leave this number high, for maximum performance.
+
+MaxKeepAliveRequests 100
+
+# 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 a_domain.com another_domain.edu joes.garage_sale.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.some_domain.com>
+#ServerAdmin webmaster@host.some_domain.com
+#DocumentRoot /www/docs/host.some_domain.com
+#ServerName host.some_domain.com
+#ErrorLog logs/host.some_domain.com-error_log
+#TransferLog logs/host.some_domain.com-access_log
+#</VirtualHost>
+
+
diff --git a/APACHE_1_2_X/conf/mime.types b/APACHE_1_2_X/conf/mime.types
new file mode 100644 (file)
index 0000000..b662c16
--- /dev/null
@@ -0,0 +1,98 @@
+# 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
+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
+application/x-hdf              hdf
+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/midi                     mid midi kar
+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/APACHE_1_2_X/conf/srm.conf-dist b/APACHE_1_2_X/conf/srm.conf-dist
new file mode 100644 (file)
index 0000000..40102cd
--- /dev/null
@@ -0,0 +1,206 @@
+# 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
+
+# Note that if you include a trailing / on fakename then the server will
+# require it to be present in the URL.  So "/icons" isn't aliased in this
+# example.
+
+#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
+
+# 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://some.other_server.com/subscription_info.html
+#
diff --git a/APACHE_1_2_X/htdocs/apache_pb.gif b/APACHE_1_2_X/htdocs/apache_pb.gif
new file mode 100644 (file)
index 0000000..3a1c139
Binary files /dev/null and b/APACHE_1_2_X/htdocs/apache_pb.gif differ
diff --git a/APACHE_1_2_X/htdocs/index.html b/APACHE_1_2_X/htdocs/index.html
new file mode 100644 (file)
index 0000000..a454ba3
--- /dev/null
@@ -0,0 +1,23 @@
+<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>
+The Apache <A HREF="manual/index.html">documentation has been
+included with this distribution.</A>
+
+<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" alt="">
+
+</BODY></HTML>
diff --git a/APACHE_1_2_X/htdocs/manual/LICENSE b/APACHE_1_2_X/htdocs/manual/LICENSE
new file mode 100644 (file)
index 0000000..ec09d30
--- /dev/null
@@ -0,0 +1,54 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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/APACHE_1_2_X/htdocs/manual/TODO b/APACHE_1_2_X/htdocs/manual/TODO
new file mode 100644 (file)
index 0000000..975ac8e
--- /dev/null
@@ -0,0 +1,4 @@
+Documentation changes/enhancements needed:
+
+- Documentation for mod_expires
+- Documentation for Satisfy
diff --git a/APACHE_1_2_X/htdocs/manual/bind.html b/APACHE_1_2_X/htdocs/manual/bind.html
new file mode 100644 (file)
index 0000000..9253168
--- /dev/null
@@ -0,0 +1,109 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html><head>
+<title>Setting which addresses and ports Apache uses</title>
+</head>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<h1 ALIGN="CENTER">Setting which addresses and ports Apache uses</h1>
+
+<hr>
+
+When Apache starts, it connects to some port and address on the
+local machine and waits for incoming requests. By default, it
+listens to all addresses on the machine, and to the port
+as specified by the <tt>Port</tt> directive in the server configuration.
+However, it can be told to listen to more the one port, or to listen
+to only selected addresses, or a combination. This is often combined
+with the Virtual Host feature which determines how Apache
+responds to different IP addresses, hostnames and ports.<p>
+
+There are two directives used to restrict or specify which addresses
+and ports Apache listens to.
+
+<ul>
+<li><a href="#bindaddress">BindAddress</a> is used to restrict the server to listening to
+  a single address, and can be used to permit multiple Apache servers
+  on the same machine listening to different IP addresses.
+<li><a href="#listen">Listen</a> can be used to make a single Apache server listen
+  to more than one address and/or port.
+</ul>
+
+<h3><a name="bindaddress">BindAddress</a></h3>
+<strong>Syntax:</strong> BindAddress <em>[ * | IP-address | hostname ]</em><br>
+<strong>Default:</strong> <code>BindAddress *</code><br>
+<strong>Context:</strong> server config<br>
+<strong>Status:</strong> Core<p>
+
+Makes the server listen to just the specified address. If the argument
+is *, the server listens to all addresses. The port listened to
+is set with the <tt>Port</tt> directive. Only one BindAddress
+should be used.
+
+<h3><a name="listen">Listen</a></h3>
+<strong>Syntax:</strong> Listen <em>[ port | IP-address:port ]</em><br>
+<strong>Default:</strong> <code>none</code><br>
+<strong>Context:</strong> server config<br>
+<strong>Status:</strong> Core<p>
+
+<tt>Listen</tt> can be used instead of <tt>BindAddress</tt> and
+<tt>Port</tt>. It tells the server to accept incoming requests on the
+specified port or address-and-port combination. If the first format is
+used, with a port number only, the server listens to the given port on
+all interfaces, instead of the port given by the <tt>Port</tt>
+directive. If an IP address is given as well as a port, the server
+will listen on the given port and interface.  <p> Multiple Listen
+directives may be used to specify a number of addresses and ports to
+listen to. The server will respond to requests from any of the listed
+addresses and ports.<p>
+
+For example, to make the server accept connections on both port
+80 and port 8000, use:
+<pre>
+   Listen 80
+   Listen 8000
+</pre>
+
+To make the server accept connections on two specified
+interfaces and port numbers, use
+<pre>
+   Listen 192.170.2.1:80
+   Listen 192.170.2.5:8000
+</pre>
+
+<h2>How this works with Virtual Hosts</h2>
+
+BindAddress and Listen do not implement Virtual Hosts. They tell the
+main server what addresses and ports to listen to.  If no
+&lt;VirtualHost&gt; directives are used, the server will behave the
+same for all accepted requests. However, &lt;VirtualHost&gt; can be
+used to specify a different behavior for one or more of the addresses
+and ports. To implement a VirtualHost, the server must first be told
+to listen to the address and port to be used. Then a
+&lt;VirtualHost&gt; section should be created for a specified address
+and port to set the behavior of this virtual host. Note that if the
+&lt;VirtualHost&gt; is set for an address and port that the server is
+not listening to, it cannot be accessed.
+
+<h2>See also</h2>
+
+See also the documentation on
+<a href="virtual-host.html">Virtual Hosts</a>,
+<a href="host.html">Non-IP virtual hosts</a>,
+<a href="mod/core.html#bindaddress">BindAddress directive</a>,
+<a href="mod/core.html#port">Port directive</a>,
+<a href="dns-caveats.html">DNS Issues</a>
+and
+<a href="mod/core.html#virtualhost">&lt;VirtualHost&gt; section</a>.
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
+
diff --git a/APACHE_1_2_X/htdocs/manual/cgi_path.html b/APACHE_1_2_X/htdocs/manual/cgi_path.html
new file mode 100644 (file)
index 0000000..8ac3bc0
--- /dev/null
@@ -0,0 +1,93 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html><head>
+<title>PATH_INFO Changes in the CGI Environment</title>
+</head>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<h1 ALIGN="CENTER">PATH_INFO Changes in the CGI Environment</h1>
+
+<hr>
+
+<h2><a name="over">Overview</a></h2>
+
+<p>As implemented in Apache 1.1.1 and earlier versions, the method
+Apache used to create PATH_INFO in the CGI environment was
+counterintuitive, and could result in crashes in certain cases. In
+Apache 1.2 and beyond, this behavior has changed. Although this
+results in some compatibility problems with certain legacy CGI
+applications, the Apache 1.2 behavior is still compatible with the
+CGI/1.1 specification, and CGI scripts can be easily modified (<a
+href="#compat">see below</a>).
+
+<h2><a name="prob">The Problem</a></h2>
+
+<p>Apache 1.1.1 and earlier implemented the PATH_INFO and SCRIPT_NAME
+environment variables by looking at the filename, not the URL. While
+this resulted in the correct values in many cases, when the filesystem
+path was overloaded to contain path information, it could result in
+errant behavior. For example, if the following appeared in a config
+file:
+<pre>
+     Alias /cgi-ralph /usr/local/httpd/cgi-bin/user.cgi/ralph
+</pre>
+<p>In this case, <code>user.cgi</code> is the CGI script, the "/ralph"
+is information to be passed onto the CGI. If this configuration was in
+place, and a request came for "<code>/cgi-ralph/script/</code>", the
+code would set PATH_INFO to "<code>/ralph/script</code>", and
+SCRIPT_NAME to "<code>/cgi-</code>". Obviously, the latter is
+incorrect. In certain cases, this could even cause the server to
+crash.</p>
+
+<h2><a name="solution">The Solution</a></h2>
+
+<p>Apache 1.2 and later now determine SCRIPT_NAME and PATH_INFO by
+looking directly at the URL, and determining how much of the URL is
+client-modifiable, and setting PATH_INFO to it. To use the above
+example, PATH_INFO would be set to "<code>/script</code>", and
+SCRIPT_NAME to "<code>/cgi-ralph</code>". This makes sense and results
+in no server behavior problems. It also permits the script to be
+guaranteed that
+"<code>http://$SERVER_NAME:$SERVER_PORT$SCRIPT_NAME$PATH_INFO</code>"
+will always be an accessible URL that points to the current script,
+something which was not necessarily true with previous versions of
+Apache.
+
+<p>However, the "<code>/ralph</code>"
+information from the <code>Alias</code> directive is lost. This is
+unfortunate, but we feel that using the filesystem to pass along this
+sort of information is not a recommended method, and a script making
+use of it "deserves" not to work. Apache 1.2b3 and later, however, do
+provide <a href="#compat">a workaround.</a>
+
+<h2><a name="compat">Compatibility with Previous Servers</a></h2>
+
+<p>It may be necessary for a script that was designed for earlier
+versions of Apache or other servers to need the information that the
+old PATH_INFO variable provided. For this purpose, Apache 1.2 (1.2b3
+and later) sets an additional variable, FILEPATH_INFO. This
+environment variable contains the value that PATH_INFO would have had
+with Apache 1.1.1.</p>
+
+<p>A script that wishes to work with both Apache 1.2 and earlier
+versions can simply test for the existence of FILEPATH_INFO, and use
+it if available. Otherwise, it can use PATH_INFO. For example, in
+Perl, one might use:
+<pre>
+    $path_info = $ENV{'FILEPATH_INFO'} || $ENV{'PATH_INFO'};
+</pre>
+
+<p>By doing this, a script can work with all servers supporting the
+CGI/1.1 specification, including all versions of Apache.</p>
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
+
diff --git a/APACHE_1_2_X/htdocs/manual/content-negotiation.html b/APACHE_1_2_X/htdocs/manual/content-negotiation.html
new file mode 100644 (file)
index 0000000..2aa06eb
--- /dev/null
@@ -0,0 +1,426 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<TITLE>Apache Content Negotiation</TITLE>
+</HEAD>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<h1 ALIGN="CENTER">Content Negotiation</h1>
+
+Apache's support for content negotiation has been updated to meet the
+HTTP/1.1 specification. It can choose the best representation of a
+resource based on the browser-supplied preferences for media type,
+languages, character set and encoding.  It is also implements a
+couple of features to give more intelligent handling of requests from
+browsers which send incomplete negotiation information.  <p>
+
+Content negotiation is provided by the 
+<a href="mod/mod_negotiation.html">mod_negotiation</a> module,
+which is compiled in by default.
+
+<hr>
+
+<h2>About Content Negotiation</h2>
+
+A resource may be available in several different representations. For
+example, it might be available in different languages or different
+media types, or a combination.  One way of selecting the most
+appropriate choice is to give the user an index page, and let them
+select. However it is often possible for the server to choose
+automatically. This works because browsers can send as part of each
+request information about what representations they prefer. For
+example, a browser could indicate that it would like to see
+information in French, if possible, else English will do. Browsers
+indicate their preferences by headers in the request. To request only
+French representations, the browser would send
+
+<pre>
+  Accept-Language: fr
+</pre>
+
+Note that this preference will only be applied when there is a choice
+of representations and they vary by language. 
+<p>
+
+As an example of a more complex request, this browser has been
+configured to accept French and English, but prefer French, and to
+accept various media types, preferring HTML over plain text or other
+text types, and preferring GIF or JPEG over other media types, but also
+allowing any other media type as a last resort:
+
+<pre>
+  Accept-Language: fr; q=1.0, en; q=0.5
+  Accept: text/html; q=1.0, text/*; q=0.8, image/gif; q=0.6,
+        image/jpeg; q=0.6, image/*; q=0.5, */*; q=0.1
+</pre>
+
+Apache 1.2 supports 'server driven' content negotiation, as defined in
+the HTTP/1.1 specification. It fully supports the Accept,
+Accept-Language, Accept-Charset and Accept-Encoding request headers.
+<p>
+
+The terms used in content negotiation are: a <b>resource</b> is an
+item which can be requested of a server, which might be selected as
+the result of a content negotiation algorithm. If a resource is
+available in several formats, these are called <b>representations</b>
+or <b>variants</b>. The ways in which the variants for a particular
+resource vary are called the <b>dimensions</b> of negotiation.
+
+<h2>Negotiation in Apache</h2>
+
+In order to negotiate a resource, the server needs to be given
+information about each of the variants. This is done in one of two
+ways: 
+
+<ul>
+  <li> Using a type map (i.e., a <code>*.var</code> file) which
+       names the files containing the variants explicitly
+  <li> Or using a 'MultiViews' search, where the server does an implicit 
+       filename pattern match, and chooses from among the results.
+</ul>
+
+<h3>Using a type-map file</h3>
+
+A type map is a document which is associated with the handler
+named <code>type-map</code> (or, for backwards-compatibility with
+older Apache configurations, the mime type
+<code>application/x-type-map</code>).  Note that to use this feature,
+you've got to have a <code>SetHandler</code> some place which defines a
+file suffix as <code>type-map</code>; this is best done with a
+<pre>
+
+  AddHandler type-map var
+
+</pre>
+in <code>srm.conf</code>.  See comments in the sample config files for
+details. <p>
+
+Type map files have an entry for each available variant; these entries
+consist of contiguous RFC822-format header lines.  Entries for
+different variants are separated by blank lines.  Blank lines are
+illegal within an entry.  It is conventional to begin a map file with
+an entry for the combined entity as a whole (although this
+is not required, and if present will be ignored). An example
+map file is:
+<pre>
+
+  URI: foo
+
+  URI: foo.en.html
+  Content-type: text/html
+  Content-language: en
+
+  URI: foo.fr.de.html
+  Content-type: text/html; charset=iso-8859-2
+  Content-language: fr, de
+</pre>
+
+If the variants have different source qualities, that may be indicated
+by the "qs" parameter to the media type, as in this picture (available
+as jpeg, gif, or ASCII-art):
+<pre>
+  URI: foo
+
+  URI: foo.jpeg
+  Content-type: image/jpeg; qs=0.8
+
+  URI: foo.gif
+  Content-type: image/gif; qs=0.5
+
+  URI: foo.txt
+  Content-type: text/plain; qs=0.01
+
+</pre>
+<p>
+
+qs values can vary between 0.000 and 1.000. Note that any variant with
+a qs value of 0.000 will never be chosen. Variants with no 'qs'
+parameter value are given a qs factor of 1.0.  <p>
+
+The full list of headers recognized is:
+
+<dl>
+  <dt> <code>URI:</code>
+  <dd> uri of the file containing the variant (of the given media
+       type, encoded with the given content encoding).  These are
+       interpreted as URLs relative to the map file; they must be on
+       the same server (!), and they must refer to files to which the
+       client would be granted access if they were to be requested
+       directly. 
+  <dt> <code>Content-type:</code>
+  <dd> media type --- charset, level and "qs" parameters may be given.  These
+       are often referred to as MIME types; typical media types are
+       <code>image/gif</code>, <code>text/plain</code>, or
+       <code>text/html;&nbsp;level=3</code>.
+  <dt> <code>Content-language:</code>
+  <dd> The languages of the variant, specified as an Internet standard
+       language code (e.g., <code>en</code> for English,
+       <code>kr</code> for Korean, etc.).
+  <dt> <code>Content-encoding:</code>
+  <dd> If the file is compressed, or otherwise encoded, rather than
+       containing the actual raw data, this says how that was done.
+       For compressed files (the only case where this generally comes
+       up), content encoding should be
+       <code>x-compress</code>, or <code>x-gzip</code>, as appropriate.
+  <dt> <code>Content-length:</code>
+  <dd> The size of the file.  Clients can ask to receive a given media
+       type only if the variant isn't too big; specifying a content
+       length in the map allows the server to compare against these
+       thresholds without checking the actual file.
+</dl>
+
+<h3>Multiviews</h3>
+
+This is a per-directory option, meaning it can be set with an
+<code>Options</code> directive within a <code>&lt;Directory&gt;</code>,
+<code>&lt;Location&gt;</code> or <code>&lt;Files&gt;</code>
+section in <code>access.conf</code>, or (if <code>AllowOverride</code>
+is properly set) in <code>.htaccess</code> files.  Note that
+<code>Options All</code> does not set <code>MultiViews</code>; you
+have to ask for it by name.  (Fixing this is a one-line change to
+<code>http_core.h</code>).
+
+<p>
+
+The effect of <code>MultiViews</code> is as follows: if the server
+receives a request for <code>/some/dir/foo</code>, if
+<code>/some/dir</code> has <code>MultiViews</code> enabled, and
+<code>/some/dir/foo</code> does <em>not</em> exist, then the server reads the
+directory looking for files named foo.*, and effectively fakes up a
+type map which names all those files, assigning them the same media
+types and content-encodings it would have if the client had asked for
+one of them by name.  It then chooses the best match to the client's
+requirements, and forwards them along.
+
+<p>
+
+This applies to searches for the file named by the
+<code>DirectoryIndex</code> directive, if the server is trying to
+index a directory; if the configuration files specify
+<pre>
+
+  DirectoryIndex index
+
+</pre> then the server will arbitrate between <code>index.html</code>
+and <code>index.html3</code> if both are present.  If neither are
+present, and <code>index.cgi</code> is there, the server will run it.
+
+<p>
+
+If one of the files found when reading the directive is a CGI script,
+it's not obvious what should happen.  The code gives that case
+special treatment --- if the request was a POST, or a GET with
+QUERY_ARGS or PATH_INFO, the script is given an extremely high quality
+rating, and generally invoked; otherwise it is given an extremely low
+quality rating, which generally causes one of the other views (if any)
+to be retrieved.
+
+<h2>The Negotiation Algorithm</h2>
+
+After Apache has obtained a list of the variants for a given resource,
+either from a type-map file or from the filenames in the directory, it
+applies a algorithm to decide on the 'best' variant to return, if
+any. To do this it calculates a quality value for each variant in each
+of the dimensions of variance. It is not necessary to know any of the
+details of how negotiation actually takes place in order to use Apache's
+content negotiation features. However the rest of this document
+explains in detail the algorithm used for those interested.  <p>
+
+In some circumstances, Apache can 'fiddle' the quality factor of a
+particular dimension to achieve a better result. The ways Apache can
+fiddle quality factors is explained in more detail below.
+
+<h3>Dimensions of Negotiation</h3>
+
+<table>
+<tr><th>Dimension
+<th>Notes
+<tr><td>Media Type
+<td>Browser indicates preferences on Accept: header. Each item 
+can have an associated quality factor. Variant description can also
+have a quality factor.
+<tr><td>Language
+<td>Browser indicates preferences on Accept-Language: header. Each
+item
+can have a quality factor. Variants can be associated with none, one
+or more languages.
+<tr><td>Encoding
+<td>Browser indicates preference with Accept-Encoding: header.
+<tr><td>Charset
+<td>Browser indicates preference with Accept-Charset: header. Variants
+can indicate a charset as a parameter of the media type.
+</table>
+
+<h3>Apache Negotiation Algorithm</h3>
+
+Apache uses an algorithm to select the 'best' variant (if any) to
+return to the browser. This algorithm is not configurable. It operates
+like this:
+<p>
+
+<ol>
+<li>
+Firstly, for each dimension of the negotiation, the appropriate
+Accept header is checked and a quality assigned to this each
+variant. If the Accept header for any dimension means that this
+variant is not acceptable, eliminate it. If no variants remain, go
+to step 4.
+
+<li>Select the 'best' variant by a process of elimination. Each of
+the following tests is applied in order. Any variants not selected at
+each stage are eliminated. After each test, if only one variant
+remains, it is selected as the best match. If more than one variant
+remains, move onto the next test.
+
+<ol>
+<li>Multiply the quality factor from the Accept header with the
+  quality-of-source factor for this variant's media type, and select
+  the variants with the highest value
+
+<li>Select the variants with the highest language quality factor
+
+<li>Select the variants with the best language match, using either the
+  order of languages on the <code>LanguagePriority</code> directive (if present),
+  else the order of languages on the Accept-Language header.
+
+<li>Select the variants with the highest 'level' media parameter
+  (used to give the version of text/html media types). 
+
+<li>Select only unencoded variants, if there is a mix of encoded
+  and non-encoded variants. If either all variants are encoded
+  or all variants are not encoded, select all.
+
+<li>Select only variants with acceptable charset media parameters,
+  as given on the Accept-Charset header line. Charset ISO-8859-1
+  is always acceptable. Variants not associated with a particular
+  charset are assumed to be in ISO-8859-1.
+
+<li>Select the variants with the smallest content length
+
+<li>Select the first variant of those remaining (this will be either the
+first listed in the type-map file, or the first read from the directory)
+and go to stage 3.
+
+</ol>
+
+<li>The algorithm has now selected one 'best' variant, so return
+  it as the response. The HTTP response header Vary is set to indicate the
+  dimensions of negotiation (browsers and caches can use this
+  information when caching the resource). End.
+
+<li>To get here means no variant was selected (because non are acceptable
+  to the browser). Return a 406 status (meaning "No acceptable representation")
+  with a response body consisting of an HTML document listing the
+  available variants. Also set the HTTP Vary header to indicate the
+  dimensions of variance.
+
+</ol>
+<h2><a name="better">Fiddling with Quality Values</a></h2>
+
+Apache sometimes changes the quality values from what would be
+expected by a strict interpretation of the algorithm above. This is to
+get a better result from the algorithm for browsers which do not send
+full or accurate information. Some of the most popular browsers send
+Accept header information which would otherwise result in the
+selection of the wrong variant in many cases. If a browser
+sends full and correct information these fiddles will not
+be applied.
+<p>
+
+<h3>Media Types and Wildcards</h3>
+
+The Accept: request header indicates preferences for media types. It
+can also include 'wildcard' media types, such as "image/*" or "*/*"
+where the * matches any string. So a request including:
+<pre>
+  Accept: image/*, */*
+</pre>
+
+would indicate that any type starting "image/" is acceptable,
+as is any other type (so the first "image/*" is redundant). Some
+browsers routinely send wildcards in addition to explicit types they
+can handle. For example:
+<pre>
+  Accept: text/html, text/plain, image/gif, image/jpeg, */*
+</pre>
+
+The intention of this is to indicate that the explicitly
+listed types are preferred, but if a different representation is
+available, that is ok too. However under the basic algorithm, as given
+above, the */* wildcard has exactly equal preference to all the other
+types, so they are not being preferred. The browser should really have
+sent a request with a lower quality (preference) value for *.*, such
+as:
+<pre>
+  Accept: text/html, text/plain, image/gif, image/jpeg, */*; q=0.01
+</pre>
+
+The explicit types have no quality factor, so they default to a
+preference of 1.0 (the highest). The wildcard */* is given
+a low preference of 0.01, so other types will only be returned if
+no variant matches an explicitly listed type. 
+<p>
+
+If the Accept: header contains <i>no</i> q factors at all, Apache sets
+the q value of "*/*", if present, to 0.01 to emulate the desired
+behavior. It also sets the q value of wildcards of the format
+"type/*" to 0.02 (so these are preferred over matches against
+"*/*". If any media type on the Accept: header contains a q factor,
+these special values are <i>not</i> applied, so requests from browsers
+which send the correct information to start with work as expected.
+
+<h3>Variants with no Language</h3>
+
+If some of the variants for a particular resource have a language
+attribute, and some do not, those variants with no language
+are given a very low language quality factor of 0.001.<p>
+
+The reason for setting this language quality factor for
+variant with no language to a very low value is to allow
+for a default variant which can be supplied if none of the
+other variants match the browser's language preferences. 
+
+For example, consider the situation with three variants:
+
+<ul>
+<li>foo.en.html, language en
+<li>foo.fr.html, language en
+<li>foo.html, no language
+</ul>
+
+The meaning of a variant with no language is that it is
+always acceptable to the browser. If the request Accept-Language
+header includes either en or fr (or both) one of foo.en.html
+or foo.fr.html will be returned. If the browser does not list
+either en or fr as acceptable, foo.html will be returned instead.
+
+<h2>Note on Caching</h2>
+
+When a cache stores a document, it associates it with the request URL.
+The next time that URL is requested, the cache can use the stored
+document, provided it is still within date. But if the resource is
+subject to content negotiation at the server, this would result in
+only the first requested variant being cached, and subsequent cache
+hits could return the wrong response. To prevent this, 
+Apache normally marks all responses that are returned after content negotiation
+as non-cacheable by HTTP/1.0 clients. Apache also supports the HTTP/1.1 
+protocol features to allow caching of negotiated responses. <P>
+
+For requests which come from a HTTP/1.0 compliant client (either a
+browser or a cache), the directive <tt>CacheNegotiatedDocs</tt> can be
+used to allow caching of responses which were subject to negotiation.
+This directive can be given in the server config or virtual host, and
+takes no arguments. It has no effect on requests from HTTP/1.1
+clients.
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
diff --git a/APACHE_1_2_X/htdocs/manual/custom-error.html b/APACHE_1_2_X/htdocs/manual/custom-error.html
new file mode 100644 (file)
index 0000000..3f04af0
--- /dev/null
@@ -0,0 +1,153 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<TITLE>Custom error responses</TITLE>
+</HEAD>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<H1 ALIGN="CENTER">Custom error responses</H1>
+
+<DL>
+
+<DT>Purpose
+
+  <DD>Additional functionality. Allows webmasters to configure the response of
+      Apache to some error or problem.
+
+      <P>Customizable responses can be defined to be activated in the
+      event of a server detected error or problem.
+
+      <P>e.g. if a script crashes and produces a "500 Server Error"
+      response, then this response can be replaced with either some
+      friendlier text or by a redirection to another URL (local or
+      external).
+       
+      <P>
+       
+<DT>Old behavior
+
+  <DD>NCSA httpd 1.3 would return some boring old error/problem message 
+      which would often be meaningless to the user, and would provide no 
+      means of logging the symptoms which caused it.<BR>
+
+      <P>
+
+<DT>New behavior
+
+  <DD>The server can be asked to;
+  <OL>
+    <LI>Display some other text, instead of the NCSA hard coded messages, or
+    <LI>redirect to a local URL, or
+    <LI>redirect to an external URL.
+  </OL>
+
+  <P>Redirecting to another URL can be useful, but only if some information
+     can be passed which can then be used to explain and/or log the error/problem
+     more clearly.
+
+  <P>To achieve this, Apache will define new CGI-like environment
+     variables, e.g.
+
+  <blockquote><code>
+REDIRECT_HTTP_ACCEPT=*/*, image/gif, image/x-xbitmap, image/jpeg <br>
+REDIRECT_HTTP_USER_AGENT=Mozilla/1.1b2 (X11; I; HP-UX A.09.05 9000/712) <br>
+REDIRECT_PATH=.:/bin:/usr/local/bin:/etc <br>
+REDIRECT_QUERY_STRING= <br>
+REDIRECT_REMOTE_ADDR=121.345.78.123 <br>
+REDIRECT_REMOTE_HOST=ooh.ahhh.com <br>
+REDIRECT_SERVER_NAME=crash.bang.edu <br>
+REDIRECT_SERVER_PORT=80 <br>
+REDIRECT_SERVER_SOFTWARE=Apache/0.8.15 <br>
+REDIRECT_URL=/cgi-bin/buggy.pl <br>
+  </code></blockquote>
+
+  <P>note the <code>REDIRECT_</code> prefix. 
+
+  <P>At least <code>REDIRECT_URL</code> and <code>REDIRECT_QUERY_STRING</code> will
+     be passed to the new URL (assuming it's a cgi-script or a cgi-include). The
+     other variables will exist only if they existed prior to the error/problem.
+     <b>None</b> of these will be set if your ErrorDocument is an
+     <i>external</i> redirect (i.e. anything starting with a protocol name
+     like <code>http:</code>, even if it refers to the same host as the
+     server).<p>
+
+<DT>Configuration
+
+  <DD> Use of "ErrorDocument" is enabled for .htaccess files when the
+       <A HREF="mod/core.html#allowoverride">"FileInfo" override</A> is allowed.
+
+  <P>Here are some examples...
+
+  <blockquote><code>
+ErrorDocument 500 /cgi-bin/crash-recover <br>
+ErrorDocument 500 "Sorry, our script crashed. Oh dear<br>
+ErrorDocument 500 http://xxx/ <br>
+ErrorDocument 404 /Lame_excuses/not_found.html  <br>
+ErrorDocument 401 /Subscription/how_to_subscribe.html
+  </code></blockquote>
+
+  <P>The syntax is, 
+
+  <P><code><A HREF="mod/core.html#errordocument">ErrorDocument</A></code>
+&lt;3-digit-code&gt; action 
+
+  <P>where the action can be,
+
+  <OL>
+    <LI>Text to be displayed.  Prefix the text with a quote (&quot;). Whatever
+        follows the quote is displayed. <em>Note: the (&quot;) prefix isn't 
+        displayed.</em>
+
+    <LI>An external URL to redirect to.
+
+    <LI>A local URL to redirect to.
+
+  </OL>
+</DL>
+
+<P><HR><P>
+
+<h2>Custom error responses and redirects</H2>
+
+<DL>
+
+<DT>Purpose
+
+  <DD>Apache's behavior to redirected URLs has been modified so that additional
+      environment variables are available to a script/server-include.<p>
+
+<DT>Old behavior
+
+  <DD>Standard CGI vars were made available to a script which has been
+      redirected to. No indication of where the redirection came from was provided.
+
+  <p>
+
+<DT>New behavior
+  <DD>
+
+A new batch of environment variables will be initialized for use by a
+script which has been redirected to.  Each new variable will have the
+prefix <code>REDIRECT_</code>.  <code>REDIRECT_</code> environment
+variables are created from the CGI environment variables which existed
+prior to the redirect, they are renamed with a <code>REDIRECT_</code>
+prefix, i.e. <code>HTTP_USER_AGENT</code> becomes
+<code>REDIRECT_HTTP_USER_AGENT</code>.  In addition to these new
+variables, Apache will define <code>REDIRECT_URL</code> and
+<code>REDIRECT_STATUS</code> to help the script trace its origin.
+Both the original URL and the URL being redirected to can be logged in
+the access log.
+
+</DL>
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
diff --git a/APACHE_1_2_X/htdocs/manual/dns-caveats.html b/APACHE_1_2_X/htdocs/manual/dns-caveats.html
new file mode 100644 (file)
index 0000000..50a9bcf
--- /dev/null
@@ -0,0 +1,201 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html><head>
+<title>Issues Regarding DNS and Apache</title>
+</head>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<h1 ALIGN="CENTER">Issues Regarding DNS and Apache</h1>
+
+<p>This page could be summarized with the statement: <i>don't require
+Apache to use DNS for any parsing of the configuration files</i>.
+If Apache has to use DNS to parse the configuration files then your
+server may be subject to reliability problems (it might not boot), or
+denial and theft of service attacks (including users able to steal hits
+from other users).
+
+<h3>A Simple Example</h3>
+
+Consider this configuration snippet:
+
+<blockquote><pre>
+    &lt;VirtualHost www.abc.dom&gt;
+    ServerAdmin webgirl@abc.dom
+    DocumentRoot /www/abc
+    &lt;/VirtualHost&gt;
+</pre></blockquote>
+
+<p>In order for Apache to function properly it absolutely needs
+to have two pieces of information about each virtual host: the
+<a href="mod/core.html#servername"><code>ServerName</code></a>
+and at least one IP address that the server
+responds to.  This example does not include the IP address, so Apache
+must use DNS to find the address of <code>www.abc.dom</code>.  If for
+some reason DNS is not available at the time your server is parsing its
+config file, then this virtual host <b>will not be configured</b>.  It
+won't be able to respond to any hits to this virtual host (prior to
+Apache version 1.2 the server would not even boot).
+
+<p>Suppose that <code>www.abc.dom</code> has address 10.0.0.1.  Then
+consider this configuration snippet:
+
+<blockquote><pre>
+    &lt;VirtualHost 10.0.0.1&gt;
+    ServerAdmin webgirl@abc.dom
+    DocumentRoot /www/abc
+    &lt;/VirtualHost&gt;
+</pre></blockquote>
+
+<p>Now Apache needs to use reverse DNS to find the <code>ServerName</code>
+for this virtualhost.  If that reverse lookup fails then it will partially
+disable the virtualhost (prior to Apache version 1.2 the server would not
+even boot).  If the virtual host is name-based then it will effectively
+be totally disabled, but if it is IP-based then it will mostly work.
+However if Apache should ever have to generate a full URL for the server
+which includes the server name then it will fail to generate a valid URL.
+
+<p>Here is a snippet that avoids both of these problems.
+
+<blockquote><pre>
+    &lt;VirtualHost 10.0.0.1&gt;
+    ServerName www.abc.dom
+    ServerAdmin webgirl@abc.dom
+    DocumentRoot /www/abc
+    &lt;/VirtualHost&gt;
+</pre></blockquote>
+
+<h3>Denial of Service</h3>
+
+<p>There are (at least) two forms that denial of service can come in.
+If you are running a version of Apache prior to version 1.2 then your
+server will not even boot if one of the two DNS lookups mentioned above
+fails for any of your virtual hosts.  In some cases this DNS lookup may
+not even be under your control.  For example, if <code>abc.dom</code>
+is one of your customers and they control their own DNS then they
+can force your (pre-1.2) server to fail while booting simply by deleting the
+<code>www.abc.dom</code> record.
+
+<p>Another form is far more insidious.  Consider this configuration
+snippet:
+
+<blockquote><pre>
+    &lt;VirtualHost www.abc.dom&gt;
+    ServerAdmin webgirl@abc.dom
+    DocumentRoot /www/abc
+    &lt;/VirtualHost&gt;
+</pre></blockquote>
+
+<blockquote><pre>
+    &lt;VirtualHost www.def.dom&gt;
+    ServerAdmin webguy@def.dom
+    DocumentRoot /www/def
+    &lt;/VirtualHost&gt;
+</pre></blockquote>
+
+<p>Suppose that you've assigned 10.0.0.1 to <code>www.abc.dom</code> and
+10.0.0.2 to <code>www.def.dom</code>.  Furthermore, suppose that
+<code>def.com</code> has control of their own DNS.  With this config
+you have put <code>def.com</code> into a position where they can steal
+all traffic destined to <code>abc.com</code>.  To do so, all they have to
+do is set <code>www.def.dom</code> to 10.0.0.1.
+Since they control their own DNS you can't stop them from pointing the
+<code>www.def.com</code> record wherever they wish.
+
+<p>Requests coming in to 10.0.0.1 (including all those where users typed
+in URLs of the form <code>http://www.abc.dom/whatever</code>) will all be
+served by the <code>def.com</code> virtual host.  To better understand why
+this happens requires a more in-depth discussion of how Apache matches
+up incoming requests with the virtual host that will serve it.  A rough
+document describing this <a href="vhosts-in-depth.html"> is available</a>.
+
+<h3>The "main server" Address</h3>
+
+<p>The addition of <a href="host.html">non-IP-based virtual host
+support</a> in Apache 1.1 requires Apache to know the IP address(es) of
+the host that httpd is running on.  To get this address it uses either
+the global <code>ServerName</code> (if present) or calls the C function
+<code>gethostname</code> (which should return the same as typing
+"hostname" at the command prompt).  Then it performs a DNS lookup on
+this address.  At present there is no way to avoid this lookup.
+
+<p>If you fear that this lookup might fail because your DNS server is down
+then you can insert the hostname in <code>/etc/hosts</code> (where you
+probably already have it so that the machine can boot properly).  Then
+ensure that your machine is configured to use <code>/etc/hosts</code>
+in the event that DNS fails.  Depending on what OS you are using this
+might be accomplished by editing <code>/etc/resolv.conf</code>, or maybe
+<code>/etc/nsswitch.conf</code>.
+
+<p>If your server doesn't have to perform DNS for any other reason
+then you might be able to get away with running Apache with the
+<code>HOSTRESORDER</code> environment variable set to "local".  This all
+depends on what OS and resolver libraries you are using.  It also affects
+CGIs unless you use <a href="mod/mod_env.html"><code>mod_env</code></a>
+to control the environment.  It's best to consult the man pages or FAQs
+for your OS.
+
+<h3>The _default_ Address</h3>
+
+<p>Any address that happens to go to your webserver which doesn't match
+the IP address of any of the webservers will be served from the "main" or
+"default" server configurations.  The "main" server configuration consists
+of all those definitions appearing outside of any VirtualHost section.
+You may want instead to define a <code>&lt;VirtualHost _default_:*&gt;</code>
+which returns 403 or 404 for all hits.  (The trailing <code>:*</code>
+makes it apply to all ports, which is just a safety measure should you
+begin using multiple <code><a href="mod/core.html#listen">Listen</a></code>
+directives.)
+
+<h3><a name="tips">Tips to Avoid these problems</a></h3>
+
+<ul>
+<li> use IP addresses in <code>&lt;VirtualHost&gt</code>
+<li> use IP addresses in <code>Listen</code>
+<li> use IP addresses in <code>BindAddress</code>
+<li> ensure all virtual hosts have an explicit <code>ServerName</code>
+<li> create a <code>&lt;VirtualHost _default_:*&gt;</code> server that
+    has no pages to serve
+</ul>
+
+<h3>Appendix: Future Directions</h3>
+
+<p>The situation regarding DNS is highly undesirable.  For Apache
+1.2 we've attempted to make the server at least continue booting
+in the event of failed DNS, but it might not be the best we
+can do.  In any event requiring the use of explicit IP addresses in
+configuration files is highly undesirable in today's Internet where <a
+href="http://www.ietf.org/html.charters/pier-charter.html">renumbering
+</a> is a necessity.
+
+<p>A possible work around to the theft of service attack described above
+would be to perform a reverse DNS lookup on the ip address returned by
+the forward lookup and compare the two names.  In the event of a mismatch
+the virtualhost would be disabled.  This would require reverse DNS to be
+configured properly (which is something that most admins are familiar with
+because of the common use of "double-reverse" DNS lookups by FTP servers
+and TCP wrappers).
+
+<p>In any event it doesn't seem possible to reliably boot a virtual-hosted
+web server when DNS has failed unless IP addresses are used.  Partial
+solutions such as disabling portions of the configuration might be worse
+than not booting at all depending on what the webserver is supposed
+to accomplish.
+
+<p>As HTTP/1.1 is deployed and browsers and proxies start issuing the 
+<code>Host</code> header it will become possible to avoid the use of
+IP-based virtual hosts entirely.  In this event a webserver has no requirement
+to do DNS lookups during configuration.  But as of March 1997 these
+features have not been deployed widely enough to be put into use on
+critical webservers.
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
+
diff --git a/APACHE_1_2_X/htdocs/manual/env.html b/APACHE_1_2_X/htdocs/manual/env.html
new file mode 100644 (file)
index 0000000..9ef4f28
--- /dev/null
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<TITLE>Special Purpose Environment Variables</TITLE>
+</HEAD>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<h1 ALIGN="CENTER">Special Purpose Environment Variables</h1>
+<P>Interoperability problems have led to the introduction of
+mechanisms to modify the way Apache behaves when talking to particular
+clients. To make these mechanisms as flexible as possible, they
+are invoked by defining environment variables, typically with 
+<A HREF="mod/mod_browser.html#browsermatch">BrowserMatch</A>, though 
+<A HREF="mod/mod_env.html#setenv">SetEnv</A> and 
+<A HREF="mod/mod_env.html#passenv">PassEnv</A> could also be used, for
+example.</P>
+
+<H2>nokeepalive</H2>
+This disables <A HREF="mod/core.html#keepalive">KeepAlive</A> when set. Because
+of problems with Netscape 2.x and KeepAlive, we recommend the following
+directive be used:
+<BLOCKQUOTE><CODE>
+BrowserMatch Mozilla/2 nokeepalive
+</CODE></BLOCKQUOTE>
+<H2>force-response-1.0</H2>
+This forces an HTTP/1.0 response when set. It was originally implemented as a
+result of a problem with AOL's proxies. Some clients may not behave correctly
+when given an HTTP/1.1 response, and this can be used to interoperate with
+them.
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
diff --git a/APACHE_1_2_X/htdocs/manual/expand.pl b/APACHE_1_2_X/htdocs/manual/expand.pl
new file mode 100755 (executable)
index 0000000..37483ad
--- /dev/null
@@ -0,0 +1,100 @@
+#!/usr/local/bin/perl5
+
+# This is a very simple Perl script to expand server-side includes
+# in the directory it is run, and direct subdirectories. It will
+# work only on SSI directives of the form
+#
+# <!--#include virtual="filename" -->
+#
+# Filename must be relative to the directory the file appears in.
+#
+# Nov 30, 1996 - Alexei Kosut <akosut@apache.org>
+
+# ====================================================================
+# Copyright (c) 1996,1997 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/>.
+
+# Put a list of dirs (except ..) into @dirs
+
+opendir DIR, "." or die "Could not open directory: $!";
+@dirs = grep !/^\.\.$/, (grep -d, readdir DIR);
+closedir DIR;
+
+foreach $dir (@dirs) {
+    print "Entering directory $dir\n";
+    opendir SUBDIR, "$dir" or die "Could not open subdir $dir: $!";
+    foreach $file (grep /\.html$/, readdir SUBDIR) {
+       print "Expanding file $dir/$file\n";
+       rename "$dir/$file", "$dir/${file}.old";
+       open READ, "$dir/${file}.old" or die "Couldn't read $dir/$file: $!";
+       open WRITE, ">$dir/$file" or die "Couldn't write $dir/$file: $!";
+       while ($r = <READ>) {
+           if ($r =~ /<!--#include virtual="(.*)" -->/) {
+               ($pre, $include, $post) = ($`, $1, $');
+               print WRITE $pre;
+
+               open INC, "$dir/$include" or
+                   print "Could not include file $dir/$include: $!";
+               print WRITE while (<INC>);
+               close INC;
+
+               print WRITE $post;
+           }
+           else {
+               print WRITE $r;
+           }
+       }
+       close READ;
+       close WRITE;
+       unlink "$dir/$file.old";
+    }
+    closedir SUBDIR;
+}
+
+
diff --git a/APACHE_1_2_X/htdocs/manual/footer.html b/APACHE_1_2_X/htdocs/manual/footer.html
new file mode 100644 (file)
index 0000000..d1f330d
--- /dev/null
@@ -0,0 +1,3 @@
+<HR>
+
+<A HREF="./"><IMG SRC="images/index.gif" ALT="Index"></A>
diff --git a/APACHE_1_2_X/htdocs/manual/handler.html b/APACHE_1_2_X/htdocs/manual/handler.html
new file mode 100644 (file)
index 0000000..8059216
--- /dev/null
@@ -0,0 +1,141 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<TITLE>Apache's Handler Use</TITLE>
+</HEAD>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<h1 ALIGN="CENTER">Apache's Handler Use</h1>
+
+<h2>What is a Handler</h2>
+
+<p>A "handler" is an internal Apache representation of the action to be
+performed when a file is called. Generally, files have implicit
+handlers, based on the file type. Normally, all files are simply
+served by the server, but certain file typed are "handled"
+separately. For example, you may use a type of
+"application/x-httpd-cgi" to invoke CGI scripts.</p>
+
+<p>Apache 1.1 adds the additional ability to use handlers
+explicitly. Either based on filename extensions or on location, these
+handlers are unrelated to file type. This is advantageous both because
+it is a more elegant solution, but it also allows for both a type
+<strong>and</strong> a handler to be associated with a file.</p>
+
+<p>Handlers can either be built into the server or to a module, or
+they can be added with the <a
+href="mod/mod_actions.html#action">Action</a> directive. The built-in
+handlers in the standard distribution are as follows:</p>
+
+<ul>
+<li><strong>send-as-is</strong>:
+    Send file with HTTP headers as is.
+    (<a href="mod/mod_asis.html">mod_asis</a>)
+<li><strong>cgi-script</strong>:
+    Treat the file as a CGI script.
+    (<a href="mod/mod_cgi.html">mod_cgi</a>)
+<li><strong>imap-file</strong>:
+    Imagemap rule file.
+    (<a href="mod/mod_imap.html">mod_imap</a>)
+<li><strong>server-info</strong>:
+    Get the server's configuration information
+    (<a href="mod/mod_info.html">mod_info</a>)
+<li><strong>server-parsed</strong>:
+    Parse for server-side includes
+    (<a href="mod/mod_include.html">mod_include</a>)
+<li><strong>server-status</strong>:
+    Get the server's status report
+    (<a href="mod/mod_status.html">mod_status</a>)
+<li><strong>type-map</strong>:
+    Parse as a type map file for content negotiation
+    (<a href="mod/mod_negotiation.html">mod_negotiation</a>)
+</ul>
+
+<p>
+
+<h2>Directives</h2>
+<ul>
+<li><A HREF="#addhandler">AddHandler</A>
+<li><A HREF="#sethandler">SetHandler</A>
+</ul>
+
+<hr>
+
+<h2><a name="addhandler">AddHandler</a></h2>
+
+<strong>Syntax:</strong> &lt;AddHandler <em>handler-name extension</em>&gt;<br>
+<strong>Context:</strong> server config, virtual host, directory, .htaccess<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_mime
+
+<p>AddHandler maps the filename extension <em>extension</em> to the
+handler <em>handler-name</em>. For example, to activate CGI scripts
+with the file extension "<code>.cgi</code>", you might use:
+<pre>
+    AddHandler cgi-script cgi
+</pre>
+
+<p>Once that has been put into your srm.conf or httpd.conf file, any
+file ending with "<code>.cgi</code>" will be treated as a CGI
+program.</p>
+
+<hr>
+
+<h2><a name="sethandler">SetHandler</a></h2>
+
+<strong>Syntax:</strong> &lt;SetHandler <em>handler-name</em>&gt;<br>
+<strong>Context:</strong> directory, .htaccess<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_mime
+
+<p>When placed into an <code>.htaccess</code> file or a
+<code>&lt;Directory&gt;</code> or <code>&lt;Location&gt;</code> section,
+this directive forces all matching files to be parsed through the
+handler given by <em>handler-name</em>. For example, if you had a
+directory you wanted to be parsed entirely as imagemap rule files,
+regardless of extension, you might put the following into an
+<code>.htaccess</code> file in that directory:
+<pre>
+    SetHandler imap-file
+</pre>
+<p>Another example: if you wanted to have the server display a status
+report whenever a URL of <code>http://servername/status</code> was
+called, you might put the following into access.conf:
+<pre>
+    &lt;Location /status&gt;
+    SetHandler server-status
+    &lt;/Location&gt;
+</pre>
+
+<p><hr>
+
+<h2>Programmer's Note</h2>
+
+<p>In order to implement the handler features, an addition has been
+made to the <a href="misc/API.html">Apache API</a> that you may wish to
+make use of. Specifically, a new record has been added to the
+<code>request_rec</code> structure:</p>
+<pre>
+    char *handler
+</pre>
+<p>If you wish to have your module engage a handler, you need only to
+set <code>r-&gt;handler</code> to the name of the handler at any time
+prior to the <code>invoke_handler</code> stage of the
+request. Handlers are implemented as they were before, albeit using
+the handler name instead of a content type. While it is not
+necessary, the naming convention for handlers is to use a
+dash-separated word, with no slashes, so as to not invade the media
+type name-space.</p>
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
+
diff --git a/APACHE_1_2_X/htdocs/manual/header.html b/APACHE_1_2_X/htdocs/manual/header.html
new file mode 100644 (file)
index 0000000..a6e66f6
--- /dev/null
@@ -0,0 +1,3 @@
+<DIV ALIGN="CENTER">
+ <IMG SRC="images/sub.gif" ALT="[APACHE DOCUMENTATION]">
+</DIV>
diff --git a/APACHE_1_2_X/htdocs/manual/host.html b/APACHE_1_2_X/htdocs/manual/host.html
new file mode 100644 (file)
index 0000000..908cd2d
--- /dev/null
@@ -0,0 +1,173 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html><head>
+<title>Apache non-IP Virtual Hosts</title>
+</head>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<h1 ALIGN="CENTER">Apache non-IP Virtual Hosts</h1>
+
+<strong>See Also:</strong>
+<a href="virtual-host.html">Virtual Host Support</a>
+
+<hr>
+
+<h2>What is a Virtual Host</h2>
+
+<p>The "Virtual Host" refers to the practice of maintaining more than
+one server on one machine, as differentiated by their apparent
+hostname. For example, it is often desirable for companies sharing a
+web server to have their own domains, with web servers accessible as
+<code>www.company1.com</code> and <code>www.company2.com</code>,
+without requiring the user to know any extra path information.</p>
+
+<p>Apache was one of the first servers to support virtual hosts right
+out of the box, but since the base <code>HTTP</code> (HyperText
+Transport Protocol) standard does not allow any method for the server
+to determine the hostname it is being addressed as, Apache's virtual
+host support has required a separate IP address for each
+server. Documentation on using this approach (which still works very
+well) <a href="virtual-host.html">is available</a>.
+
+<p>While the approach described above works, with the available IP
+address space growing smaller, and the number of domains increasing,
+it is not the most elegant solution, and is hard to implement on some
+machines. The <code>HTTP/1.1</code> protocol contains a method for the
+server to identify what name it is being addressed as. Apache 1.1 and
+later support this approach as well as the traditional
+IP-address-per-hostname method.</p>
+
+<p>The benefits of using the new virtual host support is a practically
+unlimited number of servers, ease of configuration and use, and
+requires no additional hardware or software. The main disadvantage is
+that the user's browser must support this part of the protocol. The
+latest versions of many browsers (including Netscape Navigator 2.0 and
+later) do, but many browsers, especially older ones, do not. This can
+cause problems, although a possible solution is addressed below.</p>
+
+<h2>Using non-IP Virtual Hosts</h2>
+
+<p>Using the new virtual hosts is quite easy, and superficially looks
+like the old method. You simply add to one of the Apache configuration
+files (most likely <code>httpd.conf</code> or <code>srm.conf</code>)
+code similar to the following:</p>
+<pre>
+    &lt;VirtualHost www.apache.org&gt;
+    ServerName www.apache.org
+    DocumentRoot /usr/web/apache
+    &lt;/VirtualHost&gt;
+</pre>
+
+<p>Of course, any additional directives can (and should) be placed
+into the <code>&lt;VirtualHost&gt;</code> section. To make this work,
+all that is needed is to make sure that the <code>www.apache.org</code>
+DNS entry points to the same IP address as the main
+server. Optionally, you could simply use that IP address in the
+&lt;VirtualHost&gt; entry.</p>
+
+<p>Additionally, many servers may wish to be accessible by more than
+one name. For example, the Apache server might want to be accessible
+as <code>apache.org</code>, or <code>ftp.apache.org</code>, assuming
+the IP addresses pointed to the same server. In fact, one might want it
+so that all addresses at <code>apache.org</code> were picked up by the
+server. This is possible with the <code>ServerAlias</code>
+directive, placed inside the &lt;VirtualHost&gt; section. For
+example:</p>
+
+<pre>
+    ServerAlias apache.org *.apache.org
+</pre>
+
+<p>Note that you can use <code>*</code> and <code>?</code> as wild-card
+characters.</p>
+
+<p>You also might need ServerAlias if you are serving local users who
+do not always include the domain name.  For example, if local users are
+familiar with typing "www" or "www.physics" then you will need to add
+<code>ServerAlias www www.physics</code>.  It isn't possible for the
+server to know what domain the client uses for their name resolution
+because the client doesn't provide that information in the request.</p>
+
+<h2>Security Considerations</h2>
+
+Apache allows all virtual hosts to be made accessible via the
+<code>Host:</code> header through all IP interfaces, even those which
+are configured to use different IP interfaces.  For example, if the
+configuration for <code>www.foo.com</code> contained a virtual host
+section for <code>www.bar.com</code>, and <code>www.bar.com</code> was
+a separate IP interface, such that
+non-<code>Host:</code>-header-supporting browsers can use it, as
+before with Apache 1.0.  If a request is made to
+<code>www.foo.com</code> and the request includes the header
+<code>Host: www.bar.com</code>, a page from <code>www.bar.com</code>
+will be sent.
+
+<P>
+
+This is a security concern if you are controlling access to a
+particular server based on IP-layer controls, such as from within a
+firewall or router.  Let's say <code>www.bar.com</code> in the above
+example was instead an intra-net server called
+<code>private.foo.com</code>, and the router used by foo.com only let
+internal users access <code>private.foo.com</code>.  Obviously,
+<code>Host:</code> header functionality now allows someone who has
+access to <code>www.foo.com</code> to get
+<code>private.foo.com</code>, if they send a <code>Host:
+private.foo.com</code> header.  It is important to note that this
+condition exists only if you only implement this policy at the IP
+layer - all security controls used by Apache (i.e., <A
+HREF="mod/mod_access.html">allow, deny from,</A> etc.) are consistently
+respected.
+
+<h2>Compatibility with Older Browsers</h2>
+
+<p>As mentioned earlier, a majority of browsers do not send the
+required data for the new virtual hosts to work properly. These
+browsers will always be sent to the main server's pages. There is a
+workaround, albeit a slightly cumbersome one:</p>
+
+<p>To continue the <code>www.apache.org</code> example (Note: Apache's
+web server does not actually function in this manner), we might use the
+new <code>ServerPath</code> directive in the <code>www.apache.org</code> virtual host,
+for example:
+
+<pre>
+    ServerPath /apache
+</pre>
+<p>What does this mean? It means that a request for any file beginning
+with "<code>/apache</code>" will be looked for in the Apache
+docs. This means that the pages can be accessed as
+<code>http://www.apache.org/apache/</code> for all browsers, although
+new browsers can also access it as
+<code>http://www.apache.org/</code>.</p>
+
+<p>In order to make this work, put a link on your main server's page
+to <code>http://www.apache.org/apache/</code> (Note: Do not use
+<code>http://www.apache.org/</code> - this would create an endless
+loop). Then, in the virtual host's pages, be sure to use either purely
+relative links (e.g. "<code>file.html</code>" or
+"<code>../icons/image.gif</code>" or links containing the prefacing
+<code>/apache/</code>
+(e.g. "<code>http://www.apache.org/apache/file.html</code>" or
+"<code>/apache/docs/1.1/index.html</code>").</p>
+
+<p>This requires a bit of
+discipline, but adherence to these guidelines will, for the most part,
+ensure that your pages will work with all browsers, new and old. When
+a new browser contacts <code>http://www.apache.org/</code>, they will
+be directly taken to the Apache pages. Older browsers will be able to
+click on the link from the main server, go to
+<code>http://www.apache.org/apache/</code>, and then access the
+pages.</p> 
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
+
diff --git a/APACHE_1_2_X/htdocs/manual/images/home.gif b/APACHE_1_2_X/htdocs/manual/images/home.gif
new file mode 100644 (file)
index 0000000..11299c1
Binary files /dev/null and b/APACHE_1_2_X/htdocs/manual/images/home.gif differ
diff --git a/APACHE_1_2_X/htdocs/manual/images/index.gif b/APACHE_1_2_X/htdocs/manual/images/index.gif
new file mode 100644 (file)
index 0000000..741c893
Binary files /dev/null and b/APACHE_1_2_X/htdocs/manual/images/index.gif differ
diff --git a/APACHE_1_2_X/htdocs/manual/images/sub.gif b/APACHE_1_2_X/htdocs/manual/images/sub.gif
new file mode 100644 (file)
index 0000000..93061c5
Binary files /dev/null and b/APACHE_1_2_X/htdocs/manual/images/sub.gif differ
diff --git a/APACHE_1_2_X/htdocs/manual/index.html b/APACHE_1_2_X/htdocs/manual/index.html
new file mode 100644 (file)
index 0000000..1604b74
--- /dev/null
@@ -0,0 +1,67 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<TITLE>Apache documentation</TITLE>
+</HEAD>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<h1 ALIGN="CENTER">Apache User's Guide</h1>
+
+<hr>
+
+<h3><a name="new">Release Notes</a></h3>
+<ul>
+<li><a href="new_features_1_2.html">New features in Apache 1.2</a>
+<li><a href="new_features_1_1.html">New features in Apache 1.1</a>
+<li><a href="new_features_1_0.html">New features in Apache 1.0</a>
+</ul>
+<ul>
+<li><a href="misc/known_bugs.html">Known Bugs</a>
+<li><a href="misc/compat_notes.html">Compatibility Notes with NCSA httpd</a>
+<li><a href="LICENSE">Apache License</A>
+</ul>
+
+<H3><a name="ref">Apache Reference Manual</a></h3>
+<UL>
+ <LI><A
+      HREF="http://www.apache.org/manual-index/docs"
+     ><STRONG>Search</STRONG></A>
+     the master manual pages for key words
+ </LI>
+</UL>
+<ul>
+<li><A HREF="install.html">Compiling and Installing Apache</A>
+<li><A HREF="invoking.html">Starting Apache</A>
+<li><A HREF="stopping.html">Stopping or Restarting Apache</A>
+<li><A HREF="mod/directives.html">Apache run-time configuration directives</A>
+<li><A HREF="mod/">Apache modules</A>
+<li><A HREF="handler.html">Apache's handler use</A>
+<li><A HREF="env.html">Special purpose environment variables</A>
+<LI><A HREF="misc/API.html">Highly generalized API to server functionality</A>
+<LI><A HREF="suexec.html">Using SetUserID Execution for CGI</A>
+</ul>
+
+<h3><a name="oth">Other Notes</a></h3>
+<ul>
+<li><A HREF="misc/FAQ.html">Frequently Asked Questions list</a>
+<li><A href="misc/howto.html">How do I? documentation</A>
+<LI><A HREF="misc/security_tips.html">Security tips</A>
+<LI><A HREF="misc/perf.html">Performance hints</a> for heavily loaded web servers.
+<LI><A HREF="misc/fin_wait_2.html">Discussion of the FIN_WAIT_2 problem</A>
+<LI><A
+     HREF="http://www.apache.org/info/jdk-102.html"
+    >Java's 1.0.2 virtual machine and HTTP/1.1</A>
+</ul>
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
+
diff --git a/APACHE_1_2_X/htdocs/manual/install.html b/APACHE_1_2_X/htdocs/manual/install.html
new file mode 100644 (file)
index 0000000..52e84b0
--- /dev/null
@@ -0,0 +1,249 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<TITLE>Compiling and Installing Apache</TITLE>
+</HEAD>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+
+<H1 ALIGN="CENTER">Compiling and Installing Apache 1.2</H1>
+
+<P>If you wish to download and install an earlier version of Apache please
+read <A HREF="install_1_1.html">Compiling and Installing Apache 1.1</A>.</P>
+
+UnixWare users will want to consult <A HREF="unixware.html">build notes</A>
+for various UnixWare versions before compiling.
+
+<H2>Downloading Apache</H2>
+
+Information on the latest version of Apache can be found on the Apache
+web server at <A
+HREF="http://www.apache.org/">http://www.apache.org/</A>.  This will
+list the current release, any more recent beta-test release, together
+with details of mirror web and anonymous ftp sites.  
+
+<P>
+
+If you downloaded a binary distribution, skip to <A
+HREF="#install">Installing Apache</A>. Otherwise read the next section
+for how to compile the server.
+
+<h2>Compiling Apache</h2>
+
+Compiling Apache consists of three steps: Firstly select which Apache
+<b>modules</b> you want to include into the server. Secondly create a
+configuration for your operating system. Thirdly compile the
+executable.
+<P>
+
+All configuration of Apache is performed in the <CODE>src</CODE>
+directory of the Apache distribution. Change into this directory.
+
+<OL>
+ <LI>
+  Select modules to compile into Apache in the
+  <CODE>Configuration</CODE> file. 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
+  additional modules you have downloaded or written. (See <A
+  HREF="misc/API.html">API.html</A> for preliminary docs on how to
+  write Apache modules).  Advanced users can comment out some of the
+  default modules if they are sure they will not need them (be careful
+  though, since many of the default modules are vital for the correct
+  operation and security of the server).
+  <P>
+
+  You should also read the instructions in the <CODE>Configuration</CODE>
+  file to see if you need to set any of the <CODE>Rule</CODE> lines.
+
+
+ <LI>
+  Configure Apache for your operating system. Normally you can just
+  type run the <CODE>Configure</CODE> script as given below. However
+  if this fails or you have any special requirements (e.g. to include
+  an additional library required by an optional module) you might need
+  to edit one or more of the following options in the
+  <CODE>Configuration</CODE> file:
+    <CODE>EXTRA_CFLAGS, LIBS, LFLAGS, INCLUDES</CODE>.
+  <P>
+
+  Run the <CODE>Configure</CODE> script:
+  <BLOCKQUOTE>
+   <PRE>
+    % Configure
+    Using 'Configuration' as config file
+     + configured for &lt;whatever&gt; platform
+     + setting C compiler to &lt;whatever&gt; *
+     + setting C compiler optimization-level to &lt;whatever&gt; *
+    %
+   </PRE>
+  </BLOCKQUOTE>
+
+  (*: Depending on Configuration and your system, Configure
+  make not print these lines. That's OK).<P>
+
+  This generates a Makefile for use in stage 3. It also creates a
+  Makefile in the support directory, for compilation of the optional
+  support programs.
+  <P>
+
+  (If you want to maintain multiple configurations, you can give a
+  option to <CODE>Configure</CODE> to tell it to read an alternative
+  Configuration file, such as <CODE>Configure -file
+  Configuration.ai</CODE>).
+  <P>
+
+ <LI>
+  Type <CODE>make</CODE>.
+</OL>
+
+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 <A
+HREF="http://www.apache.org/dist/contrib/modules/">&lt;URL:http://www.apache.org/dist/contrib/modules/&gt;</a>.
+There are instructions on that page for linking these modules into the
+core Apache code.
+
+<h2><A NAME="install">Installing Apache</A></h2>
+
+You will have a binary file called <CODE>httpd</CODE> in the
+<CODE>src</CODE> directory.  A binary distribution of Apache will
+supply this file.  <P>
+
+The next step is to install the program and configure it. Apache is
+designed to be configured and run from the same set of directories
+where it is compiled. If you want to run it from somewhere else, make
+a directory and copy the <CODE>conf</CODE>, <CODE>logs</CODE> and
+<CODE>icons</CODE> directories into it.  <P>
+
+The next step is to edit the configuration files for the server. This
+consists of setting up various <B>directives</B> in up to three
+central configuration files. By default, these files are located in
+the <CODE>conf</CODE> directory and are called <CODE>srm.conf</CODE>,
+<CODE>access.conf</CODE> and <CODE>httpd.conf</CODE>.  To help you get
+started there are same files in the <CODE>conf</CODE> directory of the
+distribution, called <CODE>srm.conf-dist</CODE>,
+<CODE>access.conf-dist</CODE> and <CODE>httpd.conf-dist</CODE>. Copy
+or rename these files to the names without the <CODE>-dist</CODE>.
+Then edit each of the files. Read the comments in each file carefully.
+Failure to setup these files correctly could lead to your server not
+working or being insecure. You should also have an additional file in
+the <CODE>conf</CODE> directory called <CODE>mime.types</CODE>. This
+file usually does not need editing.
+
+<P>
+
+First edit <CODE>httpd.conf</CODE>.  This sets up general attributes
+about the server: the port number, the user it runs as, etc.  Next
+edit the <CODE>srm.conf</CODE> file; this sets up the root of the
+document tree, special functions like server-parsed HTML or internal
+imagemap parsing, etc.  Finally, edit the <CODE>access.conf</CODE>
+file to at least set the base cases of access.
+
+<P>
+
+In addition to these three files, the server behavior can be configured
+on a directory-by-directory basis by using <CODE>.htaccess</CODE>
+files in directories accessed by the server. 
+
+<H3>Starting and Stopping the Server</H3>
+
+To start the server, simply run <CODE>httpd</CODE>. This will look for
+<CODE>httpd.conf</CODE> in the location compiled into the code (by
+default <CODE>/usr/locale/etc/httpd/conf/httpd.conf</CODE>). If
+this file is somewhere else, you can give the real
+location with the -f argument. For example:
+
+<PRE>
+    /usr/local/etc/apache/src/httpd -f /usr/local/etc/apache/conf/httpd.conf
+</PRE>
+
+If all goes well this will return to the command prompt almost
+immediately.  This indicates that the server is now up and running. If
+anything goes wrong during the initialization of the server you will
+see an error message on the screen. 
+
+If the server started ok, you can now use your browser to
+connect to the server and read the documentation. If you are running
+the browser on the same machine as the server and using the default
+port of 80, a suitable URL to enter into your browser is
+
+<PRE>
+    http://localhost/
+</PRE>
+
+<P>
+
+Note that when the server starts it will create a number of
+<i>child</i> processes to handle the requests. If you started Apache
+as the root user, the parent process will continue to run as root
+while the children will change to the user as given in the httpd.conf
+file. 
+
+<P>
+
+If when you run <CODE>httpd</CODE> it complained about being unable to
+"bind" to an address, then either some other process is already using
+the port you have configured Apache to use, or you are running httpd
+as a normal user but trying to use port below 1024 (such as the
+default port 80).
+
+<P>
+
+If the server is not running, read the error message displayed
+when you run httpd. You should also check the server
+error_log for additional information (with the default configuration,
+this will be located in the file <CODE>error_log</CODE> in the
+<CODE>logs</CODE> directory).
+
+<P>
+
+If you want your server to continue running after a system reboot, you
+should add a call to <CODE>httpd</CODE> to your system startup files
+(typically <CODE>rc.local</CODE> or a file in an
+<CODE>rc.<I>N</I></CODE> directory). This will start Apache as root.
+Before doing this ensure that your server is properly configured
+for security and access restrictions.
+
+<P>
+
+To stop Apache send the parent process a TERM signal. The PID of this
+process is written to the file <CODE>httpd.pid</CODE> in the
+<CODE>logs</CODE> directory (unless configured otherwise).  Do not
+attempt to kill the child processes because they will be renewed by
+the parent.  A typical command to stop the server is:
+
+<PRE>
+    kill -TERM `cat /usr/local/etc/apache/logs/httpd.pid`
+</PRE>
+
+<P>
+
+For more information about Apache command line options, configuration
+and log files, see <A HREF="invoking.html">Starting Apache</A>. For a
+reference guide to all Apache directives supported by the distributed
+modules, see the <A HREF="mod/directives.html">Apache directives</A>.
+
+<H2>Compiling Support Programs</H2>
+
+In addition to the main <CODE>httpd</CODE> server which is compiled
+and configured as above, Apache includes a number of support programs.
+These are not compiled by default. The support programs are in the
+<CODE>support</CODE> directory of the distribution. To compile
+the support programs, change into this directory and type
+<PRE>
+    make
+</PRE>
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
diff --git a/APACHE_1_2_X/htdocs/manual/install_1_1.html b/APACHE_1_2_X/htdocs/manual/install_1_1.html
new file mode 100644 (file)
index 0000000..99fac7f
--- /dev/null
@@ -0,0 +1,112 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<TITLE>Compiling and Installing Apache</TITLE>
+</HEAD>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<h1 ALIGN="CENTER">Compiling and Installing Apache</h1>
+<h2>Downloading Apache</h2>
+<p>Information on the latest version of Apache can be found on the Apache
+web server at http://www.apache.org/. This will list the current release,
+any more recent beta-test release, together with details of mirror
+web and anonymous ftp sites.</p>
+
+UnixWare users will want to consult <A HREF="unixware.html">build notes</A>
+for various UnixWare versions before compiling.
+
+<h2>Compiling Apache</h2>
+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 (`<code>modules.c</code>') which simply has a list of them.
+<p>
+If you are satisfied with our standard module set, and expect to
+continue to be satisfied with it, then you can just edit the stock
+<code>Makefile</code> and compile as you have been doing previously.  If you
+would
+like to select optional modules, however, you need to run the
+configuration script.
+<p>
+To do this:
+<ol>
+<li>Edit the file `<code>Configuration</code>'.  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:
+<ol>
+<li> Select a compiler and compilation options as appropriate to
+your machine.
+<li> 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.
+<p>
+Note that DBM auth has to be explicitly configured in, if you want
+it; just uncomment the corresponding line.
+</ol>
+<li> Run the `Configure' script:
+<blockquote><code>
+% Configure<br>
+Using 'Configuration' as config file<br>
+%</code></blockquote>
+
+This generates new versions of the Makefile and of modules.c.  If
+you want to maintain multiple configurations, you can say, e.g.,
+<blockquote><code>
+% Configure -file Configuration.ai<br>
+Using alternate config file Configuration.ai<br>
+%</code></blockquote>
+
+<li>Type `make'.
+<p>
+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
+<A HREF="http://www.apache.org/dist/contrib/modules/">&lt;URL:http://www.apache.org/dist/contrib/modules/&gt;</A>.  There are instructions on that page for
+linking these modules into the core Apache code.
+</ol>
+
+<h2>Installing Apache</h2>
+After compilation, you will have a binary called `httpd' in the
+<code>src/</code> directory.  A binary distribution of Apache will supply this
+file.
+<p>
+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: <code>srm.conf-dist</code>,
+<code>access.conf-dist</code> and <code>httpd.conf-dist</code>. Copy them to
+<code>srm.conf</code>, <code>access.conf</code> and <code>httpd.conf</code>
+respectively.
+<p>
+First edit <code>httpd.conf</code>.  This sets up general attributes about the
+server; the port number, the user it runs as, etc.  Next edit the
+<code>srm.conf</code> file; this sets up the root of the document tree,
+special functions like server-parsed HTML or internal imagemap parsing, etc.
+Finally, edit the <code>access.conf</code> file to at least set the base cases
+of access.
+<p>
+Finally, make a call to httpd, with a -f to the full path to the
+httpd.conf file.  I.e., the common case:
+<blockquote><code>
+  /usr/local/etc/apache/src/httpd -f /usr/local/etc/apache/conf/httpd.conf
+</code></blockquote>
+The server should be now running.
+<p>
+By default the <code>srm.conf</code> and <code>access.conf</code> files are
+located by name; to specifically call them by other names, use the
+<A HREF="mod/core.html#accessconfig">AccessConfig</A> and
+<A HREF="mod/core.html#resourceconfig">ResourceConfig</A> directives in
+<code>httpd.conf</code>.
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
diff --git a/APACHE_1_2_X/htdocs/manual/invoking.html b/APACHE_1_2_X/htdocs/manual/invoking.html
new file mode 100644 (file)
index 0000000..62e6a41
--- /dev/null
@@ -0,0 +1,124 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<TITLE>Starting Apache</TITLE>
+</HEAD>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<h1 ALIGN="CENTER">Starting Apache</h1>
+
+<h2>Invoking Apache</h2>
+The <code>httpd</code> program is usually run as a daemon which executes
+continuously, handling requests.  It is possible to invoke Apache by
+the Internet daemon <code>inetd</code> each time a connection to the HTTP 
+service is made (use the 
+<A HREF="mod/core.html#servertype">ServerType</A> directive)
+but this is not recommended.  
+
+<h2>Command line options</h2>
+The following options are recognized on the httpd command line:
+<dl>
+<dt><code>-d</code> <em>serverroot</em>
+<dd>Set the initial value for the
+<A HREF="mod/core.html#serverroot">ServerRoot</A> variable to
+<em>serverroot</em>. This can be overridden by the ServerRoot command in the
+configuration file. The default is <code>/usr/local/etc/httpd</code>.
+
+<dt><code>-f</code> <em>config</em>
+<dd>Execute the commands in the file <em>config</em> on startup. If
+<em>config</em> does not begin with a <code>/</code>, then it is taken to be a
+path relative to the <A HREF="mod/core.html#serverroot">ServerRoot</A>. The
+default is <code>conf/httpd.conf</code>.
+
+<dt><code>-X</code>
+<dd>Run in single-process mode, for internal debugging purposes only; the
+daemon does not detach from the terminal or fork any children. Do <em>NOT</em>
+use this mode to provide ordinary web service.
+
+<dt><code>-v</code>
+<dd>Print the version of httpd, and then exit.
+
+<dt><a name="help"><code>-h</code></a>
+<dd>Give a list of directives together with expected arguments and
+places where the directive is valid. (New in Apache 1.2)
+
+<dt><code>-l</code>
+<dd>Give a list of all modules compiled into the server.
+
+<dt><code>-?</code>
+<dd>Print a list of the httpd options, and then exit.
+</dl>
+
+<h2>Configuration files</h2>
+The server will read three files for configuration directives. Any directive
+may appear in any of these files. The the names of these files are taken
+to be relative to the server root; this is set by the
+<A HREF="mod/core.html#serverroot">ServerRoot</A> directive, or the
+<code>-d</code> command line flag.
+
+Conventionally, the files are:
+<dl>
+<dt><code>conf/httpd.conf</code>
+<dd>Contains directives that control the operation of the server daemon.
+The filename may be overridden with the <code>-f</code> command line flag.
+
+<dt><code>conf/srm.conf</code>
+<dd>Contains directives that control the specification of documents that
+the server can provide to clients. The filename may be overridden with
+the <A HREF="mod/core.html#resourceconfig">ResourceConfig</A> directive.
+
+<dt><code>conf/access.conf</code>
+<dd>Contains directives that control access to documents.
+The filename may be overridden with the
+<A HREF="mod/core.html#accessconfig">AccessConfig</A> directive.
+</dl>
+However, these conventions need not be adhered to.
+<p>
+The server also reads a file containing mime document types; the filename
+is set by the <A HREF="mod/mod_mime.html#typesconfig">TypesConfig</A> directive,
+and is <code>conf/mime.types</code> by default.
+
+<h2>Log files</h2>
+<h3>security warning</h3>
+Anyone who can write to the directory where Apache is writing a
+log file can almost certainly gain access to the uid that the server is
+started as, which is normally root.  Do <EM>NOT</EM> give people write
+access to the directory the logs are stored in without being aware of
+the consequences; see the <A HREF="misc/security_tips.html">security tips</A>
+document for details.
+<h3>pid file</h3>
+On daemon startup, it saves the process id of the parent httpd process to
+the file <code>logs/httpd.pid</code>. This filename can be changed with the
+<A HREF="mod/core.html#pidfile">PidFile</A> directive. The process-id is for
+use by the administrator in restarting and terminating the daemon;
+A HUP or USR1 signal causes the daemon to re-read its configuration files and
+a TERM signal causes it to die gracefully.  For more information
+see the <a href="stopping.html">Stopping and Restarting</a> page.
+<p>
+If the process dies (or is killed) abnormally, then it will be necessary to
+kill the children httpd processes.
+
+<h3>Error log</h3>
+The server will log error messages to a log file, <code>logs/error_log</code>
+by default. The filename can be set using the
+<A HREF="mod/core.html#errorlog">ErrorLog</A> directive; different error logs can
+be set for different <A HREF="mod/core.html#virtualhost">virtual hosts</A>.
+
+<h3>Transfer log</h3>
+The server will typically log each request to a transfer file,
+<code>logs/access_log</code> by default. The filename can be set using a
+<A HREF="mod/mod_log_common.html#transferlog">TransferLog</A> directive; different
+transfer logs can be set for different <A HREF="mod/core.html#virtualhost">virtual
+hosts</A>.
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
diff --git a/APACHE_1_2_X/htdocs/manual/keepalive.html b/APACHE_1_2_X/htdocs/manual/keepalive.html
new file mode 100644 (file)
index 0000000..60399f3
--- /dev/null
@@ -0,0 +1,79 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html><head>
+<title>Apache Keep-Alive Support</title>
+</head>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<h1 ALIGN="CENTER">Apache Keep-Alive Support</h1>
+
+<hr>
+
+<h2>What is Keep-Alive?</h2>
+
+The Keep-Alive extension to HTTP, as defined by the
+<code>HTTP/1.1</code> draft, allows persistent connections. These
+long-lived HTTP sessions allow multiple requests to be send over the
+same TCP connection, and in some cases have been shown to result in an
+almost 50% speedup in latency times for HTML documents with lots of
+images.
+
+<h2>Enabling Keep-Alive Support</h2>
+
+Apache 1.1 comes with Keep-Alive support on by default, however there
+are some directives you can use to modify Apache's behavior:
+
+<p><strong>Note</strong>: Apache 1.2 uses a different syntax for the <a
+href="mod/core.html#keepalive">KeepAlive</a> directive.</p>
+
+<h3>KeepAlive</h3>
+<strong>Syntax:</strong> KeepAlive <em>max-requests</em><br>
+<strong>Default:</strong> <code>KeepAlive 5</code><br>
+<strong>Context:</strong> server config<br>
+<strong>Status:</strong> Core<p>
+
+This directive enables Keep-Alive support. Set <em>max-requests</em>
+to the maximum number of requests you want Apache to entertain per
+connection. A limit is imposed to prevent a client from hogging your
+server resources. Set this to <code>0</code> to disable support.
+
+<h3>KeepAliveTimeout</h3>
+<strong>Syntax:</strong> KeepAliveTimeout <em>seconds</em><br>
+<strong>Default:</strong> <code>KeepAliveTimeout 15</code><br>
+<strong>Context:</strong> server config<br>
+<strong>Status:</strong> Core<p>
+
+The number of seconds Apache will wait for a subsequent request before
+closing the connection. Once a request has been received, the timeout
+value specified by the <a
+href="mod/core.html#timeout"><code>Timeout</code></a> directive
+applies.
+
+<h2>When Keep-Alive Is Used</h2>
+
+In order for Keep-Alive support to be used, first the browser must
+support it. Many current browsers, including Netscape Navigator 2.0,
+and Spyglass Mosaic-based browsers (including Microsoft Internet
+Explorer) do. Note, however, that some Windows 95-based browsers misbehave
+with Keep-Alive-supporting servers; they may occasionally hang on a
+connect. This has been observed with several Windows browsers, and occurs
+when connecting to any Keep-Alive server, not just Apache. Netscape 3.0b5
+and later versions are known to work around this problem.
+
+<p>However, Keep-Alive support only is active with files where the
+length is known beforehand. This means that most CGI scripts,
+server-side included files and directory listings will not use
+the Keep-Alive protocol. While this should be completely transparent
+to the end user, it is something the web-master may want to keep in mind.</p>
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
+
diff --git a/APACHE_1_2_X/htdocs/manual/location.html b/APACHE_1_2_X/htdocs/manual/location.html
new file mode 100644 (file)
index 0000000..96ab3a8
--- /dev/null
@@ -0,0 +1,59 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<TITLE>Access Control by URL</TITLE>
+</HEAD>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<H1 ALIGN="CENTER">Access Control by URL</H1>
+
+<h2><a name="location">The <code>&lt;Location&gt;</code> Directive</a></h2>
+
+<strong>Syntax:</strong> &lt;Location <em>URL prefix</em>&gt;<br>
+<strong>Context:</strong> server config, virtual host<br>
+<strong>Status:</strong> core<br>
+
+<p>The &lt;Location&gt; directive provides for access control by
+URL. It is comparable to the <a
+href="mod/core.html#directory">&lt;Directory&gt;</a> directive, and
+should be matched with a &lt;/Location&gt; directive. Directives that
+apply to the URL given should be listen
+within. <code>&lt;Location&gt;</code> sections are processed in the
+order they appear in the configuration file, after the
+&lt;Directory&gt; sections and <code>.htaccess</code> files are
+read.</p>
+
+<p>Note that, due to the way HTTP functions, <em>URL prefix</em>
+should, save for proxy requests, be of the form <code>/path/</code>,
+and should not include the <code>http://servername</code>. It doesn't
+necessarily have to protect a directory (it can be an individual
+file, or a number of files), and can include wild-cards.  In a wild-card
+string, `?' matches any single character, and `*' matches any
+sequences of characters.
+
+<p>This functionality is especially useful when combined with the
+<code><a href="mod/mod_mime.html#sethandler">SetHandler</a></code>
+directive. For example, to enable status requests, but allow them only
+from browsers at foo.com, you might use:
+
+<pre>
+    &lt;Location /status&gt;
+    SetHandler server-status
+    order deny,allow
+    deny from all
+    allow from .foo.com
+    &lt;/Location&gt;
+</pre>
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
+
diff --git a/APACHE_1_2_X/htdocs/manual/man-template.html b/APACHE_1_2_X/htdocs/manual/man-template.html
new file mode 100644 (file)
index 0000000..e62beb5
--- /dev/null
@@ -0,0 +1,69 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<TITLE>Apache module mod_foobar</TITLE>
+</HEAD>
+
+<!-- read and delete all blockquotes, and this comment -->
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<H1 ALIGN="CENTER">Module mod_foobar</h1>
+
+<blockquote><em>Add this file as a link in modules.html</em></blockquote>
+
+This module is contained in the <code>mod_foobar.c</code> file, and
+<strong>is/is not</strong> compiled in by default. It provides for
+<strong>the foobar feature</strong>. Any document with the mime type
+<code>foo/bar</code> will be processed by this module.
+
+<blockquote><em>Add the magic mime type to the list in
+magic_types.html</em></blockquote>
+
+<h2>Summary</h2>
+General module documentation here.
+
+<h2>Directives</h2>
+<ul>
+<li><A HREF="#adirective">ADirective</A>
+</ul>
+
+<blockquote><em>Add these directives to the list in
+directives.html</em></blockquote>
+
+<hr>
+
+<h2><A name="adirective">ADirective</A></h2>
+<strong>Syntax:</strong> ADirective <em>some args</em><br>
+<strong>Default:</strong> <code>ADirective default value</code><br>
+<strong>Context:</strong> context-list<br>
+
+<blockquote><em>context-list is where this directive can appear;
+allowed: server config, virtual host, directory, .htaccess</em></blockquote>
+
+<strong>Override:</strong> override<br>
+
+<blockquote><em>required if the directive is allowed in .htaccess files;
+the AllowOverride option that allows the directive.</em></blockquote>
+
+<strong>Status:</strong> status<br>
+
+<blockquote><em>Core if in core apache, Base if in one of the standard
+modules, Extension if in an extension module (not compiled in by default)
+or Experimental</em></blockquote>
+
+<strong>Module:</strong> mod_foobar<p>
+
+The ADirective directive does something.
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
+
diff --git a/APACHE_1_2_X/htdocs/manual/misc/API.html b/APACHE_1_2_X/htdocs/manual/misc/API.html
new file mode 100644 (file)
index 0000000..ad539e2
--- /dev/null
@@ -0,0 +1,1004 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html><head>
+<title>Apache API notes</title>
+</head>
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<h1 ALIGN="CENTER">Apache API notes</h1>
+
+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>
+<menu>
+ <li> <a href="#HMR">Handlers, Modules, and Requests</a>
+ <li> <a href="#moduletour">A brief tour of a module</a>
+</menu>
+<li> <a href="#handlers">How handlers work</a>
+<menu>
+ <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>
+</menu>
+<li> <a href="#pools">Resource allocation and resource pools</a>
+<li> <a href="#config">Configuration, commands and the like</a>
+<menu>
+ <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>
+</menu>
+</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 every place.<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 recognize <code>ScriptAlias</code>ed URIs), 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, <i>en masse</i>, 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 *);
+
+/* Subsidiary 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 */
+
+extern 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 creator */
+   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 */
+   NULL                      /* header parser */
+};
+</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
+response (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>
+<BLOCKQUOTE>
+ Note that the <SAMP>Content-type</SAMP> header value <EM>cannot</EM> be
+ set by module content-handlers using the <SAMP>table_*()</SAMP>
+ routines.  Rather, it is set by pointing the <SAMP>content_type</SAMP>
+ field in the <SAMP>request_rec</SAMP> structure to an appropriate
+ string.  <EM>E.g.</EM>,
+ <PRE>
+  r-&gt;content_type = "text/html";
+ </PRE>
+</BLOCKQUOTE>
+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
+against the <code>If-modified-since</code> value supplied by the
+client, if any, 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
+initial 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> does not
+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><a name="pool-files">Tracking open files, etc.</a></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
+discussed 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 pre-parsed 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 pre-parsed 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
+       pre-parsed, and how they should be passed in.
+       <code>TAKE2</code> indicates two pre-parsed arguments.  Other
+       options are <code>TAKE1</code>, which indicates one pre-parsed
+       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, &amp;mime_module);
+    char *type;
+
+    if (S_ISDIR(r->finfo.st_mode)) {
+        r->content_type = DIR_MAGIC_TYPE;
+        return OK;
+    }
+    
+    if((i=rind(fn,'.')) &lt; 0) return DECLINED;
+    ++i;
+
+    if ((type = table_get (conf->encoding_types, &amp;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,'.')) &lt; 0) return OK;
+        ++i;
+    }
+
+    if ((type = table_get (conf->forced_types, &amp;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 overridden 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>
+<!--#include virtual="footer.html" -->
+</body></html>
diff --git a/APACHE_1_2_X/htdocs/manual/misc/FAQ.html b/APACHE_1_2_X/htdocs/manual/misc/FAQ.html
new file mode 100644 (file)
index 0000000..94d257d
--- /dev/null
@@ -0,0 +1,1397 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+ <HEAD>
+  <TITLE>Apache Server Frequently Asked Questions</TITLE>
+ </HEAD>
+
+ <!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+ <BODY
+  BGCOLOR="#FFFFFF"
+  TEXT="#000000"
+  LINK="#0000FF"
+  VLINK="#000080"
+  ALINK="#FF0000"
+ >
+  <!--#include virtual="header.html" -->
+  <H1 ALIGN="CENTER">Apache Server Frequently Asked Questions</H1>
+  <P>
+  $Revision: 1.63 $ ($Date: 1997/06/04 11:42:55 $)
+  </P>
+  <P>
+  The latest version of this FAQ is always available from the main
+  Apache web site, at
+  &lt;<A
+       HREF="http://www.apache.org/docs/misc/FAQ"
+       REL="Help"
+      ><SAMP>http://www.apache.org/docs/misc/FAQ</SAMP></A>&gt;.
+  </P>
+<!-- Notes about changes:                                           -->
+<!--  - If adding a relative link to another part of the            -->
+<!--    documentation, *do* include the ".html" portion.  There's a -->
+<!--    good chance that the user will be reading the documentation -->
+<!--    on his own system, which may not be configured for          -->
+<!--    multiviews.   Leave off the ".html" extension for absolute  -->
+<!--    links to sites which are known to run multiviews (e.g.,     -->
+<!--    apache.org or apacheweek.com).                              -->
+<!--  - When adding items, make sure they're put in the right place -->
+<!--    - verify that the numbering matches up.                     -->
+<!--  - Don't forget to include an HR tag after the last /P tag     -->
+<!--    but before the /LI in an item.                              -->
+  <P>
+  If you are reading a text-only version of this FAQ, you may find numbers
+  enclosed in brackets (such as &quot;[12]&quot;).  These refer to the list of
+  reference URLs to be found at the end of the document.  These references
+  do not appear, and are not needed, for the hypertext version.
+  </P>
+  <H2>The Questions</H2>
+<!-- Stuff to Add:                                                  -->
+<!-- - can't bind to port 80                                        -->
+<!--   - permission denied                                          -->
+<!--   - address already in use                                     -->
+<!-- - mod_auth & passwd lines "user:pw:.*" - ++1st colon onward is -->
+<!--   treated as pw, not just ++1st to --2nd.                      -->
+<!-- - SSL:                                                         -->
+<!--   Can I use Apache-SSL for free in Canada?                     -->
+<!--   Why can't I use Apache-SSL in the U.S.?                      -->
+<!-- - How can I found out how many visitors my site gets?          -->
+<!-- - How do I add a counter?                                      -->
+<!-- - How do I configure Apache as a proxy?                        -->
+<!-- - What browsers support HTTP/1.1?                              -->
+<!-- - What's the point of vhosts-by-name is there aren't any       -->
+<!--   HTTP/1.1 browsers?                                           -->
+<!-- - Is there an Apache for W95/WNT?                              -->
+<!-- - Why does Apache die when a vhost can't be DNS-resolved?      -->
+<!-- - How do I setup an access restriction so that people from     -->
+<!--   this domain don't have to authenticate, and all others can   -->
+<!--   do so via a username and password?                           -->
+<!-- - Why do I get "send lost connection" messages in my error     -->
+<!--   log?                                                         -->
+<!--   - specifically consider .pdf files which seem to cause this  -->
+<!--     a lot when accessed via the plugin ... and also mention    -->
+<!--     how range-requests can cause bytes served < file size      -->
+<!-- - Why does http://host/~user not work but http://host/~user/   -->
+<!--   works properly?                                              -->
+<!-- - How do I add a footer to all pages offered by my server?     -->
+<UL>
+ <LI><STRONG>Background</STRONG>
+  <OL START=1>
+   <LI><A HREF="#what">What is Apache?</A>
+   </LI>
+   <LI><A HREF="#why">Why was Apache created?</A>
+   </LI>
+   <LI><A HREF="#relate">How does The Apache Group's work relate to
+    other servers?</A> 
+   </LI>
+   <LI><A HREF="#name">Why the name &quot;Apache&quot;?</A>
+   </LI>
+   <LI><A HREF="#compare">OK, so how does Apache compare to other servers?</A>
+   </LI>
+   <LI><A HREF="#tested">How thoroughly tested is Apache?</A>
+   </LI>
+   <LI><A HREF="#future">What are the future plans for Apache?</A>
+   </LI>
+   <LI><A HREF="#support">Whom do I contact for support?</A>
+   </LI>
+   <LI><A HREF="#more">Is there any more information on Apache?</A>
+   </LI>
+   <LI><A HREF="#where">Where can I get Apache?</A>
+   </LI>
+  </OL>
+ </LI>
+ <LI><STRONG>Technical Questions</STRONG>
+  <OL START=11>
+   <LI><A HREF="#what2do">&quot;Why can't I ...?  Why won't ...
+        work?&quot;  What to do in case of problems</A>
+   </LI>
+   <LI><A HREF="#compatible">How compatible is Apache with my existing
+    NCSA 1.3 setup?</A>
+   </LI>
+   <LI><A HREF="#CGIoutsideScriptAlias">How do I enable CGI execution
+        in directories other than the ScriptAlias?</A>
+   </LI>
+   <LI><A HREF="#premature-script-headers">What does it mean when my
+        CGIs fail with &quot;<SAMP>Premature end of script
+        headers</SAMP>&quot;?</A> 
+   </LI>
+   <LI><A HREF="#ssi-part-i">How do I enable SSI (parsed HTML)?</A>
+   </LI>
+   <LI><A HREF="#ssi-part-ii">Why don't my parsed files get cached?</A>
+   </LI>
+   <LI><A HREF="#ssi-part-iii">How can I have my script output parsed?</A>
+   </LI>
+   <LI><A HREF="#proxy">Does or will Apache act as a Proxy server?</A>
+   </LI>
+   <LI><A HREF="#multiviews">What are &quot;multiviews&quot;?</A>
+   </LI>
+   <LI><A HREF="#fdlim">Why can't I run more than &lt;<EM>n</EM>&gt;
+    virtual hosts?</A>
+   </LI>
+   <LI><A HREF="#limitGET">Why do I keep getting &quot;access denied&quot; for
+    form POST requests?</A>
+   </LI>
+   <LI><A HREF="#passwdauth">Can I use my <SAMP>/etc/passwd</SAMP> file
+    for Web page authentication?</A>
+   </LI>
+   <LI><A HREF="#errordoc401">Why doesn't my <CODE>ErrorDocument
+    401</CODE> work?</A>
+   </LI>
+   <LI><A HREF="#setgid">Why do I get &quot;<SAMP>setgid: Invalid
+    argument</SAMP>&quot; at startup?</A>
+   </LI>
+   <LI><A HREF="#cookies1">Why does Apache send a cookie on every response?</A>
+   </LI>
+   <LI><A HREF="#cookies2">Why don't my cookies work, I even compiled in 
+    <SAMP>mod_cookies</SAMP>?</A>
+   </LI>
+   <LI><A HREF="#jdk1-and-http1.1">Why do my Java app[let]s give me plain text
+    when I request an URL from an Apache server?</A>
+   </LI>
+   <LI><A HREF="#putsupport">Why can't I publish to my Apache server
+    using PUT on Netscape Gold and other programs?</A>
+   </LI>
+   <LI><A HREF="#fastcgi">Why isn't FastCGI included with Apache any
+    more?</A>
+   </LI>
+   <LI><A HREF="#nodelay">Why am I getting &quot;<SAMP>httpd: could not
+    set socket option TCP_NODELAY</SAMP>&quot; in my error log?</A>
+   </LI>
+   <LI><A HREF="#nph-scripts">How can I get my script's output without
+    Apache buffering it?</A>
+   </LI>
+   <LI><A HREF="#linuxiovec">Why do I get complaints about redefinition
+    of `struct iovec' when compiling under Linux?</A>
+   </LI>
+   <LI><A HREF="#wheres-the-dump">The errorlog says Apache dumped core,
+    but where's the dump file?</A>
+   </LI>
+   <LI><A HREF="#dnsauth">Why isn't restricting access by host or domain name
+    working correctly?</A>
+   </LI>
+   <LI><A HREF="#SSL-i">Why doesn't Apache include SSL?</A>
+   </LI>
+   <LI><A HREF="#HPUX-core">Why do I get core dumps under HPUX using
+    HP's ANSI C compiler?</A>
+   </LI>
+   <LI><A HREF="#midi">How do I get Apache to send a MIDI file so the
+    browser can play it?</A>
+   </LI>
+   <LI><A HREF="#cantbuild">Why won't Apache compile with my
+    system's <SAMP>cc</SAMP>?</A>
+   </LI>
+   <LI><A HREF="#addlog">How do I add browsers and referrers to my
+    logs?</A>
+   </LI>
+  </OL>
+ </LI>
+</UL>
+
+<HR>
+
+  <H2>The Answers</H2>
+  <P>
+  </P>
+  <H3>
+   Background
+  </H3>
+<OL START=1>
+ <LI><A NAME="what">
+      <STRONG>What is Apache?</STRONG>
+     </A>
+  <P>
+  Apache was originally based on code and ideas found in the most
+  popular HTTP server of the time.. NCSA httpd 1.3 (early 1995). It has
+  since evolved into a far superior system which can rival (and probably
+  surpass) almost any other UNIX based HTTP server in terms of functionality,
+  efficiency and speed.
+  </P>
+  <P>
+  Since it began, it has been completely rewritten, and includes many new
+  features. Apache is, as of January 1997, the most popular WWW server on
+  the Internet, according to the
+  <A
+   HREF="http://www.netcraft.com/Survey/"
+  >Netcraft Survey</A>.
+  </P>
+  <HR>
+ </LI>
+ <LI><A NAME="why">
+      <STRONG>Why was Apache created?</STRONG>
+     </A>
+  <P>
+  To address the concerns of a group of WWW providers and part-time httpd
+  programmers that httpd didn't behave as they wanted it to behave.
+  Apache is an entirely volunteer effort, completely funded by its 
+  members, not by commercial sales.
+  <HR>
+  </P>
+ </LI>
+ <LI><A NAME="relate">
+      <STRONG>How does The Apache Group's work relate to other
+      server efforts, such as NCSA's?</STRONG>
+     </A>
+  <P>
+  We, of course, owe a great debt to NCSA and their programmers for
+  making the server Apache was based on. We now, however, have our own
+  server, and our project is mostly our own. The Apache Project is an
+  entirely independent venture.
+  </P>
+  <HR>
+ </LI>
+ <LI><A NAME="name">
+      <STRONG>Why the name &quot;Apache&quot;?</STRONG>
+      </A>
+  <P>
+  A cute name which stuck. Apache is &quot;<STRONG>A
+  PA</STRONG>t<STRONG>CH</STRONG>y server&quot;.  It was
+  based on some existing code and a series of &quot;patch files&quot;.
+  </P>
+  <HR>
+ </LI>
+ <LI><A NAME="compare">
+      <STRONG>OK, so how does Apache compare to other servers?</STRONG>
+     </A>
+  <P>
+  For an independent assessment, see
+  <A
+   HREF="http://webcompare.iworld.com/compare/chart.html"
+  >Web Compare</A>'s 
+  comparison chart.
+  </P>
+  <P>
+  Apache has been shown to be substantially faster than many other
+  free servers. Although certain commercial servers have claimed to
+  surpass Apache's speed (it has not been demonstrated that any of these
+  &quot;benchmarks&quot; are a good way of measuring WWW server speed at any
+  rate), we feel that it is better to have a mostly-fast free server
+  than an extremely-fast server that costs thousands of dollars. Apache
+  is run on sites that get millions of hits per day, and they have
+  experienced no performance difficulties.
+  </P>
+  <HR>
+ </LI>
+ <LI><A NAME="tested">
+      <STRONG>How thoroughly tested is Apache?</STRONG>
+     </A>
+  <P>
+  Apache is run on over 400,000 Internet servers (as of April 1997). It has
+  been tested thoroughly by both developers and users. The Apache Group
+  maintains rigorous standards before releasing new versions of their
+  server, and our server runs without a hitch on over one third of all
+  WWW servers available on the Internet.  When bugs do show up, we
+  release patches and new versions as soon as they are available.
+  </P>
+  <P>
+  The Apache project's web site includes a page with a partial list of
+  <A
+   HREF="http://www.apache.org/info/apache_users"
+  >sites running Apache</A>.
+  </P>
+  <HR>
+ </LI>
+ <LI><A NAME="future">
+      <STRONG>What are the future plans for Apache?</STRONG>
+     </A>
+  <P>
+  <UL>
+   <LI>to continue as a public domain HTTP server,
+   </LI>
+   <LI>to keep up with advances in HTTP protocol and web developments in
+    general,
+   </LI>
+   <LI>to collect suggestions for fixes/improvements from its users,
+   </LI>
+   <LI>to respond to needs of large volume providers as well as
+    occasional users.
+   </LI>
+  </UL>
+  </P>
+  <HR>
+ </LI>
+ <LI><A NAME="support">
+      <STRONG>Whom do I contact for support?</STRONG>
+     </A>
+  <P>
+  There is no official support for Apache. None of the developers want to
+  be swamped by a flood of trivial questions that can be resolved elsewhere.
+  Bug reports and suggestions should be sent <EM>via</EM>
+  <A
+   HREF="http://www.apache.org/bug_report"
+  >the bug report page</A>.
+  Other questions should be directed to the
+  <A
+   HREF="news:comp.infosystems.www.servers.unix"
+  ><SAMP>comp.infosystems.www.servers.unix</SAMP></A>
+  newsgroup, where some of the Apache team lurk,
+  in the company of many other httpd gurus who should be able
+  to help.
+  </P>
+  <P>
+  Commercial support for Apache is, however, available from a number
+  of third parties.
+  </P>
+  <HR>
+ </LI>
+ <LI><A NAME="more">
+      <STRONG>Is there any more information available on
+      Apache?</STRONG>
+     </A>
+  <P>
+  Indeed there is.  See the main
+  <A
+   HREF="http://www.apache.org/"
+  >Apache web site</A>.
+  There is also a regular electronic publication called
+  <A
+   HREF="http://www.apacheweek.com/"
+   REL="Help"
+  ><CITE>Apache Week</CITE></A>
+  available.  Links to relevant <CITE>Apache Week</CITE> articles are
+  included below where appropriate.
+  </P>
+  <HR>
+ </LI>
+ <LI><A NAME="where">
+      <STRONG>Where can I get Apache?</STRONG>
+     </A>
+  <P>
+  You can find out how to download the source for Apache at the
+  project's
+  <A
+   HREF="http://www.apache.org/"
+  >main web page</A>.
+  </P>
+  <HR>
+ </LI>
+</OL>
+  <H3>
+   Technical Questions
+  </H3>
+<OL START=11>
+ <LI><A NAME="what2do">
+      <STRONG>&quot;Why can't I ...?  Why won't ... work?&quot;  What to
+      do in case of problems</STRONG>
+     </A>
+  <P>
+  If you are having trouble with your Apache server software, you should
+  take the following steps:
+  </P>
+  <OL>
+   <LI><STRONG>Check the errorlog!</STRONG>
+    <P>
+    Apache tries to be helpful when it encounters a problem.  In many
+    cases, it will provide some details by writing one or messages to
+    the server error log.  Sometimes this is enough for you to diagnose 
+    &amp; fix the problem yourself (such as file permissions or the like).
+    The default location of the error log is 
+    <CODE>/usr/local/etc/httpd/logs/error_log</CODE>, but see the 
+    <A
+     HREF="../mod/core.html#errorlog"
+    ><SAMP>ErrorLog</SAMP></A>
+    directive in your config files for the location on your server.
+    </P>
+   </LI>
+   <LI><STRONG>Check the
+    <A
+     HREF="http://www.apache.org/docs/misc/FAQ.html"
+    >FAQ</A>!</STRONG>
+    <P>
+    The latest version of the Apache Frequently-Asked Questions list can
+    always be found at the main Apache web site.
+    </P>
+   </LI>
+   <LI><STRONG>Check the Apache bug database</STRONG>
+    <P>
+    Most problems that get reported to The Apache Group are recorded in
+    the
+    <A
+     HREF="http://www.apache.org/bugdb.cgi"
+    >bug database</A>.
+    <EM><STRONG>Please</STRONG> check the existing reports, open
+    <STRONG>and</STRONG> closed, before adding one.</EM>  If you find
+    that your issue has already been reported, please <EM>don't</EM> add
+    a &quot;me, too&quot; report.  If the original report isn't closed
+    yet, we suggest that you check it periodically.  You might also
+    consider contacting the original submitter, because there may be an
+    email exchange going on about the issue that isn't getting recorded
+    in the database.
+    </P>
+   </LI>
+   <LI><STRONG>Ask in the <SAMP>comp.infosystems.www.servers.unix</SAMP>
+    USENET newsgroup</STRONG>
+    <P>
+    A lot of common problems never make it to the bug database because
+    there's already high Q&amp;A traffic about them in the
+    <A
+     HREF="news:comp.infosystems.www.servers.unix"
+    ><SAMP>comp.infosystems.www.servers.unix</SAMP></A>
+    newsgroup.  Many Apache users, and some of the developers, can be
+    found roaming its virtual halls, so it is suggested that you seek
+    wisdom there.  The chances are good that you'll get a faster answer
+    there than from the bug database, even if you <EM>don't</EM> see
+    your question already posted.
+    </P>
+   </LI>
+   <LI><STRONG>If all else fails, report the problem in the bug
+    database</STRONG>
+    <P>
+    If you've gone through those steps above that are appropriate and
+    have obtained no relief, then please <EM>do</EM> let The Apache
+    Group know about the problem by
+    <A
+     HREF="http://www.apache.org/bugdb.cgi"
+    >logging a bug report</A>.
+    </P>
+    <P>
+    If your problem involves the server crashing and generating a core
+    dump, please include a backtrace (if possible).  As an example,
+    </P>
+    <P>
+    <CODE>
+     <DL>
+      <DD># cd <EM>ServerRoot</EM>
+      </DD>
+      <DD># dbx httpd core
+      </DD>
+      <DD>(dbx) where
+      </DD>
+     </DL>
+    </CODE>
+    </P>
+    <P>
+    (Substitute the appropriate locations for your
+    <SAMP>ServerRoot</SAMP> and your <SAMP>httpd</SAMP> and
+    <SAMP>core</SAMP> files.  You may have to use <CODE>gdb</CODE>
+    instead of <CODE>dbx</CODE>.)
+    </P>
+   </LI>
+  </OL>
+  <HR>
+ </LI>
+ <LI><A NAME="compatible">
+      <STRONG>How compatible is Apache with my existing NCSA 1.3
+      setup?</STRONG>
+     </A>
+  <P>
+  Apache attempts to offer all the features and configuration options
+  of NCSA httpd 1.3, as well as many of the additional features found in
+  NCSA httpd 1.4 and NCSA httpd 1.5.
+  </P>
+  <P>
+  NCSA httpd appears to be moving toward adding experimental features 
+  which are not generally required at the moment. Some of the experiments
+  will succeed while others will inevitably be dropped. The Apache
+  philosophy is to add what's needed as and when it is needed.
+  </P>
+  <P>
+  Friendly interaction between Apache and NCSA developers should ensure
+  that fundamental feature enhancements stay consistent between the two
+  servers for the foreseeable future.
+  </P>
+  <HR>
+ </LI>
+ <LI><A NAME="CGIoutsideScriptAlias">
+      <STRONG>How do I enable CGI execution in directories other than
+      the ScriptAlias?</STRONG>
+     </A>
+  <P>
+  Apache recognizes all files in a directory named as a
+  <A
+   HREF="../mod/mod_alias.html#scriptalias"
+  ><SAMP>ScriptAlias</SAMP></A>
+  as being eligible for execution rather than processing as normal
+  documents.  This applies regardless of the file name, so scripts in a
+  ScriptAlias directory don't need to be named
+  &quot;<SAMP>*.cgi</SAMP>&quot; or &quot;<SAMP>*.pl</SAMP>&quot; or
+  whatever.  In other words, <EM>all</EM> files in a ScriptAlias
+  directory are scripts, as far as Apache is concerned.
+  </P>
+  <P>
+  To persuade Apache to execute scripts in other locations, such as in
+  directories where normal documents may also live, you must tell it how
+  to recognize them - and also that it's okay to execute them.  For
+  this, you need to use something like the
+  <A
+   HREF="../mod/mod_mime.html#addhandler"
+  ><SAMP>AddHandler</SAMP></A>
+  directive.
+  </P>
+  <OL>
+   <LI>In an appropriate section of your server configuration files, add
+    a line such as
+    <P>
+    <DL>
+     <DD><CODE>AddHandler cgi-script .cgi</CODE>
+     </DD>
+    </DL>
+    </P>
+    The server will then recognize that all files in that location (and
+    its logical descendants) that end in &quot;<SAMP>.cgi</SAMP>&quot;
+    are script files, not documents.
+   </LI>
+   <LI>Make sure that the directory location is covered by an
+    <A
+     HREF="../mod/core.html#options"
+    ><SAMP>Options</SAMP></A>
+    declaration that includes the <SAMP>ExecCGI</SAMP> option.
+   </LI>
+  </OL>
+  <HR>
+ </LI>
+ <LI><A NAME="premature-script-headers">
+      <STRONG>What does it mean when my CGIs fail with
+      &quot;<SAMP>Premature end of script headers</SAMP>&quot;?</STRONG>
+     </A> 
+  <P>
+  It means just what it says: the server was expecting a complete set of
+  HTTP headers (one or more followed by a blank line), and didn't get
+  them.  The most common cause of this (aside from people not
+  outputting the required headers at all) a result of an interaction
+  with perl's output buffering.  To make perl flush its buffers 
+  after each output statement, insert the following statements before your
+  first <CODE>print</CODE> or <CODE>write</CODE> statement:
+  </P>
+  <P>
+  <CODE>
+   <DL>
+    <DD>$cfh = select (STDOUT);
+    </DD>
+    <DD>$| = 1;
+    </DD>
+    <DD>select ($cfh);
+    </DD>
+   </DL>
+  </CODE>
+  </P>
+  <P>
+  This is generally only necessary when you are calling external 
+  programs from your script that send output to stdout.  
+  <P>
+  If your script isn't written in Perl, do the equivalent thing for
+  whatever language you <EM>are</EM> using (<EM>e.g.</EM>, for C, call 
+  <CODE>fflush()</CODE> after writing the headers).
+  </P>
+  <HR>
+ </LI>
+ <LI><A NAME="ssi-part-i">
+      <STRONG>How do I enable SSI (parsed HTML)?</STRONG>
+     </A>
+  <P>
+  SSI (an acronym for Server-Side Include) directives allow static HTML
+  documents to be enhanced at run-time (<EM>e.g.</EM>, when delivered to
+  a client by Apache).  The format of SSI directives is covered
+  in the <A HREF="../mod/mod_include.html">mod_include manual</A>; 
+  suffice it to say that Apache supports not only SSI but
+  xSSI (eXtended SSI) directives.
+  </P>
+  <P>
+  Processing a document at run-time is called <EM>parsing</EM> it; hence
+  the term &quot;parsed HTML&quot; sometimes used for documents that
+  contain SSI instructions.  Parsing tends to be <EM>extremely</EM>
+  resource-consumptive, and is not enabled by default.
+  </P>
+  <P>
+  To enable SSI processing, you need to
+  </P>
+  <UL>
+   <LI>Build your server with the
+    <A
+     HREF="../mod/mod_include.html"
+    ><SAMP>mod_include</SAMP></A>
+    module.  This is normally compiled in by default.
+   </LI>
+   <LI>Make sure your server configuration files have an
+    <A
+     HREF="../mod/core.html#options"
+    ><SAMP>Options</SAMP></A>
+    directive which permits <SAMP>Includes</SAMP>.
+   </LI>
+   <LI>Make sure that the directory where you want the SSI documents to
+    live is covered by the &quot;server-parsed&quot; content handler,
+    either explicitly or in some ancestral location.  That can be done
+    with the following
+    <A
+     HREF="../mod/mod_mime.html#addhandler"
+    ><SAMP>AddHandler</SAMP></A>
+    directive:
+    <P>
+    <DL>
+     <DD><CODE>AddHandler server-parsed .shtml</CODE>
+     </DD>
+    </DL>
+    </P>
+    This indicates that all files ending in &quot;.shtml&quot; in that
+    location (or its descendants) should be parsed.  Note that using
+    &quot;.html&quot; will cause all normal HTML files to be parsed,
+    which may put an inordinate load on your server.
+   </LI>
+  </UL>
+  <P>
+  For additional information, see the <CITE>Apache Week</CITE> article
+  on
+  <A
+   HREF="http://www.apacheweek.com/features/ssi"
+   REL="Help"
+  ><CITE>Using Server Side Includes</CITE></A>.
+  </P>
+  <HR>
+ </LI>
+ <LI><A NAME="ssi-part-ii">
+      <STRONG>Why don't my parsed files get cached?</STRONG>
+     </A>
+  <P>
+  Since the server is performing run-time processing of your SSI
+  directives, which may change the content shipped to the client, it
+  can't know at the time it starts parsing what the final size of the
+  result will be, or whether the parsed result will always be the same.
+  This means that it can't generate <SAMP>Content-Length</SAMP> or
+  <SAMP>Last-Modified</SAMP> headers.  Caches commonly work by comparing
+  the <SAMP>Last-Modified</SAMP> of what's in the cache with that being
+  delivered by the server.  Since the server isn't sending that header
+  for a parsed document, whatever's doing the caching can't tell whether
+  the document has changed or not - and so fetches it again to be on the
+  safe side.
+  </P>
+  <P>
+  You can work around this in some cases by causing an
+  <SAMP>Expires</SAMP> header to be generated.  (See the
+  <A
+   HREF="../mod/mod_expires.html"
+   REL="Help"
+  ><SAMP>mod_expires</SAMP></A>
+  documentation for more details.)  Another possibility is to use the
+  <A
+   HREF="../mod/mod_include.html#xbithack"
+   REL="Help"
+  ><SAMP>XBitHack Full</SAMP></A>
+  mechanism, which tells Apache to send (under certain circumstances
+  detailed in the XBitHack directive description) a
+  <SAMP>Last-Modified</SAMP> header based upon the last modification
+  time of the file being parsed.  Note that this may actually be lying
+  to the client if the parsed file doesn't change but the SSI-inserted
+  content does; if the included content changes often, this can result
+  in stale copies being cached.
+  </P>
+  <HR>
+ </LI>
+ <LI><A NAME="ssi-part-iii">
+      <STRONG>How can I have my script output parsed?</STRONG>
+     </A>
+  <P>
+  So you want to include SSI directives in the output from your CGI
+  script, but can't figure out how to do it?
+  The short answer is &quot;you can't.&quot;  This is potentially
+  a security liability and, more importantly, it can not be cleanly
+  implemented under the current server API.  The best workaround
+  is for your script itself to do what the SSIs would be doing.
+  After all, it's generating the rest of the content.
+  </P>
+  <P>
+  This is a feature The Apache Group hopes to add in the next major
+  release after 1.2.
+  </P>
+  <HR>
+ </LI>
+ <LI><A NAME="proxy">
+      <STRONG>Does or will Apache act as a Proxy server?</STRONG>
+     </A>
+  <P>
+  Apache version 1.1 and above comes with a proxy module. If compiled
+  in, this will make Apache act as a caching-proxy server.  
+  </P>
+  <HR>
+ </LI>
+ <LI><A NAME="multiviews">
+      <STRONG>What are &quot;multiviews&quot;?</STRONG>
+     </A>
+  <P>
+  &quot;Multiviews&quot; is the general name given to the Apache
+  server's ability to provide language-specific document variants in
+  response to a request.  This is documented quite thoroughly in the 
+  <A
+   HREF="../content-negotiation.html"
+   REL="Help"
+  >content negotiation</A>
+  description page.  In addition, <CITE>Apache Week</CITE> carried an
+  article on this subject entitled
+  &quot;<A
+         HREF="http://www.apacheweek.com/features/negotiation"
+         REL="Help"
+        ><CITE>Content Negotiation Explained</CITE></A>&quot;.
+  </P>
+  <HR>
+ </LI>
+ <LI><A NAME="fdlim">
+      <STRONG>Why can't I run more than &lt;<EM>n</EM>&gt;
+      virtual hosts?</STRONG>
+     </A>
+  <P>
+  You are probably running into resource limitations in your 
+  operating system.  The most common limitation is the 
+  <EM>per</EM>-process limit on <STRONG>file descriptors</STRONG>, 
+  which is almost always the cause of problems seen when adding 
+  virtual hosts.  Apache often does not give an intuitive error 
+  message because it is normally some library routine (such as 
+  <CODE>gethostbyname()</CODE>) which needs file descriptors and 
+  doesn't complain intelligibly when it can't get them.  
+  </P>
+  <P>
+  Each log file requires a file descriptor, which means that if you are
+  using separate access and error logs for each virtual host, each
+  virtual host needs two file descriptors.  Each 
+  <A
+   HREF="../mod/core.html#listen"
+  ><SAMP>Listen</SAMP></A>
+  directive also needs a file descriptor.  
+  </P>
+  <P>
+  Typical values for &lt;<EM>n</EM>&gt; that we've seen are in
+  the neighborhood of 128 or 250.  When the server bumps into the file
+  descriptor limit, it may dump core with a SIGSEGV, it might just
+  hang, or it may limp along and you'll see (possibly meaningful) errors
+  in the error log.  One common problem that occurs when you run into
+  a file descriptor limit is that CGI scripts stop being executed
+  properly.
+  </P>
+  <P>
+  As to what you can do about this:
+  </P>
+  <OL>
+   <LI>Reduce the number of
+       <A
+        HREF="../mod/core.html#listen"
+       ><SAMP>Listen</SAMP></A>
+       directives.  If there are no other servers running on the machine 
+       and all of them are running on the same port, you normally don't 
+       need any Listen directives at all.
+   </LI>
+   <LI>Reduce the number of log files.  You can use 
+       <A
+        HREF="../mod/mod_log_config.html"
+       ><SAMP>mod_log_config</SAMP></A>
+       to log all requests to a single log file while including the name
+       of the virtual host in the log file.  You can then write a 
+       script to split the logfile into separate files later if
+       necessary.
+   </LI>
+   <LI>Increase the number of file descriptors available to the server
+       (see your system's documentation on the <CODE>limit</CODE> or
+       <CODE>ulimit</CODE> commands).  For some systems, information on
+       how to do this is available in the
+       <A
+        HREF="perf.html"
+       >performance hints</A>
+       page.
+   </LI>
+   <LI>&quot;Don't do that&quot; - try to run with fewer virtual hosts
+   </LI>
+   <LI>Spread your operation across multiple server processes (using
+       <A
+        HREF="../mod/core.html#listen"
+       ><SAMP>Listen</SAMP></A>
+       for example, but see the first point) and/or ports.
+   </LI>
+  </OL>
+  <P>
+  Since this is an operating-system limitation, there's not much else
+  available in the way of solutions.
+  </P>
+  <HR>
+ <LI><A NAME="limitGET">
+      <STRONG>Why do I keep getting &quot;access denied&quot; for form POST
+      requests?</STRONG>
+     </A>
+  <P>
+  The most common cause of this is a <SAMP>&lt;Limit&gt;</SAMP> section
+  that only names the <SAMP>GET</SAMP> method.  Look in your
+  configuration files for something that resembles the following and
+  would affect the location where the POST-handling script resides:
+  </P>
+  <P>
+  <CODE>
+   <DL>
+    <DD>&lt;Limit GET&gt;
+    </DD>
+    <DD>&nbsp;&nbsp;&nbsp;&nbsp;:
+    </DD>
+   </DL>
+  </CODE>
+  </P>
+  <P>
+  Change that to <SAMP>&lt;Limit GET POST&gt;</SAMP> and the problem
+  will probably go away.
+  </P>
+  <HR>
+ </LI>
+ <LI><A NAME="passwdauth">
+      <STRONG>Can I use my <SAMP>/etc/passwd</SAMP> file
+      for Web page authentication?</STRONG>
+     </A>
+  <P>
+  Yes, you can - but it's a <STRONG>very bad idea</STRONG>.  Here are
+  some of the reasons:
+  </P>
+  <UL>
+   <LI>The Web technology provides no governors on how often or how
+    rapidly password (authentication failure) retries can be made.  That
+    means that someone can hammer away at your system's
+    <SAMP>root</SAMP> password using the Web, using a dictionary or
+    similar mass attack, just as fast as the wire and your server can
+    handle the requests.  Most operating systems these days include
+    attack detection (such as <EM>n</EM> failed passwords for the same
+    account within <EM>m</EM> seconds) and evasion (breaking the
+    connection, disabling the account under attack, disabling
+    <EM>all</EM> logins from that source, <EM>et cetera</EM>), but the
+    Web does not.
+   </LI>
+   <LI>An account under attack isn't notified (unless the server is
+    heavily modified); there's no &quot;You have 19483 login
+    failures&quot; message when the legitimate owner logs in.
+   </LI>
+   <LI>Without an exhaustive and error-prone examination of the server
+    logs, you can't tell whether an account has been compromised.
+    Detecting that an attack has occurred, or is in progress, is fairly
+    obvious, though - <EM>if</EM> you look at the logs.
+   </LI>
+   <LI>Web authentication passwords (at least for Basic authentication)
+    generally fly across the wire, and through intermediate proxy
+    systems, in what amounts to plaintext.  &quot;O'er the net we
+    go/Caching all the way;/O what fun it is to surf/Giving my password
+    away!&quot;
+   </LI>
+   <LI>Since HTTP is stateless, information about the authentication is
+    transmitted <EM>each and every time</EM> a request is made to the
+    server.  Essentially, the client caches it after the first
+    successful access, and transmits it without asking for all
+    subsequent requests to the same server.
+   </LI>
+   <LI>It's relatively trivial for someone on your system to put up a
+    page that will steal the cached password from a client's cache
+    without them knowing.  Can you say &quot;password grabber&quot;?
+   </LI>
+  </UL>
+  <P>
+  If you still want to do this in light of the above disadvantages, the
+  method is left as an exercise for the reader.  It'll void your Apache
+  warranty, though, and you'll lose all accumulated UNIX guru points.
+  </P>
+  <HR>
+ <LI><A NAME="errordoc401">
+      <STRONG>Why doesn't my <CODE>ErrorDocument 401</CODE> work?</STRONG>
+     </A>
+  <P>
+  You need to use it with a URL in the form "/foo/bar" and not one
+  with a method and hostname such as "http://host/foo/bar".  See the
+  <A
+   HREF="../mod/core.html#errordocument"
+  ><SAMP>ErrorDocument</SAMP></A>
+  documentation for details.  This was incorrectly documented in the past.
+  </P>
+  <HR>
+ </LI>
+ <LI><A NAME="setgid">
+      <STRONG>Why do I get &quot;<SAMP>setgid: Invalid
+      argument</SAMP>&quot; at startup?</STRONG>
+     </A>
+  <P>
+  Your
+  <A
+   HREF="../mod/core.html#group"
+  ><SAMP>Group</SAMP></A>
+  directive (probably in <SAMP>conf/httpd.conf</SAMP>) needs to name a
+  group that actually exists in the <SAMP>/etc/group</SAMP> file (or
+  your system's equivalent).
+  </P>
+  <HR>
+ </LI>
+ <LI><A NAME="cookies1">
+      <STRONG>Why does Apache send a cookie on every response?</STRONG>
+     </A>
+  <P>
+  Apache does <EM>not</EM> send automatically send a cookie on every
+  response, unless you have re-compiled it with the 
+  <A
+   HREF="../mod/mod_cookies.html"
+  ><SAMP>mod_cookies</SAMP></A>
+  module.
+  This module was distributed with Apache prior to 1.2.
+  This module may help track users, and uses cookies to do this. If
+  you are not using the data generated by <SAMP>mod_cookies</SAMP>, do
+  not compile it into Apache. Note that in 1.2 this module was renamed
+  to the more correct name 
+  <A
+   HREF="../mod/mod_usertrack.html"
+  ><SAMP>mod_usertrack</SAMP></A>,
+  and cookies 
+  have to be specifically enabled with the
+  <A
+    HREF="../mod/mod_usertrack.html#cookietracking"
+  ><SAMP>CookieTracking</SAMP></A>
+  directive.
+  </P>
+  <HR>
+ </LI>
+ <LI><A NAME="cookies2">
+      <STRONG>Why don't my cookies work, I even compiled in
+      <SAMP>mod_cookies</SAMP>?
+      </STRONG>
+     </A>
+  <P>
+  Firstly, you do <EM>not</EM> need to compile in
+  <SAMP>mod_cookies</SAMP> in order for your scripts to work (see the
+  <A
+   HREF="#cookies1"
+  >previous question</A>
+  for more about <SAMP>mod_cookies</SAMP>). Apache passes on your
+  <SAMP>Set-Cookie</SAMP> header fine, with or without this module. If
+  cookies do not work it will be because your script does not work
+  properly or your browser does not use cookies or is not set-up to
+  accept them.
+  </P>
+  <HR>
+ </LI>
+ <LI><A NAME="jdk1-and-http1.1">
+      <STRONG>Why do my Java app[let]s give me plain text when I request
+      an URL from an Apache server?</STRONG>
+     </A>
+  <P>
+  As of version 1.2, Apache is an HTTP/1.1 (HyperText Transfer Protocol
+  version 1.1) server.  This fact is reflected in the protocol version
+  that's included in the response headers sent to a client when
+  processing a request.  Unfortunately, low-level Web access classes
+  included in the Java Development Kit (JDK) version 1.0.2 expect to see
+  the version string &quot;HTTP/1.0&quot; and do not correctly interpret
+  the &quot;HTTP/1.1&quot; value Apache is sending (this part of the
+  response is a declaration of what the server can do rather than a
+  declaration of the dialect of the response).  The result
+  is that the JDK methods do not correctly parse the headers, and
+  include them with the document content by mistake.
+  </P>
+  <P>
+  This is definitely a bug in the JDK 1.0.2 foundation classes from Sun,
+  and it has been fixed in version 1.1.  However, the classes in
+  question are part of the virtual machine environment, which means
+  they're part of the Web browser (if Java-enabled) or the Java
+  environment on the client system - so even if you develop
+  <EM>your</EM> classes with a recent JDK, the eventual users might
+  encounter the problem.
+  The classes involved are replaceable by vendors implementing the
+  Java virtual machine environment, and so even those that are based
+  upon the 1.0.2 version may not have this problem.
+  </P>
+  <P>
+  In the meantime, a workaround is to tell
+  Apache to &quot;fake&quot; an HTTP/1.0 response to requests that come
+  from the JDK methods; this can be done by including a line such as the
+  following in your server configuration files:
+  </P>
+  <P>
+  <DL>
+   <DD><CODE>BrowserMatch Java/1.0 force-response-1.0</CODE>
+   </DD>
+  </DL>
+  </P>
+  <P>
+  More information about this issue can be found in the
+  <A
+   HREF="http://www.apache.org/info/jdk-102"
+  ><CITE>Java and HTTP/1.1</CITE></A>
+  page at the Apache web site.
+  </P>
+  <HR>
+ </LI>
+ <LI><A NAME="putsupport">
+      <STRONG>Why can't I publish to my Apache server using PUT on
+      Netscape Gold and other programs?</STRONG>
+     </A>
+  <P>
+  Because you need to install and configure a script to handle
+  the uploaded files.  This script is often called a &quot;PUT&quot; handler.
+  There are several available, but they may have security problems.
+  Using FTP uploads may be easier and more secure, at least for now.
+  For more information, see the <CITE>Apache Week</CITE> article
+  <A
+   HREF="http://www.apacheweek.com/features/put"
+  ><CITE>Publishing Pages with PUT</CITE></A>.
+  </P>
+  <HR>
+  </LI>
+ <LI><A NAME="fastcgi">
+      <STRONG>Why isn't FastCGI included with Apache any more?</STRONG>
+     </A>
+  <P>
+  The simple answer is that it was becoming too difficult to keep the
+  version being included with Apache synchronized with the master copy
+  at the
+  <A
+   HREF="http://www.fastcgi.com/servers/apache/"
+  >FastCGI web site</A>.  When a new version of Apache was released, the
+  version of the FastCGI module included with it would soon be out of date.
+  </P>
+  <P>
+  You can still obtain the FastCGI module for Apache from the master
+  FastCGI web site.
+  </P>
+  <HR>
+ </LI>
+ <LI><A NAME="nodelay">
+      <STRONG>Why am I getting &quot;<SAMP>httpd: could not set socket
+      option TCP_NODELAY</SAMP>&quot; in my error log?</STRONG>
+     </A> 
+  <P>
+  This message almost always indicates that the client disconnected
+  before Apache reached the point of calling <CODE>setsockopt()</CODE>
+  for the connection.  It shouldn't occur for more than about 1% of the
+  requests your server handles, and it's advisory only in any case.
+  </P>
+  <HR>
+ </LI>
+ <LI><A NAME="nph-scripts">
+      <STRONG>How can I get my script's output without Apache buffering
+      it?</STRONG>
+     </A>
+  <P>
+  In order to improve network performance, Apache buffers script output
+  into relatively large chunks.  If you have a script that sends
+  information in bursts (such as partial-done messages in a multi-commit
+  database transaction, perhaps), the client will not necessarily get
+  the output as the script is generating it.
+  </P>
+  <P>
+  To avoid this, Apache recognizes scripts whose names begin with
+  &quot;<SAMP>nph-</SAMP>&quot; as <EM>non-parsed-header</EM> scripts.
+  That is, Apache won't buffer their output, but connect it directly to
+  the socket going back to the client.
+  </P>
+  <P>
+  While this will probably do what you want, there <EM>are</EM> some
+  disadvantages to it:
+  </P>
+  <UL>
+   <LI><STRONG>YOU</STRONG> (the script) are responsible for generating
+     <STRONG>ALL</STRONG> of the HTTP headers, and no longer
+     <EM>just</EM> the &quot;<SAMP>Content-type</SAMP>&quot; or
+     &quot;<SAMP>Location</SAMP>&quot; headers
+   </LI>
+   <LI>Unless your script generates its output carefully, you will see a
+    performance penalty as excessive numbers of packets go back and forth
+   </LI>
+  </UL>
+  <P>
+  As an example how you might handle the former (in a Perl script):
+  </P>
+  <CODE>
+   <DL>
+    <DD>if ($0 =~ m:/*nph-:) {
+        <BR>
+        &nbsp;&nbsp;&nbsp;&nbsp;
+        $HTTP_headers&nbsp;=&nbsp;
+        &quot;HTTP/1.1&nbsp;200&nbsp;OK\015\012&quot;;
+        <BR>
+        &nbsp;&nbsp;&nbsp;&nbsp;
+        $HTTP_headers&nbsp;.=&nbsp;
+        &quot;Connection:&nbsp;close\015\012&quot;;
+        <BR>
+        &nbsp;&nbsp;&nbsp;&nbsp;
+        printf&nbsp;($HTTP_headers);
+        <BR>
+        };
+    </DD>
+   </DL>
+  </CODE>
+  <P>
+  and then follow with your normal non-<SAMP>nph</SAMP> headers.
+  </P>
+  <HR>
+ </LI>
+ <LI><A NAME="linuxiovec">
+      <STRONG>Why do I get complaints about redefinition
+      of `struct iovec' when compiling under Linux?</STRONG>
+     </A>
+  <P>
+  This is a conflict between your C library includes and your kernel
+  includes.  You need to make sure that the versions of both are matched
+  properly.  There are two workarounds, either one will solve the problem:
+  </P>
+  <UL>
+   <LI>Remove the definition of <CODE>struct iovec</CODE> from your C
+    library includes.  It is located in <CODE>/usr/include/sys/uio.h</CODE>.  
+    <STRONG>Or,</STRONG>
+   </LI>
+   <LI>Add  <CODE>-DNO_WRITEV</CODE> to the <CODE>EXTRA_CFLAGS</CODE>
+    line in your <SAMP>Configuration</SAMP> and reconfigure/rebuild.
+    This hurts performance and should only be used as a last resort.
+   </LI>
+  </UL>
+  <HR>
+ </LI>
+ <LI><A NAME="wheres-the-dump">
+      <STRONG>The errorlog says Apache dumped core, but where's the dump
+      file?</STRONG>
+     </A>
+  <P>
+  In Apache version 1.2 (beginning with 1.2b8), the error log message
+  about dumped core includes the directory where the dump file should be
+  located.  However, many Unixes do not allow a process that has
+  called <CODE>setuid()</CODE> to dump core for security reasons; 
+  the typical Apache setup has the server started as root to bind to 
+  port 80, after which it changes UIDs to a non-privileged user to 
+  serve requests.
+  </P>
+  <P>
+  Dealing with this is extremely operating system-specific, and may
+  require rebuilding your system kernel.  Consult your operating system
+  documentation or vendor for more information about whether your system
+  does this and how to bypass it.  If there <EM>is</EM> a documented way
+  of bypassing it, it is recommended that you bypass it only for the
+  <SAMP>httpd</SAMP> server process if possible.
+  </P>
+  <P>
+  The canonical location for Apache's core-dump files is the
+  <A
+   HREF="../mod/core.html#serverroot"
+  >ServerRoot</A>
+  directory.
+  </P>
+  <HR>
+ </LI>
+ <LI><A NAME="dnsauth">
+      <STRONG>Why isn't restricting access by host or domain name
+      working correctly?</STRONG>
+     </A>
+  <P>
+  Two of the most common causes of this are:
+  </P>
+  <OL>
+   <LI><STRONG>An error, inconsistency, or unexpected mapping in the DNS
+    registration</STRONG>
+    <BR>
+    This happens frequently: your configuration restricts access to
+    <SAMP>Host.FooBar.Com</SAMP>, but you can't get in from that host.
+    The usual reason for this is that <SAMP>Host.FooBar.Com</SAMP> is
+    actually an alias for another name, and when Apache performs the
+    address-to-name lookup it's getting the <EM>real</EM> name, not
+    <SAMP>Host.FooBar.Com</SAMP>.  You can verify this by checking the
+    reverse lookup yourself.  The easiest way to work around it is to
+    specify the correct host name in your configuration.
+   </LI>
+   <LI><STRONG>Inadequate checking and verification in your
+    configuration of Apache</STRONG>
+    <BR>
+    If you intend to perform access checking and restriction based upon
+    the client's host or domain name, you really need to configure
+    Apache to double-check the origin information it's supplied.  You do
+    this by adding the <SAMP>-DMAXIMUM_DNS</SAMP> clause to the
+    <SAMP>EXTRA_CFLAGS</SAMP> definition in your
+    <SAMP>Configuration</SAMP> file.  For example:
+    <DL>
+     <DD><CODE>EXTRA_CFLAGS=-DMAXIMUM_DNS</CODE>
+     </DD>
+    </DL>
+    <P>
+    This will cause Apache to be very paranoid about making sure a
+    particular host address is <EM>really</EM> assigned to the name it
+    claims to be.  Note that this <EM>can</EM> incur a significant
+    performance penalty, however, because of all the name resolution
+    requests being sent to a nameserver.
+    </P>
+   </LI>
+  </OL>
+  <HR>
+ </LI>
+ <LI><A NAME="SSL-i">
+      <STRONG>Why doesn't Apache include SSL?</STRONG>
+     </A>
+  <P>
+  SSL (Secure Socket Layer) data transport requires encryption, and many
+  governments have restrictions upon the import, export, and use of
+  encryption technology.  If Apache included SSL in the base package,
+  its distribution would involve all sorts of legal and bureaucratic
+  issues, and it would no longer be freely available.  Also, some of
+  the technology required to talk to current clients using SSL is 
+  patented by <A HREF="http://www.rsa.com/">RSA Data Security</A>, 
+  who restricts its use without a license.
+  </P>
+  <P>
+  Some SSL implementations of Apache are available, however; see the
+  &quot;<A
+         HREF="http://www.apache.org/related_projects"
+        >related projects</A>&quot;
+  page at the main Apache web site.
+  </P>
+  <P>
+  You can find out more about this topic in the <CITE>Apache Week</CITE>
+  article about
+  <A
+   HREF="http://www.apacheweek.com/features/ssl"
+   REL="Help"
+  ><CITE>Apache and Secure Transactions</CITE></A>.
+  </P>
+  <HR>
+  </LI>
+  <LI><A NAME="HPUX-core">
+       <STRONG>Why do I get core dumps under HPUX using HP's ANSI 
+               C compiler?</STRONG>
+      </A>
+  <P>
+  We have had numerous reports of Apache dumping core when compiled
+  with HP's ANSI C compiler using optimization.  Disabling the compiler
+  optimization has fixed these problems.
+  </P>
+  <HR>
+ </LI>
+ <LI><A NAME="midi">
+      <STRONG>How do I get Apache to send a MIDI file so the browser can
+      play it?</STRONG>
+     </A>
+  <P>
+  Even though the registered MIME type for MIDI files is
+  <SAMP>audio/midi</SAMP>, some browsers are not set up to recognize it
+  as such; instead, they look for <SAMP>audio/x-midi</SAMP>.  There are
+  two things you can do to address this:
+  </P>
+  <OL>
+   <LI>Configure your browser to treat documents of type
+    <SAMP>audio/midi</SAMP> correctly.  This is the type that Apache
+    sends by default.  This may not be workable, however, if you have
+    many client installations to change, or if some or many of the
+    clients are not under your control.
+   </LI>
+   <LI>Instruct Apache to send a different <SAMP>Content-type</SAMP>
+    header for these files by adding the following line to your server's
+    configuration files:
+    <DL>
+     <DD><CODE>AddType audio/x-midi .mid .midi .kar</CODE>
+     </DD>
+    </DL>
+    <P>
+    Note that this may break browsers that <EM>do</EM> recognize the
+    <SAMP>audio/midi</SAMP> MIME type unless they're prepared to also
+    handle <SAMP>audio/x-midi</SAMP> the same way.
+    </P>
+   </LI>
+  </OL>
+  <HR>
+ </LI>
+ <LI><A NAME="cantbuild">
+       <STRONG>Why won't Apache compile with my system's
+       <SAMP>cc</SAMP>?</STRONG>
+      </A>
+  <P>
+  If the server won't compile on your system, it is probably due to one
+  of the following causes:
+  </P>
+  <UL>
+   <LI><STRONG>The <SAMP>Configure</SAMP> script doesn't recognize your system
+    environment.</STRONG>
+    <BR>
+    This might be either because it's completely unknown or because
+    the specific environment (include files, OS version, <EM>et
+    cetera</EM>) isn't explicitly handled.  If this happens, you may
+    need to port the server to your OS yourself.
+   </LI>
+   <LI><STRONG>Your system's C compiler is garbage.</STRONG>
+    <BR>
+    Some operating systems include a default C compiler that is either
+    not ANSI C-compliant or suffers from other deficiencies.  The usual
+    recommendation in cases like this is to acquire, install, and use
+    <SAMP>gcc</SAMP>.
+   </LI>
+   <LI><STRONG>Your <SAMP>include</SAMP> files may be confused.</STRONG>
+    <BR>
+    In some cases, we have found that a compiler installation or system
+    upgrade has left the C header files in an inconsistent state.  Make
+    sure that your include directory tree is in sync with the compiler and
+    the operating system.
+   </LI>
+   <LI><STRONG>Your operating system or compiler may be out of
+    revision.</STRONG> 
+    <BR>
+    Software vendors (including those that develop operating systems)
+    issue new releases for a reason; sometimes to add functionality, but
+    more often to fix bugs that have been discovered.  Try upgrading
+    your compiler and/or your operating system.
+   </LI>
+  </UL>
+  <P>
+  The Apache Group tests the ability to build the server on many
+  different platforms.  Unfortunately, we can't test all of the OS
+  platforms there are.  If you have verified that none of the above
+  issues is the cause of your problem, and it hasn't been reported
+  before, please submit a
+  <A
+   HREF="http://www.apache.org/bugdb.cgi"
+  >problem report</A>.
+  Be sure to include <EM>complete</EM> details, such as the compiler
+  &amp; OS versions and exact error messages.
+  </P>
+  <HR>
+ </LI>
+ <LI><A NAME="addlog">
+      <STRONG>How do I add browsers and referrers to my logs?</STRONG>
+     </A>
+  <P>
+  Apache provides a couple of different ways of doing this.  The
+  recommended method is to compile the
+  <A
+   HREF="../mod/mod_log_config.html"
+  ><SAMP>mod_log_config</SAMP></A>
+  module into your configuration and use the
+  <A
+   HREF="../mod/mod_log_config.html#customlog"
+  ><SAMP>CustomLog</SAMP></A>
+  directive.
+  </P>
+  <P>
+  You can either log the additional information in files other than your
+  normal transfer log, or you can add them to the records already being
+  written.  For example:
+  </P>
+  <P>
+  <CODE>
+   CustomLog&nbsp;logs/access_log&nbsp;"%h&nbsp;%l&nbsp;%u&nbsp;%t&nbsp;\"%r\"&nbsp;%s&nbsp;%b&nbsp;\"%{Referer}i\"&nbsp;\"%{User-Agent}i\""
+  </CODE>
+  </P>
+  <P>
+  This will add the values of the <SAMP>User-agent:</SAMP> and
+  <SAMP>Referer:</SAMP> headers, which indicate the client and the
+  referring page, respectively, to the end of each line in the access
+  log.
+  </P>
+  <P>
+  You may want to check out the <CITE>Apache Week</CITE> article
+  entitled:
+  &quot;<A
+         HREF="http://www.apacheweek.com/features/logfiles"
+         REL="Help"
+        ><CITE>Gathering Visitor Information: Customising Your
+         Logfiles</CITE></A>&quot;.
+  </P>
+  <HR>
+ </LI>
+ <LI><A NAME="jdk1.x">
+      <STRONG>Why do Java applets and applications not work
+      with documents on my Apache server?</A></STRONG>
+     </A>
+  <P>
+  The Java Development Kit (JDK) libraries versions 1.0.2 and 1.1 do not
+  correctly interpret the &quot;<SAMP>HTTP/1.1</SAMP>&quot; response
+  header that Apache 1.2 sends.  Instead, if they don't see an exact
+  match for &quot;<SAMP>HTTP/1.0</SAMP>&quot;, they assume the headers
+  are part of the document content.
+  </P>
+  <P>
+  This is a known problem, and it has been reported to Sun's JavaSoft
+  unit.  In the meantime, Apache 1.2 servers can work around this by
+  adding the following lines to their configuration files:
+  </P>
+  <DL>
+   <DD>BrowserMatch&nbsp;Java1.0&nbsp;force-response-1.0</CODE>
+   </DD>
+  </DL>
+  <HR>
+  <!-- Don't forget to add HR tags at the end of each list item.. -->
+ </LI>
+</OL>
+ <!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
diff --git a/APACHE_1_2_X/htdocs/manual/misc/client_block_api.html b/APACHE_1_2_X/htdocs/manual/misc/client_block_api.html
new file mode 100644 (file)
index 0000000..2458e0e
--- /dev/null
@@ -0,0 +1,86 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<TITLE>Reading Client Input in Apache 1.2</TITLE>
+</HEAD>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<H1 ALIGN="CENTER">Reading Client Input in Apache 1.2</h1>
+
+<hr>
+
+<p>Apache 1.1 and earlier let modules handle POST and PUT requests by
+themselves. The module would, on its own, determine whether the
+request had an entity, how many bytes it was, and then called a
+function (<code>read_client_block</code>) to get the data.
+
+<p>However, HTTP/1.1 requires several things of POST and PUT request
+handlers that did not fit into this module, and all existing modules
+have to be rewritten. The API calls for handling this have been
+further abstracted, so that future HTTP protocol changes can be
+accomplished while remaining backwards-compatible.</p>
+
+<hr>
+
+<h3>The New API Functions</h3>
+
+<pre>
+   int setup_client_block (request_rec *, int read_policy);
+   int should_client_block (request_rec *);
+   long get_client_block (request_rec *, char *buffer, int buffer_size);
+</pre>
+
+<ol>
+<li>Call <code>setup_client_block()</code> near the beginning of the request
+    handler. This will set up all the necessary properties, and
+    will return either OK, or an error code. If the latter,
+    the module should return that error code. The second parameter
+    selects the policy to apply if the request message indicates a
+    body, and how a chunked
+    transfer-coding should be interpreted. Choose one of
+<pre>
+    REQUEST_NO_BODY          Send 413 error if message has any body
+    REQUEST_CHUNKED_ERROR    Send 411 error if body without Content-Length
+    REQUEST_CHUNKED_DECHUNK  If chunked, remove the chunks for me.
+    REQUEST_CHUNKED_PASS     Pass the chunks to me without removal.
+</pre>
+    In order to use the last two options, the caller MUST provide a buffer
+    large enough to hold a chunk-size line, including any extensions.
+
+
+
+<li>When you are ready to possibly accept input, call
+    <code>should_client_block()</code>.
+    This will tell the module whether or not to read input. If it is 0,
+    the module should assume that the input is of a non-entity type
+    (e.g. a GET request). A nonzero response indicates that the module
+    should proceed (to step 3).
+    This step also sends a 100 Continue response
+    to HTTP/1.1 clients, so should not be called until the module
+    is <strong>*definitely*</strong> ready to read content. (otherwise, the point of the
+    100 response is defeated). Never call this function more than once.
+
+<li>Finally, call <code>get_client_block</code> in a loop. Pass it a
+    buffer and its 
+    size. It will put data into the buffer (not necessarily the full
+    buffer, in the case of chunked inputs), and return the length of
+    the input block. When it is done reading, it will
+    return 0 if EOF, or -1 if there was an error.
+
+</ol>
+
+<p>As an example, please look at the code in
+<code>mod_cgi.c</code>. This is properly written to the new API
+guidelines.</p>
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
diff --git a/APACHE_1_2_X/htdocs/manual/misc/compat_notes.html b/APACHE_1_2_X/htdocs/manual/misc/compat_notes.html
new file mode 100644 (file)
index 0000000..56e20bb
--- /dev/null
@@ -0,0 +1,121 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML><HEAD>
+<TITLE>Apache HTTP Server: Compatibility Notes with NCSA's Server</TITLE>
+</HEAD>
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<H1 ALIGN="CENTER">Compatibility Notes with NCSA's Server</H1>
+
+<HR>
+
+While Apache 0.8.x and beyond are for the most part a drop-in
+replacement for NCSA's httpd and earlier versions of Apache, there are
+a couple gotcha's to watch out for.  These are mostly due to the fact
+that the parser for config and access control files was rewritten from
+scratch, so certain liberties the earlier servers took may not be
+available here.  These are all easily fixable.  If you know of other
+non-fatal problems that belong here, <a
+href="http://www.apache.org/bugdb.cgi">let us know.</a>
+
+<P>Please also check the <A HREF="known_bugs.html">known bugs</A> page.
+
+
+
+<OL>
+
+<LI>The basic mod_auth <CODE>AuthGroupFile</CODE>-specified group file 
+    format allows commas between user names - Apache does not.<BR>
+    <I>- added 12/1/96</I>
+
+<LI><CODE>AddType</CODE> only accepts one file extension per line, without
+any dots (<code>.</code>) in the extension, and does not take full filenames.
+If you need multiple extensions per type, use multiple lines, e.g.
+<blockquote><code>
+AddType application/foo foo<br>
+AddType application/foo bar
+</code></blockquote>
+To map <code>.foo</code> and <code>.bar</code> to <code>application/foo</code>
+<p>
+
+
+
+  <LI><P>If you follow the NCSA guidelines for setting up access restrictions
+  based on client domain, you may well have added entries for,
+  <CODE>AuthType, AuthName, AuthUserFile</CODE> or <CODE>AuthGroupFile</CODE>.
+  <B>None</B> of these are needed (or appropriate) for restricting access
+  based on client domain.
+
+  <P>When Apache sees <CODE>AuthType</CODE> it (reasonably) assumes you
+  are using some authorization type based on username and password.
+
+  <P>Please remove <CODE>AuthType</CODE>, it's unnecessary even for NCSA.
+
+  <P>
+
+  <LI><CODE>AuthUserFile</CODE> requires a full pathname. In earlier
+      versions of NCSA httpd and Apache, you could use a filename
+      relative to the .htaccess file. This could be a major security hole,
+      as it made it trivially easy to make a ".htpass" file in the a 
+      directory easily accessible by the world. We recommend you store
+      your passwords outside your document tree.
+
+  <P>
+
+  <LI><CODE>OldScriptAlias</CODE> is no longer supported.
+
+  <P>
+
+  <LI><CODE>exec cgi=""</CODE> produces reasonable <B>malformed header</B>
+  responses when used to invoke non-CGI scripts.<BR>
+  The NCSA code ignores the missing header. (bad idea)<BR>
+  Solution: write CGI to the CGI spec or use <CODE>exec cmd=""</CODE> instead.
+  <P>We might add <CODE>virtual</CODE> support to <CODE>exec cmd</CODE> to
+  make up for this difference.
+
+  <P>
+
+  <LI>&lt;Limit&gt; silliness - in the old Apache 0.6.5, a
+   directive of &lt;Limit GET&gt; would also restrict POST methods - Apache 0.8.8's new
+   core is correct in not presuming a limit on a GET is the same limit on a POST,
+   so if you are relying on that behavior you need to change your access configurations
+   to reflect that.
+
+  <P>
+
+  <LI>Icons for FancyIndexing broken - well, no, they're not broken, we've just upgraded the
+  icons from flat .xbm files to pretty and much smaller .gif files, courtesy of 
+<a href="mailto:kevinh@eit.com">Kevin Hughes</a> at
+<a href="http://www.eit.com">EIT</a>.
+  If you are using the same srm.conf from an old distribution, make sure you add the new
+  AddIcon, AddIconByType, and DefaultIcon commands.
+
+  <P>
+
+  <LI>Under IRIX, the "Group" directive in httpd.conf needs to be a valid group name 
+  (i.e. "nogroup") not the numeric group ID.  The distribution httpd.conf, and earlier 
+  ones, had the default Group be "#-1", which was causing silent exits at startup.<p>
+
+<li><code>.asis</code> files: Apache 0.6.5 did not require a Status header;
+it added one automatically if the .asis file contained a Location header.
+0.8.14 requires a Status header. <p>
+
+  <P>
+  <LI>Apache versions before 1.2b1 will ignore the last line of configuration
+  files if the last line does not have a trailing newline. This affects
+  configuration files (httpd.conf, access.conf and srm.conf), and
+  htpasswd and htgroup files.
+</OL>
+
+More to come when we notice them....
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
diff --git a/APACHE_1_2_X/htdocs/manual/misc/fin_wait_2.html b/APACHE_1_2_X/htdocs/manual/misc/fin_wait_2.html
new file mode 100644 (file)
index 0000000..48e1087
--- /dev/null
@@ -0,0 +1,321 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<TITLE>Connections in FIN_WAIT_2 and Apache</TITLE>
+<LINK REV="made" HREF="mailto:marc@apache.org">
+
+</HEAD>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+
+<H1 ALIGN="CENTER">Connections in the FIN_WAIT_2 state and Apache</H1>
+<OL>
+<LI><H2>What is the FIN_WAIT_2 state?</H2>
+Starting with the Apache 1.2 betas, people are reporting many more
+connections in the FIN_WAIT_2 state (as reported by
+<code>netstat</code>) than they saw using older versions.  When the
+server closes a TCP connection, it sends a packet with the FIN bit
+sent to the client, which then responds with a packet with the ACK bit
+set.  The client then sends a packet with the FIN bit set to the
+server, which responds with an ACK and the connection is closed.  The
+state that the connection is in during the period between when the
+server gets the ACK from the client and the server gets the FIN from
+the client is known as FIN_WAIT_2.  See the <A
+HREF="ftp://ds.internic.net/rfc/rfc793.txt">TCP RFC</A> for the 
+technical details of the state transitions.<P>
+
+The FIN_WAIT_2 state is somewhat unusual in that there is no timeout 
+defined in the standard for it.  This means that on many operating
+systems, a connection in the FIN_WAIT_2 state will stay around until
+the system is rebooted.  If the system does not have a timeout and
+too many FIN_WAIT_2 connections build up, it can fill up the space
+allocated for storing information about the connections and crash
+the kernel.  The connections in FIN_WAIT_2 do not tie up an httpd
+process.<P>
+
+<LI><H2>But why does it happen?</H2>
+
+There are several reasons for it happening, and not all of them are
+fully understood by the Apache team yet.  What is known follows.<P>
+
+<H3>Buggy clients and persistent connections</H3>
+
+Several clients have a bug which pops up when dealing with
+<A HREF="../keepalive.html">persistent connections</A> (aka keepalives).
+When the connection is idle and the server closes the connection
+(based on the <A HREF="../mod/core.html#keepalivetimeout">
+KeepAliveTimeout</A>), the client is programmed so that the client does
+not send back a FIN and ACK to the server.  This means that the
+connection stays in the FIN_WAIT_2 state until one of the following
+happens:<P>
+<UL>
+       <LI>The client opens a new connection to the same or a different
+           site, which causes it to fully close the older connection on
+            that socket.
+       <LI>The user exits the client, which on some (most?) clients
+           causes the OS to fully shutdown the connection.
+       <LI>The FIN_WAIT_2 times out, on servers that have a timeout
+           for this state.
+</UL><P>
+If you are lucky, this means that the buggy client will fully close the
+connection and release the resources on your server.  However, there
+are some cases where the socket is never fully closed, such as a dialup
+client disconnecting from their provider before closing the client.
+In addition, a client might sit idle for days without making another
+connection, and thus may hold its end of the socket open for days
+even though it has no further use for it.
+<STRONG>This is a bug in the browser or in its operating system's
+TCP implementation.</STRONG>  <P>
+
+The clients on which this problem has been verified to exist:<P>
+<UL>
+       <LI>Mozilla/3.01 (X11; I; FreeBSD 2.1.5-RELEASE i386)
+       <LI>Mozilla/2.02 (X11; I; FreeBSD 2.1.5-RELEASE i386)
+       <LI>Mozilla/3.01Gold (X11; I; SunOS 5.5 sun4m)
+       <LI>MSIE 3.01 on the Macintosh
+       <LI>MSIE 3.01 on Windows 95
+</UL><P>
+
+This does not appear to be a problem on:
+<UL>
+       <LI>Mozilla/3.01 (Win95; I)
+</UL>
+<P>
+
+It is expected that many other clients have the same problem. What a
+client <STRONG>should do</STRONG> is periodically check its open
+socket(s) to see if they have been closed by the server, and close their
+side of the connection if the server has closed.  This check need only
+occur once every few seconds, and may even be detected by a OS signal
+on some systems (e.g., Win95 and NT clients have this capability, but
+they seem to be ignoring it).<P>
+
+Apache <STRONG>cannot</STRONG> avoid these FIN_WAIT_2 states unless it
+disables persistent connections for the buggy clients, just
+like we recommend doing for Navigator 2.x clients due to other bugs.
+However, non-persistent connections increase the total number of
+connections needed per client and slow retrieval of an image-laden
+web page.  Since non-persistent connections have their own resource
+consumptions and a short waiting period after each closure, a busy server
+may need persistence in order to best serve its clients.<P>
+
+As far as we know, the client-caused FIN_WAIT_2 problem is present for
+all servers that support persistent connections, including Apache 1.1.x
+and 1.2.<P>
+
+<H3>Something in Apache may be broken</H3>
+
+While the above bug is a problem, it is not the whole problem.
+Some users have observed no FIN_WAIT_2 problems with Apache 1.1.x,
+but with 1.2b enough connections build up in the FIN_WAIT_2 state to
+crash their server.  We have not yet identified why this would occur
+and welcome additional test input.<P>
+
+One possible (and most likely) source for additional FIN_WAIT_2 states
+is a function called <CODE>lingering_close()</CODE> which was added
+between 1.1 and 1.2.  This function is necessary for the proper
+handling of persistent connections and any request which includes
+content in the message body (e.g., PUTs and POSTs).
+What it does is read any data sent by the client for
+a certain time after the server closes the connection.  The exact
+reasons for doing this are somewhat complicated, but involve what
+happens if the client is making a request at the same time the
+server sends a response and closes the connection. Without lingering,
+the client might be forced to reset its TCP input buffer before it
+has a chance to read the server's response, and thus understand why
+the connection has closed.
+See the <A HREF="#appendix">appendix</A> for more details.<P>
+
+We have not yet tracked down the exact reason why
+<CODE>lingering_close()</CODE> causes problems.  Its code has been
+thoroughly reviewed and extensively updated in 1.2b6.  It is possible
+that there is some problem in the BSD TCP stack which is causing the
+observed problems.  It is also possible that we fixed it in 1.2b6.
+Unfortunately, we have not been able to replicate the problem on our
+test servers.<P>
+
+<H2><LI>What can I do about it?</H2>
+
+There are several possible workarounds to the problem, some of
+which work better than others.<P>
+
+<H3>Add a timeout for FIN_WAIT_2</H3>
+
+The obvious workaround is to simply have a timeout for the FIN_WAIT_2 state.
+This is not specified by the RFC, and could be claimed to be a
+violation of the RFC, but it is widely recognized as being necessary.
+The following systems are known to have a timeout:
+<P>
+<UL>
+       <LI><A HREF="http://www.freebsd.org/">FreeBSD</A> versions starting at 2.0 or possibly earlier.
+       <LI><A HREF="http://www.netbsd.org/">NetBSD</A> version 1.2(?)
+       <LI><A HREF="http://www.openbsd.org/">OpenBSD</A> all versions(?)
+       <LI><A HREF="http://www.bsdi.com/">BSD/OS</A> 2.1, with the 
+           <A HREF="ftp://ftp.bsdi.com/bsdi/patches/patches-2.1/K210-027">
+           K210-027</A> patch installed.  
+       <LI><A HREF="http://www.sun.com/">Solaris</A> as of around version
+           2.2.  The timeout can be tuned by using <CODE>ndd</CODE> to 
+           modify <CODE>tcp_fin_wait_2_flush_interval</CODE>, but the
+           default should be appropriate for most servers and improper 
+           tuning can have negative impacts.
+       <LI><A HREF="http://www.sco.com/">SCO TCP/IP Release 1.2.1</A>
+           can be modified to have a timeout by following
+           <A HREF="http://www.sco.com/cgi-bin/waisgate?WAISdocID=2242622956+0+0+0&WAISaction=retrieve"> SCO's instructions</A>.
+       <LI><A HREF="http://www.linux.org/">Linux</A> 2.0.x and
+           earlier(?)
+       <LI><A HREF="http://www.hp.com/">HP-UX</A> 10.x defaults to 
+           terminating connections in the FIN_WAIT_2 state after the 
+           normal keepalive timeouts.  This does not
+           refer to the persistent connection or HTTP keepalive
+           timeouts, but the <CODE>SO_LINGER</CODE> socket option 
+           which is enabled by Apache.  This parameter can be adjusted 
+           by using <CODE>nettune</CODE> to modify parameters such as
+           <CODE>tcp_keepstart</CODE> and <CODE>tcp_keepstop</CODE>.
+           In later revisions, there is an explicit timer for
+           connections in FIN_WAIT_2 that can be modified; contact HP
+           support for details.
+       <LI><A HREF="http://www.sgi.com/">SGI IRIX</A> can be patched to
+           support a timeout.  For IRIX 5.3, 6.2, and 6.3, 
+           use patches 1654, 1703 and 1778 respectively.  If you
+           have trouble locating these patches, please contact your
+           SGI support channel for help.
+       <LI><A HREF="http://www.ncr.com/">NCR's MP RAS Unix</A> 2.xx and
+           3.xx both have FIN_WAIT_2 timeouts.  In 2.xx it is non-tunable
+           at 600 seconds, while in 3.xx it defaults to 600 seconds and
+           is calculated based on the tunable "max keep alive probes" 
+           (default of 8) multiplied by the "keep alive interval" (default
+           75 seconds).
+       <LI><A HREF="http://www.sequent.com">Squent's ptx/TCP/IP for
+           DYNIX/ptx</A> has had a FIN_WAIT_2 timeout since around
+           release 4.1 in mid-1994.
+</UL>
+<P>
+The following systems are known to not have a timeout:
+<P>
+<UL>
+       <LI><A HREF="http://www.sun.com/">SunOS 4.x</A> does not and
+           almost certainly never will have one because it as at the
+           very end of its development cycle for Sun.  If you have kernel
+           source should be easy to patch.
+</UL>
+<P>
+There is a 
+<A HREF="http://www.apache.org/dist/contrib/patches/1.2/fin_wait_2.patch">
+patch available</A> for adding a timeout to the FIN_WAIT_2 state; it
+was originally intended for BSD/OS, but should be adaptable to most
+systems using BSD networking code.  You need kernel source code to be
+able to use it.  If you do adapt it to work for any other systems,
+please drop me a note at <A HREF="mailto:marc@apache.org">marc@apache.org</A>.
+<P>
+<H3>Compile without using <CODE>lingering_close()</CODE></H3>
+
+It is possible to compile Apache 1.2 without using the
+<CODE>lingering_close()</CODE> function.  This will result in that
+section of code being similar to that which was in 1.1.  If you do
+this, be aware that it can cause problems with PUTs, POSTs and
+persistent connections, especially if the client uses pipelining.  
+That said, it is no worse than on 1.1, and we understand that keeping your 
+server running is quite important.<P>
+
+To compile without the <CODE>lingering_close()</CODE> function, add
+<CODE>-DNO_LINGCLOSE</CODE> to the end of the
+<CODE>EXTRA_CFLAGS</CODE> line in your <CODE>Configuration</CODE> file,
+rerun <CODE>Configure</CODE> and rebuild the server.
+<P>
+<H3>Use <CODE>SO_LINGER</CODE> as an alternative to
+<CODE>lingering_close()</CODE></H3>
+
+On most systems, there is an option called <CODE>SO_LINGER</CODE> that
+can be set with <CODE>setsockopt(2)</CODE>.  It does something very
+similar to <CODE>lingering_close()</CODE>, except that it is broken
+on many systems so that it causes far more problems than
+<CODE>lingering_close</CODE>.  On some systems, it could possibly work
+better so it may be worth a try if you have no other alternatives. <P>
+
+To try it, add <CODE>-DUSE_SO_LINGER -DNO_LINGCLOSE</CODE>  to the end of the
+<CODE>EXTRA_CFLAGS</CODE> line in your <CODE>Configuration</CODE>
+file, rerun <CODE>Configure</CODE> and rebuild the server.  <P>
+
+<STRONG>NOTE:</STRONG> Attempting to use <CODE>SO_LINGER</CODE> and
+<CODE>lingering_close()</CODE> at the same time is very likely to do
+very bad things, so don't.<P>
+
+<H3>Increase the amount of memory used for storing connection state</H3>
+<DL>
+<DT>BSD based networking code:
+<DD>BSD stores network data, such as connection states,
+in something called an mbuf.  When you get so many connections
+that the kernel does not have enough mbufs to put them all in, your
+kernel will likely crash.  You can reduce the effects of the problem
+by increasing the number of mbufs that are available; this will not
+prevent the problem, it will just make the server go longer before
+crashing.<P>
+
+The exact way to increase them may depend on your OS; look
+for some reference to the number of "mbufs" or "mbuf clusters".  On
+many systems, this can be done by adding the line 
+<CODE>NMBCLUSTERS="n"</CODE>, where <CODE>n</CODE> is the number of 
+mbuf clusters you want to your kernel config file and rebuilding your 
+kernel.<P>
+</DL>
+<H2><LI>Feedback</H2>
+
+If you have any information to add to this page, please contact me at
+<A HREF="mailto:marc@apache.org">marc@apache.org</A>.<P>
+
+<H2><A NAME="appendix"><LI>Appendix</A></H2>
+<P>
+Below is a message from Roy Fielding, one of the authors of HTTP/1.1.
+
+<H3>Why the lingering close functionality is necessary with HTTP</H3>
+
+The need for a server to linger on a socket after a close is noted a couple
+times in the HTTP specs, but not explained.  This explanation is based on
+discussions between myself, Henrik Frystyk, Robert S. Thau, Dave Raggett,
+and John C. Mallery in the hallways of MIT while I was at W3C.<P>
+
+If a server closes the input side of the connection while the client
+is sending data (or is planning to send data), then the server's TCP
+stack will signal an RST (reset) back to the client.  Upon
+receipt of the RST, the client will flush its own incoming TCP buffer
+back to the un-ACKed packet indicated by the RST packet argument.
+If the server has sent a message, usually an error response, to the
+client just before the close, and the client receives the RST packet
+before its application code has read the error message from its incoming
+TCP buffer and before the server has received the ACK sent by the client
+upon receipt of that buffer, then the RST will flush the error message
+before the client application has a chance to see it. The result is
+that the client is left thinking that the connection failed for no
+apparent reason.<P>
+
+There are two conditions under which this is likely to occur:
+<OL>
+<LI>sending POST or PUT data without proper authorization
+<LI>sending multiple requests before each response (pipelining) 
+    and one of the middle requests resulting in an error or
+    other break-the-connection result.
+</OL>
+<P>
+The solution in all cases is to send the response, close only the
+write half of the connection (what shutdown is supposed to do), and
+continue reading on the socket until it is either closed by the
+client (signifying it has finally read the response) or a timeout occurs.
+That is what the kernel is supposed to do if SO_LINGER is set.
+Unfortunately, SO_LINGER has no effect on some systems; on some other
+systems, it does not have its own timeout and thus the TCP memory
+segments just pile-up until the next reboot (planned or not).<P>
+
+Please note that simply removing the linger code will not solve the
+problem -- it only moves it to a different and much harder one to detect.
+</OL>
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
diff --git a/APACHE_1_2_X/htdocs/manual/misc/footer.html b/APACHE_1_2_X/htdocs/manual/misc/footer.html
new file mode 100644 (file)
index 0000000..2c2b410
--- /dev/null
@@ -0,0 +1,4 @@
+<HR>
+
+<A HREF="./"><IMG SRC="../images/index.gif" ALT="Index"></A>
+<A HREF="../"><IMG SRC="../images/home.gif" ALT="Home"></A>
diff --git a/APACHE_1_2_X/htdocs/manual/misc/header.html b/APACHE_1_2_X/htdocs/manual/misc/header.html
new file mode 100644 (file)
index 0000000..8b23a1c
--- /dev/null
@@ -0,0 +1,3 @@
+<DIV ALIGN="CENTER">
+ <IMG SRC="../images/sub.gif" ALT="[APACHE DOCUMENTATION]">
+</DIV>
diff --git a/APACHE_1_2_X/htdocs/manual/misc/howto.html b/APACHE_1_2_X/htdocs/manual/misc/howto.html
new file mode 100644 (file)
index 0000000..98a1843
--- /dev/null
@@ -0,0 +1,147 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<META NAME="description" CONTENT="Some 'how to' tips for the Apache httpd server">
+<META NAME="keywords" CONTENT="apache,redirect,robots,rotate,logfiles">
+<TITLE>Apache HOWTO documentation</TITLE>
+</HEAD>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<H1 ALIGN="CENTER">Apache HOWTO documentation</H1>
+
+How to:
+<ul>
+<li><A HREF="#redirect">redirect an entire server or directory to a single URL</A>
+<li><A HREF="#logreset">reset your log files</A>
+<li><A HREF="#stoprob">stop/restrict robots</A>
+</ul>
+
+<HR>
+<H2><A name="redirect">How to redirect an entire server or directory to a single URL</A></H2>
+
+<P>There are two chief ways to redirect all requests for an entire
+server to a single location: one which requires the use of
+<code>mod_rewrite</code>, and another which uses a CGI script.
+
+<P>First: if all you need to do is migrate a server from one name to
+another, simply use the <code>Redirect</code> directive, as supplied
+by <code>mod_alias</code>:
+
+<blockquote><pre>
+  Redirect / http://www.apache.org/
+</pre></blockquote>
+
+<P>Since <code>Redirect</code> will forward along the complete path,
+however, it may not be appropriate - for example, when the directory
+structure has changed after the move, and you simply want to direct people
+to the home page.
+
+<P>The best option is to use the standard Apache module <code>mod_rewrite</code>.
+If that module is compiled in, the following lines:
+
+<blockquote><pre>RewriteEngine On
+RewriteRule /.* http://www.apache.org/ [R]
+</pre></blockquote>
+
+This will send an HTTP 302 Redirect back to the client, and no matter
+what they gave in the original URL, they'll be sent to
+"http://www.apache.org".
+
+The second option is to set up a <CODE>ScriptAlias</Code> pointing to
+a <B>cgi script</B> which outputs a 301 or 302 status and the location
+of the other server.</P>
+
+<P>By using a <B>cgi-script</B> you can intercept various requests and
+treat them specially, e.g. you might want to intercept <B>POST</B>
+requests, so that the client isn't redirected to a script on the other
+server which expects POST information (a redirect will lose the POST
+information.) You might also want to use a CGI script if you don't
+want to compile mod_rewrite into your server.
+
+<P>Here's how to redirect all requests to a script... In the server
+configuration file,
+<blockquote><pre>ScriptAlias / /usr/local/httpd/cgi-bin/redirect_script</pre></blockquote>
+
+and here's a simple perl script to redirect requests:
+
+<blockquote><pre>
+#!/usr/local/bin/perl
+
+print "Status: 302 Moved Temporarily\r
+Location: http://www.some.where.else.com/\r\n\r\n";
+
+</pre></blockquote></P>
+
+<HR>
+
+<H2><A name="logreset">How to reset your log files</A></H2>
+
+<P>Sooner or later, you'll want to reset your log files (access_log and
+error_log) because they are too big, or full of old information you don't
+need.</P>
+
+<P><CODE>access.log</CODE> typically grows by 1Mb for each 10,000 requests.</P>
+
+<P>Most people's first attempt at replacing the logfile is to just move the
+logfile or remove the logfile. This doesn't work.</P>
+
+<P>Apache will continue writing to the logfile at the same offset as before the
+logfile moved. This results in a new logfile being created which is just
+as big as the old one, but it now contains thousands (or millions) of null
+characters.</P>
+
+<P>The correct procedure is to move the logfile, then signal Apache to tell it to reopen the logfiles.</P>
+
+<P>Apache is signaled using the <B>SIGHUP</B> (-1) signal. e.g.
+<blockquote><code>
+mv access_log access_log.old<BR>
+kill -1 `cat httpd.pid`
+</code></blockquote>
+</P>
+
+<P>Note: <code>httpd.pid</code> is a file containing the <B>p</B>rocess <B>id</B>
+of the Apache httpd daemon, Apache saves this in the same directory as the log
+files.</P>
+
+<P>Many people use this method to replace (and backup) their logfiles on a
+nightly or weekly basis.</P>
+<HR>
+
+<H2><A name="stoprob">How to stop or restrict robots</A></H2>
+
+<P>Ever wondered why so many clients are interested in a file called
+<code>robots.txt</code> which you don't have, and never did have?</P>
+
+<P>These clients are called <B>robots</B> (also known as crawlers,
+spiders and other cute name) - special automated clients which
+wander around the web looking for interesting resources.</P>
+
+<P>Most robots are used to generate some kind of <em>web index</em> which
+is then used by a <em>search engine</em> to help locate information.</P>
+
+<P><code>robots.txt</code> provides a means to request that robots limit their
+activities at the site, or more often than not, to leave the site alone.</P>
+
+<P>When the first robots were developed, they had a bad reputation for sending hundreds/thousands of requests to each site, often resulting in the site being overloaded. Things have improved dramatically since then, thanks to <A HREF="http://info.webcrawler.com/mak/projects/robots/guidelines.html"> Guidelines for Robot Writers</A>, but even so, some robots may <A HREF="http://www.zyzzyva.com/robots/alert/">exhibit unfriendly behavior</A> which the webmaster isn't willing to tolerate, and will want to stop.</P>
+
+<P>Another reason some webmasters want to block access to robots, is to
+stop them indexing dynamic information. Many search engines will use the
+data collected from your pages for months to come - not much use if your
+serving stock quotes, news, weather reports or anything else that will be
+stale by the time people find it in a search engine.</P>
+
+<P>If you decide to exclude robots completely, or just limit the areas
+in which they can roam, create a <CODE>robots.txt</CODE> file; refer
+to the <A HREF="http://info.webcrawler.com/mak/projects/robots/robots.html">robot information pages</A> provided by Martijn Koster for the syntax.</P>
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
diff --git a/APACHE_1_2_X/htdocs/manual/misc/index.html b/APACHE_1_2_X/htdocs/manual/misc/index.html
new file mode 100755 (executable)
index 0000000..127b1f2
--- /dev/null
@@ -0,0 +1,119 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+ <HEAD>
+  <TITLE>Apache Miscellaneous Documentation</TITLE>
+ </HEAD>
+
+ <!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+ <BODY
+  BGCOLOR="#FFFFFF"
+  TEXT="#000000"
+  LINK="#0000FF"
+  VLINK="#000080"
+  ALINK="#FF0000"
+ >
+  <!--#include virtual="header.html" -->
+  <H1 ALIGN="CENTER">Apache Miscellaneous Documentation</h1>
+
+  <P>
+  Below is a list of additional documentation pages that apply to the
+  Apache web server development project.
+  </P>
+  <DL>
+   <DT><A
+               HREF="API.html"
+       >API</A>
+   </DT>
+   <DD>Description of Apache's Application Programming Interface.
+   </DD>
+   <DT><A
+               HREF="FAQ.html"
+       >FAQ</A>
+   </DT>
+   <DD>Frequently-Asked Questions concerning the Apache project and server
+   </DD>
+   <DT><A
+               HREF="client_block_api.html"
+       >Reading Client Input in Apache 1.2</A>
+   </DT>
+   <DD>Describes differences between Apache 1.1 and 1.2 in how modules
+    read information from the client
+   </DD>
+   <DT><A
+               HREF="compat_notes.html"
+       >Compatibility with NCSA</A>
+   </DT>
+   <DD>Notes about Apache's compatibility with the NCSA server
+   </DD>
+   <DT><A
+               HREF="fin_wait_2.html"
+       ><SAMP>FIN_WAIT_2</SAMP></A>
+   </DT>
+   <DD>A description of the causes of Apache processes going into the
+    <SAMP>FIN_WAIT_2</SAMP> state, and what you can do about it
+   </DD>
+   <DT><A
+               HREF="howto.html"
+       >&quot;How-To&quot;</A>
+   </DT>
+   <DD>Instructions about how to accomplish some commonly-desired server
+    functionality changes
+   </DD>
+   <DT><A
+               HREF="known_bugs.html"
+       >Known Bugs</A>
+   </DT>
+   <DD>Just what it says - a list of known bugs in each of the Apache releases
+   </DD>
+   <DT><A
+               HREF="nopgp.html"
+       >No PGP</A>
+   </DT>
+   <DD>Why we took PEM and PGP support out of the base Apache distribution
+   </DD>
+   <DT><A
+               HREF="perf-bsd44.html"
+       >Performance Notes (BSD 4.4)</A>
+   </DT>
+   <DD>Some notes about ways to improve/optimize Apache performance on
+    BSD 4.4 systems
+   </DD>
+   <DT><A
+               HREF="perf-dec.html"
+       >Performance Notes (Digital UNIX)</A>
+   </DT>
+   <DD>Extracts of USENET postings describing how to optimize Apache
+    performance on Digital UNIX systems
+   </DD>
+   <DT><A
+               HREF="perf.html"
+       >Performance Notes (General)</A>
+   </DT>
+   <DD>Some generic notes about how to improve Apache performance
+   </DD>
+   <DT><A
+               HREF="security_tips.html"
+       >Security Tips</A>
+   </DT>
+   <DD>Some &quot;do&quot;s  - and &quot;don't&quot;s - for keeping your
+    Apache web site secure
+   </DD>
+   <DT><A
+               HREF="vif-info.html"
+       >Virtual Hosts (IP-based)</A>
+   </DT>
+   <DD>Excerpts and notes about configuring and using Apache IP-based virtual
+    hosts
+   </DD>
+   <DT><A
+               HREF="windoz_keepalive.html"
+       >Windows Bug with Web Keepalive</A>
+   </DT>
+   <DD>A brief description of a known problem with Microsoft Windows and
+    web sites accessed using keepalive connections
+   </DD>
+  </DL>
+
+  <!--#include virtual="footer.html" -->
+ </BODY>
+</HTML>
diff --git a/APACHE_1_2_X/htdocs/manual/misc/known_bugs.html b/APACHE_1_2_X/htdocs/manual/misc/known_bugs.html
new file mode 100644 (file)
index 0000000..68054d4
--- /dev/null
@@ -0,0 +1,310 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<TITLE>Apache HTTP Server Project</TITLE>
+</HEAD>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<H1 ALIGN="CENTER">Known Bugs in Apache</H1>
+
+The most up-to-date resource for bug tracking and information is the
+<A HREF="http://www.apache.org/bugdb.cgi">Apache bug database</A>.
+All existing bugs will be noted there.  Below is a synopsis of
+significant outstanding bugs at release time.  In fact you really
+shouldn't trust anything this page says other than maybe the 1.2b8
+information.
+
+<P>See Also: <A HREF="compat_notes.html">Compatibility notes</A></P>
+<HR>
+
+<H2>Version 1.2 (all)</H2>
+
+<OL><a name="listenbug"></a>
+    <LI>On some architectures if your configuration uses multiple
+    <a href="../mod/core.html#listen">Listen</a> directives then it is possible
+    that the server will starve one of the sockets while serving hits on
+    another.  The work-around is to add
+    <code>-DUSE_FLOCK_SERIALIZED_ACCEPT</code> to the
+    <code>EXTRA_CFLAGS</code> line in your Configuration and rebuild.
+    (If you encounter problems with that, you can also try
+    <code>-DUSE_FCNTL_SERIALIZED_ACCEPT</code>.)
+    This affects any architecture that doesn't use one of the
+    <code>USE_xxxxx_SERIALIZED_ACCEPT</code> definitions, see the
+    source file <code>conf.h</code> for your architecture.
+    <p>This will be tracked as
+    <a href="http://www.apache.org/bugdb.cgi/full/467">PR#467</a>.
+    </LI>
+</OL>
+
+<H2>Version 1.2b8</H2>
+
+There are several known bugs in 1.2b8.  See the
+<A HREF="http://www.apache.org/dist/patches/apply_to_1.2b8/">1.2b8 patches
+directory</A> for patches for some of the ones that have been fixed since
+the release of 1.2b8.<P>
+
+<H2>Version 1.2b1</H2>
+
+<OL>
+
+       <LI>users have reported problems with many connections stuck in the
+FIN_WAIT_2 state due to server timeouts. This is a quite complicated 
+problem; see our <A HREF="fin_wait_2.html">FIN_WAIT_2</A> page for
+details.
+
+       <LI>hard_timeout() for request reads uses incorrect logic, and
+ends up waiting for an initial request read for the default "timeout"
+number of seconds, 1200, yet only the "KeepAliveTimeout" number of
+seconds on keepalive connections.  
+
+       <LI>mod_info output is not displaying current configuration as
+it should.
+
+       <LI>Invalid commands in .htaccess files may cause segmentation faults.
+
+</OL>
+
+<H2>Version 1.1.1</H2>
+
+<OL>
+
+       <LI>Hostnames such as "123.hotwired.com" are valid, yet
+find_allowdeny does not properly handle them.  This should be put on
+Known Bugs.  Be careful when fixing this because just removing the
+isalpha() check creates a security hole, consider the DNS map
+"1.1.1.1.in-addr.arpa IN PTR 2.2.2."  if the user has a config line
+"allow from 2.2.2" it will allow 1.1.1.1 in (unless -DMAXIMUM_DNS).
+-- which is bad because it breaks people who understand double reverse
+lookup and are trying to avoid it by using only IP addresses on
+allow/deny statements. - reported by Dean Gaudet, fixed in 1.2.
+
+</OL>
+
+
+<H2>Version 1.1.0</H2>
+
+<OL>
+       <LI>mod_auth_msql misbehaviors.  Grab a newer version from 
+       <A HREF="http://www.apache.org/dist/contrib/modules/">the modules distribution
+       directory</A>. -fixed in 1.1
+
+       <LI>Hanging on Netscape 2.0-3.0b4 on MSWindows (3.1 and 95) - 
+       we investigated pretty seriously, and as best we can tell 
+       this is a Netscape bug, and was fixed in 3.0b5.  Please read our
+       <A HREF="windoz_keepalive.html">lab report</A>.
+
+</OL>
+
+<H2>Version 1.1b2 (beta)</h2>
+<OL>
+       <LI>SunOS has trouble compiling mod_status.c . It'll be fixed
+       before 1.1 is released.</LI>
+
+       <LI>CGI which spawn background processes may fail to return immediately.
+       No fix exists yet.</LI>
+
+       <LI>mod_dir appears to have problems when the DocumentRoot has a 
+       trailing slash.</LI>
+
+</OL>
+<H2>Version 1.1b1 (beta)</h2>
+<OL>
+       <LI>The logfile can sometimes contain only part of a host
+       address.  This occurs if the Cookie module is compiled in
+       and enabled.  
+</OL>
+
+<H2>Version 0.8.16 (beta)</H2>
+<OL>
+  <LI>(Feature) You cannot use relative pathnames for the -f or -d flags
+ to httpd.<p>
+  <LI><code>.asis</code> files cannot be used for content-negotiation.
+</OL>
+
+<H2>Version 0.8.13 (beta)</H2>
+
+<OL>
+  <LI><CODE>AddDescription</CODE> doesn't seem to work (a fix is imminent)</LI>
+</OL>
+
+<H2>Version 0.8.11 (beta)</H2>
+<OL>
+  <LI><CODE>http_main.c</CODE> function <CODE>accept_mutex_init()</CODE>
+ horrible bug, <CODE>lock_fname</CODE> should be defined larger, e.g.
+ <CODE><BR>
+     char lock_fname[30];
+ </CODE>
+ <BR><B>Ooops.</B>
+
+<P>
+
+ <LI>There's a bug with <B>NeXT</B>. Restarting the server causes an
+   infinite loop. A fix has been provided by a user and should be included
+   in a future update.
+
+<P>
+
+</OL>
+
+
+<H2>Version 0.8.10 (beta)</H2>
+
+<OL>
+  <LI>Server side includes which include CGI output can have unbearable
+   delays on some platforms. We're looking into a fix.
+
+<P>
+
+  <LI>NCSA 1.3 and beyond allow wildcards in &lt;Directory&gt; tags; e.g.
+      &lt;Directory /home/*/public_html&gt; - Apache doesn't (yet),
+      but we have a patch coming real soon now
+
+<P>
+
+  <LI>Buggy scripts can cause server misbehavior on Solaris at least.
+
+<P>
+
+  <LI>Some of the default directives in srm.conf-dist are outdated
+
+<P>
+
+  <LI>Descriptions of args to AddIcon and AddAlt are wrong
+      in command table.
+
+<P>
+
+  <LI>DirectoryIndex sometimes gets spuriously reset to the default value.
+
+<P>
+
+  <LI>ErrorDocument is a little shaky, <CODE>" Some text %s</CODE> doesn't
+    agree with the documentation.
+
+<P>
+
+  <LI>All Aliases are checked before any ScriptAliases --- the fully
+      compatible behavior would be to check both in one pass, in the order
+      in which they occur in srm.conf.
+
+<P>
+</OL>
+
+<H2>Version 0.8.8 (beta)</H2>
+
+<OL>
+  <LI>There's a known compilation problem with <B>NeXT</B>. Knock out the
+   2nd argument to <CODE>setjmp</CODE> when your compiler complains.<BR><BR>
+  </LI>
+
+  <LI><CODE>exec cgi=""</CODE> produces reasonable <B>malformed header</B>
+  responses when used to invoke non-CGI scripts.<BR>
+  The NCSA code ignores the missing header. (bad idea)<BR>
+  Solution: write CGI to the CGI spec or use <CODE>exec cmd=""</CODE> instead.
+  <P>We might add <CODE>virtual</CODE> support to <CODE>exec cmd</CODE> to
+  make up for this difference.</P>
+
+  <LI>A <I>scoreboard</I> file for process management is currently
+  created in <B>/tmp</B>. We now find this to be a bad idea, and have plans
+  to move it into the <CODE>/logs</CODE> directory along with other
+  files created by Apache.
+  <P>If you have any <B>/tmp</B> cleaning scripts (e.g. from crontab), you
+  should have them ignore the scoreboard file, which is named 
+  <B>/tmp/htstatus.XXXXXXX</B>. If the scoreboard file is damaged, Apache
+  can become very confused (a SIGHUP repairs the damage).  Furthermore, not
+  having a /tmp at all can cause disastrous results, as there's no error 
+  checking yet.<P>  
+
+  <LI>Putting authorization information (like AuthName and AuthType) into a 
+  &lt;Directory&gt; directive without a "requires" field in the &lt;Limit&gt;
+  directive can result in a core dump.<P>
+
+  <LI>AddIcon is broken. The fix is to change<BR>
+  <CODE>
+  { "AddIcon", add_icon, BY_<B>TYPE</B>, DIR_CMD_PERMS, ITERATE2,
+  </CODE>
+  <BR>to<BR>
+  <CODE>
+  { "AddIcon", add_icon, BY_<B>PATH</B>, DIR_CMD_PERMS, ITERATE2,
+  </CODE>
+  <P>in <CODE>mod_dir.c</CODE></P></LI>
+
+  <LI>Under IRIX, the "Group" directive in httpd.conf needs to be a valid group name 
+  (i.e. "nogroup") not the numeric group ID.  The distribution httpd.conf, and earlier 
+  ones, had the default Group be "#-1", which was causing silent exits at startup. 
+
+<P>
+
+
+  <LI>Server push as regular CGI's don't work - actually, any normal CGI script 
+  that outputs additional attributes to the Content-type line (separated by a 
+  semicolon) gets that extra information chopped off, which means that the line
+  <code>Content-type: multipart/x-mixed-replace; boundary=ThisRandomString</code>
+  gets munged to just <code>Content-type: multipart/x-mixed-replace</code>, which 
+  means it doesn't know what the boundary is, and fails.  You can get around this
+  until 0.8.9 by making the CGI script a "No Parsed Header" script by prefixing the 
+  name of the script with a "nph-", but then you have to be responsible for correct
+  HTTP headers.  If the server-push animation is a constant, unchanging stream that
+  terminates at some point, you could also put that stream into a whole file and 
+  use the .asis file extension functionality.  
+
+<P>
+
+  <LI>ErrorDocument is a little shaky, <CODE>" Some text %s</CODE> doesn't
+    agree with the documentation.
+
+<P>
+
+</OL>
+
+<HR>
+
+<H2>Version 0.6.4 </H2>
+<OL>
+<LI>As with NCSA 1.3 (and 1.4 ?), some <B>HEAD</B> requests on
+directories without an <CODE>index.html</CODE> fail to be logged... harmless.</LI>
+<LI>Typo in Virtual Host #defines (accidentally defined #VIRUAL_HOST").  0.6.4b fixes this.
+</OL>
+<H2>Version 0.6.2 (first beta)</H2>
+<OL>
+
+<LI><P>Apache error_log might show <CODE>httpd: caught SIGBUS, dumping core</CODE> after a successful redirect. We hope to fix this in 0.6.3</P></LI>
+
+<LI><P>If you see a lot of messages such as,
+<PRE>access to /something: failed for foo.bar.com, reason: no multi in this directory</PRE>
+in your error log, don't panic !. It means "File not found", and we will
+fix it sooner or later.
+
+</P>
+
+<LI><P><B>WARNING</B>: Apache logs all URLs redirected <B>from</B> and
+<B>to</B>.  This isn't bug, it's deliberate, but you should be aware
+of it.  It's a recognition of the fact that the Common Log File format
+doesn't have any place to log the real object that was returned for
+the internally redirected request.  This will be changed soon.  
+
+</P>
+
+<LI><P>BSDI problems: One of the test machines (<a
+href="http://www.hyperreal.com/">Hyperreal</a>) has noticed "flocks" of
+child processes sucking up large amounts of resources when moderately
+hit (on a Pentium 90 running 1.1 serving ~2 hits/second).  Killing and
+restarting the daemon helps this disappear - it's being investigated,
+it might be a kernel bug, but then every server developer likes to say
+that.  Let us know how well it works for you if you are using BSDI and
+have a high number of hits.</P></LI>
+
+</OL>
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
+
diff --git a/APACHE_1_2_X/htdocs/manual/misc/nopgp.html b/APACHE_1_2_X/htdocs/manual/misc/nopgp.html
new file mode 100644 (file)
index 0000000..8e66fad
--- /dev/null
@@ -0,0 +1,88 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<TITLE>Why We Took PEM Out of Apache</TITLE>
+</HEAD>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<H1 ALIGN="CENTER">Why We Took PEM Out of Apache</H1>
+
+On May 17th, 1995, we were asked by a representative of NCSA to remove
+any copies of NCSA httpd prior to 1.4.1 from our web site.  They
+were mandated by the NSA to inform us that redistribution of pre-1.4.1
+code violated the same laws that make distributing Phill Zimmerman's
+PGP package to other countries illegal.  There was <B>no</B>
+encryption in NCSA's httpd, only hooks to publicly available libraries
+of PEM code.  By the NSA's rules, even hooks to this type of
+application is illegal.
+
+<P>
+
+Because Apache is based on NCSA code, and we had basically not touched
+that part of the software, we were informed that Apache was also
+illegal to distribute to foreign countries, and advised (not mandated)
+by NCSA to remove it.  So, we removed both the copies of the NCSA
+httpd we had, and all versions of Apache previous to 0.6.5.
+
+<P>
+
+The Apache members are strong advocates of the right to digital
+privacy, so the decision to submit to the NSA and remove the code was
+not an easy one.  Here are some elements in our rationale:
+
+<UL>
+
+<LI>The PEM code in httpd was not widely used.  No major site relied
+upon its use, so its loss is not a blow to encryption and security on
+the world wide web.  There are other efforts designed to give much
+more flexible security - SSL and SHTTP - so this wasn't a function
+whose absence would really be missed on a functional level.
+
+<LI>We didn't feel like being just a couple more martyrs in a fight
+being fought very well by many other people.  Rather than have the
+machine that supports the project confiscated or relocated to South
+Africa, etc., we think there are more efficient methods to address the
+issue.
+
+</UL>
+
+It kind of sickens us that we had to do it, but so be it.  
+
+<P>
+
+Patches that re-implement the PEM code may be available at a foreign
+site soon.  If it does show up, we'll point to it - that can't be illegal!
+
+<P>
+
+Finally, here is a compendium of pointers to sites related to
+encryption and export law.  We can't promise this list will be up to
+date, so send us mail when you see a problem or want a link added.
+Thanks.
+
+<UL>
+<LI><A HREF="http://www.yahoo.com/Science/Mathematics/Security_and_Encryption/">
+Yahoo - Science: Mathematics: Security and Encryption</A>
+<LI><A HREF="http://www.eff.org/pub/EFF/Policy/Crypto/">
+EFF Crypto/Privacy/Security Archive</A>
+<LI><A HREF="http://www.quadralay.com/www/Crypt/Crypt.html">
+Crypto page at Quadralay</A>
+<LI><A HREF="ftp://ftp.cygnus.com/pub/export/export.html">
+Cryptography Export Control Archives (Cygnus)</A>
+<LI><A HREF="http://www.law.indiana.edu/law/iclu.html">
+ICLU - Your Rights in Cyberspace</A>
+</UL>
+
+       <a href="http://bong.com/~brian">Brian</a>, <a href="mailto:brian@hyperreal.com">brian@hyperreal.com</a>
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
diff --git a/APACHE_1_2_X/htdocs/manual/misc/perf-bsd44.html b/APACHE_1_2_X/htdocs/manual/misc/perf-bsd44.html
new file mode 100644 (file)
index 0000000..0a1661b
--- /dev/null
@@ -0,0 +1,236 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<title>Running a High-Performance Web Server for BSD</title>
+</head>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<A NAME="initial">
+<!--#include virtual="header.html" -->
+</A>
+<H1 ALIGN="CENTER">Running a High-Performance Web Server for BSD</H1>
+
+Like other OS's, the listen queue is often the <b>first limit hit</b>.  The
+following are comments from "Aaron Gifford &lt;agifford@InfoWest.COM&gt;"
+on how to fix this on BSDI 1.x, 2.x,  and FreeBSD 2.0 (and earlier):
+
+<p>
+
+Edit the following two files:
+<blockquote><code>  /usr/include/sys/socket.h <br>
+  /usr/src/sys/sys/socket.h </code></blockquote>
+In each file, look for the following:
+<pre>
+    /*
+     * Maximum queue length specifiable by listen.
+     */
+    #define SOMAXCONN       5
+</pre>
+
+Just change the "5" to whatever appears to work.  I bumped the two
+machines I was having problems with up to 32 and haven't noticed the
+problem since.
+
+<p>
+
+After the edit, recompile the kernel and recompile the Apache server
+then reboot.  
+
+<P>
+
+FreeBSD 2.1 seems to be perfectly happy, with SOMAXCONN
+set to 32 already.
+
+<p>
+
+<A NAME="detail">
+<b>Addendum for <i>very</i> heavily loaded BSD servers</b><br>
+</A>
+from Chuck Murcko &lt;chuck@telebase.com&gt;
+
+<p>
+
+If you're running a really busy BSD Apache server, the following are useful
+things to do if the system is acting sluggish:<p>
+
+<ul>
+
+<li> Run vmstat to check memory usage, page/swap rates, etc.
+
+<li> Run netstat -m to check mbuf usage
+
+<li> Run fstat to check file descriptor usage
+
+</ul>
+
+These utilities give you an idea what you'll need to tune in your kernel,
+and whether it'll help to buy more RAM.
+
+Here are some BSD kernel config parameters (actually BSDI, but pertinent to
+FreeBSD and other 4.4-lite derivatives) from a system getting heavy usage.
+The tools mentioned above were used, and the system memory was increased to
+48 MB before these tuneups. Other system parameters remained unchanged.
+
+<p>
+
+<pre>
+maxusers        256
+</pre>
+
+Maxusers drives a <i>lot</i> of other kernel parameters:
+
+<ul>
+
+<li> Maximum # of processes
+
+<li> Maximum # of processes per user
+
+<li> System wide open files limit
+
+<li> Per-process open files limit
+
+<li> Maximum # of mbuf clusters
+
+<li> Proc/pgrp hash table size
+
+</ul>
+
+The actual formulae for these derived parameters are in
+<i>/usr/src/sys/conf/param.c</i>.
+These calculated parameters can also be overridden (in part) by specifying
+your own values in the kernel configuration file:
+
+<pre>
+# Network options. NMBCLUSTERS defines the number of mbuf clusters and
+# defaults to 256. This machine is a server that handles lots of traffic,
+# so we crank that value.
+options         SOMAXCONN=256           # max pending connects
+options         NMBCLUSTERS=4096        # mbuf clusters at 4096
+
+#
+# Misc. options
+#
+options         CHILD_MAX=512           # maximum number of child processes
+options         OPEN_MAX=512            # maximum fds (breaks RPC svcs)
+</pre>
+
+SOMAXCONN is not derived from maxusers, so you'll always need to increase
+that yourself. We used a value guaranteed to be larger than Apache's
+default for the listen() of 128, currently.
+
+<p>
+
+In many cases, NMBCLUSTERS must be set much larger than would appear
+necessary at first glance. The reason for this is that if the browser
+disconnects in mid-transfer, the socket fd associated with that particular
+connection ends up in the TIME_WAIT state for several minutes, during
+which time its mbufs are not yet freed. Another reason is that, on server
+timeouts, some connections end up in FIN_WAIT_2 state forever, because
+this state doesn't time out on the server, and the browser never sent
+a final FIN.  For more details see the 
+<A HREF="fin_wait_2.html">FIN_WAIT_2</A> page. 
+
+<p>
+
+Some more info on mbuf clusters (from sys/mbuf.h):
+<pre>
+/*
+ * Mbufs are of a single size, MSIZE (machine/machparam.h), which
+ * includes overhead.  An mbuf may add a single "mbuf cluster" of size
+ * MCLBYTES (also in machine/machparam.h), which has no additional overhead
+ * and is used instead of the internal data area; this is done when
+ * at least MINCLSIZE of data must be stored.
+ */
+</pre>
+
+<p>
+
+CHILD_MAX and OPEN_MAX are set to allow up to 512 child processes (different
+than the maximum value for processes per user ID) and file descriptors.
+These values may change for your particular configuration (a higher OPEN_MAX
+value if you've got modules or CGI scripts opening lots of connections or
+files). If you've got a lot of other activity besides httpd on the same
+machine, you'll have to set NPROC higher still. In this example, the NPROC
+value derived from maxusers proved sufficient for our load.
+
+<p>
+
+<b>Caveats</b>
+
+<p>
+
+Be aware that your system may not boot with a kernel that is configured
+to use more resources than you have available system RAM. <b>ALWAYS</b>
+have a known bootable kernel available when tuning your system this way,
+and use the system tools beforehand to learn if you need to buy more 
+memory before tuning.
+
+<p>
+
+RPC services will fail when the value of OPEN_MAX is larger than 256.
+This is a function of the original implementations of the RPC library,
+which used a byte value for holding file descriptors. BSDI has partially
+addressed this limit in its 2.1 release, but a real fix may well await
+the redesign of RPC itself.
+
+<p>
+
+Finally, there's the hard limit of child processes configured in Apache.
+
+<p>
+
+For versions of Apache later than 1.0.5 you'll need to change the
+definition for <b>HARD_SERVER_LIMIT</b> in <i>httpd.h</i> and recompile
+if you need to run more than the default 150 instances of httpd.
+
+<p>
+
+From conf/httpd.conf-dist:
+
+<pre>
+# 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
+</pre>
+
+Know what you're doing if you bump this value up, and make sure you've
+done your system monitoring, RAM expansion, and kernel tuning beforehand.
+Then you're ready to service some serious hits!
+
+<p>
+
+Thanks to <i>Tony Sanders</i> and <i>Chris Torek</i> at BSDI for their
+helpful suggestions and information.
+
+<P>
+
+"M. Teterin" &lt;mi@ALDAN.ziplink.net&gt; writes:<P>
+<blockquote>It really does help if your kernel and frequently used utilities
+are fully optimized. Rebuilding the FreeBSD kernel on an AMD-133
+(486-class CPU) web-server with<BR>
+<code>    -m486 -fexpensive-optimizations -fomit-frame-ponter -O2</code><BR>
+helped reduce the number of "unable" errors, because the CPU was
+often maxed out.</blockquote>
+<P>
+
+<HR>
+
+<H3>More welcome!</H3>
+
+If you have tips to contribute, send mail to <a
+href="mailto:brian@organic.com">brian@organic.com</a>
+
+<!--#include virtual="footer.html" -->
+</body></html>
+
diff --git a/APACHE_1_2_X/htdocs/manual/misc/perf-dec.html b/APACHE_1_2_X/htdocs/manual/misc/perf-dec.html
new file mode 100644 (file)
index 0000000..7cc8bb1
--- /dev/null
@@ -0,0 +1,279 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<TITLE>Performance Tuning Tips for Digital Unix</TITLE>
+</HEAD>
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<H1 ALIGN="CENTER">Performance Tuning Tips for Digital Unix</H1>
+
+Below is a set of newsgroup posts made by an engineer from DEC in
+response to queries about how to modify DEC's Digital Unix OS for more
+heavily loaded web sites.  Copied with permission.  
+
+<HR>
+
+<H2>Update</H2>
+From: Jeffrey Mogul &lt;mogul@pa.dec.com&gt;<BR>
+Date: Fri, 28 Jun 96 16:07:56 MDT<BR>
+
+<OL>
+<LI> The advice given in the README file regarding the
+        "tcbhashsize" variable is incorrect.  The largest value
+        this should be set to is 1024.  Setting it any higher
+        will have the perverse result of disabling the hashing
+        mechanism.
+
+<LI>Patch ID OSF350-146 has been superseded by
+<blockquote>
+                Patch ID OSF350-195 for V3.2C<BR>
+                Patch ID OSF360-350195 for V3.2D
+</blockquote>
+        Patch IDs for V3.2E and V3.2F should be available soon.
+        There is no known reason why the Patch ID OSF360-350195
+        won't work on these releases, but such use is not officially
+        supported by Digital.  This patch kit will not be needed for
+        V3.2G when it is released.
+</OL>
+<HR>
+
+
+<PRE>
+From           mogul@pa.dec.com (Jeffrey Mogul)
+Organization   DEC Western Research
+Date           30 May 1996 00:50:25 GMT
+Newsgroups     <A HREF="news:comp.unix.osf.osf1">comp.unix.osf.osf1</A>
+Message-ID     <A HREF="news:4oirch$bc8@usenet.pa.dec.com">&lt;4oirch$bc8@usenet.pa.dec.com&gt;</A>
+Subject        Re: Web Site Performance
+References     1
+
+
+
+In article &lt;skoogDs54BH.9pF@netcom.com&gt; skoog@netcom.com (Jim Skoog) writes:
+&gt;Where are the performance bottlenecks for Alpha AXP running the
+&gt;Netscape Commerce Server 1.12 with high volume internet traffic?
+&gt;We are evaluating network performance for a variety of Alpha AXP
+&gt;runing DEC UNIX 3.2C, which run DEC's seal firewall and behind
+&gt;that Alpha 1000 and 2100 webservers.
+
+Our experience (running such Web servers as <A HREF="http://altavista.digital.com">altavista.digital.com</A>
+and <A HREF="http://www.digital.com">www.digital.com</A>) is that there is one important kernel tuning
+knob to adjust in order to get good performance on V3.2C.  You
+need to patch the kernel global variable "somaxconn" (use dbx -k
+to do this) from its default value of 8 to something much larger.
+
+How much larger?  Well, no larger than 32767 (decimal).  And
+probably no less than about 2048, if you have a really high volume
+(millions of hits per day), like AltaVista does.
+
+This change allows the system to maintain more than 8 TCP
+connections in the SYN_RCVD state for the HTTP server.  (You
+can use "netstat -An |grep SYN_RCVD" to see how many such
+connections exist at any given instant).
+
+If you don't make this change, you might find that as the load gets
+high, some connection attempts take a very long time.  And if a lot
+of your clients disconnect from the Internet during the process of
+TCP connection establishment (this happens a lot with dialup
+users), these "embryonic" connections might tie up your somaxconn
+quota of SYN_RCVD-state connections.  Until the kernel times out
+these embryonic connections, no other connections will be accepted,
+and it will appear as if the server has died.
+
+The default value for somaxconn in Digital UNIX V4.0 will be quite
+a bit larger than it has been in previous versions (we inherited
+this default from 4.3BSD).
+
+Digital UNIX V4.0 includes some other performance-related changes
+that significantly improve its maximum HTTP connection rate.  However,
+we've been using V3.2C systems to front-end for altavista.digital.com
+with no obvious performance bottlenecks at the millions-of-hits-per-day
+level.
+
+We have some Webstone performance results available at
+        <A HREF="http://www.digital.com/info/alphaserver/news/webff.html">http://www.digital.com/info/alphaserver/news/webff.html</A>
+I'm not sure if these were done using V4.0 or an earlier version
+of Digital UNIX, although I suspect they were done using a test
+version of V4.0.
+
+-Jeff
+
+<HR>
+
+----------------------------------------------------------------------------
+
+From           mogul@pa.dec.com (Jeffrey Mogul)
+Organization   DEC Western Research
+Date           31 May 1996 21:01:01 GMT
+Newsgroups     <A HREF="news:comp.unix.osf.osf1">comp.unix.osf.osf1</A>
+Message-ID     <A HREF="news:4onmmd$mmd@usenet.pa.dec.com">&lt;4onmmd$mmd@usenet.pa.dec.com&gt;</A>
+Subject        Digital UNIX V3.2C Internet tuning patch info
+
+----------------------------------------------------------------------------
+
+Something that probably few people are aware of is that Digital
+has a patch kit available for Digital UNIX V3.2C that may improve
+Internet performance, especially for busy web servers.
+
+This patch kit is one way to increase the value of somaxconn,
+which I discussed in a message here a day or two ago.
+
+I've included in this message the revised README file for this
+patch kit below.  Note that the original README file in the patch
+kit itself may be an earlier version; I'm told that the version
+below is the right one.
+
+Sorry, this patch kit is NOT available for other versions of Digital
+UNIX.  Most (but not quite all) of these changes also made it into V4.0,
+so the description of the various tuning parameters in this README
+file might be useful to people running V4.0 systems.
+
+This patch kit does not appear to be available (yet?) from
+        <A HREF="http://www.service.digital.com/html/patch_service.html">http://www.service.digital.com/html/patch_service.html</A>
+so I guess you'll have to call Digital's Customer Support to get it.
+
+-Jeff
+
+DESCRIPTION: Digital UNIX Network tuning patch
+
+             Patch ID: OSF350-146
+
+             SUPERSEDED PATCHES: OSF350-151, OSF350-158
+
+        This set of files improves the performance of the network
+        subsystem on a system being used as a web server.  There are
+        additional tunable parameters included here, to be used
+        cautiously by an informed system administrator.
+
+TUNING
+
+        To tune the web server, the number of simultaneous socket
+        connection requests are limited by:
+
+        somaxconn               Sets the maximum number of pending requests
+                                allowed to wait on a listening socket.  The
+                                default value in Digital UNIX V3.2 is 8.
+                                This patch kit increases the default to 1024,
+                                which matches the value in Digital UNIX V4.0.
+
+        sominconn               Sets the minimum number of pending connections
+                                allowed on a listening socket.  When a user
+                                process calls listen with a backlog less
+                                than sominconn, the backlog will be set to
+                                sominconn.  sominconn overrides somaxconn.
+                                The default value is 1.
+
+        The effectiveness of tuning these parameters can be monitored by
+        the sobacklog variables available in the kernel:
+
+        sobacklog_hiwat         Tracks the maximum pending requests to any
+                                socket.  The initial value is 0.
+
+        sobacklog_drops         Tracks the number of drops exceeding the
+                                socket set backlog limit.  The initial
+                                value is 0.
+
+        somaxconn_drops         Tracks the number of drops exceeding the
+                                somaxconn limit.  When sominconn is larger
+                                than somaxconn, tracks the number of drops
+                                exceeding sominconn.  The initial value is 0.
+
+        TCP timer parameters also affect performance. Tuning the following
+        require some knowledge of the characteristics of the network.
+
+        tcp_msl                 Sets the tcp maximum segment lifetime.
+                                This is the maximum lifetime in half
+                                seconds that a packet can be in transit
+                                on the network.  This value, when doubled,
+                                is the length of time a connection remains
+                                in the TIME_WAIT state after a incoming
+                                close request is processed.  The unit is
+                                specified in 1/2 seconds, the initial
+                                value is 60.
+
+        tcp_rexmit_interval_min
+                                Sets the minimum TCP retransmit interval.
+                                For some WAN networks the default value may
+                                be too short, causing unnecessary duplicate
+                                packets to be sent.  The unit is specified
+                                in 1/2 seconds, the initial value is 1.
+
+        tcp_keepinit            This is the amount of time a partially
+                                established connection will sit on the listen
+                                queue before timing out (e.g. if a client
+                                sends a SYN but never answers our SYN/ACK).
+                                Partially established connections tie up slots
+                                on the listen queue.  If the queue starts to
+                                fill with connections in SYN_RCVD state,
+                                tcp_keepinit can be decreased to make those
+                                partial connects time out sooner.  This should
+                                be used with caution, since there might be
+                                legitimate clients that are taking a while
+                                to respond to SYN/ACK.  The unit is specified
+                                in 1/2 seconds, the default value is 150
+                                (ie. 75 seconds).
+
+        The hashlist size for the TCP inpcb lookup table is regulated by:
+
+        tcbhashsize             The number of hash buckets used for the
+                                TCP connection table used in the kernel.
+                                The initial value is 32.  For best results,
+                                should be specified as a power of 2.  For
+                                busy Web servers, set this to 2048 or more.
+
+        The hashlist size for the interface alias table is regulated by:
+
+        inifaddr_hsize          The number of hash buckets used for the
+                                interface alias table used in the kernel.
+                                The initial value is 32.  For best results,
+                                should be specified as a power of 2.
+
+        ipport_userreserved     The maximum number of concurrent non-reserved,
+                                dynamically allocated ports.  Default range
+                                is 1025-5000.  The maximum value is 65535.
+                                This limits the numer of times you can
+                                simultaneously telnet or ftp out to connect
+                                to other systems.
+
+        tcpnodelack             Don't delay acknowledging TCP data; this
+                                can sometimes improve performance of locally
+                                run CAD packages.  Default is value is 0,
+                                the enabled value is 1.
+
+                           Digital UNIX version:
+
+                                  V3.2C
+Feature                    V3.2C  patch  V4.0
+ =======                    =====  =====  ====
+somaxconn                   X      X      X
+sominconn                   -      X      X
+sobacklog_hiwat             -      X      -
+sobacklog_drops             -      X      -
+somaxconn_drops             -      X      -
+tcpnodelack                 X      X      X
+tcp_keepidle                X      X      X
+tcp_keepintvl               X      X      X
+tcp_keepcnt                 -      X      X
+tcp_keepinit                -      X      X
+TCP keepalive per-socket    -      -      X
+tcp_msl                     -      X      -
+tcp_rexmit_interval_min     -      X      -
+TCP inpcb hashing           -      X      X
+tcbhashsize                 -      X      X
+interface alias hashing     -      X      X
+inifaddr_hsize              -      X      X
+ipport_userreserved         -      X      -
+sysconfig -q inet           -      -      X
+sysconfig -q socket         -      -      X
+
+</PRE>
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
diff --git a/APACHE_1_2_X/htdocs/manual/misc/perf.html b/APACHE_1_2_X/htdocs/manual/misc/perf.html
new file mode 100644 (file)
index 0000000..96c48ea
--- /dev/null
@@ -0,0 +1,146 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<title>Hints on Running a High-Performance Web Server</title>
+</head>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<h1 ALIGN="CENTER">Hints on Running a High-Performance Web Server</H1>
+
+Running Apache on a heavily loaded web server, one often encounters
+problems related to the machine and OS configuration.  "Heavy" is
+relative, of course - but if you are seeing more than a couple hits
+per second on a sustained basis you should consult the pointers on
+this page.  In general the suggestions involve how to tune your kernel
+for the heavier TCP load, hardware/software conflicts that arise, etc.
+
+<UL>
+<LI><A HREF="#AUX">A/UX (Apple's UNIX)</A>
+<LI><A HREF="#BSD">BSD-based (BSDI, FreeBSD, etc)</A>
+<LI><A HREF="#DEC">Digital UNIX</A>
+<LI><A HREF="#HP">Hewlett-Packard</A>
+<LI><A HREF="#Linux">Linux</A>
+<LI><A HREF="#SGI">SGI</A>
+<LI><A HREF="#Solaris">Solaris</A>
+<LI><A HREF="#SunOS">SunOS 4.x</A>
+</UL>
+
+<HR>
+
+<H3><A NAME="AUX">
+A/UX (Apple's UNIX)
+</A></H3>
+
+If you are running Apache on A/UX, a page that gives some helpful
+performance hints (concerning the <I>listen()</I> queue and using
+virtual hosts)
+<A HREF="http://www.jaguNET.com/apache.html">can be found here</A>
+
+<P><HR>
+
+<H3><A NAME="BSD">
+BSD-based (BSDI, FreeBSD, etc)
+</A></H3>
+
+<A HREF="perf-bsd44.html#initial">Quick</A> and
+<A HREF="perf-bsd44.html#detail">detailed</A>
+performance tuning hints for BSD-derived systems.
+
+<P><HR>
+
+<H3><A NAME="DEC">
+Digital UNIX
+</A></H3>
+
+<UL> 
+  <LI><A HREF="http://www.digital.com/info/internet/document/ias/tuning.html">DIGITAL
+       UNIX Tuning Parameters for Web Servers</A> 
+  <LI>We have some <A HREF="perf-dec.html">newsgroup postings</A> on how to tune 
+       Digital UNIX 3.2 and 4.0. 
+</UL>
+
+<P><HR>
+
+<H3><A NAME="HP">
+Hewlett-Packard
+</A></H3>
+
+Some documentation on tuning HP machines can be found at <A
+HREF="http://www.software.hp.com/internet/perf/tuning.html">http://www.software.hp.com/internet/perf/tuning.html</A>.
+
+<P><HR>
+
+<H3><A NAME="Linux">
+Linux
+</A></H3>
+
+The most common problem on Linux shows up on heavily-loaded systems
+where the whole server will appear to freeze for a couple of minutes
+at a time, and then come back to life.  This has been traced to a
+listen() queue overload - certain Linux implementations have a low
+value set for the incoming connection queue which can cause problems.
+Please see our <a
+href="http://www.qosina.com/~awm/apache/linux-tcp.html">Using Apache on
+Linux</a> page for more info on how to fix this.
+
+<P><HR>
+
+<H3><A NAME="SGI">
+SGI
+</A></H3>
+
+<UL>
+<LI><A HREF="http://www.sgi.com/Products/WebFORCE/Resources/res_TuningGuide.html">
+WebFORCE Web Server Tuning Guidelines for IRIX 5.3,
+&lt;http://www.sgi.com/Products/WebFORCE/Resources/res_TuningGuide.html&gt;</A>
+</UL>
+
+<P><HR>
+
+<H3><A NAME="Solaris">
+Solaris 2.4
+</A></H3>
+
+The Solaris 2.4 TCP implementation has a few inherent limitations that
+only became apparent under heavy loads.  This has been fixed to some
+extent in 2.5 (and completely revamped in 2.6), but for now consult
+the following URL for tips on how to expand the capabilities if you
+are finding slowdowns and lags are hurting performance.
+
+<UL>
+
+<LI><A href="http://www.sun.com/sun-on-net/Sun.Internet.Solutions/performance/">
+World Wide Web Server Performance, 
+&lt;http://www.sun.com/sun-on-net/Sun.Internet.Solutions/performance/&gt;</a>
+<LI><A HREF="http://www.sun.com/solaris/products/siss/">
+Solaris Internet Server Supplement for 2.5.1</A>
+</UL>
+
+<P><HR>
+
+<H3><A NAME="SunOS">
+SunOS 4.x
+</A></H3>
+
+More information on tuning SOMAXCONN on SunOS can be found at 
+<A HREF="http://www.islandnet.com/~mark/somaxconn.html">
+http://www.islandnet.com/~mark/somaxconn.html</A>.  
+
+<P><HR>
+
+<H3>More welcome!</H3>
+
+If you have tips to contribute, send mail to <a
+href="mailto:brian@organic.com">brian@organic.com</a>
+
+<!--#include virtual="footer.html" -->
+</body></html>
+
diff --git a/APACHE_1_2_X/htdocs/manual/misc/security_tips.html b/APACHE_1_2_X/htdocs/manual/misc/security_tips.html
new file mode 100644 (file)
index 0000000..cba41ad
--- /dev/null
@@ -0,0 +1,186 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<TITLE>Apache HTTP Server: Security Tips</TITLE>
+</HEAD>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<H1 ALIGN="CENTER">Security Tips for Server Configuration</H1>
+
+<hr>
+
+<P>Some hints and tips on security issues in setting up a web server. Some of
+the suggestions will be general, others specific to Apache.
+
+<HR>
+
+<H2>Permissions on Log File Directories</H2>
+<P>When Apache starts, it opens the log files as the user who started the
+server before switching to the user defined in the 
+<a href="../mod/core.html#user"><b>User</b></a> directive.  Anyone who
+has write permission for the directory where any log files are
+being written to can append pseudo-arbitrary data to any file on the
+system which is writable by the user who starts Apache.  Since the
+server is normally started by root, you should <EM>NOT</EM> give anyone
+write permission to the directory where logs are stored unless you
+want them to have root access. 
+<P>
+<HR>
+<H2>Server Side Includes</H2>
+<P>Server side includes (SSI) can be configured so that users can execute
+arbitrary programs on the server. That thought alone should send a shiver
+down the spine of any sys-admin.<p>
+
+One solution is to disable that part of SSI. To do that you use the
+IncludesNOEXEC option to the <A HREF="../mod/core.html#options">Options</A>
+directive.<p>
+
+<HR>
+
+<H2>Non Script Aliased CGI</H2>
+<P>Allowing users to execute <B>CGI</B> scripts in any directory should only
+be considered if;
+<OL>
+ <LI>You trust your users not to write scripts which will deliberately or
+accidentally expose your system to an attack.
+ <LI>You consider security at your site to be so feeble in other areas, as to
+make one more potential hole irrelevant.
+ <LI>You have no users, and nobody ever visits your server.
+</OL><p>
+<HR>
+
+<H2>Script Alias'ed CGI</H2>
+<P>Limiting <B>CGI</B> to special directories gives the admin control over
+what goes into those directories. This is inevitably more secure than
+non script aliased CGI, but <strong>only if users with write access to the
+directories are trusted</strong> or the admin is willing to test each new CGI
+script/program for potential security holes.<P>
+
+Most sites choose this option over the non script aliased CGI approach.<p>
+
+<HR>
+<H2>CGI in general</H2>
+<P>Always remember that you must trust the writers of the CGI script/programs
+or your ability to spot potential security holes in CGI, whether they were
+deliberate or accidental.<p>
+
+All the CGI scripts will run as the same user, so they have potential to
+conflict (accidentally or deliberately) with other scripts e.g.
+User A hates User B, so he writes a script to trash User B's CGI
+database.  One program which can be used to allow scripts to run
+as different users is <A HREF="../suexec.html">suEXEC</A> which is
+included with Apache as of 1.2 and is called from special hooks in
+the Apache server code.  Another popular way of doing this is with
+<A HREF="http://wwwcgi.umr.edu/~cgiwrap/">CGIWrap</A>.  <P>
+
+<HR>
+
+
+<H2>Stopping users overriding system wide settings...</H2>
+<P>To run a really tight ship, you'll want to stop users from setting
+up <CODE>.htaccess</CODE> files which can override security features
+you've configured. Here's one way to do it...<p>
+
+In the server configuration file, put
+<blockquote><code>
+&lt;Directory /&gt; <br>
+AllowOverride None <br>
+Options None <br>
+allow from all <br>
+&lt;/Directory&gt; <br>
+</code></blockquote>
+
+Then setup for specific directories<P>
+
+This stops all overrides, Includes and accesses in all directories apart
+from those named.<p>
+<HR>
+<H2>
+ Protect server files by default
+</H2>
+<P>
+One aspect of Apache which is occasionally misunderstood is the feature
+of default access.  That is, unless you take steps to change it, if the
+server can find its way to a file through normal URL mapping rules, it
+can serve it to clients.
+</P>
+<P>
+For instance, consider the following example:
+</P>
+<OL>
+ <LI><SAMP># cd /; ln -s / public_html</SAMP>
+ </LI>
+ <LI>Accessing <SAMP>http://localhost/~root/</SAMP>
+ </LI>
+</OL>
+<P>
+This would allow clients to walk through the entire filesystem.  To work
+around this, add the following block to your server's configuration:
+</P>
+<PRE>
+ &lt;Directory /&gt;
+     Order deny,allow
+     Deny from all
+ &lt;/Directory&gt;
+</PRE>
+<P>
+This will forbid default access to filesystem locations.  Add
+appropriate
+<A
+ HREF="../mod/core.html#directory"
+><SAMP>&lt;Directory&gt;</SAMP></A>
+blocks to allow access only
+in those areas you wish.  For example,
+</P>
+<PRE>
+ &lt;Directory /usr/users/*/public_html&gt;
+     Order deny,allow
+     Allow from all
+ &lt;/Directory&gt;
+ &lt;Directory /usr/local/httpd&gt;
+     Order deny,allow
+     Allow from all
+ &lt;/Directory&gt;
+</PRE>
+<P>
+Pay particular attention to the interactions of
+<A
+ HREF="../mod/core.html#location"
+><SAMP>&lt;Location&gt;</SAMP></A>
+and
+<A
+ HREF="../mod/core.html#directory"
+><SAMP>&lt;Directory&gt;</SAMP></A>
+directives; for instance, even if <SAMP>&lt;Directory /&gt;</SAMP>
+denies access, a <SAMP>&lt;Location /&gt;</SAMP> directive might
+overturn it.
+</P>
+<P>
+Also be wary of playing games with the
+<A
+ HREF="../mod/mod_userdir.html#userdir"
+>UserDir</A>
+directive; setting it to something like <SAMP>&quot;./&quot;</SAMP>
+would have the same effect, for root, as the first example above.
+</P>
+
+<HR>
+<P>Please send any other useful security tips to The Apache Group
+by filling out a
+<A HREF="http://www.apache.org/bugdb.cgi">problem report</A>, or by
+sending mail to
+<A HREF="mailto:apache-bugs@mail.apache.org">apache-bugs@mail.apache.org</A>
+<p>
+<HR>
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
diff --git a/APACHE_1_2_X/htdocs/manual/misc/vif-info.html b/APACHE_1_2_X/htdocs/manual/misc/vif-info.html
new file mode 100644 (file)
index 0000000..f38f737
--- /dev/null
@@ -0,0 +1,399 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML><HEAD>
+<TITLE>Configuring Multiple IP Addresses</TITLE>
+</HEAD>
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<H1 ALIGN="CENTER">Configuring Multiple IP Addresses</H1>
+
+<PRE>
+This material is originally from John Ioannidis (ji@polaris.ctr.columbia.edu)
+I have condensed it some and applied some corrections for SunOS 4.1.x
+courtesy of Chuck Smoko (csmoko@relay.nswc.navy.mil).
+
+Bob Baggerman  (bob@bizweb.com)
+12 Jan 94
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+John Ionnidis writes:
+
+This is a topic that comes up once in a while on comp.protocols.tcp-ip
+and other newsgroups. The question is, how to get a machine with one
+network interface to respond to more than one IP addresses. 
+
+I have a solution than might suit you.  For my doctoral work (there's
+a paper about it in this year's ('91) SIGCOMM, also available for
+anonymous FTP from cs.columbia.edu:/pub/ji/sigcomm*.ps.Z), I've
+developed what I call the "Virtual Interface" (VIF). To the networking
+code, it looks like an interface. It gets ifattach()ed when you open
+the /dev/vif* device, and then you can ifconfig it as you like. It
+does not have an if_input procedure; it only has an if_output. Packets
+that it receives (from higher-level protocols) which have its
+IP address, it simply loops back (like any well-behaved if driver).
+Packets that it receives that are destined for some other address, it
+encapsulates in an encapsulation protocol I call IPIP (IP-within-IP,
+protocol number IPPROTO_IPIP == 94), and sends it to another machine
+that groks that encapsulation protocol. This feature you won't need,
+but here's how to have multiple IP addresses on a machine with a
+single real interface:
+
+Let's say your primary interface's IP address is 198.3.2.1, and you
+also want it to respond to addresses 198.4.3.2 and 198.5.4.3 (note
+that these are three distinct class C addresses in three distinct
+class C nets). Here are the ifconfigs:
+
+  ifconfig le0 198.3.2.1 up -trailers  # config primary interface
+
+  ifconfig vif0 198.4.3.2 up           # config first virtual interface
+  route delete net 198.4.3 198.4.3.2   # delete spurious route 
+  route add host 198.4.3.2 198.4.3.2 0 # add route for this i/f
+
+  ifconfig vif1 198.5.4.3 up           # config second virtual interface
+  route delete net 198.5.4 198.5.4.3   # delete spurious route 
+  route add host 198.5.4.3 198.5.4.3 0 # add route for this i/f
+
+The route deletes are needed because the ifconfig creates a default
+route to the interface's network, which can cause problems; all that's
+needed is the (host) route to the interface's address. 
+
+Now, get le0's ethernet address (say, 8:0:20:3:2:1), and add the
+following static ARP entries:
+
+  arp -s 198.4.3.2 8:0:20:3:2:1 pub
+  arp -s 198.5.4.3 8:0:20:3:2:1 pub
+
+This will cause any ARP requests for the VIF addresses to be replied
+with your machine's ethernet address. 
+
+Now, make sure your default route is to your segment's gateway,
+through the real interface. Finally, make sure your routers and/or
+hosts on the same segment as yours know that 198.4.3.2 and 198.5.4.3
+are on that cable. 
+
+Here's what you've accomplished.
+
+ARP requests for any of your host's addresses will be replied to with
+the host's ethernet address (the real one, because that's what it is,
+the virtual ones because of the public static arp entries). Packets
+reaching your host with any of these addresses will be accepted by the
+ip_input routine because they match the address of one of the host's
+interfaces. Packets leaving your host can have any of its addresses
+(real and virtual). 
+
+The code for vif follows. To use it, put the stuff in netinet/if_vif.c
+and netinet/if_vif.h, configure your kernel with the number of
+virtual interfaces you want using a line like:
+
+pseudo-device  vif4            # Virtual IP interface
+
+in your configuration file, and the line
+
+netinet/if_vif.c       optional vif device-driver
+
+in the "files" file. Also, add the appropriate entries in conf.c, so
+that you can access the if_attach() routine when you open the device:
+
+
+-------------------------- conf.c------------------------------------------
+
+add this in the appropriate place in the headers of conf.c:
+
+--------------------
+#include "vif.h"
+#if NVIF &gt; 0
+int     vifopen(), vifclose(), vifread(), vifwrite(), vifselect(), vifioctl();
+#else
+#define vifopen         nodev
+#define vifclose        nodev
+#define vifread         nodev
+#define vifwrite        nodev
+#define vifselect       nodev
+#define vifioctl        nodev
+#endif
+--------------------
+
+then, way down in the definition for cdevsw[]:
+
+--------------------
+       vifopen,        vifclose,       vifread,        vifwrite,       /*14*/
+       vifioctl,       nodev,          nodev,          0,
+       0,      nodev,
+--------------------
+
+Make sure you remember the correct major device number, 14 in this case!
+
+---------------------------------------------------------------------------
+
+Finally, here's the code. It has the tunneling pieces removed (you
+need more code to use that anyway), and it comes from a Mach 2.6
+kernel; it should compile on any Berkeley-derived unix with minor
+changes (most likely only in the includes). 
+
+---------------------netinet/if_vif.h--------------------------------------
+typedef struct 
+{
+       struct ifnet    vif_if;
+       struct ifnet    *vif_sif;       /* slave interface */
+       int             vif_flags;
+} vif_softc_t;
+
+#define        VIFMTU  (1024+512)
+---------------------------------------------------------------------------
+
+and
+
+---------------------netinet/if_vif.c--------------------------------------
+/*
+ * Virtual IP interface module.
+ */
+
+#include "param.h"
+#include "../sys/systm.h"
+#include "../sys/mbuf.h"
+#include "../sys/socket.h"
+#include "../sys/errno.h"
+#include "../sys/ioctl.h"
+
+#include "../net/if.h"
+#include "../net/netisr.h"
+#include "../net/route.h"
+
+#ifdef INET
+#include "../netinet/in.h"
+#include "../netinet/in_systm.h"
+#include "../netinet/in_var.h"
+#include "../netinet/ip.h"
+#endif
+
+#include "in_pcb.h"
+#include "vif.h"
+
+typedef struct
+{
+        struct ifnet    vif_if;
+        struct ifnet    *vif_sif;       /* slave interface */
+        int             vif_flags;
+} vif_softc_t;
+
+#define VIFMTU  (1024+512)
+
+vif_softc_t vif_softc[NVIF];
+
+int vifs_inited = 0;
+
+
+vifattach()
+{
+       register int i;
+       register struct ifnet *ifp;
+        int    vifoutput(), vififioctl();
+       
+       for (i=0; i&lt;NVIF; i++)
+       {
+               ifp = &vif_softc[i].vif_if;
+               ifp-&gt;if_name = "vif";
+               ifp-&gt;if_unit = i;
+               ifp-&gt;if_mtu = VIFMTU;
+               ifp-&gt;if_flags = IFF_LOOPBACK | IFF_NOARP;
+               ifp-&gt;if_ioctl = vififioctl;
+               ifp-&gt;if_output = vifoutput;
+               if_attach(ifp);
+       }
+}
+
+vifopen(dev, flag)
+int dev, flag;
+{
+       int unit;
+       
+       if (!vifs_inited)
+       {
+               vifattach();
+               vifs_inited = 1;
+               printf("vif initialized\n");
+       }
+       
+       unit = minor(dev);
+       if ((unit &lt; 0) || (unit &gt;= NVIF))
+       {
+               return ENXIO;
+       }
+       
+       return 0;
+}
+
+vifclose(dev, flag)
+int dev, flag;
+{
+       return 0;
+}
+
+vifread()
+{
+       return ENXIO;
+}
+
+vifwrite()
+{
+       return ENXIO;
+}
+
+vifselect()
+{
+       return ENXIO;
+}
+
+vifoutput(ifp, m0, dst)
+       struct ifnet *ifp;
+       register struct mbuf *m0;
+       struct sockaddr *dst;
+{
+       int s;
+       register struct ifqueue *ifq;
+       struct mbuf *m;
+       struct sockaddr_in *din;
+       
+       if (dst-&gt;sa_family != AF_INET)
+       {
+               printf("%s%d: can't handle af%d\n", 
+                      ifp-&gt;if_name, ifp-&gt;if_unit,
+                      dst-&gt;sa_family);
+               m_freem(m0);
+               return (EAFNOSUPPORT);
+       }
+
+       din = (struct sockaddr_in *)dst;
+       
+       if (din-&gt;sin_addr.s_addr == IA_SIN(ifp-&gt;if_addrlist)-&gt;sin_addr.s_addr)
+       {
+               /* printf("%s%d: looping\n", ifp-&gt;if_name, ifp-&gt;if_unit); */
+               
+               /*
+                * Place interface pointer before the data
+                * for the receiving protocol.
+                */
+               if (m0-&gt;m_off &lt;= MMAXOFF &&
+                   m0-&gt;m_off &gt;= MMINOFF + sizeof(struct ifnet *)) {
+                       m0-&gt;m_off -= sizeof(struct ifnet *);
+                       m0-&gt;m_len += sizeof(struct ifnet *);
+               } else {
+                       MGET(m, M_DONTWAIT, MT_HEADER);
+                       if (m == (struct mbuf *)0)
+                         return (ENOBUFS);
+                       m-&gt;m_off = MMINOFF;
+                       m-&gt;m_len = sizeof(struct ifnet *);
+                       m-&gt;m_next = m0;
+                       m0 = m;
+               }
+               *(mtod(m0, struct ifnet **)) = ifp;
+               s = splimp();
+               ifp-&gt;if_opackets++;
+               ifq = &ipintrq;
+               if (IF_QFULL(ifq)) {
+                       IF_DROP(ifq);
+                       m_freem(m0);
+                       splx(s);
+                       return (ENOBUFS);
+               }
+               IF_ENQUEUE(ifq, m0);
+               schednetisr(NETISR_IP);
+               ifp-&gt;if_ipackets++;
+               splx(s);
+               return (0);
+       }
+
+       return EHOSTUNREACH;
+}
+
+/*
+ * Process an ioctl request.
+ */
+/* ARGSUSED */
+vififioctl(ifp, cmd, data)
+       register struct ifnet *ifp;
+       int cmd;
+       caddr_t data;
+{
+       int error = 0;
+
+       switch (cmd) {
+
+       case SIOCSIFADDR:
+               ifp-&gt;if_flags |= IFF_UP;
+               /*
+                * Everything else is done at a higher level.
+                */
+               break;
+
+       default:
+               error = EINVAL;
+       }
+       return (error);
+}
+
+vifioctl(dev, cmd, arg, mode)
+dev_t dev;
+int cmd;
+caddr_t arg;
+int mode;
+{
+       int unit;
+       
+       unit = minor(dev);
+       if ((unit &lt; 0) || (unit &gt;= NVIF))
+         return ENXIO;
+       
+       return EINVAL;
+}
+---------------------------------------------------------------------------- 
+
+To use it, compile your kernel, and reboot. Then create the vif
+device:
+
+# mknod /dev/vif c 14 0
+
+(or whatever major number it ended up being), and echo something into
+it:
+
+# echo &gt; /dev/vif
+
+This will cause the device to be opened, which will if_attach the
+interfaces. If you feel like playing with the code, you may want to
+kmem_alloc() the vif_softc structrure at open time, and use the minor
+number of the device to tell it how many interfaces to create. 
+
+Now you can go ahead and ifconfig etc. 
+
+I'll be happy to answer minor questions, and hear about success and
+failure stories, but I cannot help you if you don't already know how
+to hack kernels.
+
+Good luck! 
+
+/ji
+
+In-Real-Life: John "Heldenprogrammer" Ioannidis
+E-Mail-To: ji@cs.columbia.edu
+V-Mail-To: +1 212 854 8120
+P-Mail-To: 450 Computer Science \n Columbia University \n New York, NY 10027
+</PRE>
+
+<P>
+
+Note: there is also a <A
+HREF="http://www.multihost.com/">commercial-product-turned-freeware
+called "Col. Patch"</A> which does this as a loadable kernel module
+for SunOS 4.1.3_U1.
+
+<P>
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
diff --git a/APACHE_1_2_X/htdocs/manual/misc/windoz_keepalive.html b/APACHE_1_2_X/htdocs/manual/misc/windoz_keepalive.html
new file mode 100644 (file)
index 0000000..d18fa00
--- /dev/null
@@ -0,0 +1,50 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<TITLE>MS Windows Netscape 3.0b4 KeepAlive problem solved</TITLE>
+</HEAD>
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<H1 ALIGN="CENTER">HTTP/1.1 KeepAlive problems with Netscape 3.0</H1>
+
+<PRE>
+Date: Mon, 1 Jul 1996 16:03:06 -0700 (PDT)
+From: Alexei Kosut &lt;akosut@organic.com&gt;
+To: Apache Group
+Subject: Re: keepalive and windoze
+
+Good news and good news (of a sort)..
+
+I was able to snag a Windows 95 machine here at Organic, and tried out
+some things:
+
+1) On Netscape 3.0b4, I was able to reproduce the bug, each and every
+time. It's really simple: go to the Network Setup panel. Set it to
+"Connect Every Time" and only let it have 1 connection at once (this may
+not be neccessary, but it's helpeful). Then load an image that's
+kept-alive. Then wait until the connection times out (this depends on the
+server - 10-30 seconds, except for MIIS, which never times out, near as I
+can tell). Then hit reload. It will hang. (actually, once it crashed).
+
+2) This happens with all forms of server. Apache 1.1, Netscape 2.0,
+Spyglass 1.2, NCSA 1.5 (although, as stated, I couldn't test MIIS).
+
+3) Netscape 3.0b5 does, indeed, *not* have this bug. At least, I couldn't
+get it to perform such. Yipee.
+
+So, we just put up a note on the web page. Make sure we say that all the
+servers have the bug, it's a Windows bug, and Netscape Navigator 3.0b5
+works around it. That way, no one can yell at us. Yes?
+
+-- Alexei Kosut &lt;akosut@organic.com&gt;            The Apache HTTP Server
+   http://www.nueva.pvt.k12.ca.us/~akosut/      http://www.apache.org/
+</PRE>
+<!--#include virtual="footer.html" -->
+</BODY></HTML>
diff --git a/APACHE_1_2_X/htdocs/manual/mod/core.html b/APACHE_1_2_X/htdocs/manual/mod/core.html
new file mode 100644 (file)
index 0000000..fde6c35
--- /dev/null
@@ -0,0 +1,1429 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<TITLE>Apache Core Features</TITLE>
+</HEAD>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+
+<H1 ALIGN="CENTER">Apache Core Features</h1>
+
+These configuration parameters control the core Apache features, and are
+always available.
+
+
+<ul>
+<li><A HREF="#accessconfig">AccessConfig</A>
+<li><A HREF="#accessfilename">AccessFileName</A>
+<li><A HREF="#addmodule">AddModule</A>
+<li><A HREF="#allowoverride">AllowOverride</A>
+<li><A HREF="#authname">AuthName</A>
+<li><A HREF="#authtype">AuthType</A>
+<li><A HREF="#bindaddress">BindAddress</A>
+<li><A HREF="#clearmodulelist">ClearModuleList</A>
+<li><A HREF="#defaulttype">DefaultType</A>
+<li><A HREF="#directory">&lt;Directory&gt;</A>
+<li><A HREF="#documentroot">DocumentRoot</A>
+<li><A HREF="#errordocument">ErrorDocument</A>
+<li><A HREF="#errorlog">ErrorLog</A>
+<li><A HREF="#files">&lt;Files&gt;</A>
+<li><A HREF="#group">Group</A>
+<li><A HREF="#hostnamelookups">HostNameLookups</A>
+<li><A HREF="#identitycheck">IdentityCheck</A>
+<li><A HREF="#ifmodule">&lt;IfModule&gt;</A>
+<li><A HREF="#keepalive">KeepAlive</A>
+<li><A HREF="#keepalivetimeout">KeepAliveTimeout</A>
+<li><A HREF="#limit">&lt;Limit&gt;</A>
+<li><A HREF="#listen">Listen</A>
+<li><A HREF="#location">&lt;Location&gt;</A>
+<li><A HREF="#maxclients">MaxClients</A>
+<li><A HREF="#maxkeepaliverequests">MaxKeepAliveRequests</a>
+<li><A HREF="#maxrequestsperchild">MaxRequestsPerChild</A>
+<li><A HREF="#maxspareservers">MaxSpareServers</A>
+<li><A HREF="#minspareservers">MinSpareServers</A>
+<li><A HREF="#options">Options</A>
+<li><A HREF="#pidfile">PidFile</A>
+<li><A HREF="#port">Port</A>
+<li><A HREF="#require">require</A>
+<li><A HREF="#resourceconfig">ResourceConfig</A>
+<li><A HREF="#rlimitcpu">RLimitCPU</A>
+<li><A HREF="#rlimitmem">RLimitMEM</A>
+<li><A HREF="#rlimitnproc">RLimitNPROC</A>
+<li><A HREF="#satisfy">Satisfy</A>
+<li><A HREF="#scoreboardfile">ScoreBoardFile</A>
+<li><A HREF="#sendbuffersize">SendBufferSize</A>
+<li><A HREF="#serveradmin">ServerAdmin</A>
+<li><A HREF="#serveralias">ServerAlias</A>
+<li><A HREF="#servername">ServerName</A>
+<li><A HREF="#serverpath">ServerPath</A>
+<li><A HREF="#serverroot">ServerRoot</A>
+<li><A HREF="#servertype">ServerType</A>
+<li><A HREF="#startservers">StartServers</A>
+<li><A HREF="#timeout">TimeOut</A>
+<li><A HREF="#user">User</A>
+<li><A HREF="#virtualhost">&lt;VirtualHost&gt;</A>
+</ul>
+<hr>
+
+<A name="accessconfig"><h2>AccessConfig directive</h2></A>
+<!--%plaintext &lt;?INDEX {\tt AccessConfig} directive&gt; -->
+<strong>Syntax:</strong> AccessConfig <em>filename</em><br>
+<strong>Default:</strong> <code>AccessConfig conf/access.conf</code><br>
+<strong>Context:</strong> server config, virtual host<br>
+<strong>Status:</strong> core<p>
+
+The server will read this file for more directives after reading the
+<A HREF="#resourceconfig">ResourceConfig</A> file. <em>Filename</em> is
+relative to the <A HREF="#serverroot">ServerRoot</A>.
+This feature can be disabled using:
+<blockquote><code>AccessConfig /dev/null</code></blockquote>
+Historically, this file only contained
+<A HREF="#directory">&lt;Directory&gt;</A> sections; in fact it can now
+contain any server directive allowed in the <em>server config</em> context.
+<p><hr>
+
+<A name="accessfilename"><h2>AccessFileName directive</h2></A>
+<!--%plaintext &lt;?INDEX {\tt AccessFileName} directive&gt; -->
+<strong>Syntax:</strong> AccessFileName <em>filename</em><br>
+<strong>Default:</strong> <code>AccessFileName .htaccess</code><br>
+<strong>Context:</strong> server config, virtual host<br>
+<strong>Status:</strong> core<p>
+
+When returning a document to the client the server looks for an
+access control file with this name in every directory of the path to
+the document, if access control files are enabled for that directory.
+
+For example:
+<blockquote><code>AccessFileName .acl</code></blockquote>
+before returning the document /usr/local/web/index.html, the
+server will read /.acl, /usr/.acl, /usr/local/.acl and /usr/local/web/.acl
+for directives, unless they have been disabled with
+<blockquote><code>
+&lt;Directory /&gt;<br>
+AllowOverride None<br>
+&lt;/Directory&gt;</code></blockquote><p><hr>
+
+<A name="addmodule"><h2>AddModule directive</h2></A>
+<!--%plaintext &lt;?INDEX {\tt AddModule} directive&gt; -->
+<strong>Syntax:</strong> AddModule <em>module module ...</em><br>
+<strong>Context:</strong> server config <br>
+<strong>Status:</strong> core<br>
+<strong>Compatibility:</strong> AddModule is only available in Apache 1.2 and later<p>
+
+The server can have modules compiled in which are not actively in use.
+This directive can be used to enable the use of those modules.  The
+server comes with a pre-loaded list of active modules; this list can
+be cleared with the <A HREF="#clearmodulelist">ClearModuleList</A>
+directive.<p><hr>
+
+<A name="allowoverride"><h2>AllowOverride directive</h2></A>
+<!--%plaintext &lt;?INDEX {\tt AllowOverride} directive&gt; -->
+<strong>Syntax:</strong> AllowOverride <em>override override ...</em><br>
+<strong>Default:</strong> <code>AllowOverride All</code><br>
+<strong>Context:</strong> directory<br>
+<strong>Status:</strong> core<p>
+
+When the server finds an .htaccess file (as specified by
+<A HREF="#accessfilename">AccessFileName</A>) it needs to know which
+directives declared in that file can override earlier access information.<p>
+
+<em>Override</em> can be set to <code>None</code>, in which case the server
+will not read the file, <code>All</code> in which case the server will
+allow all the directives, or one or more of the following:
+<dl>
+<dt>AuthConfig
+<dd>
+<!--%plaintext &lt;?INDEX {\tt AuthConfig} override&gt; -->
+Allow use of the authorization directives
+(<A HREF="mod_auth_dbm.html#authdbmgroupfile">AuthDBMGroupFile</A>,
+<A HREF="mod_auth_dbm.html#authdbmuserfile">AuthDBMUserFile</A>,
+<A HREF="mod_auth.html#authgroupfile">AuthGroupFile</A>,
+<A HREF="#authname">AuthName</A>, <A HREF="#authtype">AuthType</A>,
+<A HREF="mod_auth.html#authuserfile">AuthUserFile</A>,
+<A HREF="#require">require</A>, etc.).
+<dt>FileInfo
+<dd>
+<!--%plaintext &lt;?INDEX {\tt FileInfo} override&gt; -->
+Allow use of the directives controlling document types
+(<A HREF="mod_mime.html#addencoding">AddEncoding</A>,
+<A HREF="mod_mime.html#addlanguage">AddLanguage</A>,
+<A HREF="mod_mime.html#addtype">AddType</A>,
+<A HREF="#defaulttype">DefaultType</A>,
+<A HREF="#errordocument">ErrorDocument</A>,
+<A HREF="mod_negotiation.html#languagepriority">LanguagePriority</A>, etc.).
+<dt>Indexes
+<dd>
+<!--%plaintext &lt;?INDEX {\tt Indexes} override&gt; -->
+Allow use of the directives controlling directory indexing
+(<A HREF="mod_dir.html#adddescription">AddDescription</A>,
+<A HREF="mod_dir.html#addicon">AddIcon</A>,
+<A HREF="mod_dir.html#addiconbyencoding">AddIconByEncoding</A>,
+<A HREF="mod_dir.html#addiconbytype">AddIconByType</A>,
+<A HREF="mod_dir.html#defaulticon">DefaultIcon</A>,
+<A HREF="mod_dir.html#directoryindex">DirectoryIndex</A>,
+<A HREF="mod_dir.html#fancyindexing">FancyIndexing</A>,
+<A HREF="mod_dir.html#headername">HeaderName</A>,
+<A HREF="mod_dir.html#indexignore">IndexIgnore</A>,
+<A HREF="mod_dir.html#indexoptions">IndexOptions</A>,
+<A HREF="mod_dir.html#readmename">ReadmeName</A>, etc.).
+<dt>Limit
+<dd>
+<!--%plaintext &lt;?INDEX {\tt Limit} override&gt; -->
+Allow use of the directives controlling host access (allow, deny and order).
+<dt>Options
+<dd>
+<!--%plaintext &lt;?INDEX {\tt Options} override&gt; -->
+Allow use of the directives controlling specific directory features
+(<A HREF="#options">Options</A> and
+<A HREF="mod_include.html#xbithack">XBitHack</A>).
+</dl><p><hr>
+
+<A name="authname"><h2>AuthName directive</h2></A>
+<!--%plaintext &lt;?INDEX {\tt AuthName} directive&gt; -->
+<strong>Syntax:</strong> AuthName <em>auth-domain</em><br>
+<strong>Context:</strong> directory, .htaccess<br>
+<strong>Override:</strong> AuthConfig<br>
+<strong>Status:</strong> core<p>
+
+This directive sets the name of the authorization realm for a directory.
+This realm is given to the client so that the user knows which username and
+password to send.
+It must be accompanied by <A HREF="#authtype">AuthType</A> and
+<A HREF="#require">require</A> directives, and directives such as
+<A HREF="mod_auth.html#authuserfile">AuthUserFile</A> and
+<A HREF="mod_auth.html#authgroupfile">AuthGroupFile</A> to work.<p><hr>
+
+<A name="authtype"><h2>AuthType directive</h2></A>
+<!--%plaintext &lt;?INDEX {\tt AuthType} directive&gt; -->
+<strong>Syntax:</strong> AuthType <em>type</em><br>
+<strong>Context:</strong> directory, .htaccess<br>
+<strong>Override:</strong> AuthConfig<br>
+<strong>Status:</strong> core<p>
+
+This directive selects the type of user authentication for a directory.
+Only <code>Basic</code> is currently implemented.
+<!--%plaintext &lt;?INDEX {\tt Basic} authentication scheme&gt; -->
+It must be accompanied by <A HREF="#authname">AuthName</A> and
+<A HREF="#require">require</A> directives, and directives such as
+<A HREF="mod_auth.html#authuserfile">AuthUserFile</A> and
+<A HREF="mod_auth.html#authgroupfile">AuthGroupFile</A> to work.<p><hr>
+
+<A name="bindaddress"><h2>BindAddress directive</h2></A>
+<!--%plaintext &lt;?INDEX {\tt BindAddress} directive&gt; -->
+<strong>Syntax:</strong> BindAddress <em>saddr</em><br>
+<strong>Default:</strong> <code>BindAddress *</code><br>
+<strong>Context:</strong> server config<br>
+<strong>Status:</strong> core<p>
+
+A Unix&#174; http server can either listen for connections to every
+IP address of the server machine, or just one IP address of the server
+machine. <em>Saddr</em> can be
+
+<menu>
+<li>*
+<li>An IP address
+<li>A fully-qualified Internet domain name
+</menu>
+If the value is *, then the server will listen for connections on
+every IP address, otherwise it will only listen on the IP address
+specified. <p>
+
+This option can be used as an alternative method for supporting
+<A HREF="../virtual-host.html">virtual hosts</A> instead of using
+<A HREF="#virtualhost">&lt;VirtualHost&gt;</A> sections.
+
+<p><strong>See Also:</strong>
+<a href="../dns-caveats.html">DNS Issues</a><br>
+<strong>See Also:</strong>
+<a href="../bind.html">Setting which addresses and ports Apache uses</a></p>
+
+<hr>
+
+<A name="clearmodulelist"><h2>ClearModuleList directive</h2></A>
+<!--%plaintext &lt;?INDEX {\tt ClearModuleList} directive&gt; -->
+<strong>Syntax:</strong> ClearModuleList<br>
+<strong>Context:</strong> server config<br>
+<strong>Status:</strong> core<br>
+<strong>Compatibility:</strong> ClearModuleList is only available in Apache 1.2 and later<p>
+
+The server comes with a built-in list of active modules.  This
+directive clears the list.  It is assumed that the list will then be
+re-populated using the <A HREF="#addmodule">AddModule</A> directive.<p><hr>
+
+<A name="defaulttype"><h2>DefaultType directive</h2></A>
+<!--%plaintext &lt;?INDEX {\tt DefaultType} directive&gt; -->
+<strong>Syntax:</strong> DefaultType <em>mime-type</em><br>
+<strong>Default:</strong> <code>DefaultType text/html</code><br>
+<strong>Context:</strong> server config, virtual host, directory, .htaccess<br>
+<strong>Override:</strong> FileInfo<br>
+<strong>Status:</strong> core<p>
+
+There will be times when the server is asked to provide a document
+whose type cannot be determined by its MIME types mappings.<p>
+
+The server must inform the client of the content-type of the document, so in
+the event of an unknown type it uses the <CODE>DefaultType</CODE>. For
+example:
+<blockquote><code>DefaultType image/gif</code></blockquote>
+would be appropriate for a directory which contained many gif images
+with filenames missing the .gif extension.<p><hr>
+
+<A name="directory"><h2>&lt;Directory&gt; directive</h2></A>
+<!--%plaintext &lt;?INDEX {\tt Directory} section directive&gt; -->
+<strong>Syntax:</strong> &lt;Directory <em>directory</em>&gt; ... &lt;/Directory&gt; <br>
+<strong>Context:</strong> server config, virtual host<br>
+<strong>Status:</strong> Core. <p>
+
+&lt;Directory&gt; and &lt;/Directory&gt; are used to enclose a group of
+directives which will apply only to the named directory and sub-directories
+of that directory. Any directive which is allowed in a directory
+context may be used. <em>Directory</em> is either the full path to a directory,
+or a wild-card string. In a wild-card string, `?' matches any single character,
+and `*' matches any sequences of characters. Example:
+<pre>
+   &lt;Directory /usr/local/httpd/htdocs&gt;
+   Options Indexes FollowSymLinks
+   &lt;/Directory&gt;
+</pre>
+
+<p><strong>Apache 1.2 and above:</strong>
+Extended regular expressions can also be used, with the addition of the
+<code>~</code> character. For example:</p>
+
+<pre>
+   &lt;Directory ~ &quot;^/www/.*/[0-9]{3}&quot;&gt;
+</pre>
+
+would match directories in /www/ that consisted of three numbers.<p>
+
+<p>If multiple directory sections match the directory (or its parents) containing
+a document, then the directives are applied in the order of shortest match
+first, interspersed with the directives from the
+<A HREF="#accessfilename">.htaccess</A> files. For example, with
+<blockquote><code>
+&lt;Directory /&gt;<br>
+AllowOverride None<br>
+&lt;/Directory&gt;<br><br>
+&lt;Directory /home/*&gt;<br>
+AllowOverride FileInfo<br>
+&lt;/Directory&gt;</code></blockquote>
+for access to the document <code>/home/web/dir/doc.html</code> the
+steps are:
+<menu>
+<li>Apply directive <code>AllowOverride None</code> (disabling
+<code>.htaccess</code> files).
+<li>Apply directive <code>AllowOverride FileInfo</code> (for directory
+<code>/home/web</code>).
+<li>Apply any FileInfo directives in <code>/home/web/.htaccess</code>
+</menu>
+
+<P>
+<STRONG>
+Note that the default Apache access for &lt;Directory /&gt; is
+<SAMP>Allow from All</SAMP>.  This means that Apache will serve any file
+mapped from an URL.  It is recommended that you change this with a block
+such as
+</STRONG>
+<PRE>
+ &lt;Directory /&gt;
+     Order Deny,Allow
+     Deny from All
+ &lt;/Directory&gt;
+</PRE>
+<P>
+<STRONG>
+and then override this for directories you <EM>want</EM> accessible.
+See the
+<A
+ HREF="../misc/security_tips.html"
+>Security Tips</A>
+page for more details.
+</STRONG>
+</P>
+
+The directory sections typically occur in the access.conf file, but they
+may appear in any configuration file. &lt;Directory&gt; directives cannot
+nest, and cannot appear in a <A HREF="#limit">&lt;Limit&gt;</A> section.
+<p><hr>
+
+<A NAME="documentroot"><h2>DocumentRoot directive</h2></A>
+<!--%plaintext &lt;?INDEX {\tt DocumentRoot} directive&gt; -->
+<strong>Syntax:</strong> DocumentRoot <em>directory-filename</em><br>
+<strong>Default:</strong> <code>DocumentRoot
+/usr/local/etc/httpd/htdocs</code><br>
+<strong>Context:</strong> server config, virtual host<br>
+<strong>Status:</strong> core<p>
+
+This directive sets the directory from which httpd will serve files.
+Unless matched by a directive like Alias, the server appends the path
+from the requested URL to the document root to make the path to the
+document. Example:
+<blockquote><code>DocumentRoot /usr/web</code></blockquote>
+then an access to <code>http://www.my.host.com/index.html</code> refers
+to <code>/usr/web/index.html</code>.
+
+<P>There appears to be a bug in mod_dir which causes problems when the
+DocumentRoot has a trailing slash (i.e. "DocumentRoot /usr/web/") so
+please avoid that.
+
+<p><hr>
+
+<A name="errordocument"><h2>ErrorDocument directive</h2></A>
+<!--%plaintext &lt;?INDEX {\tt ErrorDocument} directive&gt; -->
+<strong>Syntax:</strong> ErrorDocument <em>error-code document</em><br>
+<strong>Context</strong> server config, virtual host, directory, .htaccess<br>
+<strong>Status:</strong> core<br>
+<strong>Override:</strong> FileInfo<br>
+<strong>Compatibility:</strong> The directory and .htaccess contexts
+are only available in Apache 1.1 and later.<p>
+
+In the event of a problem or error, Apache can be configured to do
+one of four things,
+
+<OL>
+<LI>output a simple hardcoded error message
+<LI>output a customized message
+<LI>redirect to a local URL to handle the problem/error
+<LI>redirect to an external URL to handle the problem/error
+</OL>
+
+<P>The first option is the default, while options 2-4 are configured 
+using the <CODE>ErrorDocument</CODE> directive, which is followed by 
+the HTTP response code and a message or URL.
+
+<P><em>Messages</em> in this context begin with a single quote
+(<code>"</code>), which does not form part of the message itself. 
+Apache will sometimes offer additional information regarding the 
+problem/error. 
+
+<P>URLs can begin with a slash (/) for local URLs, or be a full
+URL which the client can resolve. Examples:
+<blockquote><code>
+ErrorDocument 500 http://foo.example.com/cgi-bin/tester<br>
+ErrorDocument 404 /cgi-bin/bad_urls.pl<br>
+ErrorDocument 401 /subscription_info.html<br>
+ErrorDocument 403 "Sorry can't allow you access today
+</code></blockquote>
+
+<P>Note that when you specify an <CODE>ErrorDocument</CODE> that 
+points to a remote URL (ie. anything with a method such as "http" in 
+front of it) Apache will send a redirect to the client to tell it
+where to find the document, even if the document ends up being 
+on the same server..  This has several implications, the
+most important being that <STRONG>if you use an "ErrorDocument 401"
+directive then it must refer to a local document.</STRONG>  This results
+from the nature of the HTTP basic authentication scheme.
+
+<P>See Also: <A HREF="../custom-error.html">documentation of customizable
+responses.</A><p><hr>
+
+<A name="errorlog"><h2>ErrorLog directive</h2></A>
+<!--%plaintext &lt;?INDEX {\tt ErrorLog} directive&gt; -->
+<strong>Syntax:</strong> ErrorLog <em>filename</em><br>
+<strong>Default:</strong> <code>ErrorLog logs/error_log</code><br>
+<strong>Context:</strong> server config, virtual host<br>
+<strong>Status:</strong> core<p>
+
+The error log directive sets the name of the file to which the server will log
+any errors it encounters. If the filename does not begin with a slash (/)
+then it is assumed to be relative to the <A HREF="#serverroot">ServerRoot</A>.
+Example:
+<blockquote><code>ErrorLog /dev/null</code></blockquote>
+This effectively turns off error logging.<p>
+
+SECURITY: See the <A HREF="../misc/security_tips.html">security tips</A> 
+document for details on why your security could be compromised if
+the directory where logfiles are stored is writable by anyone other
+than the user that starts the server.
+
+<p><hr>
+
+<A name="files"><h2>&lt;Files&gt;</h2></A>
+<strong>Syntax:</strong> &lt;Files <em>filename</em>&gt;
+... &lt;/Files&gt;<br>
+<strong>Context:</strong> server config, virtual host, htaccess<br>
+<strong>Status:</strong> core<br>
+<strong>Compatibility:</strong> only available in Apache
+1.2 and above.<p>
+
+<p>The &lt;Files&gt; directive provides for access control by
+filename. It is comparable to the <a
+href="#directory">&lt;Directory&gt;</a> directive and
+<a href="#location">&lt;Location&gt;</a> directives. It
+should be matched with a &lt;/Files&gt; directive. Directives that
+apply to the filename given should be listed
+within. <code>&lt;Files&gt;</code> sections are processed in the
+order they appear in the configuration file, after the
+&lt;Directory&gt; sections and <code>.htaccess</code> files are
+read, but before &lt;Location&gt; sections.</p>
+
+<p>The <em>filename</em> argument should include a filename, or a 
+wild-card string, where `?' matches any single character, and `*' matches any
+sequences of characters. Extended regular expressions can also be used, with the addition of
+the <code>~</code> character. For example:</p>
+
+<pre>
+   &lt;Files ~ &quot;\.(gif|jpe?g|png)$&quot;&gt;
+</pre>
+
+would match most common Internet graphics formats.
+
+<p>Note that unlike <a
+href="#directory"><code>&lt;Directory&gt;</code></a> and <a
+href="#location"><code>&lt;Location&gt;</code></a> sections,
+<code>&lt;Files&gt;</code> sections can be used inside .htaccess
+files. This allows users to control access to their own files, at a
+file-by-file level. When used in an .htaccess file, if the
+<em>filename</em> does not begin with a <code>/</code> character,
+the directory being applied will be prefixed automatically.
+
+<p> <hr>
+
+<A name="group"><h2>Group directive</h2></A>
+<!--%plaintext &lt;?INDEX {\tt Group} directive&gt; -->
+<strong>Syntax:</strong> Group <em>unix-group</em><br>
+<strong>Default:</strong> <code>Group #-1</code><br>
+<strong>Context:</strong> server config, virtual host<br>
+<strong>Status:</strong> core<p>
+
+The Group directive sets the group under which the server will answer requests.
+In order to use this directive, the stand-alone server must be run initially
+as root. <em>Unix-group</em> is one of:
+<dl>
+<dt>A group name
+<dd>Refers to the given group by name.
+<dt># followed by a group number.
+<dd>Refers to a group by its number.
+</dl>
+
+It is recommended that you set up a new group specifically for running the
+server. Some admins use user <code>nobody</code>, but this is not always
+possible or desirable.<p>
+
+Note: if you start the server as a non-root user, it will fail to change
+to the specified group, and will instead continue to run as the group of the
+original user. <p>
+
+Special note: Use of this directive in &lt;VirtualHost&gt; requires a
+properly configured <A HREF="../suexec.html">suEXEC wrapper</A>.
+When used inside a &lt;VirtualHost&gt; in this manner, only the group
+that CGIs are run as is affected.  Non-CGI requests are still processed
+as the group specified in the main Group directive.<p>
+
+SECURITY: See <A HREF="#user">User</A> for a discussion of the security
+considerations.<p><hr>
+
+<A name="hostnamelookups"><h2>HostNameLookups directive</h2></A>
+<!--%plaintext &lt;?INDEX {\tt HostNameLookups} directive&gt; -->
+<strong>Syntax:</strong> HostNameLookups <em>boolean</em><br>
+<strong>Default:</strong> <code>HostNameLookups on</code><br>
+<strong>Context:</strong> server config, virtual host<br>
+<strong>Status:</strong> core<p>
+
+This directive enables DNS lookups so that host names can be logged.
+Having this directive set <code>on</code> also enables the use of names
+in &lt;Limit&gt; blocks for access control.<p>
+
+Heavily loaded sites should set this directive <code>off</code>, since DNS
+lookups can take considerable amounts of time. The utility <i>logresolve</i>,
+provided in the <i>/support</i> directory, can be used to look up host names
+from logged IP addresses offline.<p><hr>
+
+<A name="identitycheck"><h2>IdentityCheck directive</h2></A>
+<!--%plaintext &lt;?INDEX {\tt IdentityCheck} directive&gt; -->
+<strong>Syntax:</strong> IdentityCheck <em>boolean</em><br>
+<strong>Default:</strong> <code>IdentityCheck off</code><br>
+<strong>Context:</strong> server config, virtual host<br>
+<strong>Status:</strong> core<p>
+
+This directive enables RFC1413-compliant logging of the remote user name
+for each connection, where the client machine runs identd or something similar.
+This information is logged in the access log. <em>Boolean</em> is either
+<code>on</code> or <code>off</code>.<p>
+
+The information should not be trusted in any way except for rudimentary usage
+tracking.<p>
+
+Note that this can cause serious latency problems accessing your server
+since every request requires one of these lookups to be performed.  When
+firewalls are involved each lookup might possibly fail and add 30 seconds
+of latency to each hit.  So in general this is not very useful on public
+servers accessible from the Internet.
+<p><hr>
+
+<A NAME="ifmodule"><H2>&lt;IfModule&gt;</H2></A>
+<b>Syntax:</b> &lt;IfModule [!]<i>module-name</i>&gt; <i>...</i>
+&lt;/IfModule&gt;<br>
+<b>Default:</b> None<br>
+<b>Context:</b> all<br>
+<b>Status:</b> Core
+<strong>Compatibility:</strong> ScriptLog is only available in 1.2 and
+later.<P>
+
+<p>
+
+The &lt;IfModule <i>test</i>&gt;...&lt;/IfModule&gt;
+section is used to mark directives that are conditional. The
+directives within an IfModule section are only
+processed if the <i>test</i> is true. If <i>test</i>
+is false, everything between the start and end markers
+is ignored.<p>
+
+The <i>test</i> in the &lt;IfModule&gt; section directive
+can be one of two forms:
+
+<ul>
+<li><i>module name</i>
+<li>!<i>module name</i>
+</ul>
+
+<p>In the former case, the directives between the start and end markers
+are only processed if the module named <i>module name</i> is compiled
+in to Apache. The second format reverses the test, and only processes
+the directives if <i>module name</i> is <b>not</b> compiled in.
+
+<p>The <i>module name</i> argument is a module name as given as the file
+name of the module, at the time it was compiled. For example,
+<code>mod_rewrite.c</code>.
+
+<p>&lt;IfModule&gt; sections are nest-able, which can be used to implement
+simple multiple-module tests.
+
+<P> <hr>
+
+<h2><a name="keepalive">KeepAlive</a></h2>
+<strong>Syntax: (Apache 1.1)</strong> KeepAlive <em>max-requests</em><br>
+<strong>Default: (Apache 1.1)</strong> <code>KeepAlive 5</code><br>
+<strong>Syntax: (Apache 1.2)</strong> KeepAlive <em>on/off</em><br>
+<strong>Default: (Apache 1.2)</strong> <code>KeepAlive On</code><br>
+<strong>Context:</strong> server config<br>
+<strong>Status:</strong> Core<br>
+<strong>Compatibility:</strong> KeepAlive is only available in Apache
+1.1 and later.<p>
+
+This directive enables
+<a href="../keepalive.html">Keep-Alive</a>
+support.
+
+<p><strong>Apache 1.1</strong>: Set <em>max-requests</em>
+to the maximum number of requests you want Apache to entertain per
+request. A limit is imposed to prevent a client from hogging your
+server resources. Set this to <code>0</code> to disable support.
+
+<p><strong>Apache 1.2 and later</strong>: Set to "On" to enable
+persistent connections, "Off" to disable. See also the <a
+href="#maxkeepaliverequests">MaxKeepAliveRequests</a> directive.</p>
+
+<h2><a name="keepalivetimeout">KeepAliveTimeout</a></h2>
+<strong>Syntax:</strong> KeepAliveTimeout <em>seconds</em><br>
+<strong>Default:</strong> <code>KeepAliveTimeout 15</code><br>
+<strong>Context:</strong> server config<br>
+<strong>Status:</strong> Core<br>
+<strong>Compatibility:</strong> KeepAliveTimeout is only available in Apache
+1.1 and later.<p>
+
+The number of seconds Apache will wait for a subsequent request before
+closing the connection. Once a request has been received, the timeout
+value specified by the <a
+href="#timeout"><code>Timeout</code></a> directive
+applies.
+<hr>
+
+<A name="listen"><h2>Listen</h2></A>
+<strong>Syntax:</strong>
+Listen [<em>IP address</em>:]<em>port number</em><br>
+<strong>Context:</strong> server config<br>
+<strong>Status:</strong> core<br>
+<strong>Compatibility:</strong> Listen is only available in Apache
+1.1 and later.<p>
+
+<p>The Listen directive instructs Apache to listen to more than one IP
+address or port; by default it responds to requests on all IP
+interfaces, but only on the port given by the <a href="#port">Port</a>
+directive.</p>
+
+<p><strong>See Also:</strong>
+<a href="../dns-caveats.html">DNS Issues</a><br>
+<strong>See Also:</strong>
+<a href="../bind.html">Setting which addresses and ports Apache uses</a><br>
+<strong>See Also:</strong>
+<a href="../misc/known_bugs.html#listenbug">Known Bugs</a></p>
+<hr>
+
+<A name="limit"><h2>&lt;Limit&gt; directive</h2></A>
+<!--%plaintext &lt;?INDEX {\tt Limit} section directive&gt; -->
+<strong>Syntax:</strong>
+ &lt;Limit <em>method method</em> ... &gt; ... &lt;/Limit&gt;<br>
+<strong>Context:</strong> any<br>
+<strong>Status:</strong> core<p>
+
+&lt;Limit&gt; and &lt;/Limit&gt; are used to enclose a group of
+access control directives which will then apply only to the specified
+access methods, where <em>method</em> is any valid HTTP method.
+Any directive except another &lt;Limit&gt; or
+<A HREF="#directory">&lt;Directory&gt;</A> may be used; the majority will be
+unaffected by the &lt;Limit&gt;. Example:
+<blockquote><code>
+&lt;Limit GET POST&gt;<br>
+require valid-user<br>
+&lt;/Limit&gt;</code></blockquote>
+If an access control directive appears outside a &lt;Limit&gt; directive,
+then it applies to all access methods.<p><hr>
+
+<h2><a name="location">&lt;Location&gt;</a></h2>
+
+<strong>Syntax:</strong> &lt;Location <em>URL</em>&gt;
+... &lt;/Location&gt;<br>
+<strong>Context:</strong> server config, virtual host<br>
+<strong>Status:</strong> core<br>
+<strong>Compatibility:</strong> Location is only available in Apache
+1.1 and later.<p>
+
+<p>The &lt;Location&gt; directive provides for access control by
+URL. It is comparable to the <a
+href="#directory">&lt;Directory&gt;</a> directive, and
+should be matched with a &lt;/Location&gt; directive. Directives that
+apply to the URL given should be listed
+within. <code>&lt;Location&gt;</code> sections are processed in the
+order they appear in the configuration file, after the
+&lt;Directory&gt; sections and <code>.htaccess</code> files are
+read.</p>
+
+<p>Note that, due to the way HTTP functions, <em>URL prefix</em>
+should, save for proxy requests, be of the form <code>/path/</code>,
+and should not include the <code>http://servername</code>. It doesn't
+necessarily have to protect a directory (it can be an individual
+file, or a number of files), and can include wild-cards.  In a wild-card
+string, `?' matches any single character, and `*' matches any
+sequences of characters.
+
+<p><strong>Apache 1.2 and above:</strong>
+Extended regular expressions can also be used, with the addition of
+the
+<code>~</code> character. For example:</p>
+
+<pre>
+   &lt;Location ~ &quot;/(extra|special)/data&quot;&gt;
+</pre>
+
+would match URLs that contained the substring "/extra/data" or
+"/special/data".</p>
+
+<p>The <code>Location</code> functionality is especially useful when
+combined with the <code><a
+href="mod_mime.html#sethandler">SetHandler</a></code> directive. For example, to enable status requests, but allow them only
+from browsers at foo.com, you might use:
+
+<pre>
+    &lt;Location /status&gt;
+    SetHandler server-status
+    order deny,allow
+    deny from all
+    allow from .foo.com
+    &lt;/Location&gt;
+</pre>
+<hr>
+
+<A name="maxclients"><h2>MaxClients directive</h2></A>
+<!--%plaintext &lt;?INDEX {\tt MaxClients} directive&gt; -->
+<strong>Syntax:</strong> MaxClients <em>number</em><br>
+<strong>Default:</strong> <code>MaxClients 256</code><br>
+<strong>Context:</strong> server config<br>
+<strong>Status:</strong> core<p>
+
+The MaxClients directive sets the limit on the number of simultaneous
+requests that can be supported; not more than this number of child server
+processes will be created.<p><hr>
+
+<A name="maxkeepaliverequests"><h2>MaxKeepAliveRequests</h2></A>
+<strong>Syntax:</strong> MaxKeepAliveRequests <em>number</em><br>
+<strong>Default:</strong> <code>MaxKeepAliveRequests 100</code><br>
+<strong>Context:</strong> server config<br>
+<strong>Status:</strong> core<br>
+<strong>Compatibility:</strong> Only available in Apache
+1.2 and later.
+
+<p>The MaxKeepAliveRequests directive limits the number of requests
+allowed per connection when <a href="#keepalive">KeepAlive</a> is
+on. If it is set to "<code>0</code>", unlimited requests will be
+allowed. We recommend that this setting be kept to a high value for
+maximum server performance.
+
+<A name="maxrequestsperchild"><h2>MaxRequestsPerChild directive</h2></A>
+<!--%plaintext &lt;?INDEX {\tt MaxRequestsPerChild} directive&gt; -->
+<strong>Syntax:</strong> MaxRequestsPerChild <em>number</em><br>
+<strong>Default:</strong> <code>MaxRequestsPerChild 0</code><br>
+<strong>Context:</strong> server config<br>
+<strong>Status:</strong> core<p>
+
+The MaxRequestsPerChild directive sets the limit on the number of requests
+that an individual child server process will handle. After MaxRequestsPerChild
+requests, the child process will die. If MaxRequestsPerChild is 0, then
+the process will never expire.<p>
+
+Setting MaxRequestsPerChild to a non-zero limit has two beneficial effects:
+<ul>
+<li>it limits the amount of memory that process can consume by (accidental)
+memory leakage;
+<li> by giving processes a finite lifetime, it helps reduce the
+number of processes when the server load reduces.
+</ul><p><hr>
+
+<A name="maxspareservers"><h2>MaxSpareServers directive</h2></A>
+<!--%plaintext &lt;?INDEX {\tt MaxSpareServers} directive&gt; -->
+<strong>Syntax:</strong> MaxSpareServers <em>number</em><br>
+<strong>Default:</strong> <code>MaxSpareServers 10</code><br>
+<strong>Context:</strong> server config<br>
+<strong>Status:</strong> core<p>
+
+The MaxSpareServers directive sets the desired maximum number of <em>idle</em>
+child server processes. An idle process is one which is not handling
+a request. If there are more than MaxSpareServers idle, then the parent
+process will kill off the excess processes.<p>
+
+Tuning of this parameter should only be necessary on very busy sites.
+Setting this parameter to a large number is almost always a bad idea.<p>
+
+See also <A HREF="#minspareservers">MinSpareServers</A> and
+<A HREF="#startservers">StartServers</A>.<p><hr>
+
+<A name="minspareservers"><h2>MinSpareServers directive</h2></A>
+<!--%plaintext &lt;?INDEX {\tt MinSpareServers} directive&gt; -->
+<strong>Syntax:</strong> MinSpareServers <em>number</em><br>
+<strong>Default:</strong> <code>MinSpareServers 5</code><br>
+<strong>Context:</strong> server config<br>
+<strong>Status:</strong> core<p>
+
+The MinSpareServers directive sets the desired minimum number of <em>idle</em>
+child server processes. An idle process is one which is not handling
+a request. If there are fewer than MinSpareServers idle, then the parent
+process creates new children at a maximum rate of 1 per second.<p>
+
+Tuning of this parameter should only be necessary on very busy sites.
+Setting this parameter to a large number is almost always a bad idea.<p>
+
+See also <A HREF="#maxspareservers">MaxSpareServers</A> and
+<A HREF="#startservers">StartServers</A>.<p><hr>
+
+<A name="options"><h2>Options directive</h2></A>
+<!--%plaintext &lt;?INDEX {\tt Options} directive&gt; -->
+<strong>Syntax:</strong> Options <em>[+|-]option [+|-]option ...</em><br>
+<strong>Context:</strong> server config, virtual host, directory, .htaccess<br>
+<strong>Override:</strong> Options<br>
+<strong>Status:</strong> core<p>
+
+The Options directive controls which server features are available in
+a particular directory. 
+<p>
+<em>option</em> can be set to <code>None</code>, in which case none of
+the extra features are enabled, or one or more of the following:
+<dl>
+<dt>All
+<dd>All options except for MultiViews.
+<dt>ExecCGI
+<dd>
+<!--%plaintext &lt;?INDEX {\tt ExecCGI} option&gt; -->
+Execution of CGI scripts is permitted.
+<dt>FollowSymLinks
+<dd>
+<!--%plaintext &lt;?INDEX {\tt FollowSymLinks} option&gt; -->
+The server will follow symbolic links in this directory.
+<dt>Includes
+<dd>
+<!--%plaintext &lt;?INDEX {\tt Includes} option&gt; -->
+Server-side includes are permitted.
+<dt>IncludesNOEXEC
+<dd>
+<!--%plaintext &lt;?INDEX {\tt IncludesNOEXEC} option&gt; -->
+Server-side includes are permitted, but the #exec command and
+#include of CGI scripts are disabled.
+<dt>Indexes
+<dd>
+<!--%plaintext &lt;?INDEX {\tt Indexes} option&gt; -->
+If a URL which maps to a directory is requested, and the there is no
+DirectoryIndex (e.g. index.html) in that directory, then the server will
+return a formatted listing of the directory.
+<dt>MultiViews
+<dd>
+<!--%plaintext &lt;?INDEX {\tt MultiViews} option&gt; -->
+<A HREF="../content-negotiation.html">Content negotiated</A> MultiViews are
+allowed.
+<dt>SymLinksIfOwnerMatch
+<dd>
+<!--%plaintext &lt;?INDEX {\tt SymLinksIfOwnerMatch} option&gt; -->
+The server will only follow symbolic links for which the target
+file or directory is owned by the same user id as the link.
+</dl>
+
+Normally, if multiple <code>Options</code> could apply to a directory,
+then the most specific one is taken complete; the options are not
+merged. However if <i>all</i> the options on the <code>Options</code>
+directive are preceded by a + or - symbol, the options are
+merged. Any options preceded by a + are added to the options
+currently in force, and any options preceded by a - are removed from
+the options currently in force.  <P>
+
+For example, without any + and - symbols:
+
+<blockquote><code>
+&lt;Directory /web/docs&gt; <br>
+Options Indexes FollowSymLinks<br>
+&lt;/Directory&gt;<br>
+&lt;Directory /web/docs/spec&gt; <br>
+Options Includes<br>
+&lt;/Directory&gt;
+</code></blockquote>
+then only <code>Includes</code> will be set for the /web/docs/spec
+directory. However if the second <code>Options</code> directive uses the +
+and - symbols:<p>
+
+<blockquote><code>
+&lt;Directory /web/docs&gt; <br>
+Options Indexes FollowSymLinks<br>
+&lt;/Directory&gt;<br>
+&lt;Directory /web/docs/spec&gt; <br>
+Options +Includes -Indexes<br>
+&lt;/Directory&gt;
+</code></blockquote>
+then the options <code>FollowSymLinks</code> and <code>Includes</code>
+are set for the /web/docs/spec directory.
+<hr>
+
+<A name="pidfile"><h2>PidFile directive</h2></A>
+<!--%plaintext &lt;?INDEX {\tt PidFile} directive&gt; -->
+<strong>Syntax:</strong> PidFile <em>filename</em><br>
+<strong>Default:</strong> <code>PidFile logs/httpd.pid</code><br>
+<strong>Context:</strong> server config<br>
+<strong>Status:</strong> core<p>
+
+The PidFile directive sets the file to which the server records the
+process id of the daemon. If the filename does not begin with a slash (/)
+then it is assumed to be relative to the <A HREF="#serverroot">ServerRoot</A>.
+The PidFile is only used in <A HREF="#servertype">standalone</A> mode.<p>
+
+It is often useful to be able to send the server a signal, so that it closes
+and then reopens its <A HREF="#errorlog">ErrorLog</A> and TransferLog, and
+re-reads its configuration files. This is done by sending a SIGHUP (kill -1)
+signal to the process id listed in the PidFile.<p>
+
+The PidFile is subject to the same warnings about log file placement and
+<a href="../misc/security_tips.html">security</a>.
+
+<p><hr>
+
+<A name="port"><h2>Port directive</h2></A>
+<!--%plaintext &lt;?INDEX {\tt Port} directive&gt; -->
+<strong>Syntax:</strong> Port <em>number</em><br>
+<strong>Default:</strong> <code>Port 80</code><br>
+<strong>Context:</strong> server config<br>
+<strong>Status:</strong> core<p>
+
+<em>Number</em> is a number from 0 to 65535; some port numbers (especially below
+1024) are reserved for particular protocols. See <code>/etc/services</code>
+for a list of some defined ports; the standard port for the http protocol
+is 80.<p>
+
+The Port directive has two behaviors, the first of which is necessary for
+NCSA backwards compatibility (and which is confusing in the context of
+Apache).<p>
+
+<ul>
+<li>
+In the absence of any <a href="#listen">Listen</a> or
+<a href="#bindaddress">BindAddress</a> directives specifying a port number,
+the Port directive sets the network port on which the server listens.
+If there are any Listen or BindAddress directives specifying
+<code>:number</code> then Port has no effect on what address the server
+listens at.
+
+<li>The Port directive
+sets the <code>SERVER_PORT</code> environment variable (for
+<a href="mod_cgi.html">CGI</a> and <a href="mod_include.html">SSI</a>),
+and is used when the server must generate a URL that refers to itself
+(for example when creating an external redirect to itself).  
+</ul>
+
+In no event does a Port setting affect
+what ports a <a href="#virtualhost">VirtualHost</a> responds on, the
+VirtualHost directive itself is used for that.<p>
+
+The primary behaviour of Port should be considered to be similar to that of
+the <a href="#servername">ServerName</a> directive.  The ServerName
+and Port together specify what you consider to be the <i>canonical</i>
+address of the server.<p>
+
+Port 80 is one of Unix's special ports. All ports numbered
+below 1024 are reserved for system use, i.e. regular (non-root) users cannot
+make use of them; instead they can only use higher port numbers.
+To use port 80, you must start the server from the root account.
+After binding to the port and before accepting requests, Apache will change
+to a low privileged user as set by the <A HREF="#user">User directive</A>.<p>
+
+If you cannot use port 80, choose any other unused port. Non-root users
+will have to choose a port number higher than 1023, such as 8000.<p>
+
+SECURITY: if you do start the server as root, be sure
+not to set <A HREF="#user">User</A> to root. If you run the server as
+root whilst handling connections, your site may be open to a major security
+attack.<p><hr>
+
+<A name="require"><h2>require directive</h2></A>
+<!--%plaintext &lt;?INDEX {\tt require} directive&gt; -->
+<strong>Syntax:</strong> require <em>entity-name entity entity...</em><br>
+<strong>Context:</strong> directory, .htaccess<br>
+<strong>Override:</strong> AuthConfig<br>
+<strong>Status:</strong> core<p>
+
+This directive selects which authenticated users can access a directory.
+The allowed syntaxes are:
+<ul>
+<li>require user <em>userid userid ...</em><p>
+Only the named users can access the directory.<p>
+<li>require group <em>group-name group-name ...</em><p>
+Only users in the named groups can access the directory.<p>
+<li>require valid-user<p>
+All valid users can access the directory.
+</ul>
+<p>
+If <code>require</code> appears in a <A HREF="#limit">&lt;Limit&gt;</A>
+section, then it restricts access to the named methods, otherwise
+it restricts access for all methods. Example:
+<blockquote><code>
+AuthType Basic<br>
+AuthName somedomain<br>
+AuthUserFile /web/users<br>
+AuthGroupFile /web/groups<br>
+&lt;Limit GET POST&gt;<br>
+require group admin<br>
+&lt;/Limit&gt;
+</code></blockquote>
+
+Require must be accompanied by <A HREF="#authname">AuthName</A> and
+<A HREF="#authtype">AuthType</A> directives, and directives such as
+<A HREF="mod_auth.html#authuserfile">AuthUserFile</A> and
+<A HREF="mod_auth.html#authgroupfile">AuthGroupFile</A> (to define users and
+groups) in order to work correctly.<p><hr>
+
+<A name="resourceconfig"><h2>ResourceConfig directive</h2></A>
+<!--%plaintext &lt;?INDEX {\tt ResourceConfig} directive&gt; -->
+<strong>Syntax:</strong> ResourceConfig <em>filename</em><br>
+<strong>Default:</strong> <code>ResourceConfig conf/srm.conf</code><br>
+<strong>Context:</strong> server config, virtual host<br>
+<strong>Status:</strong> core<p>
+
+The server will read this file for more directives after reading the
+httpd.conf file. <em>Filename</em> is relative to the
+<A HREF="#serverroot">ServerRoot</A>.
+This feature can be disabled using:
+<blockquote><code>ResourceConfig /dev/null</code></blockquote>
+Historically, this file contained most directives except for server
+configuration directives and <A HREF="#directory">&lt;Directory&gt;</A>
+sections; in fact it can now contain any server directive allowed in the
+<em>server config</em> context.<p>
+
+See also <A HREF="#accessconfig">AccessConfig</A>.<p><hr>
+
+<A name="rlimit">
+<A name="rlimitcpu"><h2>RLimitCPU directive</h2></A>
+<!--%plaintext &lt;?INDEX {\tt RLimitCPU} directive&gt; -->
+<strong>Syntax:</strong> RLimitCPU <em># or 'max'</em> <em>[# or 'max']</em><br>
+<strong>Default:</strong> <code>Unset uses operating system defaults</code><br>
+<strong>Context:</strong> server config, virtual host<br>
+<strong>Status:</strong> core<br>
+<strong>Compatibility:</strong> RLimitCPU is only available in Apache 1.2 and later<p>
+
+Takes 1 or 2 parameters. The first parameter sets the soft resource limit for all
+processes and the second parameter sets the maximum resource limit. Either parameter
+can be a number, or <em>max</em> to indicate to the server that the limit should
+be set to the maximum allowed by the operating system configuration. Raising the
+maximum resource limit requires that the server is running as root, or in the initial
+startup phase.<p>
+
+CPU resource limits are expressed in seconds per process.<p>
+
+See also <A HREF="#rlimitmem">RLimitMEM</A> or <A HREF="#rlimitnproc">RLimitNPROC</A>.<p><hr>
+
+<A name="rlimitmem"><h2>RLimitMEM directive</h2></A>
+<!--%plaintext &lt;?INDEX {\tt RLimitMEM} directive&gt; -->
+<strong>Syntax:</strong> RLimitMEM <em># or 'max'</em> <em>[# or 'max']</em><br>
+<strong>Default:</strong> <code>Unset uses operating system defaults</code><br>
+<strong>Context:</strong> server config, virtual host<br>
+<strong>Status:</strong> core<br>
+<strong>Compatibility:</strong> RLimitMEM is only available in Apache 1.2 and later<p>
+
+Takes 1 or 2 parameters. The first parameter sets the soft resource limit for all
+processes and the second parameter sets the maximum resource limit. Either parameter
+can be a number, or <em>max</em> to indicate to the server that the limit should
+be set to the maximum allowed by the operating system configuration. Raising the
+maximum resource limit requires that the server is running as root, or in the initial
+startup phase.<p>
+
+Memory resource limits are expressed in bytes per process.<p>
+
+See also <A HREF="#rlimitcpu">RLimitCPU</A> or <A HREF="#rlimitnproc">RLimitNPROC</A>.<p><hr>
+
+<A name="rlimitnproc"><h2>RLimitNPROC directive</h2></A>
+<!--%plaintext &lt;?INDEX {\tt RLimitNPROC} directive&gt; -->
+<strong>Syntax:</strong> RLimitNPROC <em># or 'max'</em> <em>[# or 'max']</em><br>
+<strong>Default:</strong> <code>Unset uses operating system defaults</code><br>
+<strong>Context:</strong> server config, virtual host<br>
+<strong>Status:</strong> core<br>
+<strong>Compatibility:</strong> RLimitNPROC is only available in Apache 1.2 and later<p>
+
+Takes 1 or 2 parameters. The first parameter sets the soft resource limit for all
+processes and the second parameter sets the maximum resource limit. Either parameter
+can be a number, or <em>max</em> to indicate to the server that the limit should
+be set to the maximum allowed by the operating system configuration. Raising the
+maximum resource limit requires that the server is running as root, or in the initial
+startup phase.<p>
+
+Process limits control the number of processes per user.<p>
+
+Note: If CGI processes are <b>not</b> running under userids other than the
+web server userid, this directive will limit the number of processes that the
+server itself can create. Evidence of this situation will be indicated by
+<b><em>cannot fork</em></b> messages in the error_log.<p>
+
+See also <A HREF="#rlimitmem">RLimitMEM</A> or <A HREF="#rlimitcpu">RLimitCPU</A>.
+
+<p><hr>
+
+<A name="satisfy"><h2>Satisfy</h2></A>
+<!--%plaintext &lt;?INDEX {\tt Satisfy} directive&gt; -->
+<strong>Syntax:</strong> Satisfy <em>'any' or 'all'</em><br>
+<strong>Default:</strong> Satisfy all<br>
+<strong>Context:</strong> directory, .htaccess<br>
+<strong>Status:</strong> core<br>
+<strong>Compatibility:</strong> Satisfy is only available in Apache 1.2 and later<p>
+
+Access policy if both allow and require used. The parameter can be
+either <em>'all'</em> or <em>'any'</em>. This directive is only useful
+if access to a particular area is being restricted by both
+username/password <i>and</i> client host address. In this case the
+default behavior ("all") is to require that the client passes the
+address access restriction <i>and</i> enters a valid username and
+password. With the "any" option the client will be granted access if
+they either pass the host restriction or enter a valid username and
+password. This can be used to password restrict an area, but to let
+clients from particular addresses in without prompting for a password.
+
+
+<p><hr>
+
+<A name="scoreboardfile"><h2>ScoreBoardFile directive</h2></A>
+<!--%plaintext &lt;?INDEX {\tt ScoreBoardFile} directive&gt; -->
+<strong>Syntax:</strong> ScoreBoardFile <em>filename</em><br>
+<strong>Default:</strong> <code>ScoreBoardFile logs/apache_status</code><br>
+<strong>Context:</strong> server config<br>
+<strong>Status:</strong> core<p>
+
+The ScoreBoardFile directive is required on some architectures to place
+a file that the server will use to communicate between its children and
+the parent.  The easiest way to find out if your architecture requires
+a scoreboard file is to run Apache and see if it creates the file named
+by the directive.  If your architecture requires it then you must ensure
+that this file is not used at the same time by more than one invocation
+of Apache.<p>
+
+If you have to use a ScoreBoardFile then you may see improved speed by
+placing it on a RAM disk.  But be careful that you heed the same warnings
+about log file placement and
+<a href="../misc/security_tips.html">security</a>.<p>
+
+Apache 1.2 and above:<p>
+
+Linux 1.x users might be able to add <code>-DHAVE_SHMGET</code> to
+the <code>EXTRA_CFLAGS</code> in your <code>Configuration</code>.  This
+might work with some 1.x installations, but won't work with all of
+them.<p>
+
+SVR4 users should consider adding <code>-DHAVE_SHMGET</code> to the
+<code>EXTRA_CFLAGS</code> in your <code>Configuration</code>.  This
+is believed to work, but we were unable to test it in time for 1.2
+release.<p>
+
+<strong>See Also</strong>:
+<a href="../stopping.html">Stopping and Restarting Apache</a></p>
+
+<p><hr>
+
+<A name="sendbuffersize"><h2>SendBufferSize directive</h2></A>
+<!--%plaintext &lt;?INDEX {\tt SendBufferSize} directive&gt; -->
+<strong>Syntax:</strong> SendBufferSize <em>bytes</em><br>
+<strong>Context:</strong> server config, virtual host<br>
+<strong>Status:</strong> core<p>
+
+The server will set the TCP buffer size to the number of bytes
+specified. Very useful to increase past standard OS defaults on high
+speed high latency (i.e. 100ms or so, such as transcontinental
+fast pipes)
+<p><hr>
+
+<A name="serveradmin"><h2>ServerAdmin directive</h2></A>
+<!--%plaintext &lt;?INDEX {\tt ServerAdmin} directive&gt; -->
+<strong>Syntax:</strong> ServerAdmin <em>email-address</em><br>
+<strong>Context:</strong> server config, virtual host<br>
+<strong>Status:</strong> core<p>
+
+The ServerAdmin sets the e-mail address that the server includes in any
+error messages it returns to the client.<p>
+
+It may be worth setting up a dedicated address for this, e.g.
+<blockquote><code>ServerAdmin www-admin@foo.bar.com</code></blockquote>
+as users do not always mention that they are talking about the server!<p><hr>
+
+<A name="serveralias"><h2>ServerAlias directive</h2></A>
+
+<strong>Syntax:</strong> ServerAlias <em>host1 host2 ...</em><br>
+<strong>Context:</strong> virtual host<br>
+<strong>Status:</strong> core<br>
+<strong>Compatibility:</strong> ServerAlias is only available in Apache
+1.1 and later.<p>
+
+The ServerAlias directive sets the alternate names for a host, for use
+with
+<a href="../host.html">Host-header based virtual hosts</a>.
+<p><strong>See Also</strong>:
+<a href="../vhosts-in-depth.html">In-depth description of Virtual Host matching</a></p>
+
+<hr>
+
+<A name="servername"><h2>ServerName directive</h2></A>
+<!--%plaintext &lt;?INDEX {\tt ServerName} directive&gt; -->
+<strong>Syntax:</strong> ServerName <em>fully-qualified domain name</em><br>
+<strong>Context:</strong> server config, virtual host<br>
+<strong>Status:</strong> core<p>
+
+The ServerName directive sets the hostname of the server; this is only
+used when creating redirection URLs. If it is not specified, then the
+server attempts to deduce it from its own IP address; however this may
+not work reliably, or may not return the preferred hostname. For example:
+<blockquote><code>ServerName www.wibble.com</code></blockquote>
+would be used if the canonical (main) name of the actual machine
+were <code>monster.wibble.com</code>.<p>
+<p><strong>See Also</strong>:
+<a href="../dns-caveats.html">DNS Issues</a></p>
+<hr>
+
+<A name="serverpath"><h2>ServerPath directive</h2></A>
+
+<strong>Syntax:</strong> ServerPath <em>pathname</em><br>
+<strong>Context:</strong> virtual host<br>
+<strong>Status:</strong> core<br>
+<strong>Compatibility:</strong> ServerPath is only available in Apache
+1.1 and later.<p>
+
+The ServerPath directive sets the legacy URL pathname for a host, for
+use with <a href="../host.html">Host-header based virtual hosts</a>.
+<p><strong>See Also</strong>:
+<a href="../vhosts-in-depth.html">In-depth description of Virtual Host matching</a></p>
+<hr>
+
+<A name="serverroot"><h2>ServerRoot directive</h2></A>
+<!--%plaintext &lt;?INDEX {\tt ServerRoot} directive&gt; -->
+<strong>Syntax:</strong> ServerRoot <em>directory-filename</em><br>
+<strong>Default:</strong> <code>ServerRoot /usr/local/etc/httpd</code><br>
+<strong>Context:</strong> server config<br>
+<strong>Status:</strong> core<p>
+
+The ServerRoot directive sets the directory in which the server lives.
+Typically it will contain the subdirectories <code>conf/</code> and
+<code>logs/</code>. Relative paths for other configuration files are taken
+as relative to this directory.<br>
+See also <a href="../invoking.html">the <code>-d</code> option to httpd</a>.<p><hr>
+
+<A name="servertype"><h2>ServerType directive</h2></A>
+<!--%plaintext &lt;?INDEX {\tt ServerType} directive&gt; -->
+<strong>Syntax:</strong> ServerType <em>type</em><br>
+<strong>Default:</strong> <code>ServerType standalone</code><br>
+<strong>Context:</strong> server config<br>
+<strong>Status:</strong> core<p>
+
+The ServerType directive sets how the server is executed by the system.
+<em>Type</em> is one of
+<dl>
+<dt>inetd
+<dd>The server will be run from the system process inetd; the command to start
+the server is added to <code>/etc/inetd.conf</code>
+<dt>standalone
+<dd>The server will run as a daemon process; the command to start the server
+is added to the system startup scripts. (<code>/etc/rc.local</code> or
+<code>/etc/rc3.d/...</code>.)
+</dl>
+
+Inetd is the lesser used of the two options. For each http
+connection received, a new copy of the server is started from scratch;
+after the connection is complete, this program exits. There is a high price to
+pay per connection, but for security reasons, some admins prefer this option.
+<p>
+
+Standalone is the most common setting for ServerType since
+it is far more efficient. The server is started once, and services all
+subsequent connections. If you intend running Apache to serve a busy site,
+standalone will probably be your only option.<p>
+
+SECURITY: if you are paranoid about security, run in inetd mode. Security
+cannot be guaranteed in either, but whilst most people are happy to use
+standalone, inetd is probably least prone to attack.<p><hr>
+
+<A name="startservers"><h2>StartServers directive</h2></A>
+<!--%plaintext &lt;?INDEX {\tt StartServers} directive&gt; -->
+<strong>Syntax:</strong> StartServers <em>number</em><br>
+<strong>Default:</strong> <code>StartServers 5</code><br>
+<strong>Context:</strong> server config<br>
+<strong>Status:</strong> core<p>
+
+The StartServers directive sets the number of child server processes created
+on startup. As the number of processes is dynamically controlled depending
+on the load, there is usually little reason to adjust this parameter.<p>
+
+See also <A HREF="#minspareservers">MinSpareServers</A> and
+<A HREF="#maxspareservers">MaxSpareServers</A>.<p><hr>
+
+<A name="timeout"><h2>TimeOut directive</h2></A>
+<!--%plaintext &lt;?INDEX {\tt TimeOut} directive&gt; -->
+<strong>Syntax:</strong> TimeOut <em>number</em><br>
+<strong>Default:</strong> <code>TimeOut 300</code><br>
+<strong>Context:</strong> server config<br>
+<strong>Status:</strong> core<p>
+
+The TimeOut directive currently defines the amount of time Apache will
+wait for three things:
+
+<OL>
+  <LI>The total amount of time it takes to receive a GET request.
+  <LI>The amount of time between receipt of TCP packets on a POST or
+      PUT request.
+  <LI>The amount of time between ACKs on transmissions of TCP packets 
+      in responses.
+</OL>
+
+We plan on making these separately configurable at some point down the
+road.  The timer used to default to 1200 before 1.2, but has been
+lowered to 300 which is still far more than necessary in most
+situations.  It is not set any lower by default because there may
+still be odd places in the code where the timer is not reset when
+a packet is sent.
+
+<p><hr>
+
+<A name="user"><h2>User directive</h2></A>
+<!--%plaintext &lt;?INDEX {\tt User} directive&gt; -->
+<strong>Syntax:</strong> User <em>unix-userid</em><br>
+<strong>Default:</strong> <code>User #-1</code><br>
+<strong>Context:</strong> server config, virtual host<br>
+<strong>Status:</strong> core<p>
+
+The User directive sets the userid as which the server will answer requests.
+In order to use this directive, the standalone server must be run initially
+as root. <em>Unix-userid</em> is one of:
+<dl>
+<dt>A username
+<dd>Refers to the given user by name.
+<dt># followed by a user number.
+<dd>Refers to a user by their number.
+</dl>
+
+The user should have no privileges which result in it being able to access
+files which are not intended to be visible to the outside world, and
+similarly, the user should not be able to execute code which is not
+meant for httpd requests. It is recommended that you set up a new user and
+group specifically for running the server. Some admins use user
+<code>nobody</code>, but this is not always possible or desirable.<p>
+
+Notes: If you start the server as a non-root user, it will fail to change
+to the lesser privileged user, and will instead continue to run as
+that original user. If you do start the server as root, then it is normal
+for the parent process to remain running as root.<p>
+
+Special note: Use of this directive in &lt;VirtualHost&gt; requires a
+properly configured <A HREF="../suexec.html">suEXEC wrapper</A>.
+When used inside a &lt;VirtualHost&gt; in this manner, only the user
+that CGIs are run as is affected.  Non-CGI requests are still processed
+with the user specified in the main User directive.<p>
+
+SECURITY: Don't set User (or <A HREF="#group">Group</A>) to
+<code>root</code> unless you know exactly what you are doing, and what the
+dangers are.<p><hr>
+
+<A name="virtualhost"><h2>&lt;VirtualHost&gt; directive</h2></A>
+<!--%plaintext &lt;?INDEX {\tt VirtualHost} section directive&gt; -->
+<strong>Syntax:</strong> &lt;VirtualHost <em>addr</em>[:<em>port</em>] ...&gt; ...
+&lt;/VirtualHost&gt; <br>
+<strong>Context:</strong> server config<br>
+<strong>Status:</strong> Core.<br>
+<strong>Compatibility:</strong> Non-IP address-based Virtual Hosting only
+available in Apache 1.1 and later.<br>
+<strong>Compatibility:</strong> Multiple address support only available in
+Apache 1.2 and later.<p>
+
+&lt;VirtualHost&gt; and &lt;/VirtualHost&gt; are used to enclose a group of
+directives which will apply only to a particular virtual host.
+Any directive which is allowed in a virtual host context may be used. 
+When the server receives a request for a document on a particular virtual
+host, it uses the configuration directives enclosed in the &lt;VirtualHost&gt;
+section. <em>Addr</em> can be
+<menu>
+<li>The IP address of the virtual host
+<li>A fully qualified domain name for the IP address of the virtual host.
+</menu> Example:
+<blockquote>
+<code>
+&lt;VirtualHost 10.1.2.3&gt; <br>
+ServerAdmin webmaster@host.foo.com <br>
+DocumentRoot /www/docs/host.foo.com <br>
+ServerName host.foo.com <br>
+ErrorLog logs/host.foo.com-error_log <br>
+TransferLog logs/host.foo.com-access_log <br>
+&lt;/VirtualHost&gt;
+</code></blockquote>
+
+Each VirtualHost must correspond to a different IP address or a
+different host name for the server, in the latter case the server
+machine must be configured to accept IP packets for multiple
+addresses. (If the machine does not have multiple network interfaces,
+then this can be accomplished with the <code>ifconfig alias</code>
+command (if your OS supports it), or with kernel patches like <A
+HREF="../misc/vif-info.html">VIF</A> (for SunOS(TM) 4.1.x)).<p>
+
+The special name <code>_default_</code> can be specified in which case
+this virtual host will match any IP address that is not explicitly listed
+in another virtual host.  In the absence of any _default_ virtual host
+the "main" server config, consisting of all those definitions outside
+any VirtualHost section, is used when no match occurs.<p>
+
+You can specify a <code>:port</code> to change the port that is matched.
+If unspecified then it defaults to the same port as the most recent
+<code><a href="#port">Port</a></code> statement of the main server.  You
+may also specify <code>:*</code> to match all ports on that address.
+(This is recommended when used with <code>_default_</code>.)<p>
+
+<strong>SECURITY</strong>: See the
+<A HREF="../misc/security_tips.html">security tips</A> 
+document for details on why your security could be compromised if
+the directory where logfiles are stored is writable by anyone other
+than the user that starts the server.
+
+<p><strong>See also:</strong>
+<A HREF="../dns-caveats.html">Warnings about DNS and Apache</a><br>
+<strong>See also:</strong>
+<A HREF="../virtual-host.html">Information on Virtual Hosts.
+(multihome)</A><br>
+<strong>See also:</strong>
+<a href="../host.html">Non-IP address-based Virtual Hosts</a><br>
+<strong>See also:</strong>
+<a href="../vhosts-in-depth.html">In-depth description of Virtual Host matching</a>
+</p>
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
+
diff --git a/APACHE_1_2_X/htdocs/manual/mod/directives.html b/APACHE_1_2_X/htdocs/manual/mod/directives.html
new file mode 100644 (file)
index 0000000..2359909
--- /dev/null
@@ -0,0 +1,176 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<TITLE>Apache directives</TITLE>
+</HEAD>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<H1 ALIGN="CENTER">Apache directives</H1>
+
+<ul>
+<li><A HREF="core.html#accessconfig">AccessConfig</A>
+<li><A HREF="core.html#accessfilename">AccessFileName</A>
+<li><A HREF="mod_actions.html#action">Action</A>
+<li><A HREF="mod_dir.html#addalt">AddAlt</A>
+<li><A HREF="mod_dir.html#addaltbyencoding">AddAltByEncoding</A>
+<li><A HREF="mod_dir.html#addaltbytype">AddAltByType</A>
+<li><A HREF="mod_dir.html#adddescription">AddDescription</A>
+<li><A HREF="mod_mime.html#addencoding">AddEncoding</A>
+<li><A HREF="mod_mime.html#addhandler">AddHandler</A>
+<li><A HREF="mod_dir.html#addicon">AddIcon</A>
+<li><A HREF="mod_dir.html#addiconbyencoding">AddIconByEncoding</A>
+<li><A HREF="mod_dir.html#addiconbytype">AddIconByType</A>
+<li><A HREF="mod_mime.html#addlanguage">AddLanguage</A>
+<li><A HREF="core.html#addmodule">AddModule</A>
+<li><A HREF="mod_mime.html#addtype">AddType</A>
+<li><A HREF="mod_log_agent.html#agentlog">AgentLog</A>
+<li><A HREF="mod_alias.html#alias">Alias</A>
+<li><A HREF="mod_access.html#allow">allow</A>
+<li><A HREF="core.html#allowoverride">AllowOverride</A>
+<li><A HREF="mod_auth_anon.html#anonymous">Anonymous</A>
+<li><A HREF="mod_auth_anon.html#Authoritative">Anonymous_Authoritative</A>
+<li><A HREF="mod_auth_anon.html#LogEmail">Anonymous_LogEmail</A>
+<li><A HREF="mod_auth_anon.html#MustGiveEmail">Anonymous_MustGiveEmail</A>
+<li><A HREF="mod_auth_anon.html#NoUserID">Anonymous_NoUserID</A>
+<li><A HREF="mod_auth_anon.html#VerifyEmail">Anonymous_VerifyEmail</A>
+<li><A HREF="mod_auth.html#authauthoritative">AuthAuthoritative</A>
+<li><A HREF="mod_auth_db.html#authdbauthoritative">AuthDBAuthoritative</A>
+<li><A HREF="mod_auth_db.html#authdbgroupfile">AuthDBGroupFile</A>
+<li><A HREF="mod_auth_dbm.html#authdbmauthoritative">AuthDBMAuthoritative</A>
+<li><A HREF="mod_auth_dbm.html#authdbmgroupfile">AuthDBMGroupFile</A>
+<li><A HREF="mod_auth_dbm.html#authdbmgroupfile">AuthDBMGroupFile</A>
+<li><A HREF="mod_auth_db.html#authdbuserfile">AuthDBUserFile</A>
+<li><A HREF="mod_auth_dbm.html#authdbmuserfile">AuthDBMUserFile</A>
+<li><A HREF="mod_digest.html#authdigestfile">AuthDigestFile</A>
+<li><A HREF="mod_auth.html#authgroupfile">AuthGroupFile</A>
+<li><A HREF="core.html#authname">AuthName</A>
+<li><A HREF="core.html#authtype">AuthType</A>
+<li><A HREF="mod_auth.html#authuserfile">AuthUserFile</A>
+<li><A HREF="core.html#bindaddress">BindAddress</A>
+<li><A HREF="mod_browser.html#browsermatch">BrowserMatch</A>
+<li><A HREF="mod_browser.html#browsermatchnocase">BrowserMatchNoCase</A>
+<li><A HREF="mod_proxy.html#cachedefaultexpire">CacheDefaultExpire</A>
+<li><A HREF="mod_proxy.html#cachedirlength">CacheDirLength</A>
+<li><A HREF="mod_proxy.html#cachedirlevels">CacheDirLevels</A>
+<li><A HREF="mod_proxy.html#cachegcinterval">CacheGcInterval</A>
+<li><A HREF="mod_proxy.html#cachelastmodifiedfactor">CacheLastModifiedFactor</A>
+<li><A HREF="mod_proxy.html#cachemaxexpire">CacheMaxExpire</A>
+<li><A HREF="mod_negotiation.html#cachenegotiateddocs">CacheNegotiatedDocs</A>
+<li><A HREF="mod_proxy.html#cacheroot">CacheRoot</A>
+<li><A HREF="mod_proxy.html#cachesize">CacheSize</A>
+<li><A HREF="core.html#clearmodulelist">ClearModuleList</A>
+<li><A HREF="mod_usertrack.html#cookieexpires">CookieExpires</A>
+<li><A HREF="mod_cookies.html#cookielog">CookieLog</A> (mod_cookies)
+<li><A HREF="mod_log_config.html#cookielog">CookieLog</A> (mod_log_config)
+<li><A HREF="mod_usertrack.html#cookietracking">CookieTracking</A>
+<li><A HREF="mod_log_config.html#customlog">CustomLog</A>
+<li><A HREF="mod_dir.html#defaulticon">DefaultIcon</A>
+<li><A HREF="core.html#defaulttype">DefaultType</A>
+<li><A HREF="mod_access.html#deny">deny</A>
+<li><A HREF="core.html#directory">&lt;Directory&gt;</A>
+<li><A HREF="mod_dir.html#directoryindex">DirectoryIndex</A>
+<li><A HREF="core.html#documentroot">DocumentRoot</A>
+<li><A HREF="core.html#errordocument">ErrorDocument</A>
+<li><A HREF="core.html#errorlog">ErrorLog</A>
+<li><A HREF="mod_example.html#example">Example</A>
+<li><A HREF="mod_expires.html#expiresactive">ExpiresActive</A>
+<li><A HREF="mod_expires.html#expiresbytype">ExpiresByType</A>
+<li><A HREF="mod_expires.html#expiresdefault">ExpiresDefault</A>
+<li><A HREF="mod_dir.html#fancyindexing">FancyIndexing</A>
+<li><A HREF="core.html#files">&lt;Files&gt;</A>
+<li><A HREF="mod_mime.html#forcetype">ForceType</A>
+<li><A HREF="core.html#group">Group</A>
+<li><A HREF="mod_headers.html#header">Header</A>
+<li><A HREF="mod_dir.html#headername">HeaderName</A>
+<li><A HREF="core.html#hostnamelookups">HostNameLookups</A>
+<li><A HREF="core.html#identitycheck">IdentityCheck</A>
+<li><A HREF="core.html#ifmodule">&lt;IfModule&gt;</A>
+<li><A HREF="mod_imap.html#imapbase">ImapBase</A>
+<li><A HREF="mod_imap.html#imapdefault">ImapDefault</A>
+<li><A HREF="mod_imap.html#imapmenu">ImapMenu</A>
+<li><A HREF="mod_dir.html#indexignore">IndexIgnore</A>
+<li><A HREF="mod_dir.html#indexoptions">IndexOptions</A>
+<li><A HREF="core.html#keepalive">KeepAlive</A>
+<li><A HREF="core.html#keepalivetimeout">KeepAliveTimeout</A>
+<li><A HREF="mod_negotiation.html#languagepriority">LanguagePriority</A>
+<li><A HREF="core.html#limit">&lt;Limit&gt;</A>
+<li><A HREF="core.html#listen">Listen</A>
+<li><A HREF="mod_dld.html#loadfile">LoadFile</A>
+<li><A HREF="mod_dld.html#loadmodule">LoadModule</A>
+<li><A HREF="core.html#location">&lt;Location&gt;</A>
+<li><A HREF="mod_log_config.html#logformat">LogFormat</A>
+<li><A HREF="core.html#maxclients">MaxClients</A>
+<li><A HREF="core.html#maxkeepaliverequests">MaxKeepAliveRequests</A>
+<li><A HREF="core.html#maxrequestsperchild">MaxRequestsPerChild</A>
+<li><A HREF="core.html#maxspareservers">MaxSpareServers</A>
+<li><A HREF="mod_cern_meta.html#metadir">MetaDir</A>
+<li><A HREF="mod_cern_meta.html#metasuffix">MetaSuffix</A>
+<li><A HREF="core.html#minspareservers">MinSpareServers</A>
+<li><A HREF="mod_proxy.html#nocache">NoCache</A>
+<li><A HREF="core.html#options">Options</A>
+<li><A HREF="mod_access.html#order">order</A>
+<li><A HREF="mod_env.html#passenv">PassEnv</A>
+<li><A HREF="core.html#pidfile">PidFile</A>
+<li><A HREF="core.html#port">Port</A>
+<li><A HREF="mod_proxy.html#proxyblock">ProxyBlock</A>
+<li><A HREF="mod_proxy.html#proxypass">ProxyPass</A>
+<li><A HREF="mod_proxy.html#proxyremote">ProxyRemote</A>
+<li><A HREF="mod_proxy.html#proxyrequests">ProxyRequests</A>
+<li><A HREF="mod_dir.html#readmename">ReadmeName</A>
+<li><A HREF="mod_alias.html#redirect">Redirect</A>
+<li><A HREF="mod_alias.html#redirectperm">RedirectPermanent</A>
+<li><A HREF="mod_alias.html#redirecttemp">RedirectTemp</A>
+<li><A HREF="mod_log_referer.html#refererignore">RefererIgnore</A>
+<li><A HREF="mod_log_referer.html#refererlog">RefererLog</A>
+<li><A HREF="core.html#require">require</A>
+<li><A HREF="core.html#resourceconfig">ResourceConfig</A>
+<li><A HREF="mod_rewrite.html#RewriteBase">RewriteBase</A>
+<li><A HREF="mod_rewrite.html#RewriteCond">RewriteCond</A>
+<li><A HREF="mod_rewrite.html#RewriteEngine">RewriteEngine</A>
+<li><A HREF="mod_rewrite.html#RewriteLog">RewriteLog</A>
+<li><A HREF="mod_rewrite.html#RewriteLogLevel">RewriteLogLevel</A>
+<li><A HREF="mod_rewrite.html#RewriteMap">RewriteMap</A>
+<li><A HREF="mod_rewrite.html#RewriteOptions">RewriteOptions</A>
+<li><A HREF="mod_rewrite.html#RewriteRule">RewriteRule</A>
+<li><A HREF="core.html#rlimitcpu">RLimitCPU</A>
+<li><A HREF="core.html#rlimitmem">RLimitMEM</A>
+<li><A HREF="core.html#rlimitnproc">RLimitNPROC</A>
+<li><A HREF="core.html#satisfy">Satisfy</A>
+<li><A HREF="core.html#scoreboardfile">ScoreBoardFile</A>
+<li><A HREF="mod_actions.html#script">Script</A>
+<li><A HREF="mod_alias.html#scriptalias">ScriptAlias</A>
+<li><A HREF="mod_cgi.html#scriptlog">ScriptLog</A>
+<li><A HREF="mod_cgi.html#scriptlogbuffer">ScriptLogBuffer</A>
+<li><A HREF="mod_cgi.html#scriptloglength">ScriptLogLength</A>
+<li><A HREF="core.html#sendbuffersize">SendBufferSize</A>
+<li><A HREF="core.html#serveradmin">ServerAdmin</A>
+<li><A HREF="core.html#serveralias">ServerAlias</A>
+<li><A HREF="core.html#servername">ServerName</A>
+<li><A HREF="core.html#serverpath">ServerPath</A>
+<li><A HREF="core.html#serverroot">ServerRoot</A>
+<li><A HREF="core.html#servertype">ServerType</A>
+<li><A HREF="mod_env.html#setenv">SetEnv</A>
+<li><A HREF="mod_mime.html#sethandler">SetHandler</A>
+<li><A HREF="core.html#startservers">StartServers</A>
+<li><A HREF="core.html#timeout">TimeOut</A>
+<li><A HREF="mod_log_common.html#transferlog">TransferLog</A> (mod_log_common)
+<li><A HREF="mod_log_config.html#transferlog">TransferLog</A> (mod_log_config)
+<li><A HREF="mod_mime.html#typesconfig">TypesConfig</A>
+<li><A HREF="mod_env.html#unsetenv">UnsetEnv</A>
+<li><A HREF="core.html#user">User</A>
+<li><A HREF="mod_userdir.html#userdir">UserDir</A>
+<li><A HREF="core.html#virtualhost">&lt;VirtualHost&gt;</A>
+<li><A HREF="mod_include.html#xbithack">XBitHack</A>
+</ul>
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
diff --git a/APACHE_1_2_X/htdocs/manual/mod/footer.html b/APACHE_1_2_X/htdocs/manual/mod/footer.html
new file mode 100644 (file)
index 0000000..2c2b410
--- /dev/null
@@ -0,0 +1,4 @@
+<HR>
+
+<A HREF="./"><IMG SRC="../images/index.gif" ALT="Index"></A>
+<A HREF="../"><IMG SRC="../images/home.gif" ALT="Home"></A>
diff --git a/APACHE_1_2_X/htdocs/manual/mod/header.html b/APACHE_1_2_X/htdocs/manual/mod/header.html
new file mode 100644 (file)
index 0000000..8b23a1c
--- /dev/null
@@ -0,0 +1,3 @@
+<DIV ALIGN="CENTER">
+ <IMG SRC="../images/sub.gif" ALT="[APACHE DOCUMENTATION]">
+</DIV>
diff --git a/APACHE_1_2_X/htdocs/manual/mod/index.html b/APACHE_1_2_X/htdocs/manual/mod/index.html
new file mode 100644 (file)
index 0000000..347393f
--- /dev/null
@@ -0,0 +1,103 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<TITLE>Apache modules</TITLE>
+</HEAD>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<H1 ALIGN="CENTER">Apache modules</h1>
+
+<P>
+Below is a list of all of the modules that come as part of the
+Apache distribution.  See also the complete alphabetical list of
+<A
+ HREF="directives.html"
+>all Apache directives</A>.
+</P>
+
+<dl>
+<dt><A HREF="core.html">Core</A>
+<dd>Core Apache features.
+<dt><A HREF="mod_access.html">mod_access</A>
+<dd>Host based access control.
+<dt><A HREF="mod_actions.html">mod_actions</A> Apache 1.1 and later.
+<dd>Filetype/method-based script execution
+<dt><A HREF="mod_alias.html">mod_alias</A>
+<dd>Aliases and redirects.
+<dt><A HREF="mod_asis.html">mod_asis</A>
+<dd>The .asis file handler.
+<dt><A HREF="mod_auth.html">mod_auth</A>
+<dd>User authentication using text files.
+<dt><A HREF="mod_auth_anon.html">mod_auth_anon</A>
+<dd>Anonymous user authentication, FTP-style.
+<dt><A HREF="mod_auth_db.html">mod_auth_db</A>
+<dd>User authentication using Berkeley DB files.
+<dt><A HREF="mod_auth_dbm.html">mod_auth_dbm</A>
+<dd>User authentication using DBM files.
+<dt><A HREF="mod_auth_msql.html">mod_auth_msql</A>
+<dd>User authentication using mSQL files.
+<dt><A HREF="mod_browser.html">mod_browser</A> Apache 1.2 and up
+<dd>Set environment variables based on User-Agent strings
+<dt><A HREF="mod_cern_meta.html">mod_cern_meta</a>
+<dd>Support for HTTP header metafiles.
+<dt><A HREF="mod_cgi.html">mod_cgi</A>
+<dd>Invoking CGI scripts.
+<dt><A HREF="mod_cookies.html">mod_cookies</A> up to Apache 1.1.1
+<dd>Support for Netscape-like cookies.  Replaced in Apache 1.2 by
+mod_usertrack
+<dt><A HREF="mod_digest.html">mod_digest</A>
+<dd>MD5 authentication
+<dt><A HREF="mod_dir.html">mod_dir</A>
+<dd>Automatic directory listings.
+<dt><A HREF="mod_dld.html">mod_dld</A>
+<dd>Start-time linking with the GNU libdld.
+<dt><A HREF="mod_env.html">mod_env</A>
+<dd>Passing of environments to CGI scripts
+<dt><A HREF="mod_example.html">mod_example</A> Apache 1.2 and up
+<dd>Demonstrates Apache API
+<dt><A HREF="mod_expires.html">mod_expires</A> Apache 1.2 and up
+<dd>Apply Expires: headers to resources
+<dt><A HREF="mod_headers.html">mod_headers</A> Apache 1.2 and up
+<dd>Add arbitrary HTTP headers to resources
+<dt><A HREF="mod_imap.html">mod_imap</A>
+<dd>The imagemap file handler.
+<dt><A HREF="mod_include.html">mod_include</A>
+<dd>Server-parsed documents.
+<dt><A HREF="mod_info.html">mod_info</a>
+<dd>Server configuration information
+<dt><A HREF="mod_log_agent.html">mod_log_agent</A>
+<dd>Logging of User Agents.
+<dt><A HREF="mod_log_common.html">mod_log_common</A> up to Apache 1.1.1
+<dd>Standard logging in the Common Logfile Format.  Replaced by the 
+mod_log_config module in Apache 1.2 and up
+<dt><A HREF="mod_log_config.html">mod_log_config</A>
+<dd>User-configurable logging replacement for mod_log_common.
+<dt><A HREF="mod_log_referer.html">mod_log_referer</A>
+<dd>Logging of document references.
+<dt><A HREF="mod_mime.html">mod_mime</A>
+<dd>Determining document types.
+<dt><A HREF="mod_negotiation.html">mod_negotiation</A>
+<dd>Content negotiation.
+<dt><A HREF="mod_rewrite.html">mod_rewrite</a> Apache 1.2 and up
+<dd>Powerful URI-to-filename mapping using regular expressions
+<dt><A HREF="mod_proxy.html">mod_proxy</A>
+<dd>Caching proxy abilities
+<dt><A HREF="mod_status.html">mod_status</a>
+<dd>Server status display
+<dt><A HREF="mod_userdir.html">mod_userdir</A>
+<dd>User home directories.
+<dt><A HREF="mod_usertrack.html">mod_usertrack</A> Apache 1.2 and up
+<dd>User tracking using Cookies (replacement for mod_cookies.c) 
+</dl>
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_access.html b/APACHE_1_2_X/htdocs/manual/mod/mod_access.html
new file mode 100644 (file)
index 0000000..80c9983
--- /dev/null
@@ -0,0 +1,176 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<TITLE>Apache module mod_access</TITLE>
+</HEAD>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+
+<H1 ALIGN="CENTER">Module mod_access</h1>
+
+This module is contained in the <code>mod_access.c</code> file, and
+is compiled in by default. It provides access control based on client
+hostname or IP address.
+
+
+<menu>
+<li><A HREF="#allow">allow</A>
+<li><A HREF="#allowfromenv">allow from env=</A>
+<li><A HREF="#deny">deny</A>
+<li><A HREF="#denyfromenv">deny from env=</A>
+<li><A HREF="#order">order</A>
+</menu>
+<hr>
+
+
+<A name="allow"><h2>allow</h2></A>
+<!--%plaintext &lt;?INDEX {\tt allow} directive&gt; -->
+<strong>Syntax:</strong> allow from <em>host host ...</em><br>
+<Strong>Context:</strong> directory, .htaccess<br>
+<Strong>Override:</strong> Limit<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_access<p>
+
+The allow directive affects which hosts can access a given directory.
+<em>Host</em> is one of the following:
+<dl>
+<dt><code>all</code>
+<dd>all hosts are allowed access
+<dt>A (partial) domain-name
+<dd>host whose name is, or ends in, this string are allowed access.
+<dt>A full IP address
+<dd>An IP address of a host allowed access
+<dt>A partial IP address
+<dd>The first 1 to 3 bytes of an IP address, for subnet restriction.
+</dl>
+
+Example:<blockquote><code>allow from .ncsa.uiuc.edu</code></blockquote>
+All hosts in the specified domain are allowed access.<p>
+
+Note that this compares whole components; <code>bar.edu</code>
+would not match <code>foobar.edu</code>.<p>
+
+See also <A HREF="#deny">deny</A>, <A HREF="#order">order</A>, and
+<a href="mod_browser.html#browsermatch">BrowserMatch</a>.<p>
+
+<a name="allowfromenv"><strong>Syntax:</strong> allow from env=<em>variablename</em></a><br>
+<Strong>Context:</strong> directory, .htaccess<br>
+<Strong>Override:</strong> Limit<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_access<br>
+<strong>Compatibility:</strong> Apache 1.2 and above<p>
+
+The allow from env directive controls access to a directory by the
+existence (or non-existence) of an environment variable.
+
+Example:<blockquote><pre>
+BrowserMatch ^KnockKnock/2.0 let_me_in
+&lt;Directory /docroot&gt;
+order allow,deny
+allow from env=let_me_in
+deny from all
+&lt;/Directory&gt;
+</pre></blockquote>
+
+See also <A HREF="#denyfromenv">deny from env</A>
+and <A HREF="#order">order</A>.<p><hr>
+
+<A name="deny"><h2>deny</h2></A>
+<!--%plaintext &lt;?INDEX {\tt deny} directive&gt; -->
+<strong>Syntax:</strong> deny from <em>host host ...</em><br>
+<Strong>Context:</strong> directory, .htaccess<br>
+<Strong>Override:</strong> Limit<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_access<p>
+
+The deny directive affects which hosts can access a given directory.
+<em>Host</em> is one of the following:
+<dl>
+<dt><code>all</code>
+<dd>all hosts are denied access
+<dt>A (partial) domain-name
+<dd>host whose name is, or ends in, this string are denied access.
+<dt>A full IP address
+<dd>An IP address of a host denied access
+<dt>A partial IP address
+<dd>The first 1 to 3 bytes of an IP address, for subnet restriction.
+</dl>
+
+Example:<blockquote><code>deny from 16</code></blockquote>
+All hosts in the specified network are denied access.<p>
+
+Note that this compares whole components; <code>bar.edu</code>
+would not match <code>foobar.edu</code>.<p>
+
+See also <A HREF="#allow">allow</A> and <A HREF="#order">order</A>.<p>
+
+<a name="denyfromenv"><strong>Syntax:</strong> deny from env=<em>variablename</em></a><br>
+<Strong>Context:</strong> directory, .htaccess<br>
+<Strong>Override:</strong> Limit<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_access<br>
+<strong>Compatibility:</strong> Apache 1.2 and above<p>
+
+The deny from env directive controls access to a directory by the
+existence (or non-existence) of an environment variable.
+
+Example:<blockquote><pre>
+BrowserMatch ^BadRobot/0.9 go_away
+&lt;Directory /docroot&gt;
+order deny,allow
+deny from env=go_away
+allow from all
+&lt;/Directory&gt;
+</pre></blockquote>
+
+See also <A HREF="#allowfromenv">allow from env</A>
+and <A HREF="#order">order</A>.<p><hr>
+
+<A name="order"><h2>order</h2></A>
+<!--%plaintext &lt;?INDEX {\tt order} directive&gt; -->
+<strong>Syntax:</strong> order <em>ordering</em><br>
+<strong>Default:</strong> <code>order deny,allow</code><br>
+<strong>Context:</strong> directory, .htaccess<br>
+<strong>Override:</strong> Limit<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_access<p>
+
+The order directive controls the order in which <A HREF="#allow">allow</A> and
+<A HREF="#deny">deny</A> directives are evaluated. <em>Ordering</em> is one
+of
+<dl>
+<dt>deny,allow
+<dd>the deny directives are evaluated before the allow directives.  (The
+initial state is OK.)
+<dt>allow,deny
+<dd>the allow directives are evaluated before the deny directives.  (The
+initial state is FORBIDDEN.)
+<dt>mutual-failure
+<dd>Only those hosts which appear on the allow list and do not appear
+on the deny list are granted access.  (The initial state is irrelevant.)
+</dl>
+
+Note that in all cases every <code>allow</code> and <code>deny</code>
+statement is evaluated, there is no &quot;short-circuiting&quot;.
+
+<p>Example:
+<blockquote><code>
+order deny,allow<br>
+deny from all<br>
+allow from .ncsa.uiuc.edu<br>
+</code></blockquote>
+Hosts in the ncsa.uiuc.edu domain are allowed access; all other hosts are
+denied access.
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
+
diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_actions.html b/APACHE_1_2_X/htdocs/manual/mod/mod_actions.html
new file mode 100644 (file)
index 0000000..03709d5
--- /dev/null
@@ -0,0 +1,85 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<TITLE>Module mod_actions</TITLE>
+</HEAD>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<H1 ALIGN="CENTER">Module mod_actions</h1>
+
+This module is contained in the <code>mod_actions.c</code> file, and
+is compiled in by default. It provides for
+executing CGI scripts based on media type or request method. It is not
+present in versions prior to Apache 1.1.
+
+<h2>Summary</h2>
+
+This module lets you run CGI scripts whenever a file of a certain type
+is requested. This makes it much easier to execute scripts that
+process files.
+
+<h2>Directives</h2>
+<ul>
+<li><A HREF="#action">Action</A>
+<li><A HREF="#script">Script</A>
+</ul>
+
+<hr>
+
+<A name="action"><h2>Action</h2></A>
+<strong>Syntax:</strong> Action <em>mime-type cgi-script</em><br>
+<strong>Context:</strong> server config, virtual host, directory, .htaccess<br>
+<strong>Override:</strong> FileInfo<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_actions<br>
+<strong>Compatibility:</strong> Action is only available in Apache 1.1
+and later<p>
+
+This directive adds an action, which will activate <em>cgi-script</em> when
+a file of content type <em>mime-type</em> is requested. It sends the
+URL and file path of the requested document using the standard
+CGI PATH_INFO and PATH_TRANSLATED environment variables.
+
+<hr>
+
+<A name="script"><h2>Script</h2></A>
+<strong>Syntax:</strong> Script <em>method cgi-script</em><br>
+<strong>Context:</strong> server config, virtual host, directory<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_actions<br>
+<strong>Compatibility:</strong> Script is only available in Apache 1.1
+and later<p>
+
+<p>This directive adds an action, which will activate <em>cgi-script</em> when
+a file is requested using the method of <em>method</em>, which can be
+one of <code>GET</code>, <code>POST</code>, <code>PUT</code> or
+<code>DELETE</code>. It sends the
+URL and file path of the requested document using the standard
+CGI PATH_INFO and PATH_TRANSLATED environment variables. 
+
+<p>Note that the Script command defines default actions only. If a CGI
+script is called, or some other resource that is capable of handling
+the requested method internally, it will do so. Also note that script
+with a method of <code>GET</code> will only be called if there are
+query arguments present (e.g. foo.html?hi). Otherwise, the request
+will proceed normally.
+
+<p>Examples:
+<pre>
+    Script GET /cgi-bin/search     #e.g. for &lt;ISINDEX&gt;-style searching
+    Script PUT /~bob/put.cgi
+
+</pre>
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
+
diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_alias.html b/APACHE_1_2_X/htdocs/manual/mod/mod_alias.html
new file mode 100644 (file)
index 0000000..c5c8925
--- /dev/null
@@ -0,0 +1,146 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<TITLE>Apache module mod_alias</TITLE>
+</HEAD>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+
+<H1 ALIGN="CENTER">Module mod_alias</h1>
+
+This module is contained in the <code>mod_alias.c</code> file, and
+is compiled in by default. It provides for mapping different parts of the
+host filesystem in the the document tree, and for URL redirection.
+
+
+<menu>
+<li><A HREF="#alias">Alias</A>
+<li><A HREF="#redirect">Redirect</A>
+<li><A HREF="#redirecttemp">RedirectTemp</A>
+<li><A HREF="#redirectperm">RedirectPermanent</A>
+<li><A HREF="#scriptalias">ScriptAlias</A>
+</menu>
+<hr>
+
+
+<A name="alias"><h2>Alias</h2></A>
+<!--%plaintext &lt;?INDEX {\tt Alias} directive&gt; -->
+<strong>Syntax:</strong> Alias <em>url-path directory-filename</em><br>
+<Strong>Context:</strong> server config, virtual host<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_alias<br>
+
+The Alias directive allows documents to be stored in the local filesystem
+other than under the <A HREF="core.html#documentroot">DocumentRoot</A>.
+URLs with a (%-decoded) path beginning with <em>url-path</em> will be
+mapped to local files beginning with <em>directory-filename</em>.
+Example:
+<blockquote><code>Alias /image /ftp/pub/image</code></blockquote>
+A request for http://myserver/image/foo.gif would cause the server to
+return the file /ftp/pub/image/foo.gif.<p>
+
+Note that if you include a trailing / on the <em>url-path</em> then the
+server will require a trailing / in order to expand the alias.  That is,
+if you use <code>Alias /icons/ /usr/local/etc/httpd/icons/</code> then
+the url <code>/icons</code> will not be aliased.<p>
+
+See also <A HREF="#scriptalias">ScriptAlias</A>.<p><hr>
+
+<A name="redirect"><h2>Redirect</h2></A>
+<!--%plaintext &lt;?INDEX {\tt Redirect} directive&gt; -->
+<strong>Syntax:</strong> Redirect [ <em>status</em> ] <em>url-path url</em><br>
+<Strong>Context:</strong> server config, virtual host, directory, .htaccess<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_alias<br>
+<strong>Compatibility:</strong> The directory and .htaccess context's
+are only available in versions 1.1 and later. The <em>status</em> argument is only available in Apache 1.2 or later.<p>
+
+The Redirect directive maps an old URL into a new one. The new URL is returned
+to the client which attempts to fetch it again with the new address.
+<em>Url-path</em> a (%-decoded) path; any requests for documents beginning with
+this path will be returned a redirect error to a new (%-encoded) url
+beginning with <em>url</em>. Example:
+<blockquote><code>Redirect /service
+http://foo2.bar.com/service</code></blockquote>
+If the client requests http://myserver/service/foo.txt, it will be told to
+access http://foo2.bar.com/service/foo.txt instead.<p>
+
+Note: Redirect directives take precedence over Alias and ScriptAlias
+directives, irrespective of their ordering in the configuration file.  Also,
+<em>Url-path</em> must be an absolute path, not a relative path, even when used with
+.htaccess files or inside of &lt;Directory&gt; sections.<p>
+
+If no <em>status</em> argument is given, the redirect will be
+"temporary" (HTTP status 302). This indicates to the client that the
+resources is has moved temporarily. The <em>status</em>
+argument can be used to return other HTTP status codes:
+<dl>
+<dt>permanent<dd>Returns a permanent redirect status (301) indicating that
+the resource has moved permanently.
+<dt>temp<dd>Returns a temporary redirect status (302). This is the
+default.
+<dt>seeother<dd>Returns a "See Other" status (303) indicating that
+the resource has been replaced.
+<dt>gone<dd>Returns a "Gone" status (410) indicating that the resource
+has been permanently removed. When this status is used the <em>url</em>
+argument should be omitted.
+</dl>
+
+Other status codes can be returned by giving the numeric status code
+as the value of <em>status</em>. If the status is between 300 and 399,
+the <em>url</em> argument must be present, otherwise it must be
+omitted. Note that the status must be known to the Apache code (see
+the function <code>send_error_response</code> in http_protocol.c).
+
+<A name="redirecttemp"><h2>RedirectTemp</h2></A>
+<!--%plaintext &lt;?INDEX {\tt Redirect} directive&gt; -->
+<strong>Syntax:</strong> RedirectTemp <em>url-path url</em><br>
+<Strong>Context:</strong> server config, virtual host, directory, .htaccess<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_alias<br>
+<strong>Compatibility:</strong> This directive is only available in 1.2<P>
+
+This directive makes the client know that the Redirect is only
+temporary. (Status 302). Exactly equivalent to <code>Redirect temporary </code><P>
+
+<A name="redirectperm"><h2>RedirectPermanent</h2></A>
+<!--%plaintext &lt;?INDEX {\tt Redirect} directive&gt; -->
+<strong>Syntax:</strong> RedirectPermanent <em>url-path url</em><br>
+<Strong>Context:</strong> server config, virtual host, directory, .htaccess<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_alias<br>
+<strong>Compatibility:</strong> This directive is only available in 1.2<P>
+
+This directive makes the client know that the Redirect is permanent.
+(Status 301). Exactly equivalent to <code>Redirect permanent</code><P>
+
+<hr>
+<A name="scriptalias"><h2>ScriptAlias</h2></A>
+<!--%plaintext &lt;?INDEX {\tt ScriptAlias} directive&gt; -->
+<strong>Syntax:</strong> ScriptAlias <em>url-path directory-filename</em><br>
+<Strong>Context:</strong> server config, virtual host<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_alias<br>
+
+The ScriptAlias directive has the same behavior as the
+<A HREF="#alias">Alias</A> directive, except that in addition it
+marks the target directory as containing CGI scripts.
+URLs with a (%-decoded) path beginning with <em>url-path</em> will be
+mapped to scripts beginning with <em>directory-filename</em>.
+Example:
+<blockquote><code>ScriptAlias /cgi-bin/ /web/cgi-bin/</code></blockquote>
+A request for http://myserver/cgi-bin/foo would cause the server to
+run the script /web/cgi-bin/foo.<p>
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
+
diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_asis.html b/APACHE_1_2_X/htdocs/manual/mod/mod_asis.html
new file mode 100644 (file)
index 0000000..85e6281
--- /dev/null
@@ -0,0 +1,68 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<TITLE>Apache module mod_asis</TITLE>
+</HEAD>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+
+<H1 ALIGN="CENTER">Module mod_asis</h1>
+
+This module is contained in the <code>mod_asis.c</code> file, and
+is compiled in by default. It provides for <code>.asis</code> files. Any
+document with mime type <code>httpd/send-as-is</code> will be processed by
+this module.
+<!--%plaintext &lt;?INDEX {\tt httpd/send-as-is} mime type&gt; -->
+
+<h2>Purpose</h2>
+To allow file types to be defined such that Apache sends them without
+adding HTTP headers.<P>
+
+This can be used to send any kind of data from the server, including redirects
+and other special HTTP responses, without requiring a cgi-script or an nph
+script.
+<h2>Usage</h2>
+In the server configuration file, define a new mime type called
+<code>httpd/send-as-is</code> e.g.
+<blockquote><code>AddType httpd/send-as-is asis</code></blockquote>
+this defines the <code>.asis</code> file extension as being of the new
+<code>httpd/send-as-is</code> mime type. The contents of any file with a
+<code>.asis</code> extension will then be sent by Apache to the client with
+almost no changes. Clients will need HTTP headers to be attached, so do not
+forget them. A Status: header is also required; the data should be the
+3-digit HTTP response code, followed by a textual message.<p>
+
+Here's an example of a file whose contents are sent <em>as is</em> so as to
+tell the client that a file has redirected.
+<blockquote><code>
+Status: 302 Now where did I leave that URL <br>
+Location: http://xyz.abc.com/foo/bar.html <br>
+Content-type: text/html <br>
+<br>
+&lt;HTML&gt; <br>
+&lt;HEAD&gt; <br>
+&lt;TITLE&gt;Lame excuses'R'us&lt;/TITLE&gt; <br>
+&lt;/HEAD&gt; <br>
+&lt;BODY&gt; <br>
+&lt;H1&gt;Fred's exceptionally wonderful page has moved to <br>
+&lt;A HREF="http://xyz.abc.com/foo/bar.html"&gt;Joe's&lt;/A&gt; site.  <br>
+&lt;/H1&gt; <br>
+&lt;/BODY&gt; <br>
+&lt;/HTML&gt;
+</code></blockquote>
+Notes: the server always adds a Date: and Server: header to the data returned
+to the client, so these should not be included in the file.
+The server does <em>not</em> add a Last-Modified header; it probably should.
+<P>
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_auth.html b/APACHE_1_2_X/htdocs/manual/mod/mod_auth.html
new file mode 100644 (file)
index 0000000..bfb47a7
--- /dev/null
@@ -0,0 +1,145 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<TITLE>Apache module mod_auth</TITLE>
+</HEAD>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+
+<H1 ALIGN="CENTER">Module mod_auth</h1>
+
+This module is contained in the <code>mod_auth.c</code> file, and
+is compiled in by default. It provides for user authentication using
+textual files.
+
+
+<menu>
+<li><A HREF="#authgroupfile">AuthGroupFile</A>
+<li><A HREF="#authuserfile">AuthUserFile</A>
+<li><A HREF="#authauthoritative">AuthAuthoritative</A>
+</menu>
+<hr>
+
+
+<A name="authgroupfile"><h2>AuthGroupFile</h2></A>
+<!--%plaintext &lt;?INDEX {\tt AuthGroupFile} directive&gt; -->
+<strong>Syntax:</strong> AuthGroupFile <em>filename</em><br>
+<Strong>Context:</strong> directory, .htaccess<br>
+<Strong>Override:</strong> AuthConfig<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_auth<p>
+
+The AuthGroupFile directive sets the name of a textual file containing the list
+of user groups for user authentication. <em>Filename</em> is the absolute path
+to the group file.<p>
+Each line of the group file contains a groupname followed by a colon, followed
+by the member usernames separated by spaces. Example:
+<blockquote><code>mygroup: bob joe anne</code></blockquote>
+Note that searching large groups files is <em>very</em> inefficient;
+<A HREF="mod_auth_dbm.html#authdbmgroupfile">AuthDBMGroupFile</A> should
+be used instead.<p>
+
+Security: make sure that the AuthGroupFile is stored outside the
+document tree of the web-server; do <em>not</em> put it in the directory that
+it protects. Otherwise, clients will be able to download the AuthGroupFile.<p>
+
+See also <A HREF="core.html#authname">AuthName</A>,
+<A HREF="core.html#authtype">AuthType</A> and
+<A HREF="#authuserfile">AuthUserFile</A>.<p><hr>
+
+<A name="authuserfile"><h2>AuthUserFile</h2></A>
+<!--%plaintext &lt;?INDEX {\tt AuthUserFile} directive&gt; -->
+<strong>Syntax:</strong> AuthUserFile <em>filename</em><br>
+<Strong>Context:</strong> directory, .htaccess<br>
+<Strong>Override:</strong> AuthConfig<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_auth<p>
+
+The AuthUserFile directive sets the name of a textual file containing
+the list of users and passwords for user
+authentication. <em>Filename</em> is the absolute path to the user
+file.<p> Each line of the user file file contains a username followed
+by a colon, followed by the crypt() encrypted password. The behavior
+of multiple occurrences of the same user is undefined.<p> Note that
+searching user groups files is inefficient; <A
+HREF="mod_auth_dbm.html#authdbmuserfile">AuthDBMUserFile</A> should be
+used instead.<p>
+
+Security: make sure that the AuthUserFile is stored outside the
+document tree of the web-server; do <em>not</em> put it in the directory that
+it protects. Otherwise, clients will be able to download the AuthUserFile.<p>
+
+See also <A HREF="core.html#authname">AuthName</A>,
+<A HREF="core.html#authtype">AuthType</A> and
+<A HREF="#authgroupfile">AuthGroupFile</A>.<p>
+<hr>
+<A name="authauthoritative"><h2>AuthAuthoritative</h2></A>
+<!--%plaintext &lt;?INDEX {\tt AuthAuthoritative} directive&gt; -->
+<strong>Syntax:</strong> AuthAuthoritative &lt; <strong> on</strong>(default) | off &gt; <br>
+<Strong>Context:</strong> directory, .htaccess<br>
+<Strong>Override:</strong> AuthConfig<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_auth<p>
+
+Setting the AuthAuthoritative directive explicitly to <b>'off'</b>
+allows for both authentication and authorization to be passed on to
+lower level modules (as defined in the <code>Configuration</code> and
+<code>modules.c</code> files) if there is <b>no userID</b> or
+<b>rule</b> matching the supplied userID. If there is a userID and/or
+rule specified; the usual password and access checks will be applied
+and a failure will give an Authorization Required reply.
+
+<p>
+
+So if a userID appears in the database of more than one module; or if
+a valid require directive applies to more than one module; then the
+first module will verify the credentials; and no access is passed on;
+regardless of the AuthAuthoritative setting.
+
+<p>
+
+A common use for this is in conjunction with one of the database
+modules; such as <a
+href="mod_auth_db.html"><code>mod_auth_db.c</code></a>, <a
+href="mod_auth_dbm.html"><code>mod_auth_dbm.c</code></a>, <a
+href="mod_auth_msql.html"><code>mod_auth_msql.c</code></a> and <a
+href="mod_auth_anon.html"><code>mod_auth_anon.c</code></a>. These modules
+supply the bulk of the user credential checking; but a few
+(administrator) related accesses fall through to a lower level with a
+well protected AuthUserFile.
+
+<p>
+
+<b>Default:</b> By default; control is not passed on; and an unknown
+userID or rule will result in an Authorization Required reply. Not
+setting it thus keeps the system secure; and forces an NSCA compliant
+behaviour.
+
+<p>
+
+Security: Do consider the implications of allowing a user to allow
+fall-through in his .htaccess file; and verify that this is really
+what you want; Generally it is easier to just secure a single
+.htpasswd file, than it is to secure a database such as mSQL. Make
+sure that the AuthUserFile is stored outside the document tree of the
+web-server; do <em>not</em> put it in the directory that it
+protects. Otherwise, clients will be able to download the
+AuthUserFile.
+
+<p>
+See also <A HREF="core.html#authname">AuthName</A>,
+<A HREF="core.html#authtype">AuthType</A> and
+<A HREF="#authgroupfile">AuthGroupFile</A>.<p>
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
+
diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_auth_anon.html b/APACHE_1_2_X/htdocs/manual/mod/mod_auth_anon.html
new file mode 100644 (file)
index 0000000..c880c34
--- /dev/null
@@ -0,0 +1,249 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<TITLE>Apache module mod_auth_anon.c</TITLE>
+</HEAD>
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<H1 ALIGN="CENTER">Module mod_auth_anon</H1>
+
+This module is contained in the <code>mod_auth_anon.c</code> file and
+is not compiled in by default. It is only available in Apache 1.1 and
+later. It allows "anonymous" user access to authenticated areas.
+
+<h2>Summary</h2>
+
+It does access control in a manner similar to anonymous-ftp sites; i.e.
+have a 'magic' user id 'anonymous' and the email address as a password.
+These email addresses can be logged.
+<p>
+Combined with other (database) access control methods, this allows for
+effective user tracking and customization according to a user profile
+while still keeping the site open for 'unregistered' users. One advantage
+of using Auth-based user tracking is that, unlike magic-cookies and
+funny URL pre/postfixes, it is completely browser independent and it
+allows users to share URLs.
+<p>
+
+<a href="#Directives">Directives</a> /
+<a href="#Example">Example</a> /
+<a href="#CompileTimeOptions">Compile time options</a> /
+<a href="#RevisionHistory">RevisionHistory</a> /
+<a href="#Person">Person to blame</a> /
+<a href="#Sourcecode">Sourcecode</a>
+<p>
+
+<h2><a name="Directives">Directives</a></h2>
+<ul>
+<li><A HREF="#anonymous">Anonymous</A>
+<li><A HREF="#Authoritative">Anonymous_Authoritative</A>
+<li><A HREF="#LogEmail">Anonymous_LogEmail</A>
+<li><A HREF="#MustGiveEmail">Anonymous_MustGiveEmail</A>
+<li><A HREF="#NoUserID">Anonymous_NoUserID</A>
+<li><A HREF="#VerifyEmail">Anonymous_VerifyEmail</A>
+</ul>
+
+<hr>
+
+<A name="anonymous"><h2>Anonymous</h2></a>
+<!--%plaintext &lt;?INDEX {\tt Anonymous} directive&gt; -->
+<strong>Syntax:</strong> Anonymous <em>user user ...</em><br>
+<strong>Default:</strong> none<br>
+<strong>Context:</strong> directory, .htaccess<br>
+<strong>Override:</strong> AuthConfig<br>
+<strong>Status:</strong> Extension<br>
+<strong>Module:</strong> mod_auth_anon<p>
+
+       A list of one or more 'magic' userIDs which are allowed access
+       without password verification. The userIDs are space separated.
+       It is possible to use the ' and " quotes to allow a space in
+       a userID as well as the \ escape character.
+       <p>
+       Please note that the comparison is <b>case-IN-sensitive</b>.
+       <br>
+       I strongly suggest that the magic username '<code>anonymous</code>'
+       is always one of the allowed userIDs.
+       <p>
+       Example:<br>
+       <code>
+       Anonymous: anonymous "Not Registered" 'I don\'t know'
+       </code><p>
+       This would allow the user to enter without password verification
+       by using the userId's 'anonymous', 'AnonyMous','Not Registered' and
+       'I Don't Know'.
+<HR>
+
+<A name="Authoritative"><h2>Anonymous_Authoritative</h2></A>
+<strong>Syntax:</strong> Anonymous_Authoritative <em>on | off</em><br>
+<strong>Default:</strong> <code>Anonymous_Authoritative off</code><br>
+<strong>Context:</strong> directory, .htaccess<br>
+<strong>Override:</strong> AuthConfig<br>
+<strong>Status:</strong> Extension<br>
+<strong>Module:</strong> mod_auth_anon<p>
+
+        When set 'on', there is no
+        fall-through to other authorization methods. So if a
+        userID does not match the values specified in the
+       <code>Anonymous</code> directive, access is denied.
+       <p>
+       Be sure you know what you are doing when you decide to switch 
+       it on. And remember that it is the linking order of the modules
+       (in the Configuration / Make file) which details the order
+       in which the Authorization modules are queried.
+<hr>
+
+<A name="LogEmail"><h2>Anonymous_LogEmail</h2></A>
+<strong>Syntax:</strong> Anonymous_LogEmail <em>on | off</em><br>
+<strong>Default:</strong> <code>off</code><br>
+<strong>Context:</strong> directory, .htaccess<br>
+<strong>Override:</strong> AuthConfig<br>
+<strong>Status:</strong> Extension<br>
+<strong>Module:</strong> mod_auth_anon<p>
+
+       When set 'on', the default, the 'password' entered (which hopefully
+       contains a sensible email address) is logged in the httpd-log file.
+<hr>
+
+<A name="MustGiveEmail"><h2>Anonymous_MustGiveEmail</h2></a>
+<!--%plaintext &lt;?INDEX {\tt Anonymous_MustGiveEmail} directive&gt; -->
+<strong>Syntax:</strong> Anonymous_MustGiveEmail <em>on</em> | <em>off</em><br>
+<strong>Default:</strong> off<br>
+<strong>Context:</strong> directory, .htaccess<br>
+<strong>Override:</strong> AuthConfig<br>
+<strong>Status:</strong> Extension<br>
+<strong>Module:</strong> mod_auth_anon<p>
+
+       Specifies whether the user must specify an email
+       address as the password.  This prohibits blank passwords.
+<HR>
+
+<A name="NoUserID"><h2>Anonymous_NoUserID</h2></A>
+<strong>Syntax:</strong> Anonymous_NoUserID <em>on | off</em><br>
+<strong>Default:</strong> <code>Anonymous_NoUserID off</code><br>
+<strong>Context:</strong> directory, .htaccess<br>
+<strong>Override:</strong> AuthConfig<br>
+<strong>Status:</strong> Extension<br>
+<strong>Module:</strong> mod_auth_anon<p>
+
+       When set 'on', users can leave
+       the userID (and perhaps the password field) empty. This
+       can be very convenient for MS-Explorer users who can
+       just hit return or click directly on the OK button; which
+       seems a natural reaction.
+
+<hr>
+
+<A name="VerifyEmail"><h2>Anonymous_VerifyEmail</h2></A>
+<strong>Syntax:</strong> Anonymous <em>on | off</em><br>
+<strong>Default:</strong> <code>Anonymous_VerifyEmail off</code><br>
+<strong>Context:</strong> directory, .htaccess<br>
+<strong>Override:</strong> AuthConfig<br>
+<strong>Status:</strong> Extension<br>
+<strong>Module:</strong> mod_auth_anon<p>
+
+       When set 'on' the 'password' entered is
+       checked for at least one '@' and a '.' to encourage users to enter
+       valid email addresses (see the above <code>Auth_LogEmail</code>).
+
+<hr><a name="Example"><h2>Example</h2></a>
+
+The example below (when combined with the Auth directives
+of a htpasswd-file based (or GDM, mSQL etc) base access
+control system allows users in as 'guests' with the
+following properties:
+<ul>
+<li>
+It insists that the user enters a userId. (<code>Anonymous_NoUserId</code>)
+<li>
+It insists that the user enters a password. (<code>Anonymous_MustGiveEmail</code>)
+<li>
+The password entered must be a valid email address, ie. contain at least one '@' and a '.'.
+(<code>Anonymous_VerifyEmail</code>)
+<li>
+The userID must be one of <code>anonymous guest www test welcome</code>
+and comparison is <b>not</b> case sensitive.
+<code>&lt;directory /web/docs/public&gt;</code>
+<li>
+And the Email addresses entered in the passswd field are logged to
+the httpd-log file
+(<code>Anonymous_LogEmail</code>)
+</ul>
+<p>
+Excerpt of access.conf:
+<dl>
+<dt><code>
+Anonymous        anonymous guest www test welcome<p>
+Anonymous_MustGiveEmail        on<br>
+Anonymous_VerifyEmail    on<br>
+Anonymous_NoUserId     off<br>
+Anonymous_LogEmail     on<br>
+<p>
+AuthName                Use 'anonymous' & Email address for guest entry<br>
+AuthType                basic<p>
+
+</code></dt>
+<dd>
+                Normal Apache/NCSA tokens for access control
+                <p>
+                <code>&lt;limit get post head&gt</code><br>
+                <code>order deny,allow          </code><br>
+                <code>allow from all            </code><br>
+                <p>
+                <code>require valid-user        </code><br>
+                <code>&lt;limit&gt              </code><br>
+</dd>
+</dl>
+
+
+<hr><h2><a name="CompileTimeOptions">Compile Time Options</a></h2>
+
+Currently there are no Compile options.
+
+<hr><h2><a name="RevisionHistory">Revision History</a></h2>
+
+This version: 23 Nov 1995, 24 Feb 1996, 16 May 1996.
+
+<dl>
+
+<dt>Version 0.4<br></dt>
+    <dd>First release
+    </dd>
+<dt>Version 0.5<br></dt>
+    <dd>Added 'VerifyEmail' and 'LogEmail' options. Multiple
+       'anonymous' tokens allowed. more docs. Added Authoritative
+       functionality.
+    </dd>
+</dl>
+
+
+<hr><h2><a name="Person">Contact/person to blame</a></h2>
+
+This module was written for the
+<a href="http://ewse.ceo.org">European Wide Service Exchange</a> by
+&lt<a href="mailto:Dirk.vanGulik@jrc.it"><code>Dirk.vanGulik@jrc.it</code></a>&gt.
+Feel free to contact me if you have any problems, ice-creams or bugs. This
+documentation, courtesy of Nick Himba, <a href="mailto:himba@cs.utwente.nl">
+<code>&lt;himba@cs.utwente.nl&gt;</code></a>.
+<p>
+
+
+<hr><h2><a NAME="Sourcecode">Sourcecode</a></h2>
+
+The source code can be found at <a href="http://www.apache.org"><code>
+http://www.apache.org</code></a>. A snapshot of a development version
+usually resides at <a href="http://me-www.jrc.it/~dirkx/mod_auth_anon.c"><code>
+http://me-www.jrc.it/~dirkx/mod_auth_anon.c</code></a>. Please make sure
+that you always quote the version you use when filing a bug report.
+<p>
+
+<!--#include virtual="footer.html" -->
+</body>
+</html>
+
diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_auth_db.html b/APACHE_1_2_X/htdocs/manual/mod/mod_auth_db.html
new file mode 100644 (file)
index 0000000..d97035b
--- /dev/null
@@ -0,0 +1,160 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<TITLE>Apache module mod_auth_db</TITLE>
+</HEAD>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<H1 ALIGN="CENTER">Module mod_auth_db</h1>
+
+This module is contained in the <code>mod_auth_db.c</code> file, and
+is not compiled in by default. It provides for user authentication using
+Berkeley DB files. It is an alternative to <A HREF="mod_auth_dbm.html">DBM</A>
+files for those systems which support DB and not DBM. It is only
+available in Apache 1.1 and later.
+
+
+<menu>
+<li><A HREF="#authdbgroupfile">AuthDBGroupFile</A>
+<li><A HREF="#authdbuserfile">AuthDBUserFile</A>
+<li><A HREF="#authdbauthoritative">AuthDBAuthoritative</A>
+</menu>
+<hr>
+
+
+<A name="authdbgroupfile"><h2>AuthDBGroupFile</h2></A>
+<!--%plaintext &lt;?INDEX {\tt AuthDBGroupFile} directive&gt; -->
+<strong>Syntax:</strong> AuthDBGroupFile <em>filename</em><br>
+<Strong>Context:</strong> directory, .htaccess<br>
+<Strong>Override:</strong> AuthConfig<br>
+<strong>Status:</strong> Extension<br>
+<strong>Module:</strong> mod_auth_db<p>
+
+The AuthDBGroupFile directive sets the name of a DB file containing the list
+of user groups for user authentication. <em>Filename</em> is the absolute path
+to the group file.<p>
+
+The group file is keyed on the username. The value for a user is a
+comma-separated list of the groups to which the users belongs. There must
+be no whitespace within the value, and it must never contain any colons.<p>
+
+Security: make sure that the AuthDBGroupFile is stored outside the
+document tree of the web-server; do <em>not</em> put it in the directory that
+it protects. Otherwise, clients will be able to download the
+AuthDBGroupFile unless otherwise protected.<p>
+
+Combining Group and Password DB files: In some cases it is easier to
+manage a single database which contains both the password and group
+details for each user. This simplifies any support programs that need
+to be written: they now only have to deal with writing to and locking
+a single DBM file. This can be accomplished by first setting the group
+and password files to point to the same DB file:<p>
+
+<blockquote><code>
+AuthDBGroupFile /www/userbase<br>
+AuthDBUserFile /www/userbase
+</code></blockquote>
+
+The key for the single DB record is the username. The value consists of <p>
+
+<blockquote><code>
+Unix Crypt-ed Password : List of Groups [ : (ignored) ]
+</code></blockquote>
+
+The password section contains the Unix crypt() password as before. This is
+followed by a colon and the comma separated list of groups. Other data may
+optionally be left in the DB file after another colon; it is ignored by the
+authentication module. <p>
+
+See also <A HREF="core.html#authname">AuthName</A>,
+<A HREF="core.html#authtype">AuthType</A> and
+<A HREF="#authdbuserfile">AuthDBUserFile</A>.<p><hr>
+
+<A name="authdbuserfile"><h2>AuthDBUserFile</h2></A>
+<!--%plaintext &lt;?INDEX {\tt AuthDBUserFile} directive&gt; -->
+<strong>Syntax:</strong> AuthDBUserFile <em>filename</em><br>
+<Strong>Context:</strong> directory, .htaccess<br>
+<Strong>Override:</strong> AuthConfig<br>
+<strong>Status:</strong> Extension<br>
+<strong>Module:</strong> mod_auth_db<p>
+
+The AuthDBUserFile directive sets the name of a DB file containing the list
+of users and passwords for user authentication. <em>Filename</em> is the
+absolute path to the user file.<p>
+
+The user file is keyed on the username. The value for a user is the
+crypt() encrypted password, optionally followed by a colon and
+arbitrary data.  The colon and the data following it will be ignored
+by the server.<p>
+
+Security: make sure that the AuthDBUserFile is stored outside the
+document tree of the web-server; do <em>not</em> put it in the directory that
+it protects. Otherwise, clients will be able to download the
+AuthDBUserFile.<p>
+
+Important compatibility note: The implementation of "dbmopen" in the
+apache modules reads the string length of the hashed values from the
+DB data structures, rather than relying upon the string being
+NULL-appended. Some applications, such as the Netscape web server,
+rely upon the string being NULL-appended, so if you are having trouble
+using DB files interchangeably between applications this may be a
+part of the problem. <p>
+
+See also <A HREF="core.html#authname">AuthName</A>,
+<A HREF="core.html#authtype">AuthType</A> and
+<A HREF="#authdbgroupfile">AuthDBGroupFile</A>.<p>
+<hr>
+<A name="authdbauthoritative"><h2>AuthDBAuthoritative</h2></A>
+<!--%plaintext &lt;?INDEX {\tt AuthDBAuthoritative} directive&gt; -->
+<strong>Syntax:</strong> AuthDBAuthoritative &lt; <strong> on</strong>(default) | off &gt; <br>
+<Strong>Context:</strong> directory, .htaccess<br>
+<Strong>Override:</strong> AuthConfig<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_auth<p>
+
+Setting the AuthDBAuthoritative directive explicitly to <b>'off'</b>
+allows for both authentication and authorization to be passed on
+to lower level modules (as defined in the <code>Configuration</code>
+and <code>modules.c</code> file if there is <b>no userID</b> or
+<b>rule</b> matching the supplied userID. If there is a userID
+and/or rule specified; the usual password and access checks will
+be applied and a failure will give an Authorization Required reply.
+<p>
+So if a userID appears in the database of more than one module; or
+if a valid require directive applies to more than one module; then
+the first module will verify the credentials; and no access is
+passed on; regardless of the AuthAuthoritative setting.  <p>
+
+A common use for this is in conjunction with one of the basic auth
+modules; such as <a href="mod_auth.html"><code>mod_auth.c</code></a>.
+Whereas this DB module supplies the bulk of the user credential
+checking; a few (administrator) related accesses fall through to
+a lower level with a well protected .htpasswd file.  <p>
+
+<b>Default:</b> By default; control is not passed on; and an unknown
+userID or rule will result in an Authorization Required reply. Not
+setting it thus keeps the system secure; and forces an NSCA compliant
+behaviour.  <p>
+Security: Do consider the implications of allowing a user to allow
+fall-through in his .htaccess file; and verify that this is really
+what you want; Generally it is easier to just secure a single
+.htpasswd file, than it is to secure a database which might have
+more access interfaces.
+
+<p>
+See also <A HREF="core.html#authname">AuthName</A>,
+<A HREF="core.html#authtype">AuthType</A> and
+<A HREF="#authdbgroupfile">AuthDBGroupFile</A>.<p>
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
+
diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_auth_dbm.html b/APACHE_1_2_X/htdocs/manual/mod/mod_auth_dbm.html
new file mode 100644 (file)
index 0000000..42e0b64
--- /dev/null
@@ -0,0 +1,162 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<TITLE>Apache module mod_auth_dbm</TITLE>
+</HEAD>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+
+<H1 ALIGN="CENTER">Module mod_auth_dbm</h1>
+
+This module is contained in the <code>mod_auth_dbm.c</code> file, and
+is not compiled in by default. It provides for user authentication using
+DBM files. 
+
+
+<menu>
+<li><A HREF="#authdbmgroupfile">AuthDBMGroupFile</A>
+<li><A HREF="#authdbmuserfile">AuthDBMUserFile</A>
+<li><A HREF="#authdbmauthoritative">AuthDBMAuthoritative</A>
+</menu>
+<hr>
+
+
+<A name="authdbmgroupfile"><h2>AuthDbmGroupFile</h2></A>
+<!--%plaintext &lt;?INDEX {\tt AuthDbmGroupFile} directive&gt; -->
+<strong>Syntax:</strong> AuthDBMGroupFile <em>filename</em><br>
+<Strong>Context:</strong> directory, .htaccess<br>
+<Strong>Override:</strong> AuthConfig<br>
+<strong>Status:</strong> Extension<br>
+<strong>Module:</strong> mod_auth_dbm<p>
+
+The AuthDBMGroupFile directive sets the name of a DBM file containing the list
+of user groups for user authentication. <em>Filename</em> is the absolute path
+to the group file.<p>
+
+The group file is keyed on the username. The value for a user is a
+comma-separated list of the groups to which the users belongs. There must
+be no whitespace within the value, and it must never contain any colons.<p>
+
+Security: make sure that the AuthDBMGroupFile is stored outside the
+document tree of the web-server; do <em>not</em> put it in the directory that
+it protects. Otherwise, clients will be able to download the
+AuthDBMGroupFile unless otherwise protected.<p>
+
+Combining Group and Password DBM files: In some cases it is easier to
+manage a single database which contains both the password and group
+details for each user. This simplifies any support programs that need
+to be written: they now only have to deal with writing to and locking
+a single DBM file. This can be accomplished by first setting the group
+and password files to point to the same DBM:<p>
+
+<blockquote><code>
+AuthDBMGroupFile /www/userbase<br>
+AuthDBMUserFile /www/userbase
+</code></blockquote>
+
+The key for the single DBM is the username. The value consists of <p>
+
+<blockquote><code>
+Unix Crypt-ed Password : List of Groups [ : (ignored) ]
+</code></blockquote>
+
+The password section contains the Unix crypt() password as before. This is
+followed by a colon and the comma separated list of groups. Other data may
+optionally be left in the DBM file after another colon; it is ignored by the
+authentication module. This is what www.telescope.org uses for its combined
+password and group database. <p>
+
+See also <A HREF="core.html#authname">AuthName</A>,
+<A HREF="core.html#authtype">AuthType</A> and
+<A HREF="#authdbmuserfile">AuthDBMUserFile</A>.<p><hr>
+
+<A name="authdbmuserfile"><h2>AuthDBMUserFile</h2></A>
+<!--%plaintext &lt;?INDEX {\tt AuthDBMUserFile} directive&gt; -->
+<strong>Syntax:</strong> AuthDBMUserFile <em>filename</em><br>
+<Strong>Context:</strong> directory, .htaccess<br>
+<Strong>Override:</strong> AuthConfig<br>
+<strong>Status:</strong> Extension<br>
+<strong>Module:</strong> mod_auth_dbm<p>
+
+The AuthDBMUserFile directive sets the name of a DBM file containing the list
+of users and passwords for user authentication. <em>Filename</em> is the
+absolute path to the user file.<p>
+
+The user file is keyed on the username. The value for a user is the
+crypt() encrypted password, optionally followed by a colon and
+arbitrary data.  The colon and the data following it will be ignored
+by the server.<p>
+
+Security: make sure that the AuthDBMUserFile is stored outside the
+document tree of the web-server; do <em>not</em> put it in the directory that
+it protects. Otherwise, clients will be able to download the
+AuthDBMUserFile.<p>
+
+Important compatibility note: The implementation of "dbmopen" in the
+apache modules reads the string length of the hashed values from the
+DBM data structures, rather than relying upon the string being
+NULL-appended. Some applications, such as the Netscape web server,
+rely upon the string being NULL-appended, so if you are having trouble
+using DBM files interchangeably between applications this may be a
+part of the problem. <p>
+
+See also <A HREF="core.html#authname">AuthName</A>,
+<A HREF="core.html#authtype">AuthType</A> and
+<A HREF="#authdbmgroupfile">AuthDBMGroupFile</A>.<p>
+
+<hr>
+<A name="authdbmauthoritative"><h2>AuthDBMAuthoritative</h2></A>
+<!--%plaintext &lt;?INDEX {\tt AuthDBMAuthoritative} directive&gt; -->
+<strong>Syntax:</strong> AuthDBMAuthoritative &lt; <strong> on</strong>(default) | off &gt; <br>
+<Strong>Context:</strong> directory, .htaccess<br>
+<Strong>Override:</strong> AuthConfig<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_auth<p>
+
+Setting the AuthDBMAuthoritative directive explicitly to <b>'off'</b>
+allows for both authentication and authorization to be passed on
+to lower level modules (as defined in the <code>Configuration</code>
+and <code>modules.c</code> file if there is <b>no userID</b> or
+<b>rule</b> matching the supplied userID. If there is a userID
+and/or rule specified; the usual password and access checks will
+be applied and a failure will give an Authorization Required reply.
+<p>
+So if a userID appears in the database of more than one module; or
+if a valid require directive applies to more than one module; then
+the first module will verify the credentials; and no access is
+passed on; regardless of the AuthAuthoritative setting.  <p>
+
+A common use for this is in conjunction with one of the basic auth
+modules; such as <a href="mod_auth.html"><code>mod_auth.c</code></a>.
+Whereas this DBM module supplies the bulk of the user credential
+checking; a few (administrator) related accesses fall through to
+a lower level with a well protected .htpasswd file.  <p>
+
+<b>Default:</b> By default; control is not passed on; and an unknown
+userID or rule will result in an Authorization Required reply. Not
+setting it thus keeps the system secure; and forces an NSCA compliant
+behaviour.  <p>
+
+Security: Do consider the implications of allowing a user to allow
+fall-through in his .htaccess file; and verify that this is really
+what you want; Generally it is easier to just secure a single
+.htpasswd file, than it is to secure a database which might have
+more access interfaces.
+
+<p>
+See also <A HREF="core.html#authname">AuthName</A>,
+<A HREF="core.html#authtype">AuthType</A> and
+<A HREF="#authdbmgroupfile">AuthDBMGroupFile</A>.<p>
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
+
diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_auth_msql.html b/APACHE_1_2_X/htdocs/manual/mod/mod_auth_msql.html
new file mode 100644 (file)
index 0000000..f1cae19
--- /dev/null
@@ -0,0 +1,475 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<title>Module mod_auth_msql</title>
+</head>
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<H1 ALIGN="CENTER">Module mod_auth_msql</H1>
+
+This module is contained in the <code>mod_auth_msql.c</code> file and
+is compiled in by default.  It allows access control using the public
+domain mSQL database <code><a
+href="ftp://ftp.bond.edu.au/pub/Minerva/msql">ftp://ftp.bond.edu.au/pub/Minerva/msql</a></code>,
+a fast but limited SQL engine which can be contacted over an internal
+Unix domain protocol as well as over normal TCP/IP socket
+communication. It is only available in Apache 1.1 and later. <p>
+
+<a href="#FullDescription">Full description</a> /
+<a href="#Example">Example</a> /
+<a href="#CompileTimeOptions">Compile time options</a> /
+<a href="#RevisionHistory">RevisionHistory</a> /
+<a href="#Person">Person to blame</a> /
+<a href="#Sourcecode">Sourcecode</a>
+<p>
+
+<hr><h2><a name="FullDescription">Full description of all tokens</a></h2>
+<dl>
+
+<code><dt>
+Auth_MSQLhost &lt; FQHN | IP Address | localhost &gt
+</dt></code><dd>
+        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 <code>localhost</code>, it is passed to the mSQL library as a null
+        pointer. This effectively forces it to use /dev/msql rather than the
+        (slower) socket communication.
+</dd>
+
+<code><dt>
+Auth_MSQLdatabase &lt; mSQL database name &gt
+</dt></code><dd>
+        Name of the database in which the following table(s) are contained (Quick check: use the
+        mSQL command <code>relshow [&lt;hostname&gt dbase]</code> to verify the spelling of the
+        database name).
+</dd>
+
+<code><dt>
+Auth_MSQLpwd_table &lt; mSQL table name &gt
+</dt></code><dd>
+        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 <a href="#Authoritative"><code>Auth_MSQL_Authoritative</code></a>
+        directive below.
+</dd>
+
+<code><dt>
+Auth_MSQLgrp_table &lt; mSQL table name in the above database &gt
+</dt></code><dd>
+        Contains at least the fields with the
+        username and the groupname. A user which
+        is in multiple groups has therefore
+        multiple entries. There might be some performance
+        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 need to specify this table when doing
+        group control.
+</dd>
+
+<code><dt>
+Auth_MSQLuid_field &lt; mSQL field name &gt
+</dt></code><dd>
+        Name of the field containing the username in the <code>
+        Auth_MSQLpwd_table</code> and optionally in the <code>
+        Auth_MSQLgrp_table</code> tables.
+</dd>
+
+<code><dt>
+Auth_MSQLpwd_field &lt; mSQL field name &gt
+</dt></code><dd>
+        Fieldname for the passwords in the <code>
+        Auth_MSQLpwd_table</code> table.
+</dd>
+
+<code><dt>
+Auth_MSQLgrp_field &lt; mSQL field name &gt
+</dt></code><dd>
+        Fieldname for the groupname<br>
+        Only the fields used need to be specified. When this
+        module is compiled with the
+        <a href="#VITEK"><code>BACKWARD_VITEK</code></a> option then
+        the uid and pwd field names default to 'user' and 'password'.
+        However you are strongly encouraged to always specify these values
+        explicitly given the security issues involved.
+</dd>
+
+<code><dt>
+Auth_MSQL_nopasswd &lt; on | off &gt
+</dt></code><dd>
+        Skip password comparison if passwd field is
+        empty, i.e. allow any password. This is 'off'
+        by default to ensure that an empty field
+        in the mSQL table does not allow people in by
+        default with a random password.
+</dd>
+
+<code><dt>
+<a name="Authoritative">Auth_MSQL_Authoritative &lt; on | off &gt</a>
+</dt></code><dd>
+        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 with the htpasswd
+        file or the Unix-(g)dbm modules. The default is 'on'
+        to avoid nasty 'fall-through' surprises. Be sure you
+        know what you are doing when you decide to switch it off.
+</dd>
+
+<code><dt>
+Auth_MSQL_EncryptedPasswords &lt; on | off &gt
+</dt></code><dd>
+        Default is 'on'. When set on, the values in the
+        pwd_field are assumed to be crypt-ed 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 think 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.
+</dd>
+</dl>
+
+
+<hr><h2><a name="Example">Example</a></h2>
+
+An example mSQL table could be created with the following commands:
+<pre>
+     % msqladmin create www               <br>
+     % msql www                           <br>
+     -> create table user_records (       <br>
+     ->   User_id  char(32) primary key,  <br>
+     ->   Cpasswd  char(32),              <br>
+     ->   Xgroup   char(32)               <br>
+     ->   ) \g                            <br>
+     query OK                             <br>
+     -> \q                                <br>
+     %                                    <br>
+</pre><br>
+
+The <code>User_id</code> can be as long as desired. However some of the
+popular web browsers truncate names at 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 <code>require users uid [uid..]</code> directive in the
+<code>access.conf</code> file where the uid's are separated by
+spaces can possibly prohibit the use of spaces in your usernames.
+Also, please note the <a href="#MAX_FIELD_LEN"><code>MAX_FIELD_LEN</code></a>
+directive somewhere below.
+<p>
+To use the above, the following example could be in your
+<code>access.conf</code> file. Also there is a more elaborate description
+below this example.
+<p>
+
+<code>&lt;directory /web/docs/private&gt;</code>
+<p>
+
+<dl>
+<dt><code>
+Auth_MSQLhost        localhost<br>
+</code></dt>
+    <blockquote>or</blockquote>
+<dt><code>
+Auth_MSQLhost        datab.machine.your.org
+</code></dt><dd>
+                If this directive is omitted or set to <code>localhost</code>,
+                it is assumed that Apache and the mSQL
+                database run on the same (physical) machine and the faster
+                /dev/msql communication channel will be used. Otherwise,
+                it is the machine to contact by TCP/IP. Consult the mSQL
+                documentation for more information.
+</dd>
+<p>
+
+<dt><code>
+Auth_MSQLdatabase    www
+</code></dt><dd>
+                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 <code>msql.acl</code> (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.
+</dd>
+
+<code><dt>
+Auth_MSQLpwd_table   user_records
+</dt></code><dd>
+                This is the table which contain the uid/password combination
+                is specified.
+</dd>
+
+<code><dt>
+Auth_MSQLuid_field   User_id <br>
+Auth_MSQLpwd_field   Cpasswd
+</dt></code><dd>
+                These two directive specify the field names in the <code>user_record</code>
+                table. If this module is compiled with the <a href="#VITEK"><code>BACKWARD_VITEK</code></a>
+                compatibility switch, the defaults <code>user</code> and <code>password</code> 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 <b>once</b> in the table. If a uid occurs twice access is
+                denied by default; but see the <code><a href="#ONLY_ONCE">ONLY_ONCE</a></code>
+                compiler directive for more information.
+</dd>
+
+<code><dt>
+Auth_MSQLgrp_table   user_records <br>
+Auth_MSQLgrp_field   Xgroup       <br>
+</dt></code><dd>
+                Optionally 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 different table with multiple entries.
+</dd>
+
+<code><dt>
+Auth_MSQL_nopasswd           off <br>
+Auth_MSQL_Authoritative        on  <br>
+Auth_MSQL_EncryptedPasswords on  <br>
+</dt></code><dd>
+                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 then
+                the above, be very sure you understand the security implications and
+                do verify that Apache does what you expect it to do.
+</dd>
+
+<code><dt>
+AuthName                example mSQL realm <br>
+AuthType                basic
+</dt></code>
+<dd>
+                Normal Apache/NCSA tokens for access control
+                <p>
+                <code>&lt;limit get post head&gt</code><br>
+                <code>order deny,allow          </code><br>
+                <code>allow from all            </code><br>
+                <p>
+                <code>require valid-user        </code><br>
+                    <ul><li><code>valid-user</code>; allow in any user which has a valid uid/passwd
+                    pair in the above pwd_table.
+                    </ul>
+                or<br>
+                <code>require user smith jones  </code><br>
+                    <ul><li>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.
+                    </ul>
+                <code>require group has_paid</code><br>
+                    <ul><li>Optionally also ensure that the uid has the value 'has_paid' in
+                    the group field in the group table.
+                    </ul>
+                <code>&lt;limit&gt              </code><br>
+</dd>
+</dl>
+
+
+<hr><h2><a name="CompileTimeOptions">Compile Time Options</a></h2>
+
+<dl>
+<dt><code>
+<a name="ONLY_ONCE">#define ONLY_ONCE 1</a>
+</code></dt><dd>
+   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 <code>ONLY_ONCE</code>
+   directive set, access is denied if the uid occurs 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<br>
+   <p><code>"select password form pwd_table where user='UID'"</code><p>
+   this might lead to unpredictable results. For this reason as well
+   as for performance reasons you are strongly advised to make the
+   uid field a primary key. Use at your own peril :-)
+</dd>
+
+<dt><code>
+<a name="KEEP_MSQL_CONNECTION_OPEN">#define KEEP_MSQL_CONNECTION_OPEN</a>
+</code></dt><dd>
+   Normally the (TCP/IP) connection with the database is opened and
+   closed for each SQL query. When the Apache web-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 directive is set defined the server leaves
+   the connection open, i.e. no call to <code>msqlClose()</code>.
+   If an error occurs an attempt is made to reopen the connection for
+   the next http request.
+   <p>
+   This has a number of very serious drawbacks
+   <ul><li> It costs 2 already rare file-descriptors for each child.
+       <li> 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.
+       <li> When a child dies, it might not free that connection properly
+            or quick enough.
+       <li> When errors start to occur, connection/file-descriptor resources
+            might become exhausted very quickly.
+   </ul>
+   <p>
+   In short, use this at your own peril and only in a highly controlled and
+   monitored environment.
+</dd>
+
+<dt><code>
+<a name="VITEK">
+#define BACKWARD_VITEK<br></a>
+#define VITEK_uid_name "user"<br>
+#define VITEK_gid_name "passwd"
+</code></dt><dd>
+   A second mSQL auth module for Apache has also been developed by Vivek Khera
+   &lt<a href="mailto:khera@kciLink.com"><code>khera@kciLink.com</code></a>&gt
+   and was subsequently distributed with some early versions of Apache. It
+   can be obtained from
+   <code><a href="ftp://ftp.kcilink.com/pub/">ftp://ftp.kcilink.com/pub/mod_auth_msql.c*</a></code>.
+   Older 'vitek' versions had the field/table names compiled in. Newer
+   versions, v.1.11 have more <code>access.conf</code> configuration
+   options. However these where chosen not to be in line the 'ewse'
+   version of this module. Also, the 'vitek' module does not give group
+   control or 'empty' password control.
+   <p>
+   To get things slightly more in line this version (0.9) should
+   be backward compatible with the 'vitek' module by:
+   <ul><li> Adding support for the <code>Auth_MSQL_EncryptedPasswords</code> on/off functionality
+       <li> Adding support for the different spelling of the 4 configuration
+            tokens for user-table-name, user/password-field-name and dbase-name.
+       <li> Setting some field names to a default which used to be hard
+            coded in in older 'vitek' modules.
+   </ul>
+   <p>
+   If this troubles you, remove the 'BACKWARD_VITEK' define.
+</dd>
+
+<dt><code>
+<a name="MAX_FIELD_LEN">
+#define MAX_FIELD_LEN (64)<br>
+#define MAX_QUERY_LEN (32+24+MAX_FIELD_LEN*2+3*MSQL_FIELD_NAME_LEN+1*MSQL_TABLE_NAME_LEN)<br></a>
+</code></dt><dd>
+   In order to avoid using the very large <code>HUGE_STRING_LENGTH</code>, the above two compile
+   time directives are supplies. The <code>MAX_FIELD_LEN</code> contains the maximum number of
+   characters in your user, password and group fields. The maximum query length is derived
+   from those values.
+   <p>
+   We only do the following two queries:
+   <ul><li>For the user/passwd combination
+           <p><code>"select PWDFIELD from PWDTABLE where USERFIELD='UID'"</code><br>
+       <li>Optionally for the user/group combination:
+           <p><code>"select GROUPFIELD from GROUPTABLE where USERFIELD='UID' and GROUPFIELD='GID'"</code><br>
+   </ul>
+   <p>
+   This leads to the above limit for the query string. We are ignoring escaping a wee bit here
+   assuming not more than 24 escapes.)
+</dd>
+</dl>
+
+
+<hr><h2><a name="RevisionHistory">Revision History</a></h2>
+
+This version: 23 Nov 1995, 24 Feb 1996, 16 May 1996.
+
+<dl>
+
+<dt>Version 0.0<br></dt>
+    <dd>First release
+    </dd>
+<dt>Version 0.1<br></dt>
+    <dd>Update to Apache 1.00
+    </dd>
+<dt>Version 0.2<br></dt>
+    <dd>Added lines which got missing God knows when
+        and which did the valid-user authentication no good at all !
+    </dd>
+<dt>Version 0.3<br></dt>
+    <dd>Added '<code>Auth_MSQL_nopasswd</code>' option
+    </dd>
+<dt>Version 0.4<br></dt>
+    <dd>Cleaned out the error messages mess.
+    </dd>
+<dt>Version 0.6<br></dt>
+    <dd>Inconsistency with gid/grp in comment/token/source
+ Make sure you really use '<code>Auth_MSQLgrp_field</code>'
+ as indicated above.
+    </dd>
+<dt>Version 0.7<br></dt>
+    <dd><code>*host</code> to <code>host</code> fixed. Credits
+        go to Rob Stout, &lt;stout@lava.et.tudelft.nl&gt; for
+        spotting this one.
+    </dd>
+<dt>Version 0.8<br></dt>
+    <dd>Authoritative directive added. See above.
+    </dd>
+<dt>Version 0.9<br></dt>
+    <dd><code>palloc</code> return code check(s), should be
+        backward compatible with 1.11 version of Vivek Khera
+        &lt;khera@kciLink.com&gt; 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
+        <code>Auth_MSQL_EncryptedPasswords</code> on/off functionality.
+        msqlClose() statements added upon error. Support for
+        persistent connections with the mSQL database (riscy).
+        Escaping of ' and \. Replaced some
+        <code>MAX_STRING_LENGTH</code> claims.
+    </dd>
+</dl>
+
+
+<hr><h2><a name="Person">Contact/person to blame</a></h2>
+
+This module was written for the
+<a href="http://ewse.ceo.org">European Wide Service Exchange</a> by
+&lt<a href="mailto:Dirk.vanGulik@jrc.it"><code>Dirk.vanGulik@jrc.it</code></a>&gt.
+Feel free to contact me if you have any problems, ice-creams or bugs. This
+documentation, courtesy of Nick Himba, <a href="mailto:himba@cs.utwente.nl">
+<code>&lt;himba@cs.utwente.nl&gt;</code></a>.
+<p>
+
+
+<hr><h2><a NAME="Sourcecode">Sourcecode</a></h2>
+
+The source code can be found at <a href="http://www.apache.org"><code>
+http://www.apache.org</code></a>. A snapshot of a development version
+usually resides at <a href="http://me-www.jrc.it/~dirkx/mod_auth_msql.c"><code>
+http://me-www.jrc.it/~dirkx/mod_auth_msql.c</code></a>. Please make sure
+that you always quote the version you use when filing a bug report.
+<p>
+Furthermore a test/demonstration suite (which assumes that you have
+both mSQL and Apache compiled and installed) is available at the contrib
+section of <a href="ftp://ftp.apache.org/apache/dist/contrib"><code>
+ftp://ftp.apache.org/apache/dist/contrib</code></a> or
+<a href="http://me-www.jrc.it/~dirkx/apache-msql-demo.tar.gz"><code>
+http://me-www.jrc.it/~dirkx/apache-msql-demo.tar.gz</code></a> and
+its <a href="http://me-www.jrc.it/~dirkx/apache-msql-demo"><code>
+README</code></a> file.
+
+<!--#include virtual="footer.html" -->
+</body>
+</html>
+
diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_browser.html b/APACHE_1_2_X/htdocs/manual/mod/mod_browser.html
new file mode 100644 (file)
index 0000000..551c38c
--- /dev/null
@@ -0,0 +1,87 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<TITLE>Apache module mod_browser</TITLE>
+</HEAD>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<H1 ALIGN="CENTER">Apache module mod_browser</h1>
+
+This module is contained in the <code>mod_browser.c</code> file, and
+is compiled in by default with Apache 1.2 and above. It provides for
+setting environment variables based on the browser.
+
+<h2>Summary</h2>
+
+<p>This module allows you to set environment variables based on the name of
+the browser accessing your document, based on the <code>User-Agent</code>
+header field. This is especially useful when combined with a conditional
+HTML language such as <a href="mod_include.html">XSSI</a> or PHP, and
+can provide for simple browser-based negotiation of HTML features.</p>
+
+<h2>Directives</h2>
+<ul>
+<li><A HREF="#browsermatch">BrowserMatch</A>
+<li><A HREF="#browsermatchnocase">BrowserMatchNoCase</A>
+</ul>
+
+<hr>
+
+<h2><A name="browsermatch">BrowserMatch</A></h2>
+<strong>Syntax:</strong> BrowserMatch <em>regex attr1 attr2...</em><br>
+<strong>Context:</strong> server config<br>
+<strong>Status:</strong> base<br>
+<strong>Module:</strong> mod_browser<br>
+<strong>Compatibility:</strong> Apache 1.2 and above<p>
+
+The BrowserMatch directive defines environment variables based on the
+User-Agent
+header. The first argument should be a POSIX.2 extended regular
+expression (similar to an egrep-style regex). The rest of the arguments
+give names of variables to set. These take the form of either
+"<code>varname</code>", "<code>!varname</code>" or
+"<code>varname=value</code>". In the first form, the value will be set
+to "1". The second will remove the given variable if already defined,
+and the third will set the variable to the value given by <code>value</code>. If a User-Agent
+string matches more than one entry, they will
+be merged. Entries are processed in the order they appear, and later
+entries can override earlier ones.
+
+<p>For example:</p>
+<pre>
+    BrowserMatch ^Mozilla forms jpeg=yes browser=netscape
+    BrowserMatch "^Mozilla/[2-3]" tables agif frames javascript
+    BrowserMatch MSIE !javascript
+</pre>
+
+<p><h2><A name="browsermatchnocase">BrowserMatchNoCase</A></h2>
+<strong>Syntax:</strong> BrowserMatchNoCase <em>regex attr1 attr2...</em><br>
+<strong>Context:</strong> server config<br>
+<strong>Status:</strong> base<br>
+<strong>Module:</strong> mod_browser<br>
+<strong>Compatibility:</strong> Apache 1.2 and above
+
+<p>The <code>BrowserMatchNoCase</code> directive is semantically identical to
+   the <a href="#browsermatch"><code>BrowserMatch</code></a>
+   directive. However, it provides for case-insensitive matching. For
+   example:</p>
+<pre>
+    BrowserMatchNoCase mac platform=macintosh
+    BrowserMatchNoCase win platform=windows
+</pre>
+
+
+<p>
+<!--#include virtual="footer.html" -->
+
+</BODY>
+</HTML>
+
diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_cern_meta.html b/APACHE_1_2_X/htdocs/manual/mod/mod_cern_meta.html
new file mode 100644 (file)
index 0000000..98a7410
--- /dev/null
@@ -0,0 +1,81 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<TITLE>Module mod_cern_meta</TITLE>
+</HEAD>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<H1 ALIGN="CENTER">Apache module mod_cern_meta</h1>
+
+This module is contained in the <code>mod_cern_meta.c</code> file, and
+is not compiled in by default. It provides for CERN httpd metafile
+semantics. It is only available in Apache 1.1 and later.
+
+<h2>Summary</h2>
+
+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. 
+
+<p>More information on the
+<a href="http://www.w3.org/pub/WWW/Daemon/User/Config/General.html#MetaDir
+">CERN metafile semantics</a> is available.
+
+<h2>Directives</h2>
+<ul>
+<li><A HREF="#metadir">MetaDir</A>
+<li><A HREF="#metasuffix">MetaSuffix</A>
+</ul>
+
+<hr>
+
+<h2><A name="metadir">MetaDir</A></h2>
+<strong>Syntax:</strong> MetaDir <em>directory name</em><br>
+<strong>Default:</strong> <code>MetaDir .web</code><br>
+<strong>Context:</strong> server config<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_cern_meta<br>
+<strong>Compatibility:</strong> MetaDir is only available in Apache 1.1
+and later.<p>
+
+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. Set to "<code>.</code>" to look in the same directory as the
+file.
+
+<h2><A name="metasuffix">MetaSuffix</A></h2>
+<strong>Syntax:</strong> MetaSuffix <em>suffix</em><br>
+<strong>Default:</strong> <code>MetaSuffix .meta</code><br>
+<strong>Context:</strong> server config<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_cern_meta<br>
+<strong>Compatibility:</strong> MetaSuffix is only available in Apache 1.1
+and later.<p>
+
+Specifies the file name suffix for the file containing the
+meta information. For example, the default values for the two
+directives will cause a request to <code>
+DOCUMENT_ROOT/somedir/index.html</code> to look in
+<code>DOCUMENT_ROOT/somedir/.web/index.html.meta</code> and  will use
+its contents to generate additional MIME header information.
+
+<p>
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
+
diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_cgi.html b/APACHE_1_2_X/htdocs/manual/mod/mod_cgi.html
new file mode 100644 (file)
index 0000000..fc06cf5
--- /dev/null
@@ -0,0 +1,174 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<title>Apache module mod_cgi</title>
+</head>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+
+<h1 ALIGN="CENTER">Module mod_cgi</h1>
+
+This module is contained in the <code>mod_cgi.c</code> file, and
+is compiled in by default. It provides for execution of CGI scripts.
+Any file with mime type <code>application/x-httpd-cgi</code> will be
+processed by this module.
+<!--%plaintext &lt;?INDEX {\tt application/x-httpd-cgi} mime type&gt; -->
+<!--%plaintext &lt;?INDEX CGI scripts&gt; -->
+
+<h2>Summary</h2>
+Any file that has the mime type <code>application/x-httpd-cgi</code>
+or handler <code>cgi-script</code> (Apache 1.1 or later)
+will be treated as a CGI script, and run by the server, with its output
+being returned to the client. Files acquire this type either by
+having a name ending in an extension defined by the
+<A HREF="mod_mime.html#addtype">AddType</A> directive, or by being in
+a <A HREF="mod_alias.html#scriptalias">ScriptAlias</A> directory. <p>
+
+When the server invokes a CGI script, it will add a variable called
+<code>DOCUMENT_ROOT</code> to the environment. This variable will contain the
+value of the <A HREF="core.html#documentroot">DocumentRoot</A>
+configuration variable.
+
+<h2>CGI Environment variables</h2>
+The server will set the CGI environment variables as described in the CGI
+specification, with the following provisions:
+<dl>
+<dt>REMOTE_HOST
+<dd>This will only be set if the server has not been compiled with
+<code>MINIMAL_DNS</code>.
+<dt>REMOTE_IDENT
+<dd>This will only be set if
+<A HREF="core.html#identitycheck">IdentityCheck</A> is set to <code>on</code>.
+<dt>REMOTE_USER
+<dd>This will only be set if the CGI script is subject to authentication.
+</dl>
+<P>
+
+<hr>
+
+<h2><a name="cgi_debug">CGI Debugging</a></h2>
+
+Debugging CGI scripts has traditionally been difficult, mainly because
+it has
+not
+been possible to study the output (standard output and error) for
+scripts
+which are failing to run properly. These directives, included in
+Apache 1.2 and later, provide
+more detailed logging of errors when they occur.
+
+<hr>
+
+<h2>CGI Logfile Format</h2>
+
+When configured, the CGI error log logs any CGI which does not execute
+properly.  Each CGI script which fails to operate causes several lines
+of information to be logged. The first two lines are always of the
+format:
+
+<pre>
+  %% [<i>time</i>] <i>request-line</i>
+  %% <i>HTTP-status</i> <i>CGI-script-filename</i>
+</pre>
+
+If the error is that CGI script cannot be run, the log file will
+contain
+an extra two lines:
+
+<pre>
+  %%error
+  <i>error-message</i>
+</pre>
+
+Alternatively, if the error is the result of the script returning
+incorrect header information (often due to a bug in the script), the
+following information is logged:
+
+<pre>
+  %request
+  <i>All HTTP request headers received</i>
+  <i>POST or PUT entity (if any)</i>
+  %response
+  <i>All headers output by the CGI script</i>
+  %stdout
+  <i>CGI standard output</i>
+  %stderr
+  <i>CGI standard error</i>
+</pre>
+
+(The %stdout and %stderr parts may  be missing if the script did not
+output
+anything on standard output or standard error).
+
+<hr>
+
+<h2>Directives</h2>
+
+<h3><a name="scriptlog">ScriptLog</a></h3>
+
+<b>Syntax:</b> ScriptLog <i>filename</i><br>
+<b>Default:</b> none<br>
+<b>Context:</b> resource config<br>
+<b>Status:</b> mod_cgi
+<p>
+
+The <tt>ScriptLog</tt> directive sets the CGI script error logfile.
+If no ScriptLog is given, no error log is created. If given, any
+CGI errors are logged into the filename given as argument. If this
+is a relative file or path it is taken relative to the server root.
+
+<P>This log will be opened as the user the child processes run as,
+ie. the user specified in the main <A HREF="core.html#User">User</A>
+directive.  This means that either the directory the script log is
+in needs to be writable by that user or the file needs to be manually
+created and set to be writable by that user.  If you place the
+script log in your main logs directory, do <STRONG>NOT</STRONG>
+change the directory permissions to make it writable by the user
+the child processes run as.</P>
+
+<p>Note that script logging is meant to be a debugging feature when
+writing CGI scripts, and is not meant to be activated continuously on
+running servers. It is not optimized for speed or efficiency, and may
+have security problems if used in a manner other than that for which
+it was designed.</p>
+
+<h3><a name="scriptloglength">ScriptLogLength</a></h3>
+
+<b>Syntax:</b> ScriptLogLength <i>size</i><br>
+<b>Default:</b> 10385760<br>
+<b>Context:</b> resource config<br>
+<b>Status:</b> mod_cgi
+<p>
+
+<tt>ScriptLogLength</tt> can be used to limit the size of the CGI
+script logfile.  Since the logfile logs a lot of information per CGI
+error (all request headers, all script output) it can grow to be a big
+file. To prevent problems due to unbounded growth, this directive can
+be used to set an maximum file-size for the CGI logfile. If the file
+exceeds this size, no more information will be written to it.
+
+<h3><a name="scriptlogbuffer">ScriptLogBuffer</a></h3>
+
+<b>Syntax:</b> ScriptLogBuffer <i>size</i><br>
+<b>Default:</b> 1024<br>
+<b>Context:</b> resource config<br>
+<b>Status:</b> mod_cgi
+<p>
+
+The size of any PUT or POST entity body that is logged to the file is
+limited, to prevent the log file growing too big too quickly if large
+bodies are being received. By default, up to 1024 bytes are logged,
+but this can be changed with this directive.
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
+
diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_cookies.html b/APACHE_1_2_X/htdocs/manual/mod/mod_cookies.html
new file mode 100644 (file)
index 0000000..fff4d9d
--- /dev/null
@@ -0,0 +1,43 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<TITLE>Apache module mod_cookies</TITLE>
+</HEAD>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<H1 ALIGN="CENTER">Module mod_cookies</h1>
+
+This module is contained in the <code>mod_cookies.c</code> file, and
+is not compiled in by default. It provides for Netscape(TM) cookies.
+There is no documentation available for this module.
+
+
+<menu>
+<li><A HREF="#cookielog">CookieLog</A>
+</menu>
+<hr>
+
+
+<h2><A name="cookielog">CookieLog</A></h2>
+<!--%plaintext &lt;?INDEX {\tt CookieLog} directive&gt; -->
+<strong>Syntax:</strong> CookieLog <em>filename</em><br>
+<Strong>Context:</strong> server config, virtual host<br>
+<strong>Status:</strong> Experimental<br>
+<strong>Module:</strong> mod_cookies<p>
+
+The CookieLog directive sets the filename for logging of cookies.
+The filename is relative to the <A HREF="core.html#serverroot">ServerRoot</A>.
+<p>
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
+
diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_digest.html b/APACHE_1_2_X/htdocs/manual/mod/mod_digest.html
new file mode 100644 (file)
index 0000000..346266c
--- /dev/null
@@ -0,0 +1,65 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<TITLE>Apache module mod_digest</TITLE>
+</HEAD>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<H1 ALIGN="CENTER">Module mod_digest</h1>
+
+This module is contained in the <code>mod_digest.c</code> file, and is
+not compiled in by default. It is only available in Apache 1.1 and
+later. It provides for user authentication using MD5 Digest
+Authentication.
+
+
+<menu>
+<li><A HREF="#authdigestfile">AuthDigestFile</A>
+</menu>
+<hr>
+
+
+<h2><A name="authdigestfile">AuthDigestFile</A></h2>
+<strong>Syntax:</strong> AuthDigestFile <em>filename</em><br>
+<Strong>Context:</strong> directory, .htaccess<br>
+<Strong>Override:</strong> AuthConfig<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_digest<p>
+
+<p>The AuthDigestFile directive sets the name of a textual file containing
+the list
+of users and encoded passwords for digest authentication.
+<em>Filename</em>
+is the absolute path to the user file.</p>
+<p>The digest file uses a special format. Files in this format can be
+created using the "htdigest" utility found in the support/ subdirectory of
+the Apache distribution.</p>
+
+<hr>
+
+<h3>Using Digest Authentication</h3>
+
+<p>Using MD5 Digest authentication is very simple. Simply set up
+authentication normally. However, use "AuthType Digest" and
+"AuthDigestFile" instead of the normal "AuthType Basic" and
+"AuthUserFile". Everything else should remain the same.</p>
+
+<p>MD5 authentication provides a more secure password system, but only
+works with supporting browsers. As of this writing (July 1996), the
+majority of browsers do not support digest authentication. Therefore, we
+do not recommend using this feature on a large Internet site. However, for
+personal and intra-net use, where browser users can be controlled, it is
+ideal.</p>
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
+
diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_dir.html b/APACHE_1_2_X/htdocs/manual/mod/mod_dir.html
new file mode 100644 (file)
index 0000000..aebd31a
--- /dev/null
@@ -0,0 +1,367 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<TITLE>Apache module mod_dir</TITLE>
+</HEAD>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<H1 ALIGN="CENTER">Module mod_dir</H1>
+
+This module is contained in the <code>mod_dir.c</code> file, and
+is compiled in by default. It provides for directory indexing.
+
+<h2>Summary</h2>
+This module controls the directory indexing. The index of a directory
+can come from one of two sources:
+<ul>
+<li>A file written by the user, typically called <code>index.html</code>.
+The <A HREF="#directoryindex">DirectoryIndex</A> directive sets the name
+of this file.
+<li>Otherwise, a listing generated by the server. The other directives
+control the format of this listing. The <A HREF="#addicon">AddIcon</A>,
+<A HREF="#addiconbyencoding">AddIconByEncoding</A> and
+<A HREF="#addiconbytype">AddIconByType</A> are used to set a list of
+icons to display for various file types; for each file listed, the
+first icon listed that matches the file is displayed.
+</ul>
+
+
+<h2>Directives</h2>
+
+<menu>
+<li><A HREF="#addalt">AddAlt</A>
+<li><A HREF="#addaltbyencoding">AddAltByEncoding</A>
+<li><A HREF="#addaltbytype">AddAltByType</A>
+<li><A HREF="#adddescription">AddDescription</A>
+<li><A HREF="#addicon">AddIcon</A>
+<li><A HREF="#addiconbyencoding">AddIconByEncoding</A>
+<li><A HREF="#addiconbytype">AddIconByType</A>
+<li><A HREF="#defaulticon">DefaultIcon</A>
+<li><A HREF="#directoryindex">DirectoryIndex</A>
+<li><A HREF="#fancyindexing">FancyIndexing</A>
+<li><A HREF="#headername">HeaderName</A>
+<li><A HREF="#indexignore">IndexIgnore</A>
+<li><A HREF="#indexoptions">IndexOptions</A>
+<li><A HREF="#readmename">ReadmeName</A>
+</menu>
+<hr>
+
+<A name="addalt"><h2>AddAlt</h2></A>
+<!--%plaintext &lt;?INDEX {\tt AddAlt} directive&gt; -->
+<strong>Syntax:</strong> AddAlt <em>string file file...</em><br>
+<Strong>Context:</strong> server config, virtual host, directory, .htaccess<br>
+<Strong>Override:</strong> Indexes<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_dir<p>
+
+This sets the alternate text to display for a file, instead of an icon, for
+<A HREF="#fancyindexing">FancyIndexing</A>. <em>File</em> is a file
+extension, partial filename, wild-card expression or full filename for files
+to describe. <em>String</em> is enclosed in double quotes
+(<code>&quot;</code>).  This alternate text is displayed if the client is
+image-incapable or has image loading disabled.
+
+<HR>
+<A name="addaltbyencoding"><h2>AddAltByEncoding</h2></A>
+<!--%plaintext &lt;?INDEX {\tt AddAltByEncoding} directive&gt; -->
+<strong>Syntax:</strong> AddAltByEncoding <em>string MIME-encoding
+    MIME-encoding...</em><br>
+<Strong>Context:</strong> server config, virtual host, directory, .htaccess<br>
+<Strong>Override:</strong> Indexes<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_dir<p>
+
+This sets the alternate text to display for a file, instead of an icon, for
+<A HREF="#fancyindexing">FancyIndexing</A>. <em>MIME-encoding</em> is a
+valid content-encoding, such as <SAMP>x-compress</SAMP>.
+<em>String</em> is enclosed in double quotes
+(<code>&quot;</code>).  This alternate text is displayed if the client is
+image-incapable or has image loading disabled.
+
+<HR>
+<A name="addaltbytype"><h2>AddAltByType</h2></A>
+<!--%plaintext &lt;?INDEX {\tt AddAltByType} directive&gt; -->
+<strong>Syntax:</strong> AddAltByType <em>string MIME-type MIME-type...</em><br>
+<Strong>Context:</strong> server config, virtual host, directory, .htaccess<br>
+<Strong>Override:</strong> Indexes<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_dir<p>
+
+This sets the alternate text to display for a file, instead of an icon, for
+<A HREF="#fancyindexing">FancyIndexing</A>. <em>MIME-type</em> is a
+valid content-type, such as <SAMP>text/html</SAMP>.
+<em>String</em> is enclosed in double quotes
+(<code>&quot;</code>).  This alternate text is displayed if the client is
+image-incapable or has image loading disabled.
+
+<HR>
+
+<A name="adddescription"><h2>AddDescription</h2></A>
+<!--%plaintext &lt;?INDEX {\tt AddDescription} directive&gt; -->
+<strong>Syntax:</strong> AddDescription <em>string file file...</em><br>
+<Strong>Context:</strong> server config, virtual host, directory, .htaccess<br>
+<Strong>Override:</strong> Indexes<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_dir<p>
+
+This sets the description to display for a file, for
+<A HREF="#fancyindexing">FancyIndexing</A>. <em>File</em> is a file
+extension, partial filename, wild-card expression or full filename for files
+to describe. <em>String</em> is enclosed in double quotes
+(<code>&quot;</code>). Example:
+<blockquote><code>AddDescription "The planet Mars" /web/pics/mars.gif
+</code></blockquote><p><hr>
+
+<A name="addicon"><h2>AddIcon</h2></A>
+<!--%plaintext &lt;?INDEX {\tt AddIcon} directive&gt; -->
+<strong>Syntax:</strong> AddIcon <em>icon name name ...</em><br>
+<Strong>Context:</strong> server config, virtual host, directory, .htaccess<br>
+<Strong>Override:</strong> Indexes<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_dir<p>
+
+This sets the icon to display next to a file ending in <em>name</em> for
+<A HREF="#fancyindexing">FancyIndexing</A>. <em>Icon</em> is either a
+(%-escaped) relative URL to the icon, or of the format
+(<em>alttext</em>,<em>url</em>) where <em>alttext</em> is the text tag given
+for an icon for non-graphical browsers.<p>
+
+<em>Name</em> is either ^^DIRECTORY^^ for directories, ^^BLANKICON^^ for
+blank lines (to format the list correctly), a file extension, a wildcard
+expression, a partial filename or a complete filename. Examples:
+<blockquote><code>
+AddIcon (IMG,/icons/image.xbm) .gif .jpg .xbm <br>
+AddIcon /icons/dir.xbm ^^DIRECTORY^^ <br>
+AddIcon /icons/backup.xbm *~
+</code></blockquote>
+<A HREF="#addiconbytype">AddIconByType</A> should be used in preference to
+AddIcon, when possible.<p><hr>
+
+<A name="addiconbyencoding"><h2>AddIconByEncoding</h2></A>
+<!--%plaintext &lt;?INDEX {\tt AddIconByEncoding} directive&gt; -->
+<strong>Syntax:</strong> AddIconByEncoding <em>icon mime-encoding mime-encoding
+...</em><br>
+<Strong>Context:</strong> server config, virtual host, directory, .htaccess<br>
+<Strong>Override:</strong> Indexes<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_dir<p>
+
+This sets the icon to display next to files with
+<em>mime-encoding</em> for <A HREF="#fancyindexing">FancyIndexing</A>.
+<em>Icon</em> is either a (%-escaped) relative URL to the icon, or of the
+format (<em>alttext</em>,<em>url</em>) where <em>alttext</em> is the text tag
+given for an icon for non-graphical browsers.<p>
+
+<em>Mime-encoding</em> is a wildcard expression matching required the 
+content-encoding. Examples:
+<blockquote><code>
+AddIconByEncoding /icons/compress.xbm x-compress
+</code></blockquote><p><hr>
+
+<A name="addiconbytype"><h2>AddIconByType</h2></A>
+<!--%plaintext &lt;?INDEX {\tt AddIconByType} directive&gt; -->
+<strong>Syntax:</strong> AddIconByType <em>icon mime-type mime-type ...</em><br>
+<Strong>Context:</strong> server config, virtual host, directory, .htaccess<br>
+<Strong>Override:</strong> Indexes<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_dir<p>
+
+This sets the icon to display next to files of type <em>mime-type</em> for
+<A HREF="#fancyindexing">FancyIndexing</A>. <em>Icon</em> is either a
+(%-escaped) relative URL to the icon, or of the format
+(<em>alttext</em>,<em>url</em>) where <em>alttext</em> is the text tag given
+for an icon for non-graphical browsers.<p>
+<em>Mime-type</em> is a wildcard expression matching required the mime types.
+Examples:
+<blockquote><code>
+AddIconByType (IMG,/icons/image.xbm) image/*
+</code></blockquote><p><hr>
+
+<A name="defaulticon"><h2>DefaultIcon</h2></A>
+<!--%plaintext &lt;?INDEX {\tt DefaultIcon} directive&gt; -->
+<strong>Syntax:</strong> DefaultIcon <em>url</em><br>
+<Strong>Context:</strong> server config, virtual host, directory, .htaccess<br>
+<Strong>Override:</strong> Indexes<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_dir<p>
+
+The DefaultIcon directive sets the icon to display for files when no
+specific icon is known, for <A HREF="#fancyindexing">FancyIndexing</A>.
+<em>Url</em> is a (%-escaped) relative URL to the icon. Examples:
+<blockquote><code>
+DefaultIcon /icon/unknown.xbm
+</code></blockquote><p><hr>
+
+<A name="directoryindex"><h2>DirectoryIndex</h2></A>
+<!--%plaintext &lt;?INDEX {\tt DirectoryIndex} directive&gt; -->
+<strong>Syntax:</strong> DirectoryIndex <em>local-url local-url ...</em><br>
+<strong>Default:</strong> <code>DirectoryIndex index.html</code><br>
+<Strong>Context:</strong> server config, virtual host, directory, .htaccess<br>
+<Strong>Override:</strong> Indexes<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_dir<p>
+
+The DirectoryIndex directive sets the list of resources to look for,
+when the client requests an index of the directory by specifying a /
+at the end of the a directory name. <em>Local-url</em> is the
+(%-encoded) URL of a document on the server relative to the requested
+directory; it is usually the name of a file in the directory. Several
+URLs may be given, in which case the server will return the first one
+that it finds. If none of the resources exist and the
+<CODE>Indexes</CODE> option is set, the server will generate its own
+listing of the directory.
+<P>
+
+Example:
+<blockquote><code>
+DirectoryIndex index.html
+</code></blockquote>
+then a request for <code>http://myserver/docs/</code> would return
+<code>http://myserver/docs/index.html</code> if it exists, or would list
+the directory if it did not. <p>
+
+Note that the documents do not need to be relative to the directory;
+<blockquote><code>
+DirectoryIndex index.html index.txt /cgi-bin/index.pl</code></blockquote>
+would cause the CGI script <code>/cgi-bin/index.pl</code> to be executed
+if neither <code>index.html</code> or <code>index.txt</code> existed in
+a directory.<p><hr>
+
+<A name="fancyindexing"><h2>FancyIndexing</h2></A>
+<!--%plaintext &lt;?INDEX {\tt FancyIndexing} directive&gt; -->
+<strong>Syntax:</strong> FancyIndexing <em>boolean</em><br>
+<Strong>Context:</strong> server config, virtual host, directory, .htaccess<br>
+<Strong>Override:</strong> Indexes<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_dir<p>
+
+The FancyIndexing directive sets the FancyIndexing option for a directory.
+<em>Boolean</em> can be <code>on</code> or <code>off</code>. The
+<A HREF="#indexoptions">IndexOptions</A> directive should be used in
+preference.<p><hr>
+
+<A name="headername"><h2>HeaderName</h2></A>
+<!--%plaintext &lt;?INDEX {\tt HeaderName} directive&gt; -->
+<strong>Syntax:</strong> HeaderName <em>filename</em><br>
+<Strong>Context:</strong> server config, virtual host, directory, .htaccess<br>
+<Strong>Override:</strong> Indexes<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_dir<p>
+
+The HeaderName directive sets the name of the file that will be inserted
+at the top of the index listing. <em>Filename</em> is the name of the file
+to include, and is taken to be relative to the directory being indexed.
+The server first attempts to include <em>filename</em><code>.html</code>
+as an HTML document, otherwise it will include <em>filename</em> as plain
+text. Example:
+<blockquote><code>HeaderName HEADER</code></blockquote>
+when indexing the directory <code>/web</code>, the server will first look for
+the HTML file <code>/web/HEADER.html</code> and include it if found, otherwise
+it will include the plain text file <code>/web/HEADER</code>, if it exists.
+
+<p>See also <A HREF="#readmename">ReadmeName</A>.<p><hr>
+
+<A name="indexignore"><h2>IndexIgnore</h2></A>
+<!--%plaintext &lt;?INDEX {\tt IndexIgnore} directive&gt; -->
+<strong>Syntax:</strong> IndexIgnore <em>file file ...</em><br>
+<Strong>Context:</strong> server config, virtual host, directory, .htaccess<br>
+<Strong>Override:</strong> Indexes<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_dir<p>
+
+The IndexIgnore directive adds to the list of files to hide when listing
+a directory. <em>File</em> is a file extension, partial filename,
+wildcard expression or full filename for files to ignore. Multiple
+IndexIgnore directives add to the list, rather than the replacing the list
+of ignored files. By default, the list contains `<code>.</code>'. Example:
+<blockquote><code>
+IndexIgnore README .htaccess *~
+</code></blockquote><p><hr>
+
+<A name="indexoptions"><h2>IndexOptions</h2></A>
+<!--%plaintext &lt;?INDEX {\tt IndexOptions} directive&gt; -->
+<strong>Syntax:</strong> IndexOptions <em>option option ...</em><br>
+<Strong>Context:</strong> server config, virtual host, directory, .htaccess<br>
+<Strong>Override:</strong> Indexes<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_dir<p>
+
+The IndexOptions directive specifies the behavior of the directory indexing.
+<em>Option</em> can be one of
+<dl>
+<dt>FancyIndexing
+<dd><!--%plaintext &lt;?INDEX {\tt FancyIndexing} index option&gt; -->
+This turns on fancy indexing of directories.
+<dt>IconsAreLinks
+<dd>
+<!--%plaintext &lt;?INDEX {\tt IconsAreLinks} index option&gt; -->
+This makes the icons part of the anchor for the filename, for
+fancy indexing.
+<dt>ScanHTMLTitles
+<dd><!--%plaintext &lt;?INDEX {\tt ScanHTMLTitles} index option&gt; -->
+This enables the extraction of the title from HTML documents for fancy
+indexing. If the file does not have a description given by
+<A HREF="#adddescription">AddDescription</A> then httpd will read the
+document for the value of the TITLE tag.  This is CPU and disk intensive.
+<dt>SuppressLastModified
+<dd>
+<!--%plaintext &lt;?INDEX {\tt SuppressLastModified} index option&gt; -->
+This will suppress the display of the last modification date, in fancy
+indexing listings.
+<dt>SuppressSize
+<dd>
+<!--%plaintext &lt;?INDEX {\tt SuppressSize} index option&gt; -->
+This will suppress the file size in fancy indexing listings.
+<dt>SuppressDescription
+<dd>
+<!--%plaintext &lt;?INDEX {\tt SuppressDescription} index option&gt; -->
+This will suppress the file description in fancy indexing listings.
+</dl>
+This default is that no options are enabled. If multiple IndexOptions
+could apply to a directory, then the most specific one is taken complete;
+the options are not merged. For example:
+<blockquote><code>
+&lt;Directory /web/docs&gt; <br>
+IndexOptions FancyIndexing <br>
+&lt;/Directory&gt;<br>
+&lt;Directory /web/docs/spec&gt; <br>
+IndexOptions ScanHTMLTitles <br>
+&lt;/Directory&gt;
+</code></blockquote>
+then only <code>ScanHTMLTitles</code> will be set for the /web/docs/spec
+directory.<p><hr>
+
+<A name="readmename"><h2>ReadmeName</h2></A>
+<!--%plaintext &lt;?INDEX {\tt ReadmeName} directive&gt; -->
+<strong>Syntax:</strong> ReadmeName <em>filename</em><br>
+<Strong>Context:</strong> server config, virtual host, directory, .htaccess<br>
+<Strong>Override:</strong> Indexes<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_dir<p>
+
+The ReadmeName directive sets the name of the file that will be appended
+to the end of the index listing. <em>Filename</em> is the name of the file
+to include, and is taken to be relative to the directory being indexed.
+The server first attempts to include <em>filename</em><code>.html</code>
+as an HTML document, otherwise it will include <em>filename</em> as plain
+text. Example:
+<blockquote><code>ReadmeName README</code></blockquote>
+when indexing the directory <code>/web</code>, the server will first look for
+the HTML file <code>/web/README.html</code> and include it if found, otherwise
+it will include the plain text file <code>/web/README</code>, if it exists.
+
+<p>See also <A HREF="#headername">HeaderName</A>.<p>
+
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
+
diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_dld.html b/APACHE_1_2_X/htdocs/manual/mod/mod_dld.html
new file mode 100644 (file)
index 0000000..d07273a
--- /dev/null
@@ -0,0 +1,80 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<TITLE>Apache module mod_dld</TITLE>
+</HEAD>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<H1 ALIGN="CENTER">Module mod_dld</h1>
+
+This module is contained in the <code>mod_dld.c</code> file, and is not
+compiled in by default. It provides for loading of executable code
+and modules into the server at start-up time, using the GNU dld library.
+
+<h2>Summary</h2>
+
+The optional dld module is a proof-of-concept piece of code which
+loads other modules into the server as it is configuring itself (the
+first time only; for now, rereading the config files cannot affect the
+state of loaded modules), using the GNU dynamic linking library, DLD.
+It isn't compiled into the server by default, since not everyone has
+DLD, but it works when I try it.  (Famous last words.)  <p>
+
+Note that for some reason, <code>LoadFile /lib/libc.a</code> seems to be
+required for just about everything.<p>
+
+Note: that DLD needs to read the symbol table out of the server binary
+when starting up; these commands will fail if the server can't find
+its own binary when it starts up, or if that binary is stripped.<p>
+
+
+<h2>Directives</h2>
+<ul>
+<li><A HREF="#loadfile">LoadFile</A>
+<li><A HREF="#loadmodule">LoadModule</A>
+</ul>
+<hr>
+
+
+<h2><A name="loadfile">LoadFile</A></h2>
+<!--%plaintext &lt;?INDEX {\tt LoadFile} directive&gt; -->
+<strong>Syntax:</strong> LoadFile <em>filename filename ...</em><br>
+<Strong>Context:</strong> server config<br>
+<strong>Status:</strong> Experimental<br>
+<strong>Module:</strong> mod_dld<p>
+
+The LoadFile directive links in the named object files or libraries when
+the server is started; this is used to load additional code which
+may be required for some module to work. <em>Filename</em> is relative
+to <A HREF="core.html#serverroot">ServerRoot</A>.<p><hr>
+
+<h2><A name="loadmodule">LoadModule</A></h2>
+<!--%plaintext &lt;?INDEX {\tt LoadModule} directive&gt; -->
+<strong>Syntax:</strong> LoadModule <em>module filename</em><br>
+<Strong>Context:</strong> server config<br>
+<strong>Status:</strong> Experimental<br>
+<strong>Module:</strong> mod_dld<p>
+
+The LoadModule directive links in the object file or library <em>filename</em>
+and adds the module structure named <em>module</em> to the list of active
+modules. <em>Module</em> is the name of the external variable of type
+<code>module</code> in the file. Example:
+<blockquote><code>
+LoadModule ai_backcompat_module modules/mod_ai_backcompat.o<br>
+LoadFile /lib/libc.a
+</code></blockquote>
+loads the module in the modules subdirectory of the ServerRoot.<p>
+
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
+
diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_env.html b/APACHE_1_2_X/htdocs/manual/mod/mod_env.html
new file mode 100644 (file)
index 0000000..0ee7193
--- /dev/null
@@ -0,0 +1,92 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<TITLE>Apache module mod_env</TITLE>
+</HEAD>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<H1 ALIGN="CENTER">Apache module mod_env</h1>
+
+This module is contained in the <code>mod_env.c</code> file, and
+is not compiled in by default. It provides for
+passing environment variables to CGI/SSI scripts. Is is only available
+in Apache 1.1 and later.
+
+<h2>Summary</h2>
+
+This module allows Apache's CGI and SSI environment to inherit
+environment variables from the shell which invoked the httpd process.
+CERN web-servers are able to do this, so this module is especially
+useful to web-admins who wish to migrate from CERN to Apache without
+rewriting all their scripts
+<h2>Directives</h2>
+<ul>
+<li><A HREF="#passenv">PassEnv</A>
+<li><A HREF="#setenv">SetEnv</A>
+<li><A HREF="#unsetenv">UnsetEnv</A>
+</ul>
+
+<hr>
+
+<h2><A name="passenv">PassEnv</A></h2>
+<strong>Syntax:</strong> PassEnv <em>variable variable ...</em><br>
+<strong>Context:</strong> server config, virtual host<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_env<br>
+<strong>Compatibility:</strong> PassEnv is only available in
+Apache 1.1 and later.<p>
+
+Specifies one or more environment variables to pass to CGI scripts
+from the server's own environment. Example:
+<pre>
+    PassEnv LD_LIBRARY_PATH
+</pre>
+
+<HR>
+
+<h2><A name="setenv">SetEnv</A></h2>
+<strong>Syntax:</strong> SetEnv <em>variable value</em><br>
+<strong>Context:</strong> server config, virtual host<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_env<br>
+<strong>Compatibility:</strong> SetEnv is only available in
+Apache 1.1 and later.<p>
+
+Sets an environment variable, which is then passed on to CGI
+scripts. Example:
+<pre>
+    SetEnv SPECIAL_PATH /foo/bin
+</pre>
+
+<hr>
+
+<h2><A name="unsetenv">UnsetEnv</A></h2>
+<strong>Syntax:</strong> UnsetEnv <em>variable variable ...</em><br>
+<strong>Context:</strong> server config, virtual host<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_env<br>
+<strong>Compatibility:</strong> UnsetEnv is only available in
+Apache 1.1 and later.<p>
+
+Removes one or more environment variables from those passed on to
+CGI scripts. Example:
+<pre>
+    UnsetEnv LD_LIBRARY_PATH
+</pre>
+
+
+
+<p>
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
+
diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_example.html b/APACHE_1_2_X/htdocs/manual/mod/mod_example.html
new file mode 100644 (file)
index 0000000..5ac54af
--- /dev/null
@@ -0,0 +1,140 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+ <HEAD>
+  <TITLE>Apache module mod_example</TITLE>
+ </HEAD>
+ <!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+ <BODY
+  BGCOLOR="#FFFFFF"
+  TEXT="#000000"
+  LINK="#0000FF"
+  VLINK="#000080"
+  ALINK="#FF0000"
+ >
+  <!--#include virtual="header.html" -->
+  <H1 ALIGN="CENTER">Module mod_example</h1>
+  <P>
+  This module is contained in the <CODE>modules/mod_example.c</CODE> file, and
+  <STRONG>is not</STRONG> compiled in by default.  It illustrates many of
+  the aspects of the
+  <A
+   HREF="../misc/API.html"
+   REL="Help"
+  >Apache 1.2 API</A>
+  and, when used, demonstrates the manner in which module callbacks are
+  triggered by the server.
+  </P>
+  <H2>Summary</H2>
+  <P>
+  The files in the <CODE>src/modules/example directory</CODE> under the
+  Apache distribution directory tree are provided as an example to those
+  that wish to write modules that use the Apache API.
+  </P>
+  <P>
+  The main file is <CODE>mod_example.c</CODE>, which illustrates all
+  the different callback mechanisms and call syntaces.  By no means does
+  an add-on module need to include routines for all of the callbacks -
+  quite the contrary!
+  </P>
+  <P>
+  The example module is an actual working module.  If you link it into
+  your server, enable the "example-handler" handler for a location, and
+  then browse to that location, you will see a display of
+  some of the tracing the example module did as the various callbacks
+  were made.
+  </P>
+  <P>
+  To include the example module in your server, follow the steps below:
+  </P>
+  <OL>
+   <LI>Uncomment the "Module example_module" line near the bottom of
+    the <CODE>src/Configuration</CODE> file.  If there isn't one, add
+    it; it should look like this:
+    <PRE>
+     Module example_module        modules/example/mod_example.o
+    </PRE>
+   </LI>
+   <LI>Run the <CODE>src/Configure</CODE> script
+    ("<SAMP>cd&nbsp;src;&nbsp;./Configure</SAMP>").  This will
+    build the Makefile for the server itself, and update the
+    <CODE>src/modules/Makefile</CODE> for any additional modules you
+    have requested from beneath that subdirectory.
+   </LI>
+   <LI>Make the server (run "<SAMP>make</SAMP>" in the <CODE>src</CODE>
+    directory).
+   </LI>
+  </OL>
+  <P>
+  To add another module of your own:
+  </P>
+  <OL TYPE="A">
+   <LI><SAMP>mkdir src/modules/<EM>mymodule</EM></SAMP>
+   </LI>
+   <LI><SAMP>cp src/modules/example/* src/modules/<EM>mymodule</EM></SAMP>
+   </LI>
+   <LI>Modify the files in the new directory.
+   </LI>
+   <LI>Follow steps [1] through [3] above, with appropriate changes.
+   </LI>
+  </OL>
+  <H3>
+   Using the <SAMP>mod_example</SAMP> Module
+  </H3>
+  <P>
+  To activate the example module, include a block similar to the
+  following in your <SAMP>srm.conf</SAMP> file:
+  </P>
+  <PRE>
+   &lt;Location /example-info&gt;
+       SetHandler example-handler
+   &lt;/Location&gt;
+  </PRE>
+  <P>
+  As an alternative, you can put the following into a
+  <A
+   HREF="core.html#accessfilename"
+  ><SAMP>.htaccess</SAMP></A>
+  file and then request the file &quot;test.example&quot; from that
+  location:
+  </P>
+  <PRE>
+   AddHandler example-handler .example
+  </PRE>
+  <P>
+  After reloading/restarting your server, you should be able to browse
+  to this location and see the brief display mentioned earlier.
+  </P>
+  <H2>Directives</H2>
+  <P>
+  <UL>
+   <LI><A HREF="#example">Example</A>
+   </LI>
+  </UL>
+  </P>
+  <HR>
+  <H2><A NAME="example">
+   Example
+  </A></H2>
+  <P>
+  <STRONG>Syntax:</STRONG> Example
+  <BR>
+  <STRONG>Default:</STRONG> None
+  <BR>
+  <STRONG>Context:</STRONG> server config, virtual host, directory, .htaccess
+  <BR>
+  <STRONG>Override:</STRONG> Options
+  <BR>
+  <STRONG>Status:</STRONG> Extension
+  <BR>
+  <STRONG>Module:</STRONG> mod_example
+  </P>
+  <P>
+  The Example directive activates the example module's content handler
+  for a particular location or file type.  It takes no arguments.  If
+  you browse to an URL to which the example content-handler applies, you
+  will get a display of the routines within the module and how and in
+  what order they were called to service the document request.
+  </P>
+  <!--#include virtual="footer.html" -->
+ </BODY>
+</HTML>
diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_expires.html b/APACHE_1_2_X/htdocs/manual/mod/mod_expires.html
new file mode 100644 (file)
index 0000000..3ec53d1
--- /dev/null
@@ -0,0 +1,185 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+ <HEAD>
+  <TITLE>Apache module mod_expires</TITLE>
+ </HEAD>
+ <!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+ <BODY
+  BGCOLOR="#FFFFFF"
+  TEXT="#000000"
+  LINK="#0000FF"
+  VLINK="#000080"
+  ALINK="#FF0000"
+ >
+  <!--#include virtual="header.html" -->
+  <H1 ALIGN="CENTER">Module mod_expires</H1>
+  <P>
+  This module is contained in the <CODE>mod_expires.c</CODE> file, and
+  is <STRONG>not</STRONG> compiled in by default.  It provides for the
+  generation of <CODE>Expires</CODE> headers according to user-specified
+  criteria.
+  </P>
+  <H2>Summary</H2>
+  <P>
+  This module controls the setting of the <CODE>Expires</CODE> HTTP
+  header in server responses.  The expiration date can set to be
+  relative to either the time the source file was last modified, or to
+  the time of the client access.
+  </P>
+  <P>
+  The <CODE>Expires</CODE> HTTP header is an instruction to the client
+  about the document's validity and persistence.  If cached, the document
+  may be fetched from the cache rather than from the source until this
+  time has passed.  After that, the cache copy is considered
+  &quot;expired&quot; and invalid, and a new copy must be obtained from
+  the source.
+  </P>
+  <H2>Directives</H2>
+  <P>
+  <MENU>
+   <LI><A
+        HREF="#expiresactive"
+       >ExpiresActive</A>
+   </LI>
+   <LI><A
+        HREF="#expiresbytype"
+       >ExpiresByType</A>
+   </LI>
+   <LI><A
+        HREF="#expiresdefault"
+       >ExpiresDefault</A>
+   </LI>
+  </MENU>
+  <HR>
+  <H2><A NAME="expiresactive">
+   ExpiresActive directive
+  </A></H2>
+  <!--%plaintext &lt;?INDEX {\tt ExpiresActive} directive&gt; -->
+  <P>
+  <STRONG>Syntax:</STRONG> ExpiresActive <EM>boolean</EM>
+  <BR>
+  <STRONG>Context:</STRONG> server config, virtual host, directory, .htaccess
+  <br>
+  <STRONG>Override:</STRONG> Indexes
+  <br>
+  <STRONG>Status:</STRONG> Extension
+  <br>
+  <STRONG>Module:</STRONG> mod_expires
+  </P>
+  <P>
+  This directive enables or disables the generation of the
+  <CODE>Expires</CODE> header for the document realm in question.  (That
+  is, if found in an <CODE>.htaccess</CODE> file, for instance, it
+  applies only to documents generated from that directory.)  If set to
+  <EM><CODE>Off</CODE></EM>, no <CODE>Expires</CODE> header will be
+  generated for any document in the realm (unless overridden at a lower
+  level, such as an <CODE>.htaccess</CODE> file overriding a server
+  config file).  If set to <EM><CODE>On</CODE></EM>, the header will be
+  added to served documents according to the criteria defined by the
+  <A
+   HREF="#expiresbytype"
+  >ExpiresByType</A>
+  and
+  <A
+   HREF="#expiresdefault"
+  >ExpiresDefault</A>
+  directives (<EM>q.v.</EM>).
+  </P>
+  <P>
+  Note that this directive does not guarantee that an
+  <CODE>Expires</CODE> header will be generated.  If the criteria aren't
+  met, no header will be sent, and the effect will be as though this
+  directive wasn't even specified.
+  </P>
+  <HR>
+  <H2><A NAME="expiresbytype">
+   ExpiresByType directive
+  </A></H2>
+  <!--%plaintext &lt;?INDEX {\tt ExpiresByType} directive&gt; -->
+  <P>
+  <STRONG>Syntax:</STRONG> ExpiresByType <EM>mime-type &lt;code&gt;seconds</EM>
+  <BR>
+  <STRONG>Context:</STRONG> server config, virtual host, directory, .htaccess
+  <br>
+  <STRONG>Override:</STRONG> Indexes
+  <br>
+  <STRONG>Status:</STRONG> Extension
+  <br>
+  <STRONG>Module:</STRONG> mod_expires
+  </P>
+  <P>
+  This directive defines the value of the <CODE>Expires</CODE> header
+  generated for documents of the specified type (<EM>e.g.</EM>,
+  <CODE>text/html</CODE>).  The second argument sets the number of
+  seconds that will be added to a base time to construct the expiration
+  date.
+  </P>
+  <P>
+  The base time is either the last modification time of the file, or the
+  time of the client's access to the document.  Which should be used is
+  specified by the <CODE><EM>&lt;code&gt;</EM></CODE> field;
+  <STRONG>M</STRONG> means that the file's last modification time should
+  be used as the base time, and <STRONG>A</STRONG> means the client's
+  access time should be used.
+  </P>
+  <P>
+  The difference in effect is subtle.  If <EM>M</EM> is used, all current
+  copies of the document in all caches will expire at the same time,
+  which can be good for something like a weekly notice that's always
+  found at the same URL.  If <EM>A</EM> is used, the date of expiration
+  is different for each client; this can be good for image files that
+  don't change very often, particularly for a set of related documents
+  that all refer to the same images (<EM>i.e.</EM>, the images will be
+  accessed repeatedly within a relatively short timespan).
+  </P>
+  <P>
+  <STRONG>Example:</STRONG>
+  </P>
+  <P>
+  <PRE>
+   ExpiresActive On                  # enable expirations
+   ExpiresByType image/gif A2592000  # expire GIF images after a month
+                                     #  in the client's cache
+   ExpiresByType text/html M604800   # HTML documents are good for a
+                                     #  week from the time they were
+                                     #  changed, period
+  </PRE>
+  </P>
+  <P>
+  Note that this directive only has effect if <CODE>ExpiresActive
+  On</CODE> has been specified.  It overrides, for the specified MIME
+  type <EM>only</EM>, any expiration date set by the
+  <A
+   HREF="#expiresdefault"
+  >ExpiresDefault</A>
+  directive.
+  </P>
+  <HR>
+  <H2><A NAME="expiresdefault">
+   ExpiresDefault directive
+  </A></H2>
+  <!--%plaintext &lt;?INDEX {\tt ExpiresDefault} directive&gt; -->
+  <P>
+  <STRONG>Syntax:</STRONG> ExpiresDefault <EM>&lt;code&gt;seconds</EM>
+  <BR>
+  <STRONG>Context:</STRONG> server config, virtual host, directory, .htaccess
+  <br>
+  <STRONG>Override:</STRONG> Indexes
+  <br>
+  <STRONG>Status:</STRONG> Extension
+  <br>
+  <STRONG>Module:</STRONG> mod_expires
+  </P>
+  <P>
+  This directive sets the default algorithm for calculating the
+  expiration time for all documents in the affected realm.  It can be
+  overridden on a type-by-type basis by the
+  <A
+   HREF="#expiresbytype"
+  >ExpiresByType</A>
+  directive.  See the description of that directive for details about
+  the syntax of the argument.
+  </P>
+  <!--#include virtual="footer.html" -->
+ </BODY>
+</HTML>
diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_headers.html b/APACHE_1_2_X/htdocs/manual/mod/mod_headers.html
new file mode 100644 (file)
index 0000000..aed34f0
--- /dev/null
@@ -0,0 +1,104 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<TITLE>Apache module mod_headers</TITLE>
+</HEAD>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<h1 ALIGN="CENTER">Headers Module</h1>
+
+The optional headers module allows for the customization of HTTP
+response headers. Headers can be merged, replaced or removed. The
+directives described in this document are only available if Apache is
+compiled with <b>mod_headers.c</b>.
+
+<hr>
+
+<h2>Directive</h2>
+<ul>
+<li><A HREF="#header">Header</A>
+</ul>
+
+<hr>
+
+<h2><A name="header">Header</A></h2>
+<strong>Syntax:</strong> Header [ set | append | add ] <em>header</em> <em>value</em><br>
+<strong>Syntax:</strong> Header unset <em>header</em><br>
+<strong>Context:</strong> server config, virtual host, access.conf, .htaccess<br>
+<strong>Status:</strong> optional<br>
+<strong>Module:</strong> mod_header<p>
+
+This directive can replace, merge or remove HTTP response headers. The
+action it performs is determined by the first argument. This can be one
+of the following values:
+
+<ul>
+<li><b>set</b><br>
+  The response header is set, replacing any previous header with this name
+
+<li><b>append</b><br>
+  The response header is appended to any existing header of the same
+  name. When a new value is merged onto an existing header it is
+  separated from the existing header with a comma. This is the HTTP standard
+  way of giving a header multiple values.
+
+<li><b>add</b><br>
+  The response header is added to the existing set of headers, even if
+  this header already exists. This can result in two (or more) headers
+  having the same name. This can lead to unforeseen consequences, and in
+  general "append" should be used instead.
+
+<li><b>unset</b><br>
+  The response header of this name is removed, if it exists. If there are
+  multiple headers of the same name, only the first one set will be removed.
+</ul>
+
+This argument is followed by a header name, which can include the
+final colon, but it is not required. Case is ignored. For
+add, append and set a value is given as the third argument. If this
+value contains spaces, it should be surrounded by double quotes.
+For unset, no value should be given.
+
+<h3>Order of Processing</h3>
+
+The Header directive can occur almost anywhere within the server
+configuration. It is valid in the main server config and virtual host
+sections, inside &lt;Directory&gt;, &lt;Location&gt; and &lt;Files&gt;
+sections, and within .htaccess files.
+<p>
+The Header directives are processed in the following order:
+<ol>
+<li>main server
+<li>virtual host
+<li>&lt;Directory&gt; sections and .htaccess
+<li>&lt;Location&gt;
+<li>&lt;Files&gt;
+</ol>
+
+Order is important. These two headers have a different effect if reversed:
+<pre>
+Header append Author "John P. Doe"
+Header unset Author
+</pre>
+
+This way round, the Author header is not set. If reversed, the Author
+header is set to "John P. Doe".
+<p>
+
+The Header directives are processed just before the response is sent
+by its handler. These means that some headers that are added just
+before the response is sent cannot be unset or overridden. This
+includes headers such as "Date" and "Server".
+<P>
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_imap.html b/APACHE_1_2_X/htdocs/manual/mod/mod_imap.html
new file mode 100644 (file)
index 0000000..718f3fb
--- /dev/null
@@ -0,0 +1,284 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<title>Apache module mod_imap</title>
+</head>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<h1 ALIGN="CENTER">Module mod_imap</h1>
+
+This module is contained in the <code>mod_imap.c</code> file, and is
+compiled in by default. It provides for <code>.map</code> files,
+replacing the functionality of the <code>imagemap</code> CGI
+program. Any directory or document type configured to use the handler
+<code>imap-file</code> (using either <code><A
+HREF="mod_mime.html#addhandler">AddHandler</A> </code> or <code><A
+HREF="mod_mime.html#sethandler">SetHandler</A></code>) will be
+processed by this module.
+
+<h2>Summary</h2>
+
+This module is in the default Apache distribution. The following directive will
+activate files ending with <code>.map</code> as imagemap files:
+
+<blockquote><code>AddHandler imap-file map</code></blockquote>
+
+Note that the following is still supported:
+
+ <blockquote><code>AddType application/x-httpd-imap map</code></blockquote>
+
+However, we are trying to phase out "magic MIME types" so we are deprecating
+this method.
+
+<H2>New Features</H2>
+The imagemap module adds some new features that were not
+possible with previously distributed imagemap programs.<P>
+
+<ul>
+<LI>URL references relative to the Referer: information.
+<LI>Default &lt;BASE&gt; assignment through a new map directive
+<code>base</code>.
+<LI>No need for <code>imagemap.conf</code> file.
+<LI>Point references.
+<LI>Configurable generation of imagemap menus.
+</ul>
+<P>
+
+<h2>Configuration Directives</h2>
+<ul>
+<li><A HREF="#imapmenu">ImapMenu</A>
+<li><A HREF="#imapdefault">ImapDefault</A>
+<li><A HREF="#imapbase">ImapBase</A>
+</ul>
+
+
+<p>
+
+<h3><A name="imapmenu">ImapMenu</A></h3>
+<strong>Syntax:</strong> ImapMenu <code>{none, formatted, semi-formatted,
+                                                      unformatted}</code><br>
+<Strong>Context:</strong> server config, virtual host, directory, .htaccess<br>
+<Strong>Override:</strong> Indexes<br>
+<strong>Module:</strong> mod_imap.c<br>
+<strong>Compatibility:</strong> ImapMenu is only available in Apache
+1.1 and later.<p>
+
+The ImapMenu directive determines the action taken if an imagemap file
+is called without valid coordinates.
+<dl>
+  <dt><code>none</code>
+  <dd>If ImapMenu is
+       <code>none</code>, no menu is generated, and the <code>default</code>
+       action is performed.  
+  <dt><code>formatted</code>
+  <dd>A <code>formatted</code> menu is the simplest menu.  Comments
+       in the imagemap file are ignored.  A level one header is
+       printed, then an hrule, then the links each on a separate line.
+       The menu has a consistent, plain look close to that of
+       a directory listing.
+  <dt><code>semiformatted</code>
+  <dd>In the <code>semiformatted</code> menu, comments are printed
+       where they occur in the imagemap file.  Blank lines are turned
+       into HTML breaks.  No header or hrule is printed, but otherwise
+       the menu is the same as a <code>formatted</code> menu.
+  <dt><code>unformatted</code>
+  <dd>Comments are printed, blank lines are ignored.  Nothing is
+       printed that does not appear in the imagemap file.  All breaks
+       and headers must be included as comments in the imagemap file.
+       This gives you the most flexibility over the appearance of your
+       menus, but requires you to treat your map files as HTML instead
+       of plaintext.
+</dl>
+
+<p>
+
+<h3><A name="imapdefault">ImapDefault</A></h3>
+<strong>Syntax:</strong> ImapDefault <code>{error, nocontent,
+                                                 map, referer, URL}</code><br>
+<Strong>Context:</strong> server config, virtual host, directory, .htaccess<br>
+<Strong>Override:</strong> Indexes<br>
+<strong>Module:</strong> mod_imap.c<br>
+<strong>Compatibility:</strong> ImapDefault is only available in Apache
+1.1 and later.<p>
+
+
+The ImapDefault directive sets the default <code>default</code> used in
+the imagemap files.  It's value is overridden by a <code>default</code>
+directive within the imagemap file.  If not present, the
+<code>default</code> action is <code>nocontent</code>, which means
+that a <code>204 No Content</code> is sent to the client.  In this
+case, the client should continue to display the original page.
+
+<p>
+
+<h3><A name="imapbase">ImapBase</A></h3>
+<strong>Syntax:</strong> ImapBase <code>{map, referer, URL}</code><br>
+<Strong>Context:</strong> server config, virtual host, directory, .htaccess<br>
+<Strong>Override:</strong> Indexes<br>
+<strong>Module:</strong> mod_imap.c<br>
+<strong>Compatibility:</strong> ImapBase is only available in Apache
+1.1 and later.<p>
+
+The ImapBase directive sets the default <code>base</code> used in
+the imagemap files.  It's value is overridden by a <code>base</code>
+directive within the imagemap file.  If not present, the
+<code>base</code> defaults to <code>http://servername/</code>.
+
+<hr>
+<p>
+
+<h2>Imagemap File</h2>
+The lines in the imagemap files can have one of several formats:
+<blockquote>
+<code>directive value [x,y ...]</code><br>
+<code>directive value "Menu text" [x,y ...]</code><br>
+<code>directive value x,y ... "Menu text"</code><br>
+</blockquote>
+The directive is one of <code>base</code>, <code>default</code>,
+<code>poly</code>, <code>circle</code>, <code>rect</code>, or
+<code>point</code>.  The value is an absolute or relative URL, or one
+of the special values listed below.  The coordinates are
+<code>x,y</code> pairs separated by whitespace.  The quoted text is
+used as the text of the link if a imagemap menu is generated.  Lines
+beginning with '#' are comments.
+
+<h3>Imagemap File Directives</h3>
+There are six directives allowed in the imagemap file.  The directives
+can come in any order, but are processed in the order they are found
+in the imagemap file.  
+<dl>  
+<dt><code>base</code> Directive
+<dd>Has the effect of <code>&lt;BASE href="value"&gt;</code>.  The
+     non-absolute URLs of the map-file are taken relative to this value.
+     The <code>base</code> directive overrides ImapBase as set in a
+     .htaccess file or in the server configuration files.  In the absence
+     of an ImapBase configuration directive, <code>base</code> defaults to
+     <code>http://server_name/</code>. <br>
+     <code>base_uri</code> is synonymous with <code>base</code>.  Note that
+     a trailing slash on the URL is significant.
+<p>
+<dt><code>default</code> Directive
+<dd>The action taken if the coordinates given do not fit any of the
+     <code>poly</code>, <code>circle</code> or <code>rect</code>
+     directives, and there are no <code>point</code> directives.  Defaults
+     to <code>nocontent</code> in the absence of an ImapDefault
+     configuration setting, causing a status code of <code>204 No
+     Content</code> to be returned.  The client should keep the same
+     page displayed.
+<p>
+<dt><code>poly</code> Directive
+<dd>Takes three to one-hundred points, and is obeyed if the user selected
+     coordinates fall within the polygon defined by these points.
+<p>
+<dt><code>circle</code>
+<dd>Takes the center coordinates of a circle and a point on the circle. Is
+     obeyed if the user selected point is with the circle.
+<p>
+<dt><code>rect</code> Directive
+<dd>Takes the coordinates of two opposing corners of a rectangle.  Obeyed
+     if the point selected is within this rectangle.
+<p>
+<dt><code>point</code> Directive
+<dd>Takes a single point.  The point directive closest to the user
+     selected point is obeyed if no other directives are satisfied.
+     Note that <code>default</code> will not be followed if a
+     <code>point</code> directive is present and valid coordinates are
+     given.
+</dl>
+
+
+
+<h3>Values</h3>
+The values for each of the directives can any of the following:
+<dl>
+  <dt>a URL
+  <dd>The URL can be relative or absolute URL.  Relative URLs can
+       contain '..' syntax and will be resolved relative to the
+       <code>base</code> value. <br>
+       <code>base</code> itself will not resolved according to the current
+       value. A statement <code>base mailto:</code> will work properly, though.
+<p>
+  <dt><code>map</code>
+  <dd>Equivalent to the URL of the imagemap file itself.  No
+       coordinates are sent with this, so a menu will be generated
+       unless ImapMenu is set to 'none'.
+<p>
+  <dt><code>menu</code>
+  <dd>Synonymous with <code>map</code>.
+<p>
+  <dt><code>referer</code>
+  <dd>Equivalent to the URL of the referring document.
+       Defaults to <code>http://servername/</code> if no Referer:
+       header was present. 
+<p>
+  <dt><code>nocontent</code>
+  <dd>Sends a status code of <code>204 No Content</code>,
+       telling the client to keep the same page displayed.  Valid for
+       all but <code>base</code>.
+<p>
+  <dt><code>error</code>
+  <dd>Fails with a <code>500 Server Error</code>.  Valid for all but
+       <code>base</code>, but sort of silly for anything but
+       <code>default</code>. 
+</dl>
+
+<h3>Coordinates</h3>
+<dl>
+  <dt><code>0,0 200,200</code>
+  <dd>A coordinate consists of an <tt>x</tt> and a <tt>y</tt> value
+       separated by a comma.  The coordinates are separated from each other
+       by whitespace.  To accommodate the way Lynx handles imagemaps, should a
+       user select the coordinate <code>0,0</code>, it is as if
+       no coordinate had been selected.   
+</dl>
+
+<h3>Quoted Text</h3>
+<dl>
+  <dt><code>"Menu Text"</code>
+  <dd>After the value or after the coordinates, the line optionally may 
+       contain text within double quotes.  This string is used as the
+       text for the link if a menu is generated:<br>
+     <code>&lt;a href="http://foo.com/"&gt;Menu text&lt;/a&gt;</code><br>
+       If no quoted text is present, the name of the link will be used
+       as the text:<br>
+     <code>&lt;a href="http://foo.com/"&gt;http://foo.com&lt;/a&gt;</code><br>
+       It is impossible to escape double quotes within this text.
+</dl>
+
+<hr>
+
+<h2>Example Mapfile</h2>
+<blockquote><code>
+#Comments are printed in a 'formatted' or 'semiformatted' menu. <br>
+#And can contain html tags. &lt;hr&gt; <br>
+base referer  <br>
+poly map "Could I have a menu, please?"  0,0 0,10 10,10 10,0 <br>
+rect .. 0,0 77,27 "the directory of the referer"<br>
+circle http://www.inetnebr.com/lincoln/feedback/ 195,0 305,27 <br>
+rect another_file "in same directory as referer" 306,0 419,27  <br>
+point http://www.zyzzyva.com/ 100,100 <br>
+point http://www.tripod.com/  200,200 <br>
+rect mailto:nate@tripod.com 100,150 200,0 "Bugs?" <br>
+</code></blockquote>
+<P>
+
+<h2>Referencing your mapfile</h2>
+<blockquote><code>
+&lt;A HREF="/maps/imagmap1.map"&gt; <br>
+&lt;IMG ISMAP SRC="/images/imagemap1.gif"&gt; <br>
+&lt;/A&gt;
+</code></blockquote><p>
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
+
+
diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_include.html b/APACHE_1_2_X/htdocs/manual/mod/mod_include.html
new file mode 100644 (file)
index 0000000..6f51130
--- /dev/null
@@ -0,0 +1,385 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<TITLE>Apache module mod_include</TITLE>
+</HEAD>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<H1 ALIGN="CENTER">Module mod_include</H1>
+
+This module is contained in the <code>mod_include.c</code> file, and
+is compiled in by default. It provides for server-parsed html
+documents. Several directives beyond the original NCSA definition have been
+included in Apache 1.2 - these are flagged below with the phrase
+"Apache 1.2 and above".  Of particular significance are the new flow 
+control directives documented at the bottom.
+
+<H2>Enabling Server-Side Includes</H2>
+
+Any document with handler of "server-parsed" will be parsed by this
+module, if the <CODE>Includes</CODE> option is set. If documents
+containing server-side include directives are given the extension
+.shtml, the following directives will make Apache parse them and
+assign the resulting document the mime type of <CODE>text/html</CODE>:
+
+<PRE>
+AddType text/html .shtml
+AddHandler server-parsed .shtml
+</PRE>
+
+The following directive must be given for the directories containing
+the shtml files (typically in a <CODE>&lt;Directory&gt;</CODE> section,
+but this directive is also valid .htaccess files if <CODE>AllowOverride
+Options</CODE> is set):
+
+<PRE>
+Options +Includes
+</PRE>
+
+Alternatively the <A HREF="#xbithack"><CODE>XBitHack</CODE></A>
+directive can be used to parse normal (<CODE>text/html</CODE>) files,
+based on file permissions.  <P>
+
+For backwards compatibility, documents with mime type
+<code>text/x-server-parsed-html</code> or
+<code>text/x-server-parsed-html3</code> will also be parsed
+(and the resulting output given the mime type <code>text/html</code>).
+
+<h2>Basic Elements</h2>
+
+The document is parsed as an HTML document, with special commands embedded
+as SGML comments. A command has the syntax:
+
+<blockquote><code>
+&lt;!--#</code><em>element attribute=value attribute=value ...</em>
+<code> --&gt;
+</code></blockquote>
+
+The value will often be enclosed in double quotes; many commands only allow
+a single attribute-value pair.  Note that the comment terminator
+(<SAMP>--&gt;</SAMP>) should be preceded by whitespace to ensure that it
+isn't considered part of an SSI token.
+<p>
+The allowed elements are:<p>
+
+<dl>
+
+<dt><strong>config</strong>
+<dd>
+This command controls various aspects of the parsing. The valid attributes
+are:
+<dl>
+<dt>errmsg
+<dd>The value is a message that is sent back to the client if an error occurs
+whilst parsing the document.
+<dt>sizefmt
+<dd>The value sets the format to be used which displaying the size of a file.
+Valid values are <code>bytes</code> for a count in bytes, or
+<code>abbrev</code> for a count in Kb or Mb as appropriate.
+<dt>timefmt
+<dd>The value is a string to be used by the <code>strftime(3)</code> library
+routine when printing dates.
+</dl>
+
+<dt><strong>echo</strong>
+<dd>
+This command prints one of the include variables, defined below.
+If the variable is unset, it is printed as <code>(none)</code>.
+Any dates printed are subject to the currently configured <code>timefmt</code>.
+Attributes:
+<dl>
+<dt>var
+<dd>The value is the name of the variable to print.
+</dl>
+
+<dt><strong>exec</strong>
+<dd>
+The exec command executes a given shell command or CGI script.
+The IncludesNOEXEC <A HREF="core.html#options">Option</A> disables this command
+completely. The valid attributes are:
+<dl>
+<dt>cgi
+<dd>
+The value specifies a (%-encoded) URL relative path to the CGI script.
+If the path does not begin with a (/), then it is taken to be relative to
+the current document. The document referenced by this path is invoked
+as a CGI script, even if the server would not normally recognize it as
+such. However, the directory containing the script must be enabled for
+CGI scripts (with <A HREF="mod_alias.html#scriptalias">ScriptAlias</A>
+or the ExecCGI <A HREF="core.html#options">Option</A>).<p>
+The CGI script is given the PATH_INFO and query string (QUERY_STRING) of the
+original request from the client; these cannot be specified in the URL path.
+The include variables will be available to the script in addition to the
+standard <A HREF="mod_cgi.html">CGI</A> environment.<p>
+If the script returns a Location: header instead of output, then this
+will be translated into an HTML anchor.<p>
+The <code>include virtual</code> element should be used in preference to
+<code>exec cgi</code>.
+<dt>cmd
+<dd>The server will execute the given string using <code>/bin/sh</code>.
+The include variables are available to the command.
+</dl>
+
+<dt><strong>fsize</strong>
+<dd>
+This command prints the size of the specified file, subject to the
+<code>sizefmt</code> format specification. Attributes:
+<dl>
+<dt>file
+<dd>The value is a path relative to the directory containing the current
+document being parsed.
+<dt>virtual
+<dd>The value is a (%-encoded) URL-path relative to the current document being
+parsed. If it does not begin with a slash (/) then it is taken to be relative
+to the current document.
+</dl>
+
+<dt><strong>flastmod</strong>
+<dd>
+This command prints the last modification date of the specified file,
+subject to the <code>timefmt</code> format specification. The attributes are
+the same as for the <code>fsize</code> command.
+
+<dt><strong>include</strong>
+<dd>
+This command inserts the text of another document or file into the parsed
+file. Any included file is subject to the usual access control. If the
+directory containing the parsed file has the
+<A HREF="core.html#options">Option</A>
+IncludesNOEXEC set, and the including the document would cause a program
+to be executed, then it will not be included; this prevents the execution of
+CGI scripts. Otherwise CGI scripts are invoked as normal using the complete
+URL given in the command, including any query string.
+<!--%plaintext &lt;?INDEX CGI scripts, {\tt include} element and&gt; -->
+<p>
+
+An attribute defines the location of the document; the inclusion is done for
+each attribute given to the include command. The valid attributes are:
+<dl>
+<dt>file
+<dd>The value is a path relative to the directory containing the current
+document being parsed. It cannot contain <code>../</code>, nor can it be an
+absolute path. The <code>virtual</code> attribute should always be used
+in preference to this one.
+<dt>virtual
+<dd>The value is a (%-encoded) URL relative to the current document being
+parsed. The URL cannot contain a scheme or hostname, only a path and
+an optional query string. If it does not begin with a slash (/) then it
+is taken to be relative to the current document.
+</dl>
+A URL is constructed from the attribute, and the output the server
+would return if the URL were accessed by the client is included in the parsed
+output. Thus included files can be nested.
+
+<dt><strong>printenv</strong>
+<dd>This prints out a listing of all existing variables and their values.
+    No attributes.
+<dd>For example: <code>&lt;!--#printenv --&gt;</code>
+<dd>Apache 1.2 and above.
+
+<dt><strong>set</strong>
+<dd>This sets the value of a variable.  Attributes:
+<dl>
+<dt>var
+<dd>The name of the variable to set.
+<dt>value
+<dd>The value to give a variable.
+</dl>
+For example: 
+  <CODE>&lt;!--#set var="category" value="help" --&gt;</CODE>
+<dd>Apache 1.2 and above.
+
+</dl>
+
+<h2>Include Variables</h2>
+
+In addition to the variables in the standard CGI environment, these are
+available for the <code>echo</code> command, for <code>if</code> and
+<code>elif</code>, and to any program invoked by the document.  
+
+<dl>
+<dt>DATE_GMT
+<dd>The current date in Greenwich Mean Time.
+<dt>DATE_LOCAL
+<dd>The current date in the local time zone.
+<dt>DOCUMENT_NAME
+<dd>The filename (excluding directories) of the document requested by the
+user.
+<dt>DOCUMENT_URI
+<dd>The (%-decoded) URL path of the document requested by the user. Note that
+in the case of nested include files, this is <em>not</em> then URL for the
+current document.
+<dt>LAST_MODIFIED
+<dd>The last modification date of the document requested by the user.
+</dl>
+<p>
+
+<H2>Variable Substitution</H2>
+<P> Variable substitution is done within quoted strings in most cases
+    where they may reasonably occur as an argument to an SSI directive.
+    This includes the
+    <SAMP>config</SAMP>,
+    <SAMP>exec</SAMP>,
+    <SAMP>flastmod</SAMP>,
+    <SAMP>fsize</SAMP>,
+    <SAMP>include</SAMP>, and
+    <SAMP>set</SAMP>
+    directives, as well as the arguments to conditional operators.
+    You can insert a literal dollar sign into the string using backslash
+    quoting:
+
+<PRE>
+    &lt;!--#if expr="$a = \$test" --&gt;
+</PRE>
+
+<P> If a variable reference needs to be substituted in the middle of a
+    character sequence that might otherwise be considered a valid
+    identifier in its own right, it can be disambiguated by enclosing
+    the reference in braces, <EM>&agrave; la</EM> shell substitution:
+
+<PRE>
+    &lt;!--#set var="Zed" value="${REMOTE_HOST}_${REQUEST_METHOD}" --&gt;
+</PRE>
+
+<P> This will result in the <SAMP>Zed</SAMP> variable being set to
+    &quot;<SAMP>X_Y</SAMP>&quot; if <SAMP>REMOTE_HOST</SAMP> is
+    &quot;<SAMP>X</SAMP>&quot; and <SAMP>REQUEST_METHOD</SAMP> is
+    &quot;<SAMP>Y</SAMP>&quot;.
+
+<P> EXAMPLE: the below example will print "in foo" if the DOCUMENT_URI is 
+/foo/file.html, "in bar" if it is /bar/file.html and "in neither" 
+otherwise:
+<PRE>
+    &lt;!--#if expr="\"$DOCUMENT_URI\" = \"/foo/file.html\"" --&gt;
+    in foo
+    &lt;!--#elif expr="\"$DOCUMENT_URI\" = \"/bar/file.html\"" --&gt;
+    in bar
+    &lt;!--#else --&gt;
+    in neither
+    &lt;!--#endif --&gt;
+</PRE>
+
+<H2>Flow Control Elements</H2>
+
+These are available in Apache 1.2 and above.  The basic flow control
+elements are:
+
+<PRE>
+    &lt;!--#if expr="<I>test_condition</I>" --&gt;
+    &lt;!--#elif expr="<I>test_condition</I>" --&gt;
+    &lt;!--#else --&gt;
+    &lt;!--#endif --&gt;
+</PRE>
+
+<P> The <B><CODE>if</CODE></B> element works like an
+    if statement in a programming language.  The test condition
+    is evaluated and if the result is true, then the text until
+    the next <B><CODE>elif</CODE></B>, <B><CODE>else</CODE></B>.
+    or <B><CODE>endif</CODE></B> element is included in the
+    output stream.
+
+<P> The <B><CODE>elif</CODE></B> or <B><CODE>else</CODE></B>
+    statements are be used the put text into the output stream
+    if the original test_condition was false.  These elements
+    are optional.
+
+<P> The <B><CODE>endif</CODE></B> element ends the 
+    <B><CODE>if</CODE></B> element and is required.
+
+<P> <I>test_condition</I> is one of the following:
+
+<DL>
+
+<DT><I>string</I><DD>true if <I>string</I> is not empty
+
+<DT><I>string1</I> = <I>string2</I><BR>
+    <I>string1</I> != <I>string2</I>
+
+<DD>Compare string1 with string 2.  If string2 has the form <I>/string/</I>
+    than it is compared as a regular expression.
+    Regular expressions have the same syntax as those found in the
+    Unix egrep command.
+
+<DT>( <I>test_condition</I> )
+       <DD>true if <I>test_condition</I> is true 
+<DT>! <I>test_condition</I>
+       <DD>true if <I>test_condition</I> is false
+<DT><I>test_condition1</I> && <I>test_condition2</I>
+       <DD>true if both <I>test_condition1</I> and
+       <I>test_condition2</I> are true 
+<DT><I>test_condition1</I> || <I>test_condition2</I>
+       <DD>true if either <I>test_condition1</I> or
+       <I>test_condition2</I> is true 
+</DL>
+
+<P> "<I>=</I>" and "<I>!=</I>" bind more tightly than "<I>&&</I>" and
+    "<I>||</I>". 
+    "<I>!</I>" binds most tightly.  Thus, the following are equivalent:
+
+<PRE>
+    &lt;!--#if expr="$a = test1 && $b = test2" --&gt;
+    &lt;!--#if expr="($a = test1) && ($b = test2)" --&gt;
+</PRE>
+
+<P> Anything that's not recognized as a variable or an operator is
+    treated as a string.  Strings can also be quoted: <I>'string'</I>.
+    Unquoted strings can't contain whitespace (blanks and tabs)
+    because it is used to separate tokens such as variables.  If
+    multiple strings are found in a row, they are concatenated using
+    blanks.  So,
+
+<PRE>
+     <I>string1    string2</I>  results in <I>string1 string2</I>
+    <I>'string1    string2'</I> results in <I>string1    string2</I>
+</PRE>
+
+<hr>
+<h2>Directives</h2>
+<ul>
+<li><A HREF="#xbithack">XBitHack</A>
+</ul>
+<hr>
+
+
+<h2><A name="xbithack">XBitHack</A></h2>
+<!--%plaintext &lt;?INDEX {\tt XBitHack} directive&gt; -->
+<strong>Syntax:</strong> XBitHack <em>status</em><br>
+<strong>Default:</strong> <code>XBitHack off</code><br>
+<Strong>Context:</strong> server config, virtual host, directory, .htaccess<br>
+<Strong>Override:</strong> Options<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_include<p>
+
+The XBitHack directives controls the parsing of ordinary html documents.
+This directive only affects files associated with the MIME type
+<CODE>text/html</CODE>. 
+<em>Status</em> can have the following values:
+<dl>
+<dt>off
+<dd>No special treatment of executable files.
+<dt>on
+<dd>Any file that has the user-execute bit set will be treated as a
+server-parsed html document.
+<dt>full
+<dd>As for <code>on</code> but also test the group-execute bit. If it
+is set, then set the Last-modified date of the returned file to be the
+last modified time of the file. If it is not set, then no last-modified date
+is sent. Setting this bit allows clients and proxies to cache the result of
+the request.
+<p><b>Note:</b> you would not want to use this, for example, when you
+<code>#include</code> a CGI that produces different output on each hit
+(or potentially depends on the hit).
+</dl>
+<p>
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_info.html b/APACHE_1_2_X/htdocs/manual/mod/mod_info.html
new file mode 100644 (file)
index 0000000..dd75349
--- /dev/null
@@ -0,0 +1,73 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<title>Apache module mod_info</title>
+</head>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<h1 ALIGN="CENTER">Module mod_info</h1>
+
+This module is contained in the <code>mod_info.c</code> file.  It
+provides a comprehensive overview of the server configuration
+including all installed modules and directives in the configuration
+files.  This module is not compiled into the
+server by default.  It is only available in Apache 1.1 and later. To
+enable it, add the following line to the server build Configuration
+file, and rebuild the server:
+
+<PRE>
+Module info_module   mod_info.o
+</PRE>
+
+<HR>
+<P>
+To configure it, add the following to your <code>access.conf</code> file.
+
+<PRE>
+&lt;Location /server-info&gt;
+SetHandler server-info
+&lt;/Location&gt;
+</PRE>
+
+You may wish to add a
+<A
+ HREF="core.html#limit"
+>&lt;Limit&gt;</A>
+clause inside the
+<A
+ HREF="core.html#location"
+>location</A>
+directive to limit access to your server configuration information.<p>
+Once configured, the server information is obtained by accessing
+<tt>http://your.host.dom/server-info</tt><p>
+<BLOCKQUOTE>
+ <STRONG>
+  Note that the configuration files are read by the module at run-time,
+  and therefore the display may <EM>not</EM> reflect the running
+  server's active configuration if the files have been changed since the
+  server was last reloaded.  Also, the configuration files must be
+  readable by the user as which the server is running (see the
+  <A
+   HREF="core.html#user"
+  ><SAMP>User</SAMP></A>
+  directive), or else the directive settings will not be listed.
+  <P>
+  It should also be noted that if <SAMP>mod_info</SAMP> is compiled into
+  the server, its handler capability is available in <EM>all</EM>
+  configuration files, including <EM>per</EM>-directory files
+  (<EM>e.g.</EM>, <SAMP>.htaccess</SAMP>).  This may have
+  security-related ramifications for your site.
+  </P>
+ </STRONG>
+</BLOCKQUOTE>
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_log_agent.html b/APACHE_1_2_X/htdocs/manual/mod/mod_log_agent.html
new file mode 100644 (file)
index 0000000..9e8fa50
--- /dev/null
@@ -0,0 +1,61 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<TITLE>Module mod_log_agent</TITLE>
+</HEAD>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<H1 ALIGN="CENTER">Module mod_log_agent</h1>
+
+This module is contained in the <code>mod_log_agent.c</code> file, and is not
+compiled in by default. It provides for logging of the client user agents.
+
+
+<ul>
+<li><A HREF="#agentlog">AgentLog</A>
+</ul>
+<hr>
+
+
+<h2><A name="agentlog">AgentLog</A></h2>
+<!--%plaintext &lt;?INDEX {\tt AgentLog} directive&gt; -->
+<strong>Syntax:</strong> AgentLog <em>file-pipe</em><br>
+<strong>Default:</strong> <code>AgentLog logs/agent_log</code><br>
+<Strong>Context:</strong> server config, virtual host<br>
+<strong>Status:</strong> Extension<br>
+<strong>Module:</strong> mod_log_agent<p>
+
+The AgentLog directive sets the name of the file to which the server will
+log the UserAgent header of incoming requests. <em>File-pipe</em> is one
+of
+<dl><dt>A filename
+<dd>A filename relative to the <A HREF="core.html#serverroot">ServerRoot</A>.
+<dt> `|' followed by a command
+<dd>A program to receive the agent log information on its standard input.
+Note the a new program will not be started for a VirtualHost if it inherits
+the AgentLog from the main server.
+</dl>
+<strong>Security:</strong> if a program is used, then it will be
+run under the user who started httpd. This will be root if the server
+was started by root; be sure that the program is secure.<p>
+
+<strong>Security:</strong> See the <A
+HREF="../misc/security_tips.html">security tips</A> document for
+details on why your security could be compromised if the directory
+where logfiles are stored is writable by anyone other than the user
+that starts the server.<P>
+
+This directive is provided for compatibility with NCSA 1.4.<p>
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
+
diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_log_common.html b/APACHE_1_2_X/htdocs/manual/mod/mod_log_common.html
new file mode 100644 (file)
index 0000000..1a85177
--- /dev/null
@@ -0,0 +1,101 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<TITLE>Apache module mod_log_common</TITLE>
+</HEAD>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<H1 ALIGN="CENTER">Module mod_log_common</h1>
+
+This module is contained in the <code>mod_log_common.c</code> file,
+and is compiled in by default. It provides for logging of the requests
+made to the server using the Common Logfile Format. This module has
+been replaced by mod_log_config in Apache 1.2
+
+<h2>Log file format</h2>
+The log file contains a separate line for each request. A line is composed
+of several tokens separated by spaces:
+<blockquote>
+host ident authuser date request status bytes
+</blockquote>
+If a token does not have a value then it is represented by a hyphen (-).
+The meanings and values of these tokens are as follows:
+<dl>
+<dt>host
+<dd>The fully-qualified domain name of the client, or its IP number if the
+name is not available.
+<dt>ident
+<dd>If <A HREF="core.html#identitycheck">IdentityCheck</A> is enabled and the
+client machine runs identd, then this is the identity information reported
+by the client.
+<dt>authuser
+<dd>If the request was for an password protected document, then this is
+the userid used in the request.
+<dt>date
+<dd>The date and time of the request, in the following format:
+<dl><dd><blockquote><code> date = [day/month/year:hour:minute:second zone] <br>
+day = 2*digit<br>
+month = 3*letter<br>
+year = 4*digit<br>
+hour = 2*digit<br>
+minute = 2*digit<br>
+second = 2*digit<br>
+zone = (`+' | `-') 4*digit</code></blockquote></dl>
+<dt>request
+<dd>The request line from the client, enclosed in double quotes
+(<code>&quot;</code>).
+<dt>status
+<dd>The three digit status code returned to the client.
+<dt>bytes
+<dd>The number of bytes in the object returned to the client, not including
+any headers.
+</dl>
+
+
+<h2>Directives</h2>
+<ul>
+<li><A HREF="#transferlog">TransferLog</A>
+</ul>
+<hr>
+
+
+<h2><A name="transferlog">TransferLog</A></h2>
+<!--%plaintext &lt;?INDEX {\tt TransferLog} directive&gt; -->
+<strong>Syntax:</strong> TransferLog <em>file-pipe</em><br>
+<strong>Default:</strong> <code>TransferLog logs/transfer_log</code><br>
+<Strong>Context:</strong> server config, virtual host<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_log_common<p>
+
+The TransferLog directive sets the name of the file to which the server will
+log the incoming requests. <em>File-pipe</em> is one
+of
+<dl><dt>A filename
+<dd>A filename relative to the <A HREF="core.html#serverroot">ServerRoot</A>.
+<dt> `|' followed by a command
+<dd>A program to receive the agent log information on its standard input.
+Note the a new program will not be started for a VirtualHost if it inherits
+the TransferLog from the main server.
+</dl>
+<strong>Security:</strong> if a program is used, then it will be
+run under the user who started httpd. This will be root if the server
+was started by root; be sure that the program is secure.<p>
+
+<strong>Security:</strong> See the <A
+HREF="../misc/security_tips.html">security tips</A> document for
+details on why your security could be compromised if the directory
+where logfiles are stored is writable by anyone other than the user
+that starts the server.<P>
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
+
diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_log_config.html b/APACHE_1_2_X/htdocs/manual/mod/mod_log_config.html
new file mode 100644 (file)
index 0000000..8ffc86c
--- /dev/null
@@ -0,0 +1,263 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<TITLE>Apache module mod_log_config</TITLE>
+</HEAD>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<H1 ALIGN="CENTER">Module mod_log_config</h1>
+
+This module is contained in the <code>mod_log_config.c</code> file,
+and is compiled in by default in Apache 1.2. mod_log_config replaces
+mod_log_common in Apache 1.2. Prior to version 1.2, mod_log_config was
+an optional module. It provides for logging of the requests made to
+the server, using the Common Log Format or a user-specified format.
+
+<h2>Summary</h2>
+
+Three directives are provided by this module: <code>TransferLog</code>
+to create a log file, <code>LogFormat</code> to set a custom format,
+and <code>CustomLog</code> to define a log file and format in one go.
+The <code>TransferLog</code> and <code>CustomLog</code> directives can
+be used multiple times in each server to cause each request to be
+logged to multiple files.
+<P>
+
+<h3>Compatibility notes</h3>
+
+<ul>
+<li>This module is based on mod_log_config distributed with
+previous Apache releases, now updated to handle multiple logs.
+There is now no need to re-configure Apache to use configuration log
+formats.
+
+<li>The module also implements the <code>CookieLog</code> directive,
+used to log user-tracking information created by <a
+href="mod_usertrack.html">mod_usertrack</a>. The use of
+<code>CookieLog</code> is deprecated, and a <code>CustomLog</code>
+should be defined to log user-tracking information instead.
+
+</ul>
+
+<h2>Log File Formats</h2>
+
+Unless told otherwise with <tt>LogFormat</tt> the log files created by
+<tt>TransferLog</tt> will be in standard "Common Log Format"
+(CLF). The contents of each line in a CLF file are explained
+below. Alternatively, the log file can be customized (and if multiple
+log files are used, each can have a different format). Custom formats
+are set with <code>LogFormat</code> and <code>CustomLog</code>.
+
+<h3>Common Log Format</h3>
+
+The Common Log Format (CLF) file contains a separate line for each
+request. A line is composed of several tokens separated by spaces:
+
+<blockquote>
+host ident authuser date request status bytes
+</blockquote>
+If a token does not have a value then it is represented by a hyphen (-).
+The meanings and values of these tokens are as follows:
+<dl>
+<dt>host
+<dd>The fully-qualified domain name of the client, or its IP number if the
+name is not available.
+<dt>ident
+<dd>If <A HREF="core.html#identitycheck">IdentityCheck</A> is enabled and the
+client machine runs identd, then this is the identity information reported
+by the client.
+<dt>authuser
+<dd>If the request was for an password protected document, then this is
+the userid used in the request.
+<dt>date
+<dd>The date and time of the request, in the following format:
+<dl><dd><blockquote><code> date = [day/month/year:hour:minute:second zone] <br>
+day = 2*digit<br>
+month = 3*letter<br>
+year = 4*digit<br>
+hour = 2*digit<br>
+minute = 2*digit<br>
+second = 2*digit<br>
+zone = (`+' | `-') 4*digit</code></blockquote></dl>
+<dt>request
+<dd>The request line from the client, enclosed in double quotes
+(<code>&quot;</code>).
+<dt>status
+<dd>The three digit status code returned to the client.
+<dt>bytes
+<dd>The number of bytes in the object returned to the client, not including
+any headers.
+</dl>
+
+<h3><A NAME="formats">Custom Log Formats</A></h3>
+
+The format argument to the <code>LogFormat</code> and
+<code>CustomLog</code> is a string. This string is logged to the log
+file for each request. It can contain literal characters copied into
+the log files, and `%' directives which are replaced in the log file
+by the values as follows:
+
+<PRE>
+%...b:          Bytes sent, excluding HTTP headers.
+%...f:          Filename
+%...{FOOBAR}e:  The contents of the environment variable FOOBAR
+%...h:          Remote host
+%...{Foobar}i:  The contents of Foobar: header line(s) in the request
+                sent to the server.
+%...l:          Remote logname (from identd, if supplied)
+%...{Foobar}n:  The contents of note "Foobar" from another module.
+%...{Foobar}o:  The contents of Foobar: header line(s) in the reply.
+%...p:          The port the request was served to
+%...P:          The process ID of the child that serviced the request.
+%...r:          First line of request
+%...s:          Status.  For requests that got internally redirected, this
+                is status of the *original* request --- %...&gt;s for the last.
+%...t:          Time, in common log format time format
+%...{format}t:  The time, in the form given by format, which should
+                be in strftime(3) format.
+%...T:          The time taken to serve the request, in seconds.
+%...u:          Remote user (from auth; may be bogus if return status (%s) is 401)
+%...U:          The URL path requested.
+%...v:          The name of the server (i.e. which virtual host?)
+</PRE>
+
+The `...' can be nothing at all (e.g. <code>"%h %u %r %s %b"</code>), 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.
+
+<P>
+
+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 <b>not</b> return some sort of normal status.
+
+<P>
+
+Note that the common log format is defined by the string <code>"%h %l
+%u %t \"%r\" %s %b"</code>, which can be used as the basis for
+extending for format if desired (e.g. to add extra fields at the end).
+NCSA's extended/combined log format would be <code>"%h %l %u %t \"%r\" %s %b \"%{Referer}i\" \"%{User-agent}i\""</code>.
+
+<h2>Using Multiple Log Files</h2>
+
+The <code>TransferLog</code> and <code>CustomLog</code> directives can
+be given more than once to log requests to multiple log files. Each
+request will be logged to all the log files defined by either of these
+directives.
+
+<h3>Use with Virtual Hosts</h3>
+
+If a &lt;VirtualHost&gt; section does not contain any
+<tt>TransferLog</tt> or <tt>CustomLog</tt> directives, the
+logs defined for the main server will be used. If it does
+contain one or more of these directives, requests serviced by
+this virtual host will only be logged in the log files defined
+within its definition, not in any of the main server's log files.
+See the examples below.
+<p>
+
+<h2>Security Considerations</h2>
+
+See the <A HREF="../misc/security_tips.html">security tips</A> document
+for details on why your security could be compromised if the directory
+where logfiles are stored is writable by anyone other than the user
+that starts the server.
+<p>
+<h2>Directives</h2>
+
+<ul>
+<li><A HREF="#cookielog">CookieLog</A>
+<LI><A HREF="#customlog">CustomLog</A>
+<li><A HREF="#logformat">LogFormat</A>
+<li><A HREF="#transferlog">TransferLog</A>
+</ul>
+<hr>
+
+
+<h2><A name="cookielog">CookieLog</A></h2>
+<!--%plaintext &lt;?INDEX {\tt CookieLog} directive&gt; -->
+<strong>Syntax:</strong> CookieLog <em>filename</em><br>
+<Strong>Context:</strong> server config, virtual host<br>
+<strong>Module:</strong> mod_cookies<br>
+<strong>Compatibility:</strong> Only available in Apache 1.2 and above<p>
+
+The CookieLog directive sets the filename for logging of cookies.
+The filename is relative to the <A
+HREF="core.html#serverroot">ServerRoot</A>. This directive is included
+only for compatibility with <a
+href="mod_cookies.html">mod_cookies</a>, and is deprecated.
+<p>
+
+<H2><A NAME="customlog">CustomLog</A></H2>
+<STRONG>Syntax:</STRONG> CustomLog <em>file-pipe</em> <em>format</em><BR>
+<STRONG>Context:</STRONG> server config, virtual host<BR>
+<STRONG>Status:</STRONG> Base<BR>
+<STRONG>Module:</STRONG> mod_log_config<P>
+
+The first argument is the filename to log to. This is used
+exactly like the argument to <tt>TransferLog</tt>, that is,
+it is either a full path, or relative to the current
+server root. <p>
+
+The format argument specifies a format for each line of the log file.
+The options available for the format are exactly the same as for
+the argument of the <tt>LogFormat</tt> directive. If the format
+includes any spaces (which it will do in almost all cases) it
+should be enclosed in double quotes.
+
+<h2><A name="logformat">LogFormat</A></h2>
+<!--%plaintext &lt;?INDEX {\tt LogFormat} directive&gt; -->
+<strong>Syntax:</strong> LogFormat <em>string</em><br>
+<strong>Default:</strong> <code>LogFormat &quot;%h %l %u %t \&quot;%r\&quot;
+%s %b&quot;</code><br>
+<Strong>Context:</strong> server config, virtual host<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_log_config<p>
+
+This sets the format of the logfile.  See <A HREF="#formats">
+Custom Log Formats</A> for details on the format arguments.<p><hr>
+
+
+<h2><A name="transferlog">TransferLog</A></h2>
+<!--%plaintext &lt;?INDEX {\tt TransferLog} directive&gt; -->
+<strong>Syntax:</strong> TransferLog <em>file-pipe</em><br>
+<strong>Default:</strong> none<br>
+<Strong>Context:</strong> server config, virtual host<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_log_config<p>
+
+The TransferLog directive adds a log file in Common Log Format.
+<em>File-pipe</em> is one
+of
+<dl><dt>A filename
+<dd>A filename relative to the <A HREF="core.html#serverroot">ServerRoot</A>.
+<dt> `|' followed by a command
+<dd>A program to receive the agent log information on its standard input.
+Note the a new program will not be started for a VirtualHost if it inherits
+the TransferLog from the main server.
+</dl>
+<strong>Security:</strong> if a program is used, then it will be
+run under the user who started httpd. This will be root if the server
+was started by root; be sure that the program is secure.<p>
+
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
+
+
diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_log_referer.html b/APACHE_1_2_X/htdocs/manual/mod/mod_log_referer.html
new file mode 100644 (file)
index 0000000..8a51464
--- /dev/null
@@ -0,0 +1,88 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<TITLE>Apache module mod_log_referer</TITLE>
+</HEAD>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<H1 ALIGN="CENTER">Module mod_log_referer</h1>
+
+This module is contained in the <code>mod_log_referer.c</code> file, and is not
+compiled in by default. It provides for logging of the documents which
+reference documents on the server.
+
+<h2>Log file format</h2>
+The log file contains a separate line for each refer. Each line has the
+format
+<blockquote><em>uri</em> <code>-&gt;</code> <em>document</em></blockquote>
+where <em>uri</em> is the (%-escaped) URI for the document that references
+the one requested by the client, and <em>document</em> is the (%-decoded)
+local URL to the document being referred to.
+
+
+<h2>Directives</h2>
+<ul>
+<li><A HREF="#refererignore">RefererIgnore</A>
+<li><A HREF="#refererlog">RefererLog</A>
+</ul>
+<hr>
+
+
+<h2><A name="refererignore">RefererIgnore</A></h2>
+<!--%plaintext &lt;?INDEX {\tt RefererIgnore} directive&gt; -->
+<strong>Syntax:</strong> RefererIgnore <em>string string ...</em><br>
+<Strong>Context:</strong> server config, virtual host<br>
+<strong>Status:</strong> Extension<br>
+<strong>Module:</strong> mod_log_referer<p>
+
+The RefererIgnore directive adds to the list of strings to ignore in
+Referer headers. If any of the strings in the list is contained in
+the Referer header, then no referrer information will be logged for the
+request. Example:
+<blockquote><code>RefererIgnore www.ncsa.uiuc.edu</code></blockquote>
+This avoids logging references from www.ncsa.uiuc.edu.
+<p><hr>
+
+
+<h2><A name="refererlog">RefererLog</A></h2>
+<!--%plaintext &lt;?INDEX {\tt RefererLog} directive&gt; -->
+<strong>Syntax:</strong> RefererLog <em>file-pipe</em><br>
+<strong>Default:</strong> <code>RefererLog logs/referer_log</code><br>
+<Strong>Context:</strong> server config, virtual host<br>
+<strong>Status:</strong> Extension<br>
+<strong>Module:</strong> mod_log_referer<p>
+
+The RefererLog directive sets the name of the file to which the server will
+log the Referer header of incoming requests. <em>File-pipe</em> is one
+of
+<dl><dt>A filename
+<dd>A filename relative to the <A HREF="core.html#serverroot">ServerRoot</A>.
+<dt> `|' followed by a command
+<dd>A program to receive the referrer log information on its standard input.
+Note the a new program will not be started for a VirtualHost if it inherits
+the RefererLog from the main server.
+</dl>
+<strong>Security:</strong> if a program is used, then it will be
+run under the user who started httpd. This will be root if the server
+was started by root; be sure that the program is secure.<p>
+
+<strong>Security:</strong> See the <A
+HREF="../misc/security_tips.html">security tips</A> document for
+details on why your security could be compromised if the directory
+where logfiles are stored is writable by anyone other than the user
+that starts the server.<P>
+
+This directive is provided for compatibility with NCSA 1.4.<p>
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
+
diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_mime.html b/APACHE_1_2_X/htdocs/manual/mod/mod_mime.html
new file mode 100644 (file)
index 0000000..fa150c8
--- /dev/null
@@ -0,0 +1,212 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<TITLE>Apache module mod_mime</TITLE>
+</HEAD>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<H1 ALIGN="CENTER">Module mod_mime</h1>
+
+This module is contained in the <code>mod_mime.c</code> file, and is
+compiled in by default. It provides for determining the types of files
+from the filename.
+
+<h2>Summary</h2>
+This module is used to determine the mime types of documents. Some mime
+types indicate special processing to be performed by the server, otherwise
+the type is returned to the client so that the browser can deal with
+the document appropriately.<p>
+
+The filename of a document is treated as being composed of a basename followed
+by some extensions, in the following order:
+<blockquote><em>base.type.language.enc</em></blockquote>
+The <em>type</em> extension sets the type of the document; types are defined
+in the <A HREF="#typesconfig">TypesConfig</A> file and by the
+<A HREF="#addtype">AddType</A> directive. The <em>language</em> extension
+sets the language of the document, as defined by the
+<A HREF="#addlanguage">AddLanguage</A> directive. Finally, the
+<em>enc</em> directive sets the encoding of the document, as defined by
+the <A HREF="#addencoding">AddEncoding</A> directive.
+
+
+<h2> Directives</h2>
+<ul>
+<li><A HREF="#addencoding">AddEncoding</A>
+<li><A HREF="#addhandler">AddHandler</A>
+<li><A HREF="#addlanguage">AddLanguage</A>
+<li><A HREF="#addtype">AddType</A>
+<li><A HREF="#forcetype">ForceType</A>
+<li><A HREF="#sethandler">SetHandler</A>
+<li><A HREF="#typesconfig">TypesConfig</A>
+</ul>
+<hr>
+
+
+<h2><A name="addencoding">AddEncoding</A></h2>
+<!--%plaintext &lt;?INDEX {\tt AddEncoding} directive&gt; -->
+<strong>Syntax:</strong> AddEncoding <em>mime-enc extension extension...</em><br>
+<Strong>Context:</strong> server config, virtual host, directory, .htaccess<br>
+<Strong>Override:</strong> FileInfo<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_mime<p>
+
+The AddEncoding directive adds to the list of filename extensions which
+filenames may end in for the specified encoding type. <em>Mime-enc</em>
+is the mime encoding to use for documents ending in <em>extension</em>.
+Example:
+<blockquote><code>
+AddEncoding x-gzip gz<br>
+AddEncoding x-compress Z
+</code></blockquote>
+
+This will cause files ending in .gz to be marked as encoded using the x-gzip
+encoding, and .Z files to be marked as encoded with x-compress.<p><hr>
+
+<h2><a name="addhandler">AddHandler</a></h2>
+
+<strong>Syntax:</strong> &lt;AddHandler <em>handler-name extension</em>&gt;<br>
+<strong>Context:</strong> server config, virtual host, directory, .htaccess<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_mime<br>
+<strong>Compatibility:</strong> AddHandler is only available in Apache
+1.1 and later<p>
+
+<p>AddHandler maps the filename extension <em>extension</em> to the
+<a href="../handler.html">handler</a>
+<em>handler-name</em>. For example, to activate CGI scripts
+with the file extension "<code>.cgi</code>", you might use:
+<pre>
+    AddHandler cgi-script cgi
+</pre>
+
+<p>Once that has been put into your srm.conf or httpd.conf file, any
+file ending with "<code>.cgi</code>" will be treated as a CGI
+program.</p>
+<HR>
+
+<h2><A name="addlanguage">AddLanguage</A></h2>
+<!--%plaintext &lt;?INDEX {\tt AddLanguage} directive&gt; -->
+<strong>Syntax:</strong> AddLanguage <em>mime-lang extension extension...</em><br>
+<Strong>Context:</strong> server config, virtual host, directory, .htaccess<br>
+<Strong>Override:</strong> FileInfo<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_mime<p>
+
+The AddLanguage directive adds to the list of filename extensions which
+filenames may end in for the specified content language. <em>Mime-lang</em>
+is the mime language of files with names ending <em>extension</em>,
+after any content encoding extensions have been removed. Example:
+<blockquote><code>
+AddEncoding x-compress Z<br>
+AddLanguage en .en<br>
+AddLanguage fr .fr<br>
+</code></blockquote>
+
+Then the document <code>xxxx.en.Z</code> will be treated as being a compressed
+English document. Although the content language is reported to the client,
+the browser is unlikely to use this information. The AddLanguage directive
+is more useful for content negotiation, where the server returns one
+from several documents based on the client's language preference.<p><hr>
+
+<h2><A name="addtype">AddType</A></h2>
+<!--%plaintext &lt;?INDEX {\tt AddType} directive&gt; -->
+<strong>Syntax:</strong> AddType <em>mime-type extension extension...</em><br>
+<Strong>Context:</strong> server config, virtual host, directory, .htaccess<br>
+<Strong>Override:</strong> FileInfo<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_mime<p>
+
+The AddType directive adds to the list of filename extensions which
+filenames may end in for the specified content type. <em>Mime-enc</em>
+is the mime type to use for documents ending in <em>extension</em>.
+after content-encoding and language extensions have been removed. Example:
+<blockquote><code>
+AddType image/gif GIF
+</code></blockquote>
+It is recommended that new mime types be added using the AddType directive
+rather than changing the <A HREF="#typesconfig">TypesConfig</A> file.<p>
+Note that, unlike the NCSA httpd, this directive cannot be used to set the
+type of particular files.<p><hr>
+
+<h2><a name="forcetype">ForceType</a></h2>
+
+<strong>Syntax:</strong> &lt;ForceType <em>media type</em>&gt;<br>
+<strong>Context:</strong> directory, .htaccess<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_mime<br>
+<strong>Compatibility:</strong> ForceType is only available in Apache
+1.1 and later.<p>
+
+<p>When placed into an <code>.htaccess</code> file or a
+<code>&lt;Directory&gt;</code> or <code>&lt;Location&gt;</code> section,
+this directive forces all matching files to be served
+as the content type given by <em>media type</em>. For example, if you
+had a directory full of GIF files, but did not want to label them all with
+".gif", you might want to use:
+<pre>
+    ForceType image/gif
+</pre>
+<p>Note that this will override any filename extensions that might
+media type.</p>
+
+<h2><a name="sethandler">SetHandler</a></h2>
+
+<strong>Syntax:</strong> &lt;SetHandler <em>handler-name</em>&gt;<br>
+<strong>Context:</strong> directory, .htaccess<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_mime<br>
+<strong>Compatibility:</strong> SetHandler is only available in Apache
+1.1 and later.<p>
+
+<p>When placed into an <code>.htaccess</code> file or a
+<code>&lt;Directory&gt;</code> or <code>&lt;Location&gt;</code> section,
+this directive forces all matching files to be parsed through the
+<a href="../handler.html">handler</a>
+given by <em>handler-name</em>. For example, if you had a
+directory you wanted to be parsed entirely as imagemap rule files,
+regardless of extension, you might put the following into an
+<code>.htaccess</code> file in that directory:
+<pre>
+    SetHandler imap-file
+</pre>
+
+<p>Another example: if you wanted to have the server display a status
+report whenever a URL of <code>http://servername/status</code> was
+called, you might put the following into access.conf:
+<pre>
+    &lt;Location /status&gt;
+    SetHandler server-status
+    &lt;/Location&gt;
+</pre>
+<HR>
+
+<h2><A name="typesconfig">TypesConfig</A></h2>
+<!--%plaintext &lt;?INDEX {\tt TypesConfig} directive&gt; -->
+<strong>Syntax:</strong> TypesConfig <em>filename</em><br>
+<strong>Default:</strong> <code>TypesConfig conf/mime.types</code><br>
+<Strong>Context:</strong> server config<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_mime<p>
+
+The TypesConfig directive sets the location of the mime types configuration
+file. <em>Filename</em> is relative to the
+<A HREF="core.html#serverroot">ServerRoot</A>. This file sets the default list of
+mappings from filename extensions to content types; changing this file is not
+recommended. Use the <A HREF="#addtype">AddType</A> directive instead. The
+file contains lines in the format of the arguments to an AddType command:
+<blockquote><em>mime-type extension extension ...</em></blockquote>
+The extensions are lower-cased. Blank lines, and lines beginning with a hash
+character (`#') are ignored.<p>
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
+
diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_negotiation.html b/APACHE_1_2_X/htdocs/manual/mod/mod_negotiation.html
new file mode 100644 (file)
index 0000000..141b74b
--- /dev/null
@@ -0,0 +1,147 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<TITLE>Apache module mod_negotiation</TITLE>
+</HEAD>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<H1 ALIGN="CENTER">Module mod_negotiation</h1>
+
+This module is contained in the <code>mod_negotiation.c</code> file,
+and is compiled in by default. It provides for <A
+HREF="../content-negotiation.html">content negotiation</A>. 
+
+<h2>Summary</h2>
+Content negotiation, or more accurately content selection, is the
+selection of the document that best matches the clients
+capabilities, from one of several available documents.
+There are two implementations of this.
+<ul>
+<li> A type map (a file with the handler <code>type-map</code>)
+which explicitly lists the files containing the variants.
+<li> A MultiViews search (enabled by the MultiViews
+<A HREF="core.html#options">Option</A>, where the server does an implicit
+filename pattern match, and choose from amongst the results.
+</ul>
+
+<h3>Type maps</h3>
+A type map has the same format as RFC822 mail headers. It contains document
+descriptions separated by blank lines, with lines beginning with a hash
+character ('#') treated as comments. A document description consists of
+several header records; records may be continued on multiple lines if the
+continuation lines start with spaces. The leading space will be deleted
+and the lines concatenated. A header record consists of a keyword
+name, which always ends in a colon, followed by a value. Whitespace is allowed
+between the header name and value, and between the tokens of value.
+
+The headers allowed are:
+
+<dl>
+<dt>Content-Encoding:
+<dd>The encoding of the file. Currently only two encodings are recognized
+by http; <code>x-compress</code> for compressed files, and <code>x-gzip</code>
+for gzipped files.
+<dt>Content-Language:
+<dd>The language of the variant, as an Internet standard language code, such
+as <code>en</code>.
+<dt>Content-Length:
+<dd>The length of the file, in bytes. If this header is not present, then
+the actual length of the file is used.
+<dt>Content-Type:
+<dd>The MIME media type of the document, with optional parameters. 
+parameters are separated from the media type and from one another by
+semi-colons. Parameter syntax is name=value; allowed parameters are:
+<dl>
+<dt>level
+<dd>the value is an integer, which specifies the version of the media type.
+For <code>text/html</code> this defaults to 2, otherwise 0.
+<dt>qs
+<dd>the value is a floating-point number with value between 0. and 1.
+It indications the 'quality' of this variant.
+</dl>
+Example:
+<blockquote><code>Content-Type: image/jpeg; qs=0.8</code></blockquote>
+<dt>URI:
+<dd>The path to the file containing this variant, relative to the map file.
+</dl>
+
+<h3>MultiViews</h3>
+A MultiViews search is enabled by the MultiViews
+<A HREF="core.html#options">Option</A>.
+If the server receives a request for <code>/some/dir/foo</code> and
+<code>/some/dir/foo</code> does <em>not</em> exist, then the server reads the
+directory looking for all files named <code>foo.*</code>, and effectively
+fakes up a type map which names all those files, assigning them the same media
+types and content-encodings it would have if the client had asked for
+one of them by name.  It then chooses the best match to the client's
+requirements, and returns that document.<p>
+
+
+
+<h2>Directives</h2>
+<ul>
+<li><A href="#cachenegotiateddocs">CacheNegotiatedDocs</a>
+<li><A HREF="#languagepriority">LanguagePriority</A>
+</ul>
+<hr>
+
+
+<h2><A name="cachenegotiateddocs">CacheNegotiatedDocs</A></h2>
+<strong>Syntax:</strong> CacheNegotiatedDocs<br>
+<Strong>Context:</strong> server config<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_negotiation<br>
+<strong>Compatibility:</strong> CacheNegotiatedDocs is only available
+in Apache 1.1 and later.<p>
+
+<p>If set, this directive allows content-negotiated documents to be
+cached by proxy servers. This could mean that clients behind those
+proxys could retrieve versions of the documents that are not the best
+match for their abilities, but it will make caching more
+efficient.
+<p>
+
+This directive only applies to requests which come from HTTP/1.0 browsers.
+HTTP/1.1 provides much better control over the caching of negotiated
+documents, and this directive has no effect in responses to 
+HTTP/1.1 requests.
+
+
+
+<h2><A name="languagepriority">LanguagePriority</A></h2>
+<!--%plaintext &lt;?INDEX {\tt LanguagePriority} directive&gt; -->
+<strong>Syntax:</strong> LanguagePriority <em>mime-lang mime-lang...</em><br>
+<Strong>Context:</strong> server config, virtual host, directory, .htaccess<br>
+<Strong>Override:</strong> FileInfo<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_negotiation<p>
+
+The LanguagePriority sets the precedence of language variants for the case
+where the client does not express a preference, when handling a
+MultiViews request. The list of <em>mime-lang</em> are in order of decreasing
+preference. Example:
+
+<blockquote><code>LanguagePriority en fr de</code></blockquote>
+
+For a request for <code>foo.html</code>, where <code>foo.html.fr</code>
+and <code>foo.html.de</code> both existed, but the browser did not express
+a language preference, then <code>foo.html.fr</code> would be returned.<p>
+
+<P>
+
+Note that this directive only has an effect if a 'best' language
+cannot be determined by other any other means. Correctly implemented
+HTTP/1.1 requests will mean this directive has no effect. 
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
+
diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_proxy.html b/APACHE_1_2_X/htdocs/manual/mod/mod_proxy.html
new file mode 100644 (file)
index 0000000..e0aef68
--- /dev/null
@@ -0,0 +1,366 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<TITLE>Apache module mod_proxy</TITLE>
+</HEAD>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<H1 ALIGN="CENTER">Apache module mod_proxy</h1>
+
+This module is contained in the <code>mod_proxy.c</code> file for Apache 1.1.x,
+or the <code>modules/proxy</code> subdirectory for Apache 1.2, and
+is not compiled in by default. It provides for an <b>HTTP 1.0</b> caching proxy
+server. It is only available in Apache 1.1 and later. Common configuration
+questions are addressed <a href="#configs">here</a>.
+
+<h3>Note:</h3>
+<p>This module was experimental in Apache 1.1.x. As of Apache 1.2, mod_proxy
+stability is <i>greatly</i> improved.<p>
+
+<h2>Summary</h2>
+
+This module implements a proxy/cache for Apache. It implements
+proxying capability for 
+<code>FTP</code>,
+<code>CONNECT</code> (for SSL),
+<code>HTTP/0.9</code>, and
+<code>HTTP/1.0</code>.
+The module can be configured to connect to other proxy modules for these
+and other protocols.
+
+<h2>Directives</h2>
+<ul>
+<li><a href="#proxyrequests">ProxyRequests</a>
+<li><a href="#proxyremote">ProxyRemote</a>
+<li><a href="#proxypass">ProxyPass</a>
+<li><a href="#proxyblock">ProxyBlock</a>
+<li><a href="#cacheroot">CacheRoot</a>
+<li><a href="#cachesize">CacheSize</a>
+<li><a href="#cachemaxexpire">CacheMaxExpire</a>
+<li><a href="#cachedefaultexpire">CacheDefaultExpire</a>
+<li><a href="#cachelastmodifiedfactor">CacheLastModifiedFactor</a>
+<li><a href="#cachegcinterval">CacheGcInterval</a>
+<li><a href="#cachedirlevels">CacheDirLevels</a>
+<li><a href="#cachedirlength">CacheDirLength</a>
+<li><a href="#nocache">NoCache</a>
+</ul>
+
+<hr>
+
+<A name="proxyrequests"><h2>ProxyRequests</h2></A>
+<strong>Syntax:</strong> ProxyRequests <em>on/off</em><br>
+<strong>Default:</strong> <code>ProxyRequests Off</code><br>
+<strong>Context:</strong> server config<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_proxy<br>
+<strong>Compatibility:</strong> ProxyRequest is only available in
+Apache 1.1 and later.<p>
+
+This allows or prevents Apache from functioning as a proxy
+server. Setting ProxyRequests to 'off' does not disable use of the <a
+href="#proxypass">ProxyPass</a> directive.
+
+<A name="proxyremote"><h2>ProxyRemote</h2></A>
+<strong>Syntax:</strong> ProxyRemote <em>&lt;match&gt; &lt;remote-server&gt;</em><br>
+<strong>Context:</strong> server config<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_proxy<br>
+<strong>Compatibility:</strong> ProxyRemote is only available in
+Apache 1.1 and later.<p>
+
+This defines remote proxies to this proxy. &lt;match&gt; is either the
+name of a URL-scheme that the remote server supports, or a partial URL
+for which the remote server should be used, or '*' to indicate the
+server should be contacted for all requests. &lt;remote-server&gt; is a
+partial URL for the remote server. Syntax:
+
+<pre>
+  &lt;remote-server&gt; = &lt;protocol&gt;://&lt;hostname&gt;[:port]
+</pre>
+
+&lt;protocol&gt; is the protocol that should be used to communicate
+with the remote server; only "http" is supported by this module.
+
+Example:
+<pre>
+  ProxyRemote http://goodguys.com/ http://mirrorguys.com:8000
+  ProxyRemote * http://cleversite.com
+  ProxyRemote ftp http://ftpproxy.mydomain.com:8080
+</pre>
+
+In the last example, the proxy will forward FTP requests, encapsulated
+as yet another HTTP proxy request, to another proxy which can handle
+them.
+
+<A name="proxypass"><h2>ProxyPass</h2></A>
+<strong>Syntax:</strong> ProxyPass <em>&lt;path&gt; &lt;url&gt;</em><br>
+<strong>Context:</strong> server config<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_proxy<br>
+<strong>Compatibility:</strong> ProxyPass is only available in
+Apache 1.1 and later.<p>
+
+This directive allows remote servers to be mapped into the space of the local
+server; the local server does not act as a proxy in the conventional sense,
+but appears to be a mirror of the remote server. &lt;path&gt; is the name of
+a local virtual path; &lt;url&gt; is a partial URL for the remote server.
+
+Suppose the local server has address http://wibble.org; then
+<pre>
+   ProxyPass /mirror/foo http://foo.com
+</pre>
+Will cause a local request for the http://wibble.org/mirror/foo/bar to be
+internally converted into a proxy request to http://foo.com/bar
+
+<A name="proxyblock"><h2>ProxyBlock</h2></A>
+<strong>Syntax:</strong> ProxyBlock <em>&lt;word/host/domain list&gt;</em><br>
+<strong>Context:</strong> server config<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_proxy<br>
+<strong>Compatibility:</strong> ProxyBlock is only available in
+Apache 1.2 and later.<p>
+
+The ProxyBlock directive specifies a list of words, hosts and/or domains,
+separated by spaces. HTTP, HTTPS, and FTP document requests to matched words,
+hosts or domains are <em>blocked</em> by the proxy server. The proxy module
+will also attempt to determine IP addresses of list items which may be
+hostnames during startup, and cache them for match test as well. Example:
+
+<pre>
+  ProxyBlock joes_garage.com some_host.co.uk rocky.wotsamattau.edu
+</pre>
+
+'rocky.wotsamattau.edu' would also be matched if referenced by IP address.<p>
+
+Note that 'wotsamattau' would also be sufficient to match 'wotsamattau.edu'.<p>
+
+Note also that
+
+<pre>
+ProxyBlock *
+</pre>
+
+blocks connections to all sites.
+
+<A name="cacheroot"><h2>CacheRoot</h2></A>
+<strong>Syntax:</strong> CacheRoot <em>&lt;directory&gt;</em><br>
+<strong>Context:</strong> server config<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_proxy<br>
+<strong>Compatibility:</strong> CacheRoot is only available in
+Apache 1.1 and later.<p>
+
+Sets the name of the directory to contain cache files; this must be
+writable
+by the httpd server.
+
+<A name="cachesize"><h2>CacheSize</h2></A>
+<strong>Syntax:</strong> CacheSize <em>&lt;size&gt;</em><br>
+<strong>Default:</strong> <code>CacheSize 5</code><br>
+<strong>Context:</strong> server config<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_proxy<br>
+<strong>Compatibility:</strong> CacheSize is only available in
+Apache 1.1 and later.<p>
+
+Sets the desired space usage of the cache, in Kb (1024 byte units). Although
+usage may grow above this setting, the garbage collection will delete files
+until the usage is at or below this setting.
+
+<A name="cachegcinterval"><h2>CacheGcInterval</h2></A>
+<strong>Syntax:</strong> CacheGcInterval <em>&lt;time&gt;</em><br>
+<strong>Context:</strong> server config<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_proxy<br>
+<strong>Compatibility:</strong> CacheGcinterval is only available in
+Apache 1.1 and later.<p>
+
+Check the cache every &lt;time&gt; hours, and delete files if the space
+usage is greater than that set by CacheSize.
+
+<A name="cachemaxexpire"><h2>CacheMaxExpire</h2></A>
+<strong>Syntax:</strong> CacheMaxExpire <em>&lt;time&gt;</em><br>
+<strong>Default:</strong> <code>CacheMaxExpire 24</code><br>
+<strong>Context:</strong> server config<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_proxy<br>
+<strong>Compatibility:</strong> CacheMaxExpire is only available in
+Apache 1.1 and later.<p>
+
+Cachable HTTP documents will be retained for at most &lt;time&gt; hours without
+checking the origin server. Thus documents can be at most &lt;time&gt;
+hours out of date. This restriction is enforced even if an expiry date
+was supplied with the document.
+
+<A name="cachelastmodifiedfactor"><h2>CacheLastModifiedFactor</h2></A>
+<strong>Syntax:</strong> CacheLastModifiedFactor <em>&lt;factor&gt;</em><br>
+<strong>Default:</strong> <code>CacheLastModifiedFactor 0.1</code><br>
+<strong>Context:</strong> server config<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_proxy<br>
+<strong>Compatibility:</strong> CacheLastModifiedFactor is only available in
+Apache 1.1 and later.<p>
+
+If the origin HTTP server did not supply an expiry date for the
+document, then estimate one using the formula
+<pre>
+  expiry-period = time-since-last-modification * &lt;factor&gt;
+</pre>
+For example, if the document was last modified 10 hours ago, and
+&lt;factor&gt; is 0.1, then the expiry period will be set to 10*0.1 = 1 hour.
+
+<p>If the expiry-period would be longer than that set by CacheMaxExpire,
+then the latter takes precedence.
+
+<A name="cachedirlevels"><h2>CacheDirLevels</h2></A>
+<strong>Syntax:</strong> CacheDirLevels <em>&lt;levels&gt;</em><br>
+<strong>Default:</strong> <code>CacheDirLevels 3</code><br>
+<strong>Context:</strong> server config<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_proxy<br>
+<strong>Compatibility:</strong> CacheDirLevels is only available in
+Apache 1.1 and later.<p>
+
+CacheDirLevels sets the number of levels of subdirectories in the cache.
+Cached data will be saved this many directory levels below CacheRoot.
+
+<A name="cachedirlength"><h2>CacheDirLength</h2></A>
+<strong>Syntax:</strong> CacheDirLength <em>&lt;length&gt;</em><br>
+<strong>Default:</strong> <code>CacheDirLength 1</code><br>
+<strong>Context:</strong> server config<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_proxy<br>
+<strong>Compatibility:</strong> CacheDirLength is only available in
+Apache 1.1 and later.<p>
+
+CacheDirLength sets the number of characters in proxy cache subdirectory names.
+
+<A name="cachedefaultexpire"><h2>CacheDefaultExpire</h2></A>
+<strong>Syntax:</strong> CacheDefaultExpire <em>&lt;time&gt;</em><br>
+<strong>Default:</strong> <code>CacheDefaultExpire 1</code><br>
+<strong>Context:</strong> server config<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_proxy<br>
+<strong>Compatibility:</strong> CacheDefaultExpire is only available in
+Apache 1.1 and later.<p>
+
+If the document is fetched via a protocol that does not support expiry times,
+then use &lt;time&gt; hours as the expiry time.
+<a href="#cachemaxexpire">CacheMaxExpire</a> does <strong>not</strong>
+override.
+
+<A name="nocache"><h2>NoCache</h2></A>
+<strong>Syntax:</strong> NoCache <em>&lt;word/host/domain list&gt;</em><br>
+<strong>Context:</strong> server config<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_proxy<br>
+<strong>Compatibility:</strong> NoCache is only available in
+Apache 1.1 and later.<p>
+
+The NoCache directive specifies a list of words, hosts and/or domains, separated
+by spaces. HTTP and non-passworded FTP documents from matched words, hosts or
+domains are <em>not</em> cached by the proxy server. The proxy module will
+also attempt to determine IP addresses of list items which may be hostnames
+during startup, and cache them for match test as well. Example:
+
+<pre>
+  NoCache joes_garage.com some_host.co.uk bullwinkle.wotsamattau.edu
+</pre>
+
+'bullwinkle.wotsamattau.edu' would also be matched if referenced by IP
+address.<p>
+
+Note that 'wotsamattau' would also be sufficient to match 'wotsamattau.edu'.<p>
+
+Note also that
+
+<pre>
+NoCache *
+</pre>
+
+disables caching completely.<p>
+
+<hr>
+
+<a name="configs"><h2>Common configuration topics</h2></a>
+
+<ul>
+<li><a href="#access">Controlling access to your proxy</a>
+<li><a href="#shortname">Using Netscape hostname shortcuts</a>
+<li><a href="#mimetypes">Why doesn't file type <i>xxx</i> download via FTP?</a>
+<li><a href="#startup">Why does Apache start more slowly when using the
+       proxy module?</a>
+<li><a href="#socks">Can I use the Apache proxy module with my SOCKS proxy?</a>
+</ul>
+
+<h2><a name="access">Controlling access to your proxy</a></h2>
+
+You can control who can access your proxy via the normal &lt;Directory&gt;
+control block using the following example:<p>
+
+<pre>
+&lt;Directory proxy:*&gt;
+&lt;Limit GET PUT POST DELETE CONNECT OPTIONS&gt;
+order deny,allow
+deny from [machines you'd like *not* to allow by IP address or name]
+allow from [machines you'd like to allow by IP address or name]
+&lt;/Limit&gt;
+&lt;/Directory&gt;
+</pre><p>
+
+A &lt;Files&gt; block will also work, and is the only method known to work
+for all possible URLs in Apache versions earlier than 1.2b10.<p>
+
+<h2><a name="shortname">Using Netscape hostname shortcuts</a></h2>
+
+There is an optional patch to the proxy module to allow Netscape-like
+hostname shortcuts to be used. It's available
+<a href="http://www.apache.org/dist/contrib/patches/1.2/netscapehost.patch">
+here</a>.<p>
+
+<h2><a name="mimetypes">Why doesn't file type <i>xxx</i> download via FTP?</a></h2>
+
+You probably don't have that particular file type defined as
+<i>application/octet-stream</i> in your proxy's mime.types configuration
+file. A useful line can be<p>
+
+<pre>
+application/octet-stream        bin dms lha lzh exe class tgz taz
+</pre>
+
+<h2><a name="startup">Why does Apache start more slowly when using the
+       proxy module?</a></h2>
+
+If you're using the <code>ProxyBlock</code> or <code>NoCache</code>
+directives, hostnames' IP addresses are looked up and cached during
+startup for later match test. This may take a few seconds (or more)
+depending on the speed with which the hostname lookups occur.<p>
+
+<h2><a name="socks">Can I use the Apache proxy module with my SOCKS proxy?</a></h2>
+
+Yes. Just build Apache with the rule <code>SOCKS4=yes</code> in your
+<i>Configuration</i> file, and follow the instructions there. SOCKS5 
+capability can be added in a similar way (there's no <code>SOCKS5</code>
+rule yet), so use the <code>EXTRA_LFLAGS</code> definition, or build Apache
+normally and run it with the <i>runsocks</i> wrapper provided with SOCKS5,
+if your OS supports dynamically linked libraries.<p>
+
+Some users have reported problems when using SOCKS version 4.2 on Solaris.
+The problem was solved by upgrading to SOCKS 4.3.<p>
+
+Remember that you'll also have to grant access to your Apache proxy machine by
+permitting connections on the appropriate ports in your SOCKS daemon's
+configuration.<p>
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
+
diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_rewrite.html b/APACHE_1_2_X/htdocs/manual/mod/mod_rewrite.html
new file mode 100644 (file)
index 0000000..03eaa58
--- /dev/null
@@ -0,0 +1,1161 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!--%hypertext -->
+<!-- mod_rewrite.html                                 -->
+<!-- Documentation for the mod_rewrite Apache module  -->
+<html>
+<head>
+<title>Apache module mod_rewrite</title>
+</head>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+
+<h1 ALIGN="CENTER">Module mod_rewrite (Version 3.0)</h1>
+
+This module is contained in the <code>mod_rewrite.c</code> file, with Apache
+1.2 and later.  It provides a rule-based rewriting engine to rewrite requested
+URLs on the fly.   <code>mod_rewrite</code> is not compiled into the server by
+default. To use <code>mod_rewrite</code> you have to enable the following line
+in the server build Configuration file:
+<pre>
+    Module  rewrite_module   mod_rewrite.o
+</pre>
+
+<h2>Summary</h2>
+
+This module uses a rule-based rewriting engine (based on a
+regular-expression parser) to rewrite requested URLs on the fly. 
+
+<p>
+It supports an unlimited number of additional rule conditions (which can
+operate on a lot of variables, including HTTP headers) for granular
+matching and external database lookups (either via plain text
+tables, DBM hash files or external processes) for advanced URL
+substitution.
+
+<p>
+It operates on the full URLs (including the PATH_INFO part) both in
+per-server context (httpd.conf) and per-dir context (.htaccess) and even
+can generate QUERY_STRING parts on result.   The rewritten result can lead to internal sub-processing, external request redirection or to internal proxy throughput.
+</b>
+
+<p>
+The latest version can be found on<br>
+<a href="http://www.engelschall.com/sw/mod_rewrite/">
+<code><b>http://www.engelschall.com/sw/mod_rewrite/</b></code></a>
+
+<p>
+Copyright &copy; 1996,1997 <b>The Apache Group</b>, All rights reserved.<br>
+Copyright &copy; 1996,1997 <i>Ralf S. Engelschall</i>, All rights reserved.
+<p>
+Written for <b>The Apache Group</b> by
+<blockquote>
+    <i>Ralf S. Engelschall</i><br>
+    <a href="mailto:rse@engelschall.com"><tt>rse@engelschall.com</tt></a><br>
+    <a href="http://www.engelschall.com/"><tt>www.engelschall.com</tt></a> 
+</blockquote>
+
+<!--%hypertext -->
+<HR>
+<!--/%hypertext -->
+
+<p>
+<h2>Directives</h2>
+
+<ul>
+    <li><a href="#RewriteEngine">RewriteEngine</a>
+    <li><a href="#RewriteOptions">RewriteOptions</a>
+    <li><a href="#RewriteLog">RewriteLog</a>
+    <li><a href="#RewriteLogLevel">RewriteLogLevel</a>
+    <li><a href="#RewriteMap">RewriteMap</a>
+    <li><a href="#RewriteBase">RewriteBase</a>
+    <li><a href="#RewriteCond">RewriteCond</a>
+    <li><a href="#RewriteRule">RewriteRule</a>
+</ul>
+
+<!--%hypertext -->
+<hr>
+<!--/%hypertext -->
+
+
+<center>
+<a name="Configuration">
+<h1>Configuration Directives</h1>
+</a>
+</center>
+
+<a name="RewriteEngine"><h3>RewriteEngine</h3></a>
+<strong>Syntax:</strong> <code>RewriteEngine</code> {<code>on,off</code>}<br>
+<strong>Default:</strong> <strong><code>RewriteEngine off</code></strong><br>
+<strong>Context:</strong> server config, virtual host, per-directory config<br>
+<p>
+
+The <tt>RewriteEngine</tt> directive enables or disables the
+runtime rewriting engine. If it is set to <code>off</code> this module does
+no runtime processing at all. It does not even update the <tt>SCRIPT_URx</tt>
+environment variables. 
+
+<p>
+Use this directive to disable the module instead of commenting out
+all <tt>RewriteRule</tt> directives!
+
+<p>
+<hr noshade size=1>
+<p>
+
+<a name="RewriteOptions"><h3>RewriteOptions</h3></a>
+<strong>Syntax:</strong> <code>RewriteOptions</code> <em>Option</em> ...<br>
+<strong>Default:</strong> -<em>None</em>-<br>
+<strong>Context:</strong> server config, virtual host, per-directory config<br>
+<p>
+
+The <tt>RewriteOption</tt> directive sets some special options for the
+current per-server or per-directory configuration. The <em>Option</em>
+strings can be one of the following:
+
+<ul>
+<li>'<strong><code>inherit</code></strong>'<br>
+    This forces the current configuration to inherit the configuration of the
+    parent. In per-virtual-server context this means that the maps,
+    conditions and rules of the main server gets inherited. In per-directory
+    context this means that conditions and rules of the parent directory's
+    <tt>.htaccess</tt> configuration gets inherited.
+<p>
+</ul>
+
+<p>
+<hr noshade size=1>
+<p>
+
+<a name="RewriteLog"><h3>RewriteLog</h3></a>
+<strong>Syntax:</strong> <code>RewriteLog</code> <em>Filename</em><br>
+<strong>Default:</strong> -<em>None</em>-<br>
+<strong>Context:</strong> server config, virtual host<br>
+<p>
+
+The <tt>RewriteLog</tt> directive sets the name of the file to which the
+server logs any rewriting actions it performs. If the name does not begin
+with a slash ('<tt>/</tt>') then it is assumed to be relative to the
+<em>Server Root</em>.  The directive should occur only once per server
+config. 
+
+<p>
+<table width=70% border=2 bgcolor="#c0c0e0" cellspacing=0 cellpadding=10>
+<tr><td>
+To disable the logging of rewriting actions it is not recommended
+to set <em>Filename</em>
+to <code>/dev/null</code>, because although the rewriting engine does
+not create output to a logfile it still creates the logfile
+output internally. <b>This will slow down the server with no advantage to the
+administrator!</b>
+To disable logging either remove or comment out the
+<tt>RewriteLog</tt> directive or use <tt>RewriteLogLevel 0</tt>!
+</td></tr>
+</table>
+
+<p>
+<table width=70% border=2 bgcolor="#c0c0e0" cellspacing=0 cellpadding=10>
+<tr><td>
+SECURITY: See the <a
+href="../misc/security_tips.html">Apache Security
+Tips</a> document for details on why your security could be compromised if the
+directory where logfiles are stored is writable by anyone other than the user
+that starts the server.
+</td></tr>
+</table>
+
+<p>
+<b>Example:</b>
+<blockquote>
+<pre>
+RewriteLog "/usr/local/var/apache/logs/rewrite.log"
+</pre>
+</blockquote>
+
+<p>
+<hr noshade size=1>
+<p>
+
+<a name="RewriteLogLevel"><h3>RewriteLogLevel</h3></a>
+<strong>Syntax:</strong> <code>RewriteLogLevel</code> <em>Level</em><br>
+<strong>Default:</strong> <strong><code>RewriteLogLevel 0</code></strong><br>
+<strong>Context:</strong> server config, virtual host<br>
+<p>
+
+The <tt>RewriteLogLevel</tt> directive set the verbosity level of the rewriting
+logfile.  The default level 0 means no logging, while 9 or more means
+that practically all actions are logged.
+
+<p>
+To disable the logging of rewriting actions simply set <em>Level</em> to 0.
+This disables all rewrite action logs.
+
+<p>
+<table width=70% border=2 bgcolor="#c0c0e0" cellspacing=0 cellpadding=10>
+<tr><td>
+<b>Notice:</b> Using a high value for <i>Level</i> will slow down your Apache
+server dramatically! Use the rewriting logfile only for debugging or at least
+at <em>Level</em> not greater than 2!
+</td></tr>
+</table>
+
+
+<p>
+<b>Example:</b>
+<blockquote>
+<pre>
+RewriteLogLevel 3
+</pre>
+</blockquote>
+
+<p>
+<hr noshade size=1>
+<p>
+
+<a name="RewriteMap"><h3>RewriteMap</h3></a>
+<strong>Syntax:</strong> <code>RewriteMap</code> <em>Mapname</em> <code>{txt,dbm,prg}:</code><em>Filename</em><br>
+<strong>Default:</strong> not used per default<br>
+<strong>Context:</strong> server config, virtual host<br>
+<p>
+
+The <tt>RewriteMap</tt> directive defines an external <em>Rewriting Map</em>
+which can be used inside rule substitution strings by the mapping-functions
+to insert/substitute fields through a key lookup.
+<p>
+
+The <a name="mapfunc"><em>Mapname</em></a> is the name of the map and will
+be used to specify a mapping-function for the substitution strings of a
+rewriting rule via
+
+<blockquote><strong>
+<code>${</code> <em>Mapname</em> <code>:</code> <em>LookupKey</em>
+<code>|</code> <em>DefaultValue</em> <code>}</code>
+</strong></blockquote>
+
+When such a directive occurs the map <em>Mapname</em>
+is consulted and the key <em>LookupKey</em> is looked-up. If the key is
+found, the map-function directive is substituted by <em>SubstValue</em>. If
+the key is not found then it is substituted by <em>DefaultValue</em>.
+
+<p>
+The <em>Filename</em> must be a valid Unix filepath, containing one
+of the following formats:
+
+<ol>
+<li><b>Plain Text Format</b>
+    <p>
+    This is a ASCII file which contains either blank lines, comment lines
+    (starting with a '#' character) or
+
+    <blockquote><strong>
+    <em>MatchingKey</em>  <em>SubstValue</em>
+    </strong></blockquote>
+
+    pairs - one per line. You can create such files either manually,
+    using your favorite editor, or by using the programs
+    <tt>mapcollect</tt> and <tt>mapmerge</tt> from the <tt>support</tt>
+    directory of the <b>mod_rewrite</b> distribution.
+    <p>
+    To declare such a map prefix, <em>Filename</em> with a <code>txt:</code>
+    string as in the following example:
+
+<p>
+<table border=2 cellspacing=1 cellpadding=5 bgcolor="#d0d0d0">
+<tr><td><pre>
+#
+#   map.real-to-user -- maps realnames to usernames
+#
+
+Ralf.S.Engelschall    rse   # Bastard Operator From Hell 
+Dr.Fred.Klabuster     fred  # Mr. DAU
+</pre></td></tr>
+</table>
+
+<p>
+<table border=2 cellspacing=1 cellpadding=5 bgcolor="#d0d0d0">
+<tr><td><pre>
+RewriteMap real-to-host txt:/path/to/file/map.real-to-user
+</pre></td></tr>
+</table>
+
+<p>
+<li><b>DBM Hashfile Format</b>
+    <p>
+    This is a binary NDBM format file containing the
+    same contents as the <em>Plain Text Format</b> files. You can create
+    such a file with any NDBM tool or with the <tt>dbmmanage</tt> program
+    from the <tt>support</tt> directory of the Apache distribution.
+    <p>
+    To declare such a map prefix <em>Filename</em> with a <code>dbm:</code>
+    string.
+<p>
+<li><b>Program Format</b>
+    <p>
+    This is a Unix executable, not a lookup file.  To create it you can use
+    the language of your choice, but the result has to be a run-able Unix
+    binary (i.e. either object-code or a script with the
+    magic cookie trick '<tt>#!/path/to/interpreter</tt>' as the first line).
+    <p>
+    This program gets started once at startup of the Apache servers and then
+    communicates with the rewriting engine over its <tt>stdin</tt> and
+    <tt>stdout</tt> file-handles.  For each map-function lookup it will
+    receive the key to lookup as a newline-terminated string on
+    <tt>stdin</tt>. It then has to give back the looked-up value as a
+    newline-terminated string on <tt>stdout</tt> or the four-character string
+    ``<tt>NULL</tt>'' if it fails (i.e. there is no corresponding value
+    for the given key). A trivial program which will implement a 1:1 map
+    (i.e. key == value) could be:
+    <p>
+<table border=2 cellspacing=1 cellpadding=5 bgcolor="#d0d0d0">
+<tr><td><pre>
+#!/usr/bin/perl
+$| = 1;
+while (&lt;STDIN&gt;) {
+    # ...here any transformations 
+    # or lookups should occur...
+    print $_;
+}
+</pre></td></tr>
+</table>
+    <p>
+    <b>But be very careful:</b><br>
+    <ol>
+    <li>``<i>Keep the program simple, stupid</i>'' (KISS), because
+        if this program hangs it will lead to a hang of the Apache server
+        when the rule occurs.
+    <li>Avoid one common mistake: never do buffered I/O on <tt>stdout</tt>!
+    This will cause a deadloop! Hence the ``<tt>$|=1</tt>'' in the above
+    example...
+    </ol>
+    <p>
+    To declare such a map prefix <em>Filename</em> with a <code>prg:</code>
+    string.
+</ol>
+
+The <tt>RewriteMap</tt> directive can occur more than once. For each
+mapping-function use one <tt>RewriteMap</tt> directive to declare its
+rewriting mapfile. While you cannot <b>declare</b> a map in per-directory
+context it is of course possible to <b>use</b> this map in per-directory
+context.  
+
+<p>
+<table width=70% border=2 bgcolor="#c0c0e0" cellspacing=0 cellpadding=10>
+<tr><td>
+For plain text and DBM format files the looked-up keys are cached in-core
+until the <tt>mtime</tt> of the mapfile changes or the server does a
+restart. This way you can have map-functions in rules which are used
+for <b>every</b> request. This is no problem, because the external lookup
+only happens once!
+</td></tr>
+</table>
+
+
+<p>
+<hr noshade size=1>
+<p>
+
+<a name="RewriteBase"><h3>RewriteBase</h3></a>
+<strong>Syntax:</strong> <code>RewriteBase</code> <em>BaseURL</em><br>
+<strong>Default:</strong> <em>default is the physical directory path</em><br>
+<strong>Context:</strong> per-directory config<br>
+<p>
+
+The <tt>RewriteBase</tt> directive explicitly sets the base URL for
+per-directory rewrites. As you will see below, <tt>RewriteRule</tt> can be
+used in per-directory config files (<tt>.htaccess</tt>). There it will act
+locally, i.e. the local directory prefix is stripped at this stage of
+processing and your rewriting rules act only on the remainder. At the end
+it is automatically added.
+
+<p>
+When a substitution occurs for a new URL, this module has to
+re-inject the URL into the server processing. To be able to do this it needs
+to know what the corresponding URL-prefix or URL-base is. By default this
+prefix is the corresponding filepath itself. <b>But at most websites URLs are
+<b>NOT</b> directly related to physical filename paths, so this assumption
+will be usually be wrong!</b> There you have to use the <tt>RewriteBase</tt>
+directive to specify the correct URL-prefix. 
+
+<p>
+<table width=70% border=2 bgcolor="#c0c0e0" cellspacing=0 cellpadding=10>
+<tr><td>
+So, if your webserver's URLs are <b>not</b> directly
+related to physical file paths, you have to use <tt>RewriteBase</tt> in every
+<tt>.htaccess</tt> files where you want to use <tt>RewriteRule</tt>
+directives.
+</td></tr>
+</table>
+
+<p>
+<b>Example:</b>
+
+<blockquote>
+   Assume the following per-directory config file:
+
+<p>
+<table border=2 cellspacing=1 cellpadding=5 bgcolor="#d0d0d0">
+<tr><td><pre>
+#
+#  /abc/def/.htaccess -- per-dir config file for directory /abc/def
+#  Remember: /abc/def is the physical path of /xyz, i.e. the server
+#            has a 'Alias /xyz /abc/def' directive e.g.
+#
+
+RewriteEngine On
+
+#  let the server know that we are reached via /xyz and not 
+#  via the physical path prefix /abc/def
+RewriteBase   /xyz
+
+#  now the rewriting rules
+RewriteRule   ^oldstuff\.html$  newstuff.html
+</pre></td></tr>
+</table>
+
+<p>
+In the above example, a request to <tt>/xyz/oldstuff.html</tt> gets correctly
+rewritten to the physical file <tt>/abc/def/newstuff.html</tt>. 
+
+<p>
+<table width=70% border=2 bgcolor="#c0c0e0" cellspacing=0 cellpadding=10>
+<tr><td>
+<font size=-1>
+<b>For the Apache hackers:</b><br>
+The following list gives detailed information about the internal
+processing steps:
+
+<p>
+<pre>
+Request:
+  /xyz/oldstuff.html
+
+Internal Processing:
+  /xyz/oldstuff.html     -> /abc/def/oldstuff.html    (per-server Alias)
+  /abc/def/oldstuff.html -> /abc/def/newstuff.html    (per-dir    RewriteRule)
+  /abc/def/newstuff.html -> /xyz/newstuff.html        (per-dir    RewriteBase)
+  /xyz/newstuff.html     -> /abc/def/newstuff.html    (per-server Alias)
+
+Result:
+  /abc/def/newstuff.html
+</pre>
+
+This seems very complicated but is the correct Apache internal processing,
+because the per-directory rewriting comes too late in the process.  So,
+when it occurs the (rewritten) request has to be re-injected into the Apache
+kernel! BUT: While this seems like a serious overhead, it really isn't, because
+this re-injection happens fully internal to the Apache server and the same
+procedure is used by many other operations inside Apache. So, you can be 
+sure the design and implementation is correct.
+</font>
+</td></tr>
+</table>
+
+</blockquote>
+
+
+<p>
+<hr noshade size=1>
+<p>
+
+<a name="RewriteCond"><h3>RewriteCond</h3></a>
+<strong>Syntax:</strong> <code>RewriteCond</code> <em>TestString</em> <em>CondPattern</em><br>
+<strong>Default:</strong> -<em>None</em>-<br>
+<strong>Context:</strong> server config, virtual host, per-directory config<br>
+<p>
+
+The <tt>RewriteCond</tt> directive defines a rule condition. Precede a
+<tt>RewriteRule</tt> directive with one or more <t>RewriteCond</tt>
+directives.
+
+The following rewriting rule is only used if its pattern matches the current
+state of the URI <b>AND</b> if these additional conditions apply, too.
+
+<p>
+<em>TestString</em> is a string which contains server-variables of the form
+
+<blockquote><strong>
+<tt>%{</tt> <em>NAME_OF_VARIABLE</em> <tt>}</tt> 
+</strong></blockquote>
+
+where <em>NAME_OF_VARIABLE</em> can be a string
+of the following list:
+
+<p>
+<table bgcolor="#d0d0d0" cellspacing=0 cellpadding=5>
+<tr>
+<td valign=top>
+<b>HTTP headers:</b><p>
+<font size=-1>
+HTTP_USER_AGENT<br>
+HTTP_REFERER<br>
+HTTP_COOKIE<br>
+HTTP_FORWARDED<br>
+HTTP_HOST<br>
+HTTP_PROXY_CONNECTION<br>
+HTTP_ACCEPT<br>
+</font>
+</td>
+
+<td valign=top>
+<b>connection &amp; request:</b><p>
+<font size=-1>
+REMOTE_ADDR<br>
+REMOTE_HOST<br>
+REMOTE_USER<br>
+REMOTE_IDENT<br>
+REQUEST_METHOD<br>
+SCRIPT_FILENAME<br>
+PATH_INFO<br>
+QUERY_STRING<br>
+AUTH_TYPE<br>
+</font>
+</td>
+
+</tr>
+<tr>
+
+<td valign=top>
+<b>server internals:</b><p>
+<font size=-1>
+DOCUMENT_ROOT<br>
+SERVER_ADMIN<br>
+SERVER_NAME<br>
+SERVER_PORT<br>
+SERVER_PROTOCOL<br>
+SERVER_SOFTWARE<br>
+SERVER_VERSION<br>
+</font>
+</td>
+
+<td valign=top>
+<b>system stuff:</b><p>
+<font size=-1>
+TIME_YEAR<br>
+TIME_MON<br>
+TIME_DAY<br>
+TIME_HOUR<br>
+TIME_MIN<br>
+TIME_SEC<br>
+TIME_WDAY<br>
+</font>
+</td>
+
+<td valign=top>
+<b>specials:</b><p>
+<font size=-1>
+API_VERSION<br>
+THE_REQUEST<br>
+REQUEST_URI<br>
+REQUEST_FILENAME<br>
+IS_SUBREQ<br>
+</font>
+</td>
+</tr>
+</table>
+
+
+<p>
+<table width=70% border=2 bgcolor="#c0c0e0" cellspacing=0 cellpadding=10>
+<tr><td>
+These variables all correspond to the similar named HTTP MIME-headers, C
+variables of the Apache server or <tt>struct tm</tt> fields of the Unix
+system.
+</td></tr>
+</table>
+
+<p>
+Special Notes:
+<ol>
+<li>The variables SCRIPT_FILENAME and REQUEST_FILENAME contain the same
+value, i.e. the value of the <tt>filename</tt> field of the internal
+<tt>request_rec</tt> structure of the Apache server. The first name is just the
+commonly known CGI variable name while the second is the consistent
+counterpart to REQUEST_URI (which contains the value of the <tt>uri</tt>
+field of <tt>request_rec</tt>).
+
+<p>
+<li>There is the special format: <tt>%{ENV:variable}</tt> where
+<i>variable</i> can be any environment variable. This is looked-up via
+internal Apache structures and (if not found there) via <tt>getenv()</tt> from
+the Apache server process.
+
+<p>
+<li>There is the special format: <tt>%{HTTP:header}</tt> where
+<i>header</i> can be any HTTP MIME-header name. This is looked-up
+from the HTTP request. Example: <tt>%{HTTP:Proxy-Connection}</tt>
+is the value of the HTTP header ``<tt>Proxy-Connection:</tt>''.
+
+<p>
+<li>There is the special format: <tt>%{LA-U:url}</tt>
+for look-aheads like <tt>-U</tt>. This performs a internal sub-request to
+look-ahead for the final value of <i>url</i>.
+
+<p>
+<li>There is the special format: <tt>%{LA-F:file}</tt>
+for look-aheads like <tt>-F</tt>. This performs a internal sub-request to
+look-ahead for the final value of <i>file</i>.
+</ol>
+
+<p>
+<em>CondPattern</em> is the condition pattern, i.e. a regular expression
+which gets applied to the current instance of the <em>TestString</em>, i.e.
+<em>TestString</em> gets evaluated and then matched against
+<em>CondPattern</em>. 
+
+<p>
+<b>Remember:</b> <em>CondPattern</em> is a standard
+<em>Extended Regular Expression</em> with some additions:
+
+<ol>
+<li>You can precede the pattern string with a '<tt>!</tt>' character
+(exclamation mark) to specify a <b>non</b>-matching pattern.
+
+<p>
+<li>
+There are some special variants of <em>CondPatterns</em>. Instead of real
+regular expression strings you can also use one of the following:
+<p>
+<ul>
+<li>'<b>-d</b>' (is <b>d</b>irectory)<br>
+Treats the <i>TestString</i> as a pathname and
+tests if it exists and is a directory.
+<p>
+<li>'<b>-f</b>' (is regular <b>f</b>ile)<br>
+Treats the <i>TestString</i> as a pathname and
+tests if it exists and is a regular file.
+<p>
+<li>'<b>-s</b>' (is regular file with <b>s</b>ize)<br>
+Treats the <i>TestString</i> as a pathname and
+tests if it exists and is a regular file with size greater then zero.
+<p>
+<li>'<b>-l</b>' (is symbolic <b>l</b>ink)<br>
+Treats the <i>TestString</i> as a pathname and
+tests if it exists and is a symbolic link.
+<p>
+<li>'<b>-F</b>' (is existing file via subrequest)<br>
+Checks if <i>TestString</i> is a valid file and accessible via all the
+server's currently-configured access controls for that path.  This uses an
+internal subrequest to determine the check, so use it with care because it
+decreases your servers performance!
+<p>
+<li>'<b>-U</b>' (is existing URL via subrequest)<br>
+Checks if <i>TestString</i> is a valid URL and accessible via all the server's
+currently-configured access controls for that path.  This uses an internal
+subrequest to determine the check, so use it with care because it decreases
+your servers performance!
+</ul>
+<p>
+Notice: All of these tests can also be prefixed by a not ('!') character
+to negate their meaning.
+</ol>
+
+<p>
+Additionally you can set special flags for <em>CondPattern</em> by appending
+
+<blockquote><strong>
+<code>[</code><em>flags</em><code>]</code>
+</strong></blockquote>
+
+as the third argument to the <tt>RewriteCond</tt> directive. <em>Flags</em>
+is a comma-separated list of the following flags:
+
+<ul>
+<li>'<strong><code>nocase|NC</code></strong>' (<b>n</b>o <b>c</b>ase)<br>
+    This makes the condition test case-insensitive, i.e. there is
+    no difference between 'A-Z' and 'a-z' both in the expanded
+    <em>TestString</em> and the <em>CondPattern</em>.
+<p>
+<li>'<strong><code>ornext|OR</code></strong>' (<b>or</b> next condition)<br>
+    Use this to combine rule conditions with a local OR instead of the
+    implicit AND. Typical example:
+    <p>
+<blockquote><pre>
+RewriteCond %{REMOTE_HOST}  ^host1.*  [OR]
+RewriteCond %{REMOTE_HOST}  ^host2.*  [OR]
+RewriteCond %{REMOTE_HOST}  ^host3.*  
+RewriteRule ...some special stuff for any of these hosts...
+</pre></blockquote>
+    Without this flag you had to write down the cond/rule three times.
+<p>
+</ul>
+
+<p>
+<b>Example:</b>
+<blockquote>
+
+To rewrite the Homepage of a site according to the ``<tt>User-Agent:</tt>''
+header of the request, you can use the following:
+
+<blockquote><pre>
+RewriteCond  %{HTTP_USER_AGENT}  ^Mozilla.*
+RewriteRule  ^/$                 /homepage.max.html  [L]
+
+RewriteCond  %{HTTP_USER_AGENT}  ^Lynx.*
+RewriteRule  ^/$                 /homepage.min.html  [L]
+
+RewriteRule  ^/$                 /homepage.std.html  [L]
+</pre></blockquote>
+
+Interpretation: If you use Netscape Navigator as your browser (which identifies
+itself as 'Mozilla'), then you get the max homepage, which includes
+Frames, etc. If you use the Lynx browser (which is Terminal-based), then you
+get the min homepage, which contains no images, no tables, etc.  If you
+use any other browser you get the standard homepage.
+</blockquote>
+<p>
+
+<p>
+<hr noshade size=1>
+<p>
+
+<a name="RewriteRule"><h3>RewriteRule</h3></a>
+<strong>Syntax:</strong> <code>RewriteRule</code> <em>Pattern</em> <em>Substitution</em><br>
+<strong>Default:</strong> -<em>None</em>-<br>
+<strong>Context:</strong> server config, virtual host, per-directory config<br>
+
+<p>
+The <tt>RewriteRule</tt> directive is the real rewriting workhorse.  The
+directive can occur more than once. Each directive then defines one single
+rewriting rule.  The <b>definition order</b> of these rules is
+<b>important</b>, because this order is used when applying the rules at
+run-time.
+
+<p>
+<a name="patterns"><em>Pattern</em></a> can be (for Apache 1.1.x a System
+V8 and for Apache 1.2.x a POSIX) <a name="regexp">regular expression</a>
+which gets applied to the current URL. Here ``current'' means the value of the
+URL when this rule gets applied. This may not be the original requested
+URL, because there could be any number of rules before which already matched
+and made alterations to it.
+
+<p>
+Some hints about the syntax of regular expressions:
+
+<p>
+<table bgcolor="#d0d0d0" cellspacing=0 cellpadding=5>
+<tr>
+<td valign=top>
+<pre>
+<strong><code>^</code></strong>           Start of line
+<strong><code>$</code></strong>           End of line
+<strong><code>.</code></strong>           Any single character
+<strong><code>[</code></strong>chars<strong><code>]</code></strong>     One of chars 
+<strong><code>[^</code></strong>chars<strong><code>]</code></strong>    None of chars 
+
+<strong><code>?</code></strong>           0 or 1 of the preceding char
+<strong><code>*</code></strong>           0 or N of the preceding char
+<strong><code>+</code></strong>           1 or N of the preceding char
+
+<strong><code>\</code></strong>char       escape that specific char 
+            (e.g. for specifying the chars "<code>.[]()</code>" etc.)
+
+<strong><code>(</code></strong>string<strong><code>)</code></strong>    Grouping of chars (the <b>N</b>th group can be used on the RHS with <code>$</code><b>N</b>)
+</pre>
+</td>
+</tr>
+</table>
+
+<p>
+Additionally the NOT character ('<tt>!</tt>') is a possible pattern
+prefix. This gives you the ability to negate a pattern; to say, for instance: ``<i>if
+the current URL does <b>NOT</b> match to this pattern</i>''. This can be used
+for special cases where it is better to match the negative pattern or as a
+last default rule.
+
+<p>
+<table width=70% border=2 bgcolor="#c0c0e0" cellspacing=0 cellpadding=10>
+<tr><td>
+<b>Notice!</b> When using the NOT character to negate a pattern you cannot
+have grouped wildcard parts in the pattern. This is impossible because when
+the pattern does NOT match, there are no contents for the groups. In
+consequence, if negated patterns are used, you cannot use <tt>$N</tt> in the
+substitution string!
+</td></tr>
+</table>
+
+<p>
+<a name="rhs"><em>Substitution</em></a> of a rewriting rule is the string
+which is substituted for (or replaces) the original URL for which
+<em>Pattern</em> matched.  Beside plain text you can use 
+
+<ol>
+<li>pattern-group back-references (<code>$N</code>)
+<li>server-variables as in rule condition test-strings (<code>%{VARNAME}</code>)
+<li><a href="#mapfunc">mapping-function</a> calls (<code>${mapname:key|default}</code>)
+</ol>
+
+Back-references are <code>$</code><b>N</b> (<b>N</b>=1..9) identifiers which
+will be replaced by the contents of the <b>N</b>th group of the matched
+<em>Pattern</em>. The server-variables are the same as for the
+<em>TestString</em> of a <tt>RewriteCond</tt> directive. The
+mapping-functions come from the <tt>RewriteMap</tt> directive and are
+explained there. These three types of variables are expanded in the order of
+the above list.
+
+<p>
+As already mentioned above, all the rewriting rules are applied to the
+<em>Substitution</em> (in the order of definition in the config file).  The
+URL is <b>completely replaced</b> by the <em>Substitution</em> and the
+rewriting process goes on until there are no more rules (unless explicitly
+terminated by a <code><b>L</b></code> flag - see below).
+
+<p>
+There is a special substitution string named '<tt>-</tt>' which means:
+<b>NO substitution</b>! Sounds silly? No, it is useful to provide rewriting
+rules which <b>only</b> match some URLs but do no substitution, e.g. in
+conjunction with the <b>C</b> (chain) flag to be able to have more than one
+pattern to be applied before a substitution occurs.
+
+<p>
+<table width=70% border=2 bgcolor="#c0c0e0" cellspacing=0 cellpadding=10>
+<tr><td>
+<b>Notice</b>: There is a special feature. When you prefix a substitution
+field with <tt>http://</tt><em>thishost</em>[<em>:thisport</em>] then
+<b>mod_rewrite</b> automatically strips it out.   This auto-reduction on
+implicit external redirect URLs is a useful and important feature when
+used in combination with a mapping-function which generates the hostname
+part.  Have a look at the first example in the example section below to
+understand this.
+<p>
+<b>Remember:</b> An unconditional external redirect to your own server will
+not work with the prefix <tt>http://thishost</tt> because of this feature.
+To achieve such a self-redirect, you have to use the <b>R</b>-flag (see
+below).
+</td></tr>
+</table>
+
+<p>
+Additionally you can set special flags for <em>Substitution</em> by appending
+
+<blockquote><strong>
+<code>[</code><em>flags</em><code>]</code>
+</strong></blockquote>
+
+as the third argument to the <tt>RewriteRule</tt> directive. <em>Flags</em> is a
+comma-separated list of the following flags:
+
+<ul>
+<li>'<strong><code>redirect|R</code>[=<i>code</i>]</strong>' (force <a name="redirect"><b>r</b>edirect</a>)<br>
+    Prefix <em>Substitution</em> 
+    with <code>http://thishost[:thisport]/</code> (which makes the new URL a URI) to
+    force a external redirection. If no <i>code</i> is given a HTTP response
+    of 302 (MOVED TEMPORARILY) is used. If you want to use other response
+    codes in the range 300-400 just specify them as a number or use
+    one of the following symbolic names: <tt>temp</tt> (default), <tt>permanent</tt>,
+    <tt>seeother</tt>.
+    Use it for rules which should 
+    canonicalize the URL and gives it back to the client, e.g. translate
+    ``<code>/~</code>'' into ``<code>/u/</code>'' or always append a slash to
+    <code>/u/</code><em>user</em>, etc.<br>
+    <p>
+    <b>Notice:</b> When you use this flag, make sure that the
+    substitution field is a valid URL! If not, you are redirecting to an
+    invalid location!  And remember that this flag itself only prefixes the
+    URL with <code>http://thishost[:thisport]/</code>, but rewriting goes on.
+    Usually you also want to stop and do the redirection immediately.  To stop
+    the rewriting you also have to provide the 'L' flag.
+<p>
+<li>'<strong><code>forbidden|F</code></strong>' (force URL to be <b>f</b>orbidden)<br>
+    This forces the current URL to be forbidden, i.e. it immediately sends
+    back a HTTP response of 403 (FORBIDDEN). Use this flag in conjunction with
+    appropriate RewriteConds to conditionally block some URLs.
+<p>
+<li>'<strong><code>gone|G</code></strong>' (force URL to be <b>g</b>one)<br>
+    This forces the current URL to be gone, i.e. it immediately sends back a
+    HTTP response of 410 (GONE). Use this flag to mark no longer existing
+    pages as gone.
+<p>
+<li>'<strong><code>proxy|P</code></strong>' (force <b>p</b>roxy)<br>
+    This flag forces the substitution part to be internally forced as a proxy
+    request and immediately (i.e. rewriting rule processing stops here) put
+    through the proxy module. You have to make sure that the substitution
+    string is a valid URI (e.g. typically <tt>http://</tt>) which can
+    be handled by the Apache proxy module. If not you get an error from
+    the proxy module. Use this flag to achieve a more powerful implementation
+    of the <tt>mod_proxy</tt> directive <tt>ProxyPass</tt>, to map
+    some remote stuff into the namespace of the local server.
+    <p>
+    Notice: <b>You really have to put <tt>ProxyRequests On</tt> into your
+    server configuration to prevent proxy requests from leading to core-dumps
+    inside the Apache kernel. If you have not compiled in the proxy module,
+    then there is no core-dump problem, because mod_rewrite checks for
+    existence of the proxy module and if lost forbids proxy URLs.  </b>
+<p>
+<li>'<strong><code>last|L</code></strong>' (<b>l</b>ast rule)<br>
+    Stop the rewriting process here and
+    don't apply any more rewriting rules. This corresponds to the Perl
+    <code>last</code> command or the <code>break</code> command from the C
+    language. Use this flag to prevent the currently rewritten URL from being
+    rewritten further by following rules which may be wrong. For
+    example, use it to rewrite the root-path URL ('<code>/</code>') to a real
+    one, e.g. '<code>/e/www/</code>'.
+<p>
+<li>'<strong><code>next|N</code></strong>' (<b>n</b>ext round)<br>
+    Re-run the rewriting process (starting again with the first rewriting
+    rule). Here the URL to match is again not the original URL but the URL
+    from the last rewriting rule.  This corresponds to the Perl
+    <code>next</code> command or the <code>continue</code> command from the C
+    language. Use this flag to restart the rewriting process, i.e.  to
+    immediately go to the top of the loop. <br> 
+    <b>But be careful not to create a deadloop!</b>
+<p>
+<li>'<strong><code>chain|C</code></strong>' (<b>c</b>hained with next rule)<br>
+    This flag chains the current rule with the next rule (which itself can
+    also be chained with its following rule, etc.). This has the following
+    effect: if a rule matches, then processing continues as usual, i.e. the
+    flag has no effect. If the rule does <b>not</b> match, then all following
+    chained rules are skipped.   For instance, use it to remove the
+    ``<tt>.www</tt>'' part inside a per-directory rule set when you let an
+    external redirect happen (where the ``<tt>.www</tt>'' part should not to
+    occur!).
+<p>
+<li>'<strong><code>type|T</code></strong>=<em>mime-type</em>' (force MIME <b>t</b>ype)<br>
+    Force the MIME-type of the target file to be <em>mime-type</em>. For
+    instance, this can be used to simulate the old <tt>mod_alias</tt>
+    directive <tt>ScriptAlias</tt> which internally forces all files inside
+    the mapped directory to have a MIME type of
+    ``<tt>application/x-httpd-cgi</tt>''.
+<p>
+<li>'<strong><code>nosubreq|NS</code></strong>' (used only if <b>n</b>o internal <b>s</b>ub-request)<br>
+    This flag forces the rewriting engine to skip a rewriting rule if the
+    current request is an internal sub-request. For instance, sub-requests
+    occur internally in Apache when <tt>mod_include</tt> tries to find out
+    information about possible directory default files (<tt>index.xxx</tt>).
+    On sub-requests it is not always useful and even sometimes causes a failure to
+    if the complete set of rules are applied. Use this flag to exclude some rules.<br>
+    <p>
+    Use the following rule for your decision: whenever you prefix some URLs
+    with CGI-scripts to force them to be processed by the CGI-script, the
+    chance is high that you will run into problems (or even overhead) on sub-requests.
+    In these cases, use this flag.
+<p>
+<li>'<strong><code>passthrough|PT</code></strong>' (<b>p</b>ass <b>t</b>hrough to next handler)<br>
+    This flag forces the rewriting engine to set the <code>uri</code> field
+    of the internal <code>request_rec</code> structure to the value
+    of the <code>filename</code> field.  This flag is just a hack to be able
+    to post-process the output of <tt>RewriteRule</tt> directives by
+    <tt>Alias</tt>, <tt>ScriptAlias</tt>, <tt>Redirect</tt>, etc. directives
+    from other URI-to-filename translators. A trivial example to show the
+    semantics:
+    If you want to rewrite <tt>/abc</tt> to <tt>/def</tt> via the rewriting
+    engine of <tt>mod_rewrite</tt> and then <tt>/def</tt> to <tt>/ghi</tt>
+    with <tt>mod_alias</tt>:
+    <pre>
+    RewriteRule ^/abc(.*)  /def$1 [PT]
+    Alias       /def       /ghi   
+    </pre>
+    If you omit the <tt>PT</tt> flag then <tt>mod_rewrite</tt>
+    will do its job fine, i.e. it rewrites <tt>uri=/abc/...</tt> to
+    <tt>filename=/def/...</tt> as a full API-compliant URI-to-filename
+    translator should do. Then <tt>mod_alias</tt> comes and tries to do a
+    URI-to-filename transition which will not work.
+    <p>
+    Notice: <b>You have to use this flag if you want to intermix directives
+    of different modules which contain URL-to-filename translators</b>. The
+    typical example is the use of <tt>mod_alias</tt> and
+    <tt>mod_rewrite</tt>..
+<p>
+<table width=70% border=2 bgcolor="#c0c0e0" cellspacing=0 cellpadding=10>
+<tr><td>
+<font size=-1>
+    <b>For the Apache hackers:</b><br>
+    If the current Apache API had a
+    filename-to-filename hook additionally to the URI-to-filename hook then
+    we wouldn't need this flag!  But without  such a hook this flag is the
+    only solution. The Apache Group has discussed this problem and will
+    add such hooks into Apache version 2.0.
+</font>
+</td></tr>
+</table>
+<p>
+<li>'<strong><code>skip|S</code></strong>=<em>num</em>' (<b>s</b>kip next rule(s))<br>
+    This flag forces the rewriting engine to skip the next <em>num</em> rules
+    in sequence when the current rule matches. Use this to make pseudo
+    if-then-else constructs: The last rule of the then-clause becomes
+    a <tt>skip=N</tt> where N is the number of rules in the else-clause.
+    (This is <b>not</b> the same as the 'chain|C' flag!)
+<p>
+<li>'<strong><code>env|E=</code></strong><i>VAR</i>:<i>VAL</i>' (set <b>e</b>nvironment variable)<br>
+    This forces an environment variable named <i>VAR</i> to be set to the value
+    <i>VAL</i>, where <i>VAL</i> can contain regexp backreferences <tt>$N</tt>
+    which will be expanded. You can use this flag more than once to set more
+    than one variable. The variables can be later dereferenced at a lot of
+    situations, but the usual location will be from within XSSI (via
+       <tt>&lt;!--#echo var="VAR"--&gt;</tt>) or CGI (e.g. <tt>$ENV{'VAR'}</tt>).
+       But additionally you can also dereference it in a following RewriteCond
+       pattern via <tt>%{ENV:VAR}</tt>. Use this to strip but remember
+       information from URLs. 
+</ul>
+
+<p>
+<table width=70% border=2 bgcolor="#c0c0e0" cellspacing=0 cellpadding=10>
+<tr><td>
+Remember: Never forget that <em>Pattern</em> gets applied to a complete URL
+in per-server configuration files. <b>But in per-directory configuration
+files, the per-directory prefix (which always is the same for a specific
+directory!) gets automatically <em>removed</em> for the pattern matching and
+automatically <em>added</em> after the substitution has been done.</b> This feature is
+essential for many sorts of rewriting, because without this prefix stripping
+you have to match the parent directory which is not always possible.
+<p>
+There is one exception: If a substitution string starts with
+``<tt>http://</tt>'' then the directory prefix will be <b>not</b> added and a
+external redirect or proxy throughput (if flag <b>P</b> is used!) is forced!
+</td></tr>
+</table>
+
+<p>
+<table width=70% border=2 bgcolor="#c0c0e0" cellspacing=0 cellpadding=10>
+<tr><td>
+Notice!  To enable the rewriting engine for per-directory configuration files
+you need to set ``<tt>RewriteEngine On</tt>'' in these files <b>and</b>
+``<tt>Option FollowSymLinks</tt>'' enabled. If your administrator has
+disabled override of <tt>FollowSymLinks</tt> for a user's directory, then
+you cannot use the rewriting engine.  This restriction is needed for
+security reasons.
+</td></tr>
+</table>
+
+<p>
+Here are all possible substitution combinations and their meanings:
+
+<p>
+<b>Inside per-server configuration (<tt>httpd.conf</tt>)<br>
+for request ``<tt>GET /somepath/pathinfo</tt>'':</b><br>
+
+<p>
+<table bgcolor="#d0d0d0" cellspacing=0 cellpadding=5>
+<tr>
+<td>
+<pre>
+<b>Given Rule</b>                                      <b>Resulting Substitution</b>
+----------------------------------------------  ----------------------------------
+^/somepath(.*) otherpath$1                      not supported, because invalid!
+
+^/somepath(.*) otherpath$1  [R]                 not supported, because invalid!
+
+^/somepath(.*) otherpath$1  [P]                 not supported, because invalid!
+----------------------------------------------  ----------------------------------
+^/somepath(.*) /otherpath$1                     /otherpath/pathinfo
+
+^/somepath(.*) /otherpath$1 [R]                 http://thishost/otherpath/pathinfo
+                                                via external redirection
+
+^/somepath(.*) /otherpath$1 [P]                 not supported, because silly!
+----------------------------------------------  ----------------------------------
+^/somepath(.*) http://thishost/otherpath$1      /otherpath/pathinfo
+
+^/somepath(.*) http://thishost/otherpath$1 [R]  http://thishost/otherpath/pathinfo
+                                                via external redirection
+
+^/somepath(.*) http://thishost/otherpath$1 [P]  not supported, because silly!
+----------------------------------------------  ----------------------------------
+^/somepath(.*) http://otherhost/otherpath$1     http://otherhost/otherpath/pathinfo
+                                                via external redirection
+
+^/somepath(.*) http://otherhost/otherpath$1 [R] http://otherhost/otherpath/pathinfo
+                                                via external redirection
+                                                (the [R] flag is redundant)
+
+^/somepath(.*) http://otherhost/otherpath$1 [P] http://otherhost/otherpath/pathinfo
+                                                via internal proxy
+</pre>
+</td>
+</tr>
+</table>
+
+<p>
+<b>Inside per-directory configuration for <tt>/somepath</tt><br>
+(i.e. file <tt>.htaccess</tt> in dir <tt>/physical/path/to/somepath</tt> containing
+<tt>RewriteBase /somepath</tt>)<br> for
+request ``<tt>GET /somepath/localpath/pathinfo</tt>'':</b><br>
+
+<p>
+<table bgcolor="#d0d0d0" cellspacing=0 cellpadding=5>
+<tr>
+<td>
+<pre>
+<b>Given Rule</b>                                      <b>Resulting Substitution</b>
+----------------------------------------------  ----------------------------------
+^localpath(.*) otherpath$1                      /somepath/otherpath/pathinfo
+
+^localpath(.*) otherpath$1  [R]                 http://thishost/somepath/otherpath/pathinfo
+                                                via external redirection
+
+^localpath(.*) otherpath$1  [P]                 not supported, because silly!
+----------------------------------------------  ----------------------------------
+^localpath(.*) /otherpath$1                     /otherpath/pathinfo
+
+^localpath(.*) /otherpath$1 [R]                 http://thishost/otherpath/pathinfo
+                                                via external redirection
+
+^localpath(.*) /otherpath$1 [P]                 not supported, because silly!
+----------------------------------------------  ----------------------------------
+^localpath(.*) http://thishost/otherpath$1      /otherpath/pathinfo
+
+^localpath(.*) http://thishost/otherpath$1 [R]  http://thishost/otherpath/pathinfo
+                                                via external redirection
+
+^localpath(.*) http://thishost/otherpath$1 [P]  not supported, because silly!
+----------------------------------------------  ----------------------------------
+^localpath(.*) http://otherhost/otherpath$1     http://otherhost/otherpath/pathinfo
+                                                via external redirection
+
+^localpath(.*) http://otherhost/otherpath$1 [R] http://otherhost/otherpath/pathinfo
+                                                via external redirection
+                                                (the [R] flag is redundant)
+
+^localpath(.*) http://otherhost/otherpath$1 [P] http://otherhost/otherpath/pathinfo
+                                                via internal proxy
+</pre>
+</td>
+</tr>
+</table>
+
+
+</td>
+</tr>
+</table>
+
+<p>
+<b>Example:</b>
+<p>
+<blockquote>
+We want to rewrite URLs of the form
+<blockquote>
+<code>/</code> <em>Language</em>
+<code>/~</code> <em>Realname</em>
+<code>/.../</code> <em>File</em>
+</blockquote>
+into
+<blockquote>
+<code>/u/</code> <em>Username</em>
+<code>/.../</code> <em>File</em>
+<code>.</code> <em>Language</em>
+</blockquote>
+<p>
+We take the rewrite mapfile from above and save it under
+<code>/anywhere/map.real-to-user</code>. Then we only have to add the
+following lines to the Apache server configuration file:
+
+<blockquote>
+<pre>
+RewriteLog   /anywhere/rewrite.log
+RewriteMap   real-to-user               txt:/anywhere/map.real-to-host
+RewriteRule  ^/([^/]+)/~([^/]+)/(.*)$   /u/${real-to-user:$2|nobody}/$3.$1
+</pre>
+</blockquote>
+</blockquote>
+
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
+<!--/%hypertext -->
diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_status.html b/APACHE_1_2_X/htdocs/manual/mod/mod_status.html
new file mode 100644 (file)
index 0000000..f5a55fa
--- /dev/null
@@ -0,0 +1,107 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html><head>
+<title>Apache module mod_status</title>
+</head><!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+
+<!--#include virtual="header.html" -->
+<h1 ALIGN="CENTER">Module mod_status</h1>
+
+The Status Module is only available in Apache 1.1 and later.<p>
+
+<h2>Function</h2>
+
+The Status module allows a server administrator to find out how well
+their server is performing.  A HTML page is presented that gives
+the current server statistics in an easily readable form.  If required
+this page can be made to automatically refresh (given a compatible
+browser).  Another page gives a simple machine-readable list of the current
+server state.
+<p>
+The details given are:
+<ul>
+<li>The number of children serving requests
+<li>The number of idle children
+<li>The status of each child, the number of requests that child has
+performed and the total number of bytes served by the child (*)
+<li>A total number of accesses and byte count served (*)
+<li>The time the server was started/restarted and the
+time it has been running for
+<li>Averages giving the number of requests per second, 
+the number of bytes served per second and the average number
+of bytes per request (*)
+<li>The current percentage CPU used by each child and in total by
+Apache (*)
+<li>The current hosts and requests being processed (*)
+</ul>
+
+A compile-time option must be used to display the details marked "(*)" as
+the instrumentation required for obtaining these statistics does not
+exist within standard Apache.
+
+<h2>Enabling Status Support</h2>
+
+To enable status reports only for browsers from the foo.com
+domain add this code to your <code>access.conf</code> configuration file
+<pre>
+    &lt;Location /server-status&gt;
+    SetHandler server-status
+    
+    order deny,allow
+    deny from all
+    allow from .foo.com
+    &lt;/Location&gt;
+</pre>
+<p>
+You can now access server statistics by using a Web browser to access the
+page <code>http://your.server.name/server-status</code>
+<p>
+Note that mod_status will only work when you are running Apache in 
+<A HREF="core.html#servertype">standalone</A> mode and not 
+<A HREF="core.html#servertype">inetd</A> mode.
+
+<h3>Automatic Updates</h3>
+You can get the status page to update itself automatically if you have
+a browser that supports "refresh".  Access the page
+<code>http://your.server.name/server-status?refresh=N</code> to refresh the page
+every N seconds.
+<h3>Machine Readable Status File</h3>
+A machine-readable version of the status file is available by accessing the
+page <code>http://your.server.name/server-status?auto</code>.  This is useful
+when automatically run, see the Perl program in the <code>/support</code>
+directory of Apache, <code>log_server_status</code>.
+
+<h2>Full Instrumentation</h2>
+
+To obtain full statistics you must compile Apache with a special
+directive.  On some machines there may be a small performance loss
+if you do this.  Try full statistics and see if you notice any
+difference.  If you do please contact <a href="mailto:mark@ukweb.com">
+mark@ukweb.com</a> and tell me your configuration.
+
+<p>
+
+Do this by adding the following to the AUX_CFLAGS line in the
+"Configuration" file and then recompiling as usual.
+<pre>
+       AUX_CFLAGS= (something) -DSTATUS
+</pre>
+
+<BLOCKQUOTE>
+ <STRONG>
+  It should be noted that if <SAMP>mod_status</SAMP> is compiled into
+  the server, its handler capability is available in <EM>all</EM>
+  configuration files, including <EM>per</EM>-directory files
+  (<EM>e.g.</EM>, <SAMP>.htaccess</SAMP>).  This may have
+  security-related ramifications for your site.
+ </STRONG>
+</BLOCKQUOTE>
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_userdir.html b/APACHE_1_2_X/htdocs/manual/mod/mod_userdir.html
new file mode 100644 (file)
index 0000000..cca87f5
--- /dev/null
@@ -0,0 +1,76 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<TITLE>Apache module mod_userdir</TITLE>
+</HEAD>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<H1 ALIGN="CENTER">Module mod_userdir</h1>
+
+This module is contained in the <code>mod_userdir.c</code> file, and
+is compiled in by default. It provides for user-specific directories.
+
+
+<ul>
+<li><A HREF="#userdir">UserDir</A>
+</ul>
+<hr>
+
+
+<h2><A name="userdir">UserDir</A></h2>
+<!--%plaintext &lt;?INDEX {\tt UserDir} directive&gt; -->
+<strong>Syntax:</strong> UserDir <em>directory/filename</em><br>
+<strong>Default:</strong> <code>UserDir public_html</code><br>
+<Strong>Context:</strong> server config, virtual host<br>
+<strong>Status:</strong> Base<br>
+<strong>Module:</strong> mod_userdir<br>
+<strong>Compatibility:</strong> All forms except the <code>UserDir
+public_html</code> form are only available in Apache 1.1 or above.<p>
+
+The UserDir directive sets the real directory in a user's home directory
+to use when a request for a document for a user is received.
+<em>Directory</em> is either <code>disabled</code>, to disable this feature,
+ or the name of a directory, following one of the following
+patterns. If not disabled, then a request for
+<code>http://www.foo.com/~bob/one/two.html</code> will be translated to:
+<pre>
+UserDir public_html     -> ~bob/public_html/one/two.html
+UserDir /usr/web        -> /usr/web/bob/one/two.html
+UserDir /home/*/www     -> /home/bob/www/one/two.html
+</pre>
+The following directives will send redirects to the client:
+<pre>
+UserDir http://www.foo.com/users   -> http//www.foo.com/users/bob/one/two.html
+UserDir http://www.foo.com/*/usr   -> http://www.foo.com/bob/usr/one/two.html
+UserDir http://www.foo.com/~*/     -> http://www.foo.com/~bob/one/two.html
+</pre>
+
+<P>
+<STRONG>
+Be careful when using this directive; for instance, <SAMP>&quot;UserDir
+./&quot;</SAMP> would map <SAMP>&quot;/~root&quot;</SAMP> to
+<SAMP>&quot;/&quot;</SAMP> - which is probably undesirable.  See also
+the
+<A
+ HREF="core.html#directory"
+>&lt;Directory&gt;</A>
+directive and the
+<A
+ HREF="../misc/security_tips.html"
+>Security Tips</A>
+page for more information.
+</STRONG>
+</P>
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
+
diff --git a/APACHE_1_2_X/htdocs/manual/mod/mod_usertrack.html b/APACHE_1_2_X/htdocs/manual/mod/mod_usertrack.html
new file mode 100644 (file)
index 0000000..585e45d
--- /dev/null
@@ -0,0 +1,87 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<TITLE>Apache module mod_usertrack</TITLE>
+</HEAD>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<H1 ALIGN="CENTER">Module mod_usertrack</h1>
+
+Previous releases of Apache have included a module which generates a
+'clickstream' log of user activity on a site using cookies. This was
+called the "cookies" module, mod_cookies. In Apache 1.2 and later this
+module has been renamed the "user tracking" module,
+mod_usertrack. This module has been simplified and new directives
+added.
+
+<hr>
+
+<h2>Logging</h2>
+
+Previously, the cookies module (now the user tracking module) did its
+own logging, using the <tt>CookieLog</tt> directive. In this release,
+this module does no logging at all. Instead, a configurable log
+format file should be used to log user click-streams. This is possible
+because the logging module now allows <a
+href="../multilogs.html">multiple log files</a>. The cookie itself is
+logged by using the text <tt>%{cookie}n </tt>
+
+in the log file format. For example:
+<pre>
+CustomLog logs/clickstream "%{cookie}n %r %t"
+</pre>
+
+For backward compatibility the configurable log module implements the
+old <tt>CookieLog</tt> directive, but this should be upgraded to the
+above <tt>CustomLog</tt> directive.
+
+<h2>Directives</h2>
+
+<ul>
+<li><a href="#cookieexpires">CookieExpires</a>
+<li><a href="#cookietracking">CookieTracking</a>
+</ul>
+
+<hr>
+
+<h2><a name="cookieexpires">CookieExpires</A></h2>
+<strong>Syntax:</strong> CookieExpires <em>expiry-period</em><br>
+<strong>Context:</strong> server config, virtual host<br>
+<strong>Status:</strong> optional<br>
+<strong>Module:</strong> mod_usertrack<p>
+
+When used, this directive sets an expiry time on the cookie generated
+by the usertrack module. The <i>expiry-period</i> can be given either
+as a number of seconds, or in the format such as "2 weeks 3 days 7
+hours".  Valid denominations are: years, months, weeks, hours, minutes
+and seconds.
+
+<p>If this directive is not used, cookies last only for the current
+browser session.</p>
+
+<h2><a name="cookietracking">CookieTracking</A></h2>
+<strong>Syntax:</strong> CookieTracking <em>on | off</em><br>
+<strong>Context:</strong> server config, virtual host, directory,
+.htaccess<br>
+<strong>Override:</strong> FileInfo<br>
+<strong>Status:</strong> optional<br>
+<strong>Module:</strong> mod_usertrack<p>
+
+When the user track module is compiled in, and "CookieTracking on" is
+set, Apache will start sending a user-tracking cookie for all new
+requests. This directive can be used to turn this behavior on or off
+on a per-server or per-directory basis.  By default, compiling
+mod_usertrack will not activate cookies.
+
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
diff --git a/APACHE_1_2_X/htdocs/manual/multilogs.html b/APACHE_1_2_X/htdocs/manual/multilogs.html
new file mode 100644 (file)
index 0000000..08ddd26
--- /dev/null
@@ -0,0 +1,122 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<TITLE>Apache Multiple Log Files</TITLE>
+</HEAD>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<h1 ALIGN="CENTER">Multiple Log Files</h1>
+
+It is now possible to specify multiple log files, each with a fully
+customizable format. This is compatible with existing
+configurations.  Multiple log files are implemented as part of the <a
+href="mod/mod_log_config.html">mod_log_config</a> module which as of
+Apache 1.2 is the default log module.
+
+<hr>
+
+<h2>Using Multiple Log Files</h2>
+
+Multiple log files be created with either the <code>TransferLog</code>
+or <code>CustomLog</code> directive. These directives can be
+repeated to create more than one log file (in previous releases,
+only one logfile could be given per server configuration).
+The <code>TransferLog</code> directive creates a log file
+in the standard "common log format", although this can be customized
+with <code>LogFormat</code>. The syntax of these two
+directives is the same as for the config log module in previous
+Apache releases.
+<p>
+
+The real power of multiple log files come from the ability to
+create log files in different formats. For example, as well
+as a CLF transfer log, the server could log the user agent of
+each client, or the referrer information, or any other aspect of
+the request, such as the language preferences of the user.
+<p>
+
+The new <code>CustomLog</code> directive takes both a filename to log
+to, and a log file format. 
+
+<hr>
+
+<strong>Syntax:</strong> CustomLog <em>filename "format"</em><br>
+<strong>Context:</strong> server config, virtual host<br>
+<strong>Status:</strong> base<br>
+<strong>Module:</strong> mod_log_config<p>
+
+The first argument is the filename to log to. This is used
+exactly like the argument to <code>TransferLog</code>, that is,
+it is either a file as a full path or relative to the current
+server root, or |programname.  Be aware that anyone who can write to
+the directory where a log file is written can gain access to the uid
+that starts the server.  See the <A HREF="misc/security_tips.html">
+security tips</A> document for details.<p>
+
+The format argument specifies a format for each line of the log file.
+The options available for the format are exactly the same as for
+the argument of the <code>LogFormat</code> directive. If the format
+includes any spaces (which it will do in almost all cases) it
+should be enclosed in double quotes.
+<p>
+
+<h3>Use with Virtual Hosts</h3>
+
+If a &lt;VirtualHost&gt; section does not contain any
+<code>TransferLog</code> or <code>CustomLog</code> directives, the
+logs defined for the main server will be used. If it does
+contain one or more of these directives, requests serviced by
+this virtual host will only be logged in the log files defined
+within its definition, not in any of the main server's log files.
+See the examples below.
+<p>
+
+<hr>
+
+<h3>Examples</h3>
+
+To create a normal (CLF) format log file in logs/access_log, and a
+log of user agents:
+
+<pre>
+TransferLog logs/access_log
+CustomLog   logs/agents     "%{user-agent}i"
+</pre>
+
+To define a CLF transfer log and a referrer log which log
+all accesses to both the main server and a virtual host:
+
+<pre>
+TransferLog logs/access_log
+CustomLog   logs/referer    "%{referer}i"
+
+&lt;VirtualHost&gt;
+  DocumentRoot   /whatever
+  ServerName     my.virtual.host
+&lt;/VirtualHost&gt;
+</pre>
+
+Since no TransferLog or CustomLog directives appear inside the 
+&lt;VirtualHost&gt; section, any requests for this virtual host
+will be logged in the main server's log files. If however the
+directive
+
+<pre>
+TransferLog logs/vhost_access_log
+</pre>
+
+was added inside the virtual host definition, then accesses to this
+virtual host will be logged in vhost_access_log file (in common
+log format), and <i>not</i> in logs/access_log or logs/referer.
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
diff --git a/APACHE_1_2_X/htdocs/manual/new_features_1_0.html b/APACHE_1_2_X/htdocs/manual/new_features_1_0.html
new file mode 100644 (file)
index 0000000..cd5a73c
--- /dev/null
@@ -0,0 +1,125 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<TITLE>Apache extra features</TITLE>
+</HEAD>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<h1 ALIGN="CENTER">Overview of new features</h1>
+
+<H2>New Features with Apache 1.0</H2>
+
+<P>New features with this release, as extensions of the Apache
+functionality (see also more detailed <code>CHANGES</code> file) in
+the source directory.  Because the core code has changed so
+significantly, there are certain liberties that earlier versions of
+Apache (and the NCSA daemon) took that Apache 1.0 is pickier about -
+please check the <a href="misc/compat_notes.html">compatibility notes</a> if you have any problems.
+
+<UL>
+
+<LI> API for server extensions --- see below for a brief sermon on
+philosophy, or see <a href="misc/API.html">src/API.html</a> for an actual
+overview.  Most server functionality (including includes, CGI, and
+most forms of access control) are actually implemented as
+API-conformant modules; you can also do other neat stuff (we've
+included a sample module, for instance, which one of us is using to
+track click-trails using the <a
+href="http://home.netscape.com/newsref/std/cookie_spec.html">Netscape
+cookie mechanism</a>, for visitors who come in through Netscape
+clients).  <a href="mod/mod_dld.html">Modules</a> can also be loaded dynamically using GNU DLD.
+
+<P>
+The API is not yet quite stable (see src/TODO for some possible
+changes), but anything done now will be easily adapted for future
+versions --- after all, we have more modules to adapt than you do.
+
+<P>
+
+<LI> <a href="process-model.html">New Process Model - much less forking, no fixed number of children.</a>
+
+We found that many people were using values for "MaxServers" either
+too high or too low, and were hanging themselves on it.  The model we
+adopted is still based on long-lived minimal-forking processes, but
+instead of specifying one number of persistent processes, the
+web-master specifies a maximum and minimum number of processes to be
+"spare" - every couple of seconds the parent checks the actual number
+of spare servers and adjusts accordingly.  This should keep the number
+of servers concurrently running relatively low while still ensuring
+minimal forking.  
+
+<P>
+
+<LI> <a href="virtual-host.html">&lt;VirtualHost&gt; (the configuration directive for
+multiple-homed servers)</a> is more general now.  Just about any srm.conf or
+httpd.conf command can go in a &lt;Virtualhost&gt; section, with the
+following specific exceptions: ServerType, UserId, GroupId,
+StartServers, MaxRequestsPerChild, BindAddress, PidFile, TypesConfig,
+ServerRoot.
+
+<P>
+
+<LI> <a href="content-negotiation.html">Support for content negotiation of languages through MultiViews</a>
+(*.fr, *.de, *.en suffixes), via the new AddLanguage and LanguagePriority
+commands (code written by Florent Guillaume, guillaum@clipper.ens.fr).
+
+<P>
+
+<LI> Significant internal cleanups and rearrangements.  The two externally
+   visible consequences of this are that just about all of the unchecked
+   fixed limits are gone, and that the server is somewhat pickier about
+   config file syntax (noting and complaining about extraneous command
+   arguments or other stuff at the end of command lines).
+
+<P>
+
+<LI> XBITHACK is a run-time option, and can be selectively enabled per
+   directory --- the -DXBITHACK compile-time option just changes the
+   default.  The command which configures it is "XBitHack", which is
+   allowed everywhere "Options" is; this takes an argument ---
+   "XBitHack Off" turns it off; "XBitHack On" gets you the NCSA
+   -DXBITHACK behavior; and "XBitHack Full" gets you the Apache GXBIT
+   stuff on top of that.  (-DXBITHACK makes "Full" the default;
+   otherwise, it defaults "Off").
+
+<P>
+
+<LI> TransferLog can specify a program which gets the log entries piped to it,
+   a la 'TransferLog "| /var/www/my-perl-script -arg valu"' --- this should
+   give the same SIGTERM/pause/SIGKILL treatment to the logging process on
+   server restarts that a CGI script gets on an aborted request.  NB the
+   server is counting on the logging process to work, and will probably hang
+   or worse if it dies.
+
+<P>
+
+<LI> <a href="mod/mod_log_config.html">Configurable logging module</a> --- this
+   is a replacement for the standard plane-jane Common Log Format code, which
+   supports a LogFormat directive which allows you to control the formatting of
+   entries in the TransferLog, and add some new items if you like (in
+   particular, Referer and User-Agent).  EXPERIMENTAL.
+</ul>
+<p><hr>
+
+
+<H2>Other features of Apache</h2>
+<ul>
+<LI><A HREF="mod/mod_dld.html">Dynamically loading modules using GNU DLD</A>
+<LI><A HREF="mod/mod_imap.html">Imagemap Module</A>
+<li><A HREF="mod/mod_dir.html#directoryindex">Multiple DirectoryIndex filenames</A>
+<LI><A HREF="mod/mod_asis.html"> &quot;Send as is&quot; file types</A>
+<li><A HREF="mod/mod_include.html#xbithack">XBITHACK last modified</A>
+</ul>
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
+
diff --git a/APACHE_1_2_X/htdocs/manual/new_features_1_1.html b/APACHE_1_2_X/htdocs/manual/new_features_1_1.html
new file mode 100644 (file)
index 0000000..8ab2705
--- /dev/null
@@ -0,0 +1,213 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html><head>
+<title>New features with Apache 1.1</title>
+</head>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<h1 ALIGN="CENTER">Overview of new features</h1>
+
+<h2>API Changes</h2>
+
+A few changes to the Apache API were made for 1.1.  It is possible
+that some third-party modules will no longer work with 1.1, though
+we have made every effort to provide backwards-compatibility. If you
+encounter a module that does not work with 1.1, please <a
+href="http://www.apache.org/bug_report.html">let us know</a>.
+
+
+<h2>New Features with Apache 1.1</h2>
+<p>New features with this release, as extensions of the Apache
+functionality (see also more detailed <code>CHANGES</code> file in
+the source directory.)  Because the core code has changed so
+significantly, there are certain liberties that earlier versions of
+Apache (and the NCSA daemon) took that recent Apache versions are
+pickier about - please check the <a
+href="misc/compat_notes.html">compatibility notes</a> if you have any
+problems.</p>
+<hr>
+
+<p>In addition to a number of bug fixes and internal performance
+enhancements, <a href="http://www.apache.org/dist/">Apache
+1.1</a> has the following specific new user features:</p>
+
+<ul>
+
+<li><b><a href="keepalive.html">Support for Keep-Alive Persistent
+Connections</a></b><br> 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.
+
+<li><b><a href="host.html">New non-IP Intensive VirtualHost
+Support</a></b><br>
+Apache's support for virtual hosts has been enhanced to be able to
+use information sent by some new Web browsers to determine the server
+being accessed, without requiring an additional IP address for each
+host.
+
+<li><b><a href="bind.html">Listen to Multiple Addresses and
+Ports</a></b><br>
+Using the new <code>Listen</code> directive, Apache can listen to more
+than one port and IP address, using the same configuration set.
+
+<li><b><a href="mod/mod_status.html">Status
+Module</a></b><br>
+Apache now contains a module that gives the web-master accurate,
+up-to-date information about the server's status and its resource
+consumption.  It also gives the current state of each server process
+including the current URL being processed.  For an example, check out
+<A HREF="http://www.apache.org/status">the status of the
+www.apache.org server</A>.
+
+<li><b><a href="mod/mod_info.html">Server Information Module</a></b></br>
+This module gives a plethora of information about the other modules
+installed, their directives, and their configurations.  It is
+extremely helpful in debugging configuration problems.  For an
+example, check out <A
+HREF="http://www.apache.org/serv-info">information about the
+www.apache.org server</A>.
+
+<li><b><a href="mod/mod_proxy.html">Experimental Caching Proxy Server</a></b><br>
+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.
+
+<li><b><a href="location.html">URL-based Access Protection</a></b><br>
+In addition to access checking and authorization by filename (with
+<code><a href="mod/core.html#directory">&lt;Directory&gt;</a></code>),
+the new <code>&lt;Location&gt;</code> directive allows protection by
+URL.
+
+<li><b><a href="mod/mod_actions.html">Filetype-based Script "Actions"</a></b><br>
+You can now run CGI scripts whenever a file of a certain type is
+requested. This makes it much easier to execute scripts that process
+files. In addition, you can use the new <a
+href="mod/mod_actions.html#script">Script</a> directive to enable scripts
+for files called with HTTP methods Apache does not natively support.
+
+<li><b><a href="handler.html">New "Handler" Directives</a></b><br>
+The new <code>AddHandler</code> and <code>SetHandler</code> directive
+allows "handlers" to be defined for filename extensions or
+directories. These handlers, which can either be built into Apache or
+added with the <a href="mod/mod_actions.html">Action</a> directive, extend
+Apache's range of usability, and almost entirely remove the "magic"
+media types.
+
+<li><b><a href="mod/mod_env.html">Customizable CGI Environment
+Variables</a></b><br>
+New <code>PassEnv</code> and <code>SetEnv</code> directives allow you to
+modify the environment variables passed to CGI scripts.
+
+<li><b><a href="mod/mod_cern_meta.html">CERN Metafile Support</a></b><br>
+Now emulates the CERN httpd's support for metafiles containing additional
+HTTP headers to be supplied with a document.
+
+<li><b><a href="mod/mod_imap.html">Improved Imagemap Support</a></b><br>
+The internal imagemap handling code has been rewritten and
+reorganized, adding new handling of default, base and relative URLs,
+and support for creating non-graphical menus for use with clients that
+do not support imagemaps.
+
+<li><b><a href="mod/mod_userdir.html">Improved UserDir Directive</a></b><br>
+Now supports the ability to point user's files (as specified by URLs
+beginning with the "<code>~</code>" character) at directories other
+than those specified by the Unix password file.
+
+<li><b>Minimal DNS Now Runtime Option</b><br>
+New <code>HostnameLookups</code>
+server configuration directive can be used to turn <code>On</code> or
+<code>Off</code> DNS lookups. This supersedes the -DMINIMAL_DNS
+compile-time configuration option. This option can be set per-directory.
+
+<li><b>IdentityCheck Now Per-Directory  Option</b><br>
+The <code>IdentityCheck</code> directive, which controls the use of
+ident to check the remote user name, can now be set per directory. The
+ident support is also RFC 1413-compliant.
+
+<li><b>Redirect Now Usable in <code>.htaccess</code> Files</b><br>
+The <a href="mod/mod_alias.html#redirect"><code>Redirect</code></a>
+directive can now be used in <code>.htaccess</code> files when the
+<code>FileInfo</code> directive has been set on. This allows users to
+redirect parts of their directories without requiring CGI scripts
+
+<li><b>ErrorDocument Now Usable in <code>.htaccess</code> Files</b><br>
+The <a href="custom-error.html"><code>ErrorDocument</code></a>
+directive can now be used in <code>.htaccess</code> files when the
+<code>FileInfo</code> directive has been set on. This allows users to
+have different error messages for different sections of a site.
+
+<li><b><code>ForceType</code> Directive</b><br>
+This new directive, in <code>&lt;Directory&gt;</code> sections or
+.htaccess files, allows you to override the filename extensions and
+force a single content type. (e.g. <code>ForceType
+application/octet-stream</code>)
+
+<li><b>File Owner Available to Included CGI Scripts</b><br>
+Server-side includes that call CGI scripts will now set a
+<code>USER_NAME</code> environment variable that contains the owner of
+the file which included it.
+
+<li><b>Improved Icons</b><br>
+Thanks to <a href="mailto:kevinh@eit.com">Kevin
+Hughes</a>, Apache's nifty color GIF icons for directory listings have
+been updated. In addition, the <a
+href="../apache_pb.gif">Powered by Apache</a>
+(<code>apache_pb.gif</code>) logo has been included.
+
+</ul>
+
+<hr>
+
+<h3>New Authentication Modules</h3>
+
+<p><strong>Note:</strong> 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
+<code>Configuration</code> file.</p>
+
+<ul>
+
+<li><b><a href="mod/mod_auth_anon.html">Anonymous HTTP Logins</a></b><br>
+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.
+
+<li><b><a href="mod/mod_digest.html">Support for Digest
+Authentication</a></b><br>
+Apache now supports digest authentication using RSA MD5
+encryption. When used with a supporting web browser, this provides a
+more secure alternative to Basic authentication.
+
+<li><strong><a href="mod/mod_auth_db.html">Support for Unix DB
+Authentication</a></strong> - <code>mod_auth_db.c</code><br> In
+addition to <a href="mod/mod_auth_dbm.html">DBM</a> support, Apache now
+contains optional support for Berkeley DB databases.
+
+<li><strong><a href="mod/mod_auth_msql.html">mSQL Database
+Authentication</a></strong> - <code>mod_auth_msql.html</code> <BR>
+Support for the use of mSQL databases for user authentication via HTTP
+is now supported.
+
+</ul>
+
+<hr>
+
+<h3>OS/2 Support</h3>
+
+<p>Apache now includes support for OS/2, thanks to <a href="http://www.slink.com/ApacheOS2/">Softlink Services.</a></p>
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
+
diff --git a/APACHE_1_2_X/htdocs/manual/new_features_1_2.html b/APACHE_1_2_X/htdocs/manual/new_features_1_2.html
new file mode 100644 (file)
index 0000000..1b0bda3
--- /dev/null
@@ -0,0 +1,208 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html><head>
+<title>New features with Apache 1.2</title>
+</head>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<h1 ALIGN="CENTER">Overview of new features</h1>
+
+<h2>API Changes</h2>
+
+<p>Some non-compatible changes were made to the Apache API in order to
+deal with HTTP/1.1 compatibility.  It is possible that some modules
+will no longer work (specifically, those that process input using the
+POST or PUT methods). If you encounter a module that does not work,
+please contact the author. A <a
+href="misc/client_block_api.html">programmer's note</a> on the subject is
+available.</p>
+
+<p>Additionally, some changes were made to the CGI environment that
+may cause some CGI scripts to work incorrectly. If you are
+experiencing trouble with a CGI that worked fine under Apache 1.1.1,
+please see <a href="cgi_path.html">our explanation of the changes.</a></p>
+
+<h2>New Features with Apache 1.2</h2>
+<p>New features with this release, as extensions of the Apache
+functionality. Because the core code has changed so
+significantly, there are certain liberties that earlier versions of
+Apache (and the NCSA daemon) took that recent Apache versions are
+pickier about - please check the <a
+href="misc/compat_notes.html">compatibility notes</a> if you have any
+problems.</p>
+<hr>
+
+<p>In addition to a number of bug fixes and internal performance
+enhancements, <a href="http://www.apache.org/dist/">Apache
+1.2</a> has the following specific new user features:</p>
+
+<ul>
+
+<li><b><xa href="http11.html">HTTP/1.1 Compliance</a></b>
+[Documentation to be written]<br>
+Aside from the optional proxy module (which operates as HTTP/1.0),
+Apache is conditionally compliant with the HTTP/1.1 proposed standard,
+as approved by the IESG and the
+<a href="http://www.ics.uci.edu/pub/ietf/http/">IETF HTTP working group</a>.
+HTTP/1.1 provides a much-improved protocol, and
+should allow for greater performance and efficiency when transferring
+files. Apache does, however, still work great with HTTP/1.0 browsers.
+We are very close to being unconditionally compliant; if you note any
+deviance from the proposed standard, please report it as a bug.
+
+<li><b><a href="mod/mod_include.html">eXtended Server Side Includes
+(XSSI)</a></b><br>
+A new set of server-side include
+directives allows the user to better create WWW pages. This includes
+number of powerful new features, such as the ability to set variables
+and use conditional HTML.
+
+<li><b><a href="mod/core.html#files">File-based and Regex-enabled
+Directive Sections</a></b><br>
+The new 
+<a href="mod/core.html#files"><code>&lt;Files&gt;</code></a>
+section allows directives to be enabled based on full filename, not just directory and URL. In
+addition, <code>&lt;Files&gt;</code> sections can appear in
+<code>.htaccess</code> files. <code>&lt;Files&gt;</code>, along with
+<a href="mod/core.html#directory"><code>&lt;Directory&gt;</code></a>
+ and <a href="mod/core.html#location"><code>&lt;Location&gt;</code></a>, can
+also now be based on regular expressions, not just simple prefix
+matching. 
+
+<li><b><a href="mod/mod_browser.html">Browser-based Environment
+Variables</a></b><br>
+Environment variables can now be set based on the
+<code>User-Agent</code> string of the browser. Combined with <a
+href="mod/mod_include.html">XSSI</a>, this allows you to write browser-based
+conditional HTML documents.
+
+<li><b><a href="suexec.html">SetUID CGI Execution</a></b><br>
+    Apache now
+    supports the execution of CGI scripts as users other
+    than the server user. A number of security checks are built in
+    to try and make this as safe as possible.
+
+<li><b><a href="mod/mod_rewrite.html">URL Rewriting Module</a></b><br>
+The optional <code>mod_rewrite</code> module is now included. This
+module can provide powerful URL mapping, using regular
+expressions. There's nothing this module can't do!
+
+<li><b><a href="mod/mod_log_config.html">Enhanced, Configurable
+Logging</a></b><br>
+The optional <code>mod_log_config</code> included with earlier
+versions of Apache is now standard, and has been enhanced to allow
+logging of much more detail about the transaction, and can be used to
+open <a href="multilogs.html">more than one log file</a> at once 
+(each of which can have a different log format).  If you have Apache
+write any logs to a directory which is writable by anyone other than
+the user that starts the server, see the <A HREF="misc/security_tips.html">
+security tips</A> document to be sure you aren't putting the security
+of your server at risk.
+
+
+<li><b><a href="mod/mod_usertrack.html">User Tracking (Cookies)
+Revisions</a></b><br>
+The <code>mod_cookies</code> included with previous versions of Apache
+has been renamed <code>mod_usertrack</code>, to more accurately
+reflect its function (some people inadvertently thought it enabled
+cookie support in Apache, which is not true - Apache supports the use
+of cookies directly). It is also now possible to disable the
+generation of cookies, even when
+    the cookie module is compiled in. Also, an expiry time can be set
+    on the cookies.
+
+<li><b><a href="mod/core.html#virtualhost">&lt;VirtualHost&gt; Enhancements</a></b><br>
+    The &lt;VirtualHost&gt; directive can now take more than one IP
+    address or hostname. This lets a single vhost handles requests
+    for multiple IPs or hostnames. Also the special section
+    &lt;VirtualHost _default_&gt; can be used to handle requests normally
+    left for the main server configuration.
+
+<li><b><a href="mod/mod_cgi.html#cgi_debug">CGI Debugging Environment</a></b><br>
+<code>ScriptLog</code> allows you to now set up a log that records
+all input and output to failed CGI scripts. This includes environment
+variables, input headers, POST data, output, and more. This makes CGI
+scripts much easier to debug.
+
+<li><b><a href="mod/core.html#rlimit">Resource Limits for CGI Scripts</a></b><br>
+New directives allow the limiting of resources used by CGI scripts
+(e.g. max CPU time). This is helpful in preventing 'runaway' CGI
+processes.
+
+<li><b><a href="mod/mod_alias.html">Redirect Directive Can Return Alternate Status</a></b><br>
+    The Redirect directive can return permanent or temporary redirects,
+    "Gone" or "See Other" HTTP status. For NCSA-compatibility, 
+    RedirectTemp and RedirectPermanent are also implemented.
+
+<li><b><a href="install.html">Simplified Compilation</a></b><br>
+    The process of configuring Apache for compilation has been
+    simplified.
+
+<li><b><a href="mod/core.html#options">Add or Remove Options</a></b><br>
+    The <code>Options</code> directive can now add or remove options from
+    those currently in force, rather than always replacing them.
+
+<li><b><a href="invoking.html#help">Command-line Help</a></b><br>
+The <code>-h</code> command-line option now lists all the available
+directives.
+
+<li><b><a href="mod/mod_headers.html">Optional Headers Module to Set or Remove HTTP Headers</a></b><br>
+The optional <code>mod_headers</code> module can be used to set custom
+headers in the HTTP response. It can append to existing headers,
+replace them, or remove headers from the response.
+
+<li><b><a href="mod/core.html#ifmodule">Conditional Config Directives</a></b><br>
+A new <code>&lt;IfModule&gt;</code> section allows directives to be
+enabled only if a given module is loaded into the server.
+
+<li><b><xa href="ncsa_auth.html">Authorization Directives Now Use
+NCSA-style Syntax</a></b><br>
+
+The <a href="mod/mod_auth.html#authuserfile">AuthUserFile</a>, <a
+href="mod/mod_auth.html#authgroupfile">AuthGroupFile</a> and <a
+href="mod/mod_digest.html#authdigestfile">AuthDigestFile</a> commands
+now have a syntax compatible with the NCSA server.
+
+<li><b><a href="mod/core.html#satisfy">NCSA Satisfy authentication
+directive now implemented</a></b><br> 
+<code>Satisfy</code> allows for more flexible access control
+configurations.
+
+<li><b>Better NCSA Compatibility</b><br>
+Apache directives are now more compatible with NCSA 1.5 to make
+moving between servers easier. In particular, Apache now implements the
+<a href="mod/core.html#satisfy"><code>Satisfy</code></a>,
+<a href="mod/core.html#maxkeepaliverequests">MaxKeepAliveRequests</A>,
+<a href="mod/mod_alias.html#redirectperm">RedirectPermanent</A> and
+<a href="mod/mod_alias.html#redirecttemp">RedirectTemp</A>,
+directives, and the following directives are now syntax-compatible with
+NCSA:
+<a href="mod/mod_auth.html#authuserfile">AuthUserFile</A>,
+<a href="mod/mod_auth.html#authgroupfile">AuthGroupFile</A>,
+<a href="mod/mod_digest.html#authdigestfile">AuthDigestFile</A>,
+<a href="mod/core.html#keepalive">KeepAlive</A> and
+<a href="mod/core.html#keepalivetimeout">KeepAliveTimeout</A>.
+
+<li><b><a href="mod/mod_proxy.html">Optional proxy module</a></b><br>
+An improved FTP, HTTP, and CONNECT mode SSL proxy is included with
+Apache 1.2. Some of the changes visible to users:
+       <dl><dl>
+       <dt>- Improved FTP proxy supporting PASV mode
+       <dt>- ProxyBlock directive for excluding sites to proxy
+       <dt>- NoCache * directive for disabling proxy caching
+       <dt>- Numerous bug fixes
+       </dl></dl>
+
+</ul>
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
+
diff --git a/APACHE_1_2_X/htdocs/manual/process-model.html b/APACHE_1_2_X/htdocs/manual/process-model.html
new file mode 100644 (file)
index 0000000..c130dec
--- /dev/null
@@ -0,0 +1,68 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML><HEAD>
+<TITLE>Server Pool Management</TITLE>
+</HEAD>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<H1 ALIGN="CENTER">Server Pool Management</H1>
+
+<HR>
+<P>
+We found that many people were using values for "MaxServers" either
+too high or too low, and were hanging themselves on it.  The model we
+adopted is still based on long-lived minimal-forking processes, but
+instead of specifying one number of persistent processes, the
+web-master specifies a maximum and minimum number of processes to be
+"spare" - every couple of seconds the parent checks the actual number
+of spare servers and adjusts accordingly.  This should keep the number
+of servers concurrently running relatively low while still ensuring
+minimal forking.  
+
+<P>
+
+We renamed the 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-compatibility).  The old names were generally regarded
+as too confusing.
+
+<P>
+
+The defaults for each variable are:
+
+<PRE>
+MinSpareServers                5
+MaxSpareServers                10
+StartServers           5
+</PRE>
+
+There is an absolute maximum number of simultaneous children defined
+by a compile-time limit which defaults to 256 and a "MaxClients"
+directive which specifies the number of simultaneous children that
+will be allowed.  MaxClients can be adjusted up to the compile-time
+limit (HARD_SERVER_LIMIT, defined in httpd.h).  If you need more
+than 256 simultaneous children, you need to modify both HARD_SERVER_LIMIT
+and MaxClients.<P>
+
+In versions before 1.2, HARD_SERVER_LIMIT defaulted to 150.<P>
+
+We do not recommend changing either of these values unless:
+
+<OL>
+<LI>You know you have the server resources to handle more
+<LI>You use the machine for other purposes and must limit the amount of memory
+Apache uses
+</OL>
+
+<!--#include virtual="footer.html" -->
+</body></html>
+
+
diff --git a/APACHE_1_2_X/htdocs/manual/stopping.html b/APACHE_1_2_X/htdocs/manual/stopping.html
new file mode 100644 (file)
index 0000000..373590a
--- /dev/null
@@ -0,0 +1,166 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<TITLE>Stopping and Restarting Apache</TITLE>
+</HEAD>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<h1 ALIGN="CENTER">Stopping and Restarting Apache</h1>
+
+<p>You will notice many <code>httpd</code> executables running on your system,
+but you should not send signals to any of them except the parent, whose
+pid is in the <a href="mod/core.html#pidfile">PidFile</a>.  That is to
+say you shouldn't ever need to send signals to any process except the
+parent.  There are three signals that you can send the parent:
+<code>TERM</code>, <code>HUP</code>, and <code>USR1</code>, which will
+be described in a moment.
+
+<p>To send a signal to the parent you should issue a command such as:
+<blockquote><pre>
+    kill -TERM `cat /usr/local/etc/httpd/logs/httpd.pid`
+</pre></blockquote>
+
+You can read about its progress by issuing:
+
+<blockquote><pre>
+    tail -f /usr/local/etc/httpd/logs/error_log
+</pre></blockquote>
+
+Modify those examples to match your
+<a href="mod/core.html#serverroot">ServerRoot</a> and
+<a href="mod/core.html#pidfile">PidFile</a> settings.
+
+<h3>TERM Signal: stop now</h3>
+
+<p>Sending the <code>TERM</code> signal to the parent causes it to
+immediately attempt to kill off all of its children.  It may take it
+several seconds to complete killing off its children.  Then the
+parent itself exits.  Any requests in progress are terminated, and no
+further requests are served.
+
+<h3>HUP Signal: restart now</h3>
+
+<p>Sending the <code>HUP</code> signal to the parent causes it to kill off
+its children like in <code>TERM</code> but the parent doesn't exit.  It
+re-reads its configuration files, and re-opens any log files.
+Then it spawns a new set of children and continues
+serving hits.
+
+<p>Users of the
+<a href="mod/mod_status.html">status module</a>
+will notice that the server statistics are
+set to zero when a <code>HUP</code> is sent.
+
+<p><b>Note:</b> If your configuration file has errors in it when you issue a
+restart then your parent will not restart, it will exit with an error.
+See below for a method of avoiding this.
+
+<h3>USR1 Signal: graceful restart</h3>
+
+<p><b>Note:</b> prior to release 1.2b9 this code is quite unstable and
+shouldn't be used at all.
+
+<p>The <code>USR1</code> signal causes the parent process to <i>advise</i>
+the children to exit after their current request (or to exit immediately
+if they're not serving anything).  The parent re-reads its configuration
+files and re-opens its log files.  As each child dies off the parent
+replaces it with a child from the new <i>generation</i> of the
+configuration, which begins serving new requests immediately.
+
+<p>This code is designed to always respect the
+<a href="mod/core.html#maxclients">MaxClients</a>,
+<a href="mod/core.html#minspareservers">MinSpareServers</a>,
+and <a href="mod/core.html#maxspareservers">MaxSpareServers</a> settings.
+Furthermore, it respects <a href="mod/core.html#startservers">StartServers</a>
+in the following manner:  if after one second at least StartServers new
+children have not been created, then create enough to pick up the slack.
+This is to say that the code tries to maintain both the number of children
+appropriate for the current load on the server, and respect your wishes
+with the StartServers parameter.
+
+<p>Users of the
+<a href="mod/mod_status.html">status module</a>
+will notice that the server statistics
+are <b>not</b> set to zero when a <code>USR1</code> is sent.  The code
+was written to both minimize the time in which the server is unable to serve
+new requests (they will be queued up by the operating system, so they're
+not lost in any event) and to respect your tuning parameters.  In order
+to do this it has to keep the <i>scoreboard</i> used to keep track
+of all children across generations.
+
+<p>The status module will also use a <code>G</code> to indicate those
+children which are still serving requests started before the graceful
+restart was given.
+
+<p>At present there is no way for a log rotation script using
+<code>USR1</code> to know for certain that all children writing the
+pre-restart log have finished.  We suggest that you use a suitable delay
+after sending the <code>USR1</code> signal before you do anything with the
+old log.  For example if most of your hits take less than 10 minutes to
+complete for users on low bandwidth links then you could wait 15 minutes
+before doing anything with the old log.
+
+<p><b>Note:</b> If your configuration file has errors in it when you issue a
+restart then your parent will not restart, it will exit with an error.
+In the case of graceful
+restarts it will also leave children running when it exits.  (These are
+the children which are "gracefully exiting" by handling their last request.)
+This will cause problems if you attempt to restart the server -- it will
+not be able to bind to its listening ports.  At present the only work
+around is to check the syntax of your files before doing a restart.  The
+easiest way is to just run httpd as a non-root user.  If there are no
+errors it will attempt to open its sockets and logs and fail because it's
+not root (or because the currently running httpd already has those ports
+bound).  If it fails for any other reason then it's probably a config file
+error and the error should be fixed before issuing the graceful restart.
+
+<h3>Appendix: signals and race conditions</h3>
+
+<p>Prior to Apache 1.2b9 there were several <i>race conditions</i>
+involving the restart and die signals (a simple description of race
+condition is: a time-sensitive problem, as in if something happens at just
+the wrong time it won't behave as expected).  For those architectures that
+have the "right" feature set we have eliminated as many as we can.
+But it should be noted that there still do exist race conditions on
+certain architectures.
+
+<p>Architectures that use an on disk
+<a href="mod/core.html#scoreboardfile">ScoreBoardFile</a>
+have the potential to corrupt their scoreboards.  This can result in
+the "bind: Address already in use" (after <code>HUP</code>) or
+"long lost child came home!" (after <code>USR1</code>).  The former is
+a fatal error, while the latter just causes the server to lose a scoreboard
+slot.  So it might be advisable to use graceful restarts, with
+an occasional hard restart.  These problems are very difficult to work
+around, but fortunately most architectures do not require a scoreboard file.
+See the ScoreBoardFile documentation for a method to determine if your
+architecture uses it.
+
+<p><code>NEXT</code> and <code>MACHTEN</code> (68k only) have small race
+conditions
+which can cause a restart/die signal to be lost, but should not cause the
+server to do anything otherwise problematic.
+<!-- they don't have sigaction, or we're not using it -djg -->
+
+<p>All architectures have a small race condition in each child involving
+the second and subsequent requests on a persistent HTTP connection
+(KeepAlive).  It may exit after reading the request line but before
+reading any of the request headers.  There is a fix that was discovered
+too late to make 1.2.  In theory this isn't an issue because the KeepAlive
+client has to expect these events because of network latencies and
+server timeouts.  In practice it doesn't seem to affect anything either
+-- in a test case the server was restarted twenty times per second and
+clients successfully browsed the site without getting broken images or
+empty documents.
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
diff --git a/APACHE_1_2_X/htdocs/manual/suexec.html b/APACHE_1_2_X/htdocs/manual/suexec.html
new file mode 100644 (file)
index 0000000..7806bc8
--- /dev/null
@@ -0,0 +1,505 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<TITLE>Apache suEXEC Support</TITLE>
+</HEAD>
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+
+<H1 ALIGN="CENTER">Apache suEXEC Support</H1>
+
+<P ALIGN="LEFT">
+<OL>
+       <LH><BIG><STRONG>CONTENTS</STRONG></BIG></LH>
+       <LI><A HREF="#what">What is suEXEC?</A></LI>
+       <LI><A HREF="#before">Before we begin.</A></LI>
+       <LI><A HREF="#model">suEXEC Security Model.</A></LI>
+       <LI><A HREF="#install">Configuring & Installing suEXEC</A></LI>
+       <LI><A HREF="#enable">Enabling & Disabling suEXEC</A></LI>
+       <LI><A HREF="#debug">Debugging suEXEC</A></LI>
+       <LI><A HREF="#jabberwock">Beware the Jabberwock: Warnings & Examples</A></LI>
+</OL>
+</P>
+
+<H3><A NAME="what">What is suEXEC?</A></H3>
+<P ALIGN="LEFT">
+The <STRONG>suEXEC</STRONG> feature -- introduced in Apache 1.2 -- provides
+Apache users the ability to run <STRONG>CGI</STRONG> and <STRONG>SSI</STRONG>
+programs under user IDs different from the user ID of the calling web-server.
+Normally, when a CGI or SSI program executes, it runs as the same user who is
+running the web server.
+</P>
+
+<P ALIGN="LEFT">
+Used properly, this feature can reduce considerably the security risks involved
+with allowing users to develop and run private CGI or SSI programs.  However,
+if suEXEC is improperly configured, it can cause any number of problems and
+possibly create new holes in your computer's security.  If you aren't familiar
+with managing setuid root programs and the security issues they present, we 
+highly recommend that you not consider using suEXEC.
+</P> 
+
+<P ALIGN="CENTER">
+<STRONG><A HREF="suexec.html">BACK TO CONTENTS</A></STRONG>
+</P>
+
+<H3><A NAME="before">Before we begin.</A></H3>
+<P ALIGN="LEFT">
+Before jumping head-first into this document, you should be aware of the
+assumptions made on the part of the Apache Group and this document.
+</P>
+
+<P ALIGN="LEFT">
+First, it is assumed that you are using a UNIX derivate operating system that
+is capable of <STRONG>setuid</STRONG> and <STRONG>setgid</STRONG> operations.
+All command examples are given in this regard.  Other platforms, if they are
+capable of supporting suEXEC, may differ in their configuration.
+</P>
+
+<P ALIGN="LEFT">
+Second, it is assumed you are familiar with some basic concepts of your 
+computer's security and its administration.  This involves an understanding
+of <STRONG>setuid/setgid</STRONG> operations and the various effects they
+may have on your system and its level of security.
+</P>
+
+<P ALIGN="LEFT">
+Third, it is assumed that you are using an <STRONG>unmodified</STRONG>
+version of suEXEC code.  All code for suEXEC has been carefully scrutinized and
+tested by the developers as well as numerous beta testers.  Every precaution has
+been taken to ensure a simple yet solidly safe base of code.  Altering this
+code can cause unexpected problems and new security risks.  It is 
+<STRONG>highly</STRONG> recommended you not alter the suEXEC code unless you 
+are well versed in the particulars of security programming and are willing to
+share your work with the Apache Group for consideration.
+</P>
+
+<P ALIGN="LEFT">
+Fourth, and last, it has been the decision of the Apache Group to 
+<STRONG>NOT</STRONG> make suEXEC part of the default installation of Apache.
+To this end, suEXEC configuration is a manual process requiring of the
+administrator careful attention to details.  It is through this process
+that the Apache Group hopes to limit suEXEC installation only to those
+who are determined to use it.
+</P>
+
+<P ALIGN="LEFT">
+Still with us?  Yes?  Good.  Let's move on!
+</P>
+
+<P ALIGN="CENTER">
+<STRONG><A HREF="suexec.html">BACK TO CONTENTS</A></STRONG>
+</P>
+
+<H3><A NAME="model">suEXEC Security Model</A></H3>
+<P ALIGN="LEFT">
+Before we begin configuring and installing suEXEC, we will first discuss
+the security model you are about to implement.  By doing so, you may
+better understand what exactly is going on inside suEXEC and what precautions
+are taken to ensure your system's security.
+</P>
+
+<P ALIGN="LEFT">
+<STRONG>suEXEC</STRONG> is based on a setuid "wrapper" program that is
+called by the main Apache web server.  This wrapper is called when an HTTP
+request is made for a CGI or SSI program that the administrator has designated
+to run as a userid other than that of the main server.  When such a request
+is made, Apache provides the suEXEC wrapper with the program's name and the 
+user and group IDs under which the program is to execute.
+</P>
+
+<P ALIGN="LEFT">
+The wrapper then employs the following process to determine success or
+failure -- if any one of these conditions fail, the program logs the failure
+and exits with an error, otherwise it will continue:
+       <OL>
+       <LI><STRONG>Was the wrapper called with the proper number of arguments?</STRONG>
+       <BLOCKQUOTE>
+       The wrapper will only execute if it is given the proper number of arguments.
+       The proper argument format is known to the Apache web server.  If the wrapper
+       is not receiving the proper number of arguments, it is either being hacked, or
+       there is something wrong with the suEXEC portion of your Apache binary.
+       </BLOCKQUOTE>
+       </LI>
+       <LI><STRONG>Is the user executing this wrapper a valid user of this system?</STRONG>
+       <BLOCKQUOTE>
+       This is to ensure that the user executing the wrapper is truly a user of the system.
+       </BLOCKQUOTE>
+       </LI>
+       <LI><STRONG>Is this valid user allowed to run the wrapper?</STRONG>
+       <BLOCKQUOTE>
+       Is this user the user allowed to run this wrapper?  Only one user (the Apache
+       user) is allowed to execute this program.
+       </BLOCKQUOTE>
+       </LI>
+       <LI><STRONG>Does the target program have an unsafe hierarchical reference?</STRONG>
+       <BLOCKQUOTE>
+       Does the target program contain a leading '/' or have a '..' backreference?  These
+       are not allowed; the target program must reside within the Apache webspace.
+       </BLOCKQUOTE>
+       </LI>
+       <LI><STRONG>Is the target user name valid?</STRONG>
+       <BLOCKQUOTE>
+       Does the target user exist?
+       </BLOCKQUOTE>
+       </LI>
+       <LI><STRONG>Is the target group name valid?</STRONG>
+       <BLOCKQUOTE>
+       Does the target group exist?
+       </BLOCKQUOTE>
+       </LI>
+       <LI><STRONG>Is the target user <EM>NOT</EM> superuser?</STRONG>
+       <BLOCKQUOTE>
+       Presently, suEXEC does not allow 'root' to execute CGI/SSI programs.
+       </BLOCKQUOTE>
+       </LI>
+       <LI><STRONG>Is the target userid <EM>ABOVE</EM> the minimum ID number?</STRONG>
+       <BLOCKQUOTE>
+       The minimum user ID number is specified during configuration.  This allows you
+       to set the lowest possible userid that will be allowed to execute CGI/SSI programs.
+       This is useful to block out "system" accounts.
+       </BLOCKQUOTE>
+       </LI>
+       <LI><STRONG>Is the target group <EM>NOT</EM> the superuser group?</STRONG>
+       <BLOCKQUOTE>
+       Presently, suEXEC does not allow the 'root' group to execute CGI/SSI programs.
+       </BLOCKQUOTE>
+       </LI>
+       <LI><STRONG>Is the target groupid <EM>ABOVE</EM> the minimum ID number?</STRONG>
+       <BLOCKQUOTE>
+       The minimum group ID number is specified during configuration.  This allows you
+       to set the lowest possible groupid that will be allowed to execute CGI/SSI programs.
+       This is useful to block out "system" groups.
+       </BLOCKQUOTE>
+       </LI>
+       <LI><STRONG>Can the wrapper successfully become the target user and group?</STRONG>
+       <BLOCKQUOTE>
+       Here is where the program becomes the target user and group via setuid and setgid
+       calls.  The group access list is also initialized with all of the groups of which
+       the user is a member.
+       </BLOCKQUOTE>
+       </LI>
+       <LI><STRONG>Does the directory in which the program resides exist?</STRONG>
+       <BLOCKQUOTE>
+       If it doesn't exist, it can't very well contain files.
+       </BLOCKQUOTE>
+       </LI>
+       <LI><STRONG>Is the directory within the Apache webspace?</STRONG>
+       <BLOCKQUOTE>
+       If the request is for a regular portion of the server, is the requested directory
+       within the server's document root?  If the request is for a UserDir, is the requested
+       directory within the user's document root?
+       </BLOCKQUOTE>
+       </LI>
+       <LI><STRONG>Is the directory <EM>NOT</EM> writable by anyone else?</STRONG>
+       <BLOCKQUOTE>
+       We don't want to open up the directory to others; only the owner user may be able
+       to alter this directories contents.
+       </BLOCKQUOTE>
+       </LI>
+       <LI><STRONG>Does the target program exist?</STRONG>
+       <BLOCKQUOTE>
+       If it doesn't exists, it can't very well be executed.
+       </BLOCKQUOTE>
+       </LI>
+       <LI><STRONG>Is the target program <EM>NOT</EM> writable by anyone else?</STRONG>
+       <BLOCKQUOTE>
+       We don't want to give anyone other than the owner the ability to change the program.
+       </BLOCKQUOTE>
+       </LI>
+       <LI><STRONG>Is the target program <EM>NOT</EM> setuid or setgid?</STRONG>
+       <BLOCKQUOTE>
+       We do not want to execute programs that will then change our UID/GID again.
+       </BLOCKQUOTE>
+       </LI>
+       <LI><STRONG>Is the target user/group the same as the program's user/group?</STRONG>
+       <BLOCKQUOTE>
+       Is the user the owner of the file?
+       </BLOCKQUOTE>
+       </LI>
+       <LI><STRONG>Can we successfully clean the process environment to ensure safe operations?</STRONG>
+       <BLOCKQUOTE>
+       suEXEC cleans the process' environment by establishing a safe execution PATH (defined
+       during configuration), as well as only passing through those variables whose names
+       are listed in the safe environment list (also created during configuration).
+       </BLOCKQUOTE>
+       </LI>
+       <LI><STRONG>Can we successfully become the target program and execute?</STRONG>
+       <BLOCKQUOTE>
+       Here is where suEXEC ends and the target program begins.
+       </BLOCKQUOTE>
+       </LI>
+       </OL>
+</P>
+
+<P ALIGN="LEFT">
+This is the standard operation of the the suEXEC wrapper's security model.
+It is somewhat stringent and can impose new limitations and guidelines for
+CGI/SSI design, but it was developed carefully step-by-step with security
+in mind.
+</P>
+
+<P ALIGN="LEFT">
+For more information as to how this security model can limit your possibilities
+in regards to server configuration, as well as what security risks can be avoided
+with a proper suEXEC setup, see the <A HREF="#beware">"Beware the Jabberwock"</A>
+section of this document.
+</P>
+
+<P ALIGN="CENTER">
+<STRONG><A HREF="suexec.html">BACK TO CONTENTS</A></STRONG>
+</P>
+
+<H3><A NAME="install">Configuring & Installing suEXEC</A></H3>
+<P ALIGN="LEFT">
+Here's where we begin the fun.  The configuration and installation of suEXEC is
+a four step process: edit the suEXEC header file, compile suEXEC, place the
+suEXEC binary in its proper location, and configure Apache for use with suEXEC.
+</P>
+
+<P ALIGN="LEFT">
+<STRONG>EDITING THE SUEXEC HEADER FILE</STRONG><BR>
+- From the top-level of the Apache source tree, type:&nbsp;&nbsp;
+<STRONG><code>cd support [ENTER]</code></STRONG>
+</P>
+
+<P ALIGN="LEFT">
+Edit the <code>suexec.h</code> file and change the following macros to
+match your local Apache installation.
+</P>
+
+<P ALIGN="LEFT">
+<EM>From support/suexec.h</EM>
+<PRE>
+     /*
+      * HTTPD_USER -- Define as the username under which Apache normally
+      *               runs.  This is the only user allowed to execute
+      *               this program.
+      */
+     #define HTTPD_USER "www"
+
+     /*
+      * UID_MIN -- Define this as the lowest UID allowed to be a target user
+      *            for suEXEC.  For most systems, 500 or 100 is common.
+      */
+     #define UID_MIN 100
+
+     /*
+      * GID_MIN -- Define this as the lowest GID allowed to be a target group
+      *            for suEXEC.  For most systems, 100 is common.
+      */
+     #define GID_MIN 100
+
+     /*
+      * USERDIR_SUFFIX -- Define to be the subdirectory under users' 
+      *                   home directories where suEXEC access should
+      *                   be allowed.  All executables under this directory
+      *                   will be executable by suEXEC as the user so 
+      *                   they should be "safe" programs.  If you are 
+      *                   using a "simple" UserDir directive (ie. one 
+      *                   without a "*" in it) this should be set to 
+      *                   the same value.  suEXEC will not work properly
+      *                   in cases where the UserDir directive points to 
+      *                   a location that is not the same as the user's
+      *                   home directory as referenced in the passwd file.
+      *
+      *                   If you have VirtualHosts with a different
+      *                   UserDir for each, you will need to define them to
+      *                   all reside in one parent directory; then name that
+      *                   parent directory here.  IF THIS IS NOT DEFINED
+      *                   PROPERLY, ~USERDIR CGI REQUESTS WILL NOT WORK!
+      *                   See the suEXEC documentation for more detailed
+      *                   information.
+      */
+     #define USERDIR_SUFFIX "public_html"
+
+     /*
+      * LOG_EXEC -- Define this as a filename if you want all suEXEC
+      *             transactions and errors logged for auditing and
+      *             debugging purposes.
+      */
+     #define LOG_EXEC "/usr/local/etc/httpd/logs/cgi.log" /* Need me? */
+
+     /*
+      * DOC_ROOT -- Define as the DocumentRoot set for Apache.  This
+      *             will be the only hierarchy (aside from UserDirs)
+      *             that can be used for suEXEC behavior.
+      */
+     #define DOC_ROOT "/usr/local/etc/httpd/htdocs"
+
+     /*
+      * SAFE_PATH -- Define a safe PATH environment to pass to CGI executables.
+      *
+      */
+     #define SAFE_PATH "/usr/local/bin:/usr/bin:/bin"
+</PRE>
+</P>
+
+<P ALIGN="LEFT">
+<STRONG>COMPILING THE SUEXEC WRAPPER</STRONG><BR>
+You now need to compile the suEXEC wrapper.  At the shell command prompt, 
+type:&nbsp;&nbsp;<STRONG><CODE>cc suexec.c -o suexec [ENTER]</CODE></STRONG>.
+This should create the <STRONG><em>suexec</em></STRONG> wrapper executable.
+</P>
+
+<P ALIGN="LEFT">
+<STRONG>COMPILING APACHE FOR USE WITH SUEXEC</STRONG><BR>
+By default, Apache is compiled to look for the suEXEC wrapper in the following
+location.
+</P>
+
+<P ALIGN="LEFT">
+<EM>From src/httpd.h</EM>
+<PRE>
+     /* The path to the suEXEC wrapper */
+     #define SUEXEC_BIN "/usr/local/etc/httpd/sbin/suexec"
+</PRE>
+</P>
+
+<P ALIGN="LEFT">
+If your installation requires location of the wrapper program in a different
+directory, edit src/httpd.h and recompile your Apache server.
+See <A HREF="install.html">Compiling and Installing Apache</A> for more
+info on this process.
+</P>
+
+<P ALIGN="LEFT">
+<STRONG>COPYING THE SUEXEC BINARY TO ITS PROPER LOCATION</STRONG><BR>
+Copy the <STRONG><em>suexec</em></STRONG> executable created in the
+exercise above to the defined location for <STRONG>SUEXEC_BIN</STRONG>.
+</P>
+
+<P ALIGN="LEFT">
+<STRONG><CODE>cp suexec /usr/local/etc/httpd/sbin/suexec [ENTER]</CODE></STRONG>
+</P>
+
+<P ALIGN="LEFT">
+In order for the wrapper to set the user ID, it must me installed as owner 
+<STRONG><em>root</em></STRONG> and must have the setuserid execution bit 
+set for file modes.  If you are not running a <STRONG><em>root</em></STRONG>
+user shell, do so now and execute the following commands.
+</P>
+
+<P ALIGN="LEFT">
+<STRONG><CODE>chown root /usr/local/etc/httpd/sbin/suexec [ENTER]</CODE></STRONG><BR>
+<STRONG><CODE>chmod 4711 /usr/local/etc/httpd/sbin/suexec [ENTER]</CODE></STRONG>
+</P>
+
+<P ALIGN="CENTER">
+<STRONG><A HREF="suexec.html">BACK TO CONTENTS</A></STRONG>
+</P>
+
+<H3><A NAME="enable">Enabling & Disabling suEXEC</A></H3>
+<P ALIGN="LEFT">
+After properly installing the <STRONG>suexec</STRONG> wrapper
+executable, you must kill and restart the Apache server.  A simple
+<STRONG><CODE>kill -1 `cat httpd.pid`</CODE></STRONG> will not be enough.
+Upon startup of the web-server, if Apache finds a properly configured
+<STRONG>suexec</STRONG> wrapper, it will print the following message to
+the console:
+</P>
+
+<P ALIGN="LEFT">
+<CODE>Configuring Apache for use with suexec wrapper.</CODE>
+</P>
+
+<P ALIGN="LEFT">
+If you don't see this message at server startup, the server is most
+likely not finding the wrapper program where it expects it, or the
+executable is not installed <STRONG><EM>setuid root</EM></STRONG>. Check
+your installation and try again.
+</P>
+
+<P ALIGN="LEFT">
+One way to use <STRONG>suEXEC</STRONG> is through the
+<a href="mod/core.html#user"><STRONG>User</STRONG></a> and
+<a href="mod/core.html#group"><STRONG>Group</STRONG></a> directives in
+<a href="mod/core.html#virtualhost"><STRONG>VirtualHost</STRONG></a>
+definitions. By setting these directives to values different from the
+main server user ID, all requests for CGI resources will be executed as
+the <STRONG>User</STRONG> and <STRONG>Group</STRONG> defined for that
+<STRONG>&lt;VirtualHost&gt;</STRONG>. If only one or
+neither of these directives are specified for a
+<STRONG>&lt;VirtualHost&gt;</STRONG> then the main
+server userid is assumed.<p>
+
+<STRONG>suEXEC</STRONG> can also be used to to execute CGI programs as
+the user to which the request is being directed. This is accomplished by
+using the <STRONG>~</STRONG> character prefixing the user ID for whom
+execution is desired.
+The only requirement needed for this feature to work is for CGI
+execution to be enabled for the user and that the script must meet the
+scrutiny of the <a href="#model">security checks</a> above.
+
+<P ALIGN="CENTER">
+<STRONG><A HREF="suexec.html">BACK TO CONTENTS</A></STRONG>
+</P>
+
+<H3><A NAME="debug">Debugging suEXEC</A></H3>
+<P ALIGN="LEFT">
+The suEXEC wrapper will write log information to the location defined in
+the <code>suexec.h</code> as indicated above. If you feel you have
+configured and installed the wrapper properly, have a look at this log 
+and the error_log for the server to see where you may have gone astray.
+</P>
+
+<P ALIGN="CENTER">
+<STRONG><A HREF="suexec.html">BACK TO CONTENTS</A></STRONG>
+</P>
+
+<H3><A NAME="jabberwock">Beware the Jabberwock: Warnings & Examples</A></H3>
+<P ALIGN="LEFT">
+<STRONG>NOTE!</STRONG>  This section may not be complete.  For the latest
+revision of this section of the documentation, see the Apache Group's
+<A HREF="http://www.apache.org/docs/suexec.html">Online Documentation</A>
+version.
+</P>
+
+<P ALIGN="LEFT">
+There are a few points of interest regarding the wrapper that can cause
+limitations on server setup.  Please review these before submitting any
+"bugs" regarding suEXEC.
+<UL>
+       <LH><STRONG>suEXEC Points Of Interest</STRONG></LH>
+       <LI>Hierarchy limitations
+       <BLOCKQUOTE>
+       For security and efficiency reasons, all suexec requests must
+       remain within either a top-level document root for virtual
+       host requests, or one top-level personal document root for
+       userdir requests.  For example, if you have four VirtualHosts
+       configured, you would need to structure all of your VHosts'
+       document roots off of one main Apache document hierarchy to
+       take advantage of suEXEC for VirtualHosts. (Example forthcoming.)
+       </BLOCKQUOTE>
+       </LI>
+       <LI>suEXEC's PATH environment variable
+       <BLOCKQUOTE>
+       This can be a dangerous thing to change.  Make certain every
+       path you include in this define is a <STRONG>trusted</STRONG>
+       directory.  You don't want to open people up to having someone
+       from across the world running a trojan horse on them.
+       </BLOCKQUOTE>
+       </LI>
+       <LI>Altering the suEXEC code
+       <BLOCKQUOTE>
+       Again, this can cause <STRONG>Big Trouble</STRONG> if you try
+       this without knowing what you are doing.  Stay away from it
+       if at all possible.
+       </BLOCKQUOTE>
+       </LI>
+</UL>
+
+<P ALIGN="CENTER">
+<STRONG><A HREF="suexec.html">BACK TO CONTENTS</A></STRONG>
+</P>
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
diff --git a/APACHE_1_2_X/htdocs/manual/unixware.html b/APACHE_1_2_X/htdocs/manual/unixware.html
new file mode 100644 (file)
index 0000000..eb8adbe
--- /dev/null
@@ -0,0 +1,61 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<TITLE>Compiling Apache under UnixWare</TITLE>
+</HEAD>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+
+<H1 ALIGN="CENTER">Compiling Apache under UnixWare</H1>
+
+To compile a working copy of Apache under UnixWare, there are several other
+steps you may need to take. These prevent such problems as zombie processes,
+bind errors, and accept errors, to name a few.
+
+<H2>UnixWare 1.x</H2>
+
+Make sure that USE_FCNTL_SERIALIZE_ACCEPT is defined (if not
+defined by Apache autoconfiguration). If using the UnixWare <i>cc</i>
+compiler, and you still see accept() errors, don't use compiler optimization,
+or get <i>gcc</i>.
+
+<H2>UnixWare 2.0.x</H2>
+
+SCO patch <a href="ftp://ftp.sco.com/UW20/tf2163.txt">tf2163</a> is required
+in order for Apache to work correctly on UnixWare 2.0.x. See
+<a href="http://www.sco.com">http://www.sco.com</a>
+for UnixWare patch information.<p>
+
+In addition, make sure that USE_FCNTL_SERIALIZE_ACCEPT is defined (if not
+defined by Apache autoconfiguration). To reduce instances of connections
+in FIN_WAIT_2 state, you may also want to define NO_LINGCLOSE (Apache 1.2
+only).
+
+<H2>UnixWare 2.1.x</H2>
+
+SCO patch <a href="ftp://ftp.sco.com/UW21/ptf3123b.txt">ptf3123</a> is required
+in order for Apache to work correctly on UnixWare 2.1.x. See
+<a href="http://www.sco.com">http://www.sco.com</a>
+for UnixWare patch information.<p>
+
+<b>NOTE:</b> Unixware 2.1.2 and later already have patch ptf3123 included<p>
+
+In addition, make sure that USE_FCNTL_SERIALIZE_ACCEPT is defined (if not
+defined by Apache autoconfiguration). To reduce instances of connections
+in FIN_WAIT_2 state, you may also want to define NO_LINGCLOSE (Apache 1.2
+only).<p>
+
+Thanks to Joe Doupnik &lt;JRD@cc.usu.edu&gt; and Rich Vaughn
+&lt;rvaughn@aad.com&gt; for additional info for UnixWare builds.<p>
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
diff --git a/APACHE_1_2_X/htdocs/manual/vhosts-in-depth.html b/APACHE_1_2_X/htdocs/manual/vhosts-in-depth.html
new file mode 100644 (file)
index 0000000..4e07812
--- /dev/null
@@ -0,0 +1,382 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html><head>
+<title>An In-Depth Discussion of VirtualHost Matching</title>
+</head>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<h1 ALIGN="CENTER">An In-Depth Discussion of VirtualHost Matching</h1>
+
+<p>This is a very rough document that was probably out of date the moment
+it was written.  It attempts to explain exactly what the code does when
+deciding what virtual host to serve a hit from.  It's provided on the
+assumption that something is better than nothing.  The server version
+under discussion is Apache 1.2.
+
+<p>If you just want to &quot;make it work&quot; without understanding
+how, there's a <a href="#whatworks">What Works</a> section at the bottom.
+
+<h3>Config File Parsing</h3>
+
+<p>There is a main_server which consists of all the definitions appearing
+outside of <CODE>VirtualHost</CODE> sections.  There are virtual servers,
+called <EM>vhosts</EM>, which are defined by
+<A
+ HREF="mod/core.html#virtualhost"
+><SAMP>VirtualHost</SAMP></A>
+sections.
+
+<p>The directives
+<A
+ HREF="mod/core.html#port"
+><SAMP>Port</SAMP></A>,
+<A
+ HREF="mod/core.html#servername"
+><SAMP>ServerName</SAMP></A>,
+<A
+ HREF="mod/core.html#serverpath"
+><SAMP>ServerPath</SAMP></A>,
+and
+<A
+ HREF="mod/core.html#serveralias"
+><SAMP>ServerAlias</SAMP></A>
+can appear anywhere within the definition of
+a server.  However, each appearance overrides the previous appearance
+(within that server).
+
+<p>The default value of the <code>Port</code> field for main_server
+is 80.  The main_server has no default <code>ServerName</code>,
+<code>ServerPath</code>, or <code>ServerAlias</code>.
+
+<p>In the absence of any
+<A
+ HREF="mod/core.html#listen"
+><SAMP>Listen</SAMP></A>
+directives, the (final if there
+are multiple) <code>Port</code> directive in the main_server indicates
+which port httpd will listen on.
+
+<p> The <code>Port</code> and <code>ServerName</code> directives for
+any server main or virtual are used when generating URLs such as during
+redirects.
+
+<p> Each address appearing in the <code>VirtualHost</code> directive
+can have an optional port.  If the port is unspecified it defaults to
+the value of the main_server's most recent <code>Port</code> statement.
+The special port <SAMP>*</SAMP> indicates a wildcard that matches any port.
+Collectively the entire set of addresses (including multiple
+<SAMP>A</SAMP> record
+results from DNS lookups) are called the vhost's <EM>address set</EM>.
+
+<p> The magic <code>_default_</code> address has significance during
+the matching algorithm.  It essentially matches any unspecified address.
+
+<p> After parsing the <code>VirtualHost</code> directive, the vhost server
+is given a default <code>Port</code> equal to the port assigned to the
+first name in its <code>VirtualHost</code> directive.  The complete
+list of names in the <code>VirtualHost</code> directive are treated
+just like a <code>ServerAlias</code> (but are not overridden by any
+<code>ServerAlias</code> statement).  Note that subsequent <code>Port</code>
+statements for this vhost will not affect the ports assigned in the
+address set.
+
+<p>
+All vhosts are stored in a list which is in the reverse order that
+they appeared in the config file.  For example, if the config file is:
+
+<blockquote><pre>
+    &lt;VirtualHost A&gt;
+    ...
+    &lt;/VirtualHost&gt;
+
+    &lt;VirtualHost B&gt;
+    ...
+    &lt;/VirtualHost&gt;
+
+    &lt;VirtualHost C&gt;
+    ...
+    &lt;/VirtualHost&gt;
+</pre></blockquote>
+
+Then the list will be ordered: main_server, C, B, A.  Keep this in mind.
+
+<p>
+After parsing has completed, the list of servers is scanned, and various
+merges and default values are set.  In particular:
+
+<ol>
+<li>If a vhost has no
+    <A
+     HREF="mod/core.html#serveradmin"
+    ><code>ServerAdmin</code></A>,
+    <A
+     HREF="mod/core.html#resourceconfig"
+    ><code>ResourceConfig</code></A>,
+    <A
+     HREF="mod/core.html#accessconfig"
+    ><code>AccessConfig</code></A>,
+    <A
+     HREF="mod/core.html#timeout"
+    ><code>Timeout</code></A>,
+    <A
+     HREF="mod/core.html#keepalivetimeout"
+    ><code>KeepAliveTimeout</code></A>,
+    <A
+     HREF="mod/core.html#keepalive"
+    ><code>KeepAlive</code></A>,
+    <A
+     HREF="mod/core.html#maxkeepaliverequests"
+    ><code>MaxKeepAliveRequests</code></A>,
+    or
+    <A
+     HREF="mod/core.html#sendbuffersize"
+    ><code>SendBufferSize</code></A>
+    directive then the respective value is
+    inherited from the main_server.  (That is, inherited from whatever
+    the final setting of that value is in the main_server.)
+
+<li>The &quot;lookup defaults&quot; that define the default directory
+    permissions 
+    for a vhost are merged with those of the main server.  This includes
+    any per-directory configuration information for any module.
+
+<li>The per-server configs for each module from the main_server are
+    merged into the vhost server.
+</ol>
+
+Essentially, the main_server is treated as &quot;defaults&quot; or a
+&quot;base&quot; on
+which to build each vhost.  But the positioning of these main_server
+definitions in the config file is largely irrelevant -- the entire
+config of the main_server has been parsed when this final merging occurs.
+So even if a main_server definition appears after a vhost definition
+it might affect the vhost definition.
+
+<p> If the main_server has no <code>ServerName</code> at this point,
+then the hostname of the machine that httpd is running on is used
+instead.  We will call the <EM>main_server address set</EM> those IP
+addresses returned by a DNS lookup on the <code>ServerName</code> of
+the main_server.
+
+<p> Now a pass is made through the vhosts to fill in any missing
+<code>ServerName</code> fields and to classify the vhost as either
+an <EM>IP-based</EM> vhost or a <EM>name-based</EM> vhost.  A vhost is
+considered a name-based vhost if any of its address set overlaps the
+main_server (the port associated with each address must match the
+main_server's <code>Port</code>).  Otherwise it is considered an IP-based
+vhost.
+
+<p> For any undefined <code>ServerName</code> fields, a name-based vhost
+defaults to the address given first in the <code>VirtualHost</code>
+statement defining the vhost.  Any vhost that includes the magic
+<SAMP>_default_</SAMP> wildcard is given the same <code>ServerName</code> as
+the main_server.  Otherwise the vhost (which is necessarily an IP-based
+vhost) is given a <code>ServerName</code> based on the result of a reverse
+DNS lookup on the first address given in the <code>VirtualHost</code>
+statement.
+
+<p>
+
+<h3>Vhost Matching</h3>
+
+<p>
+The server determines which vhost to use for a request as follows:
+
+<p> <code>find_virtual_server</code>: When the connection is first made
+by the client, the local IP address (the IP address to which the client
+connected) is looked up in the server list.  A vhost is matched if it
+is an IP-based vhost, the IP address matches and the port matches
+(taking into account wildcards).
+
+<p> If no vhosts are matched then the last occurrence, if it appears,
+of a <SAMP>_default_</SAMP> address (which if you recall the ordering of the
+server list mentioned above means that this would be the first occurrence
+of <SAMP>_default_</SAMP> in the config file) is matched.
+
+<p> In any event, if nothing above has matched, then the main_server is
+matched.
+
+<p> The vhost resulting from the above search is stored with data
+about the connection.  We'll call this the <EM>connection vhost</EM>.
+The connection vhost is constant over all requests in a particular TCP/IP
+session -- that is, over all requests in a KeepAlive/persistent session.
+
+<p> For each request made on the connection the following sequence of
+events further determines the actual vhost that will be used to serve
+the request.
+
+<p> <code>check_fulluri</code>: If the requestURI is an absoluteURI, that
+is it includes <code>http://hostname/</code>, then an attempt is made to
+determine if the hostname's address (and optional port) match that of
+the connection vhost.  If it does then the hostname portion of the URI
+is saved as the <EM>request_hostname</EM>.  If it does not match, then the
+URI remains untouched.  <STRONG>Note</STRONG>: to achieve this address
+comparison, 
+the hostname supplied goes through a DNS lookup unless it matches the
+<code>ServerName</code> or the local IP address of the client's socket.
+
+<p> <code>parse_uri</code>: If the URI begins with a protocol
+(<EM>i.e.</EM>, <code>http:</code>, <code>ftp:</code>) then the request is
+considered a proxy request.  Note that even though we may have stripped
+an <code>http://hostname/</code> in the previous step, this could still
+be a proxy request.
+
+<p> <code>read_request</code>: If the request does not have a hostname
+from the earlier step, then any <code>Host:</code> header sent by the
+client is used as the request hostname.
+
+<p> <code>check_hostalias</code>: If the request now has a hostname,
+then an attempt is made to match for this hostname.  The first step
+of this match is to compare any port, if one was given in the request,
+against the <code>Port</code> field of the connection vhost.  If there's
+a mismatch then the vhost used for the request is the connection vhost.
+(This is a bug, see observations.)
+
+<p>
+If the port matches, then httpd scans the list of vhosts starting with
+the next server <STRONG>after</STRONG> the connection vhost.  This scan does not
+stop if there are any matches, it goes through all possible vhosts,
+and in the end uses the last match it found.  The comparisons performed
+are as follows:
+
+<ul>
+<li>Compare the request hostname:port with the vhost
+    <code>ServerName</code> and <code>Port</code>.
+
+<li>Compare the request hostname against any and all addresses given in
+    the <code>VirtualHost</code> directive for this vhost.
+
+<li>Compare the request hostname against the <code>ServerAlias</code>
+    given for the vhost.
+</ul>
+
+<p>
+<code>check_serverpath</code>: If the request has no hostname
+(back up a few paragraphs) then a scan similar to the one
+in <code>check_hostalias</code> is performed to match any
+<code>ServerPath</code> directives given in the vhosts.  Note that the
+<STRONG>last match</STRONG> is used regardless (again consider the ordering of
+the virtual hosts).
+
+<h3>Observations</h3>
+
+<ul>
+
+<li>It is difficult to define an IP-based vhost for the machine's
+    &quot;main IP address&quot;.  You essentially have to create a bogus
+    <code>ServerName</code> for the main_server that does not match the
+    machine's IPs.
+
+<li>During the scans in both <code>check_hostalias</code> and
+    <code>check_serverpath</code> no check is made that the vhost being
+    scanned is actually a name-based vhost.  This means, for example, that
+    it's possible to match an IP-based vhost through another address.  But
+    because the scan starts in the vhost list at the first vhost that
+    matched the local IP address of the connection, not all IP-based vhosts
+    can be matched.
+
+    <p>Consider the config file above with three vhosts A, B, C.  Suppose
+    that B is a named-based vhost, and A and C are IP-based vhosts.  If
+    a request comes in on B or C's address containing a header
+    &quot;<SAMP>Host: A</SAMP>&quot; then
+    it will be served from A's config.  If a request comes in on A's
+    address then it will always be served from A's config regardless of
+    any Host: header.
+    </p>
+
+<li>Unless you have a <SAMP>_default_</SAMP> vhost,
+    it doesn't matter if you mix name-based vhosts in amongst IP-based
+    vhosts.  During the <code>find_virtual_server</code> phase above no
+    named-based vhost will be matched, so the main_server will remain the
+    connection vhost.  Then scans will cover all vhosts in the vhost list.
+
+    <p>If you do have a <SAMP>_default_</SAMP> vhost, then you cannot place
+    named-based vhosts after it in the config.  This is because on any
+    connection to the main server IPs the connection vhost will always be
+    the <SAMP>_default_</SAMP> vhost since none of the name-based are 
+    considered during <code>find_virtual_server</code>.
+    </p>
+
+<li>You should never specify DNS names in <code>VirtualHost</code>
+    directives because it will force your server to rely on DNS to boot.
+    Furthermore it poses a security threat if you do not control the
+    DNS for all the domains listed.
+    <a href="dns-caveats.html">
+    There's more information
+    available on this and the next two topics</a>.</p>
+
+<li><code>ServerName</code> should always be set for each vhost.  Otherwise
+    A DNS lookup is required for each vhost.</p>
+
+<li>A DNS lookup is always required for the main_server's
+    <code>ServerName</code> (or to generate that if it isn't specified
+    in the config).</p>
+
+<li>If a <code>ServerPath</code> directive exists which is a prefix of
+    another <code>ServerPath</code> directive that appears later in
+    the configuration file, then the former will always be matched
+    and the latter will never be matched.  (That is assuming that no
+    Host header was available to disambiguate the two.)</p>
+
+<li>If a vhost that would otherwise be a name-vhost includes a
+    <code>Port</code> statement that doesn't match the main_server
+    <code>Port</code> then it will be considered an IP-based vhost.
+    Then <code>find_virtual_server</code> will match it (because
+    the ports associated with each address in the address set default
+    to the port of the main_server) as the connection vhost.  Then
+    <code>check_hostalias</code> will refuse to check any other name-based
+    vhost because of the port mismatch.  The result is that the vhost
+    will steal all hits going to the main_server address.</p>
+
+<li>If two IP-based vhosts have an address in common, the vhost appearing
+    later in the file is always matched.  Such a thing might happen
+    inadvertently.  If the config has name-based vhosts and for some reason
+    the main_server <code>ServerName</code> resolves to the wrong address
+    then all the name-based vhosts will be parsed as ip-based vhosts.
+    Then the last of them will steal all the hits.</P>
+
+<li>The last name-based vhost in the config is always matched for any hit
+    which doesn't match one of the other name-based vhosts.</p>
+
+</ul>
+
+<h3><a name="whatworks">What Works</a></h3>
+
+<p>In addition to the tips on the <a href="dns-caveats.html#tips">DNS
+Issues</a> page, here are some further tips:
+
+<ul>
+
+<li>Place all main_server definitions before any VirtualHost definitions.
+(This is to aid the readability of the configuration -- the post-config
+merging process makes it non-obvious that definitions mixed in around
+virtualhosts might affect all virtualhosts.)</p>
+
+<li>Arrange your VirtualHosts such
+that all name-based virtual hosts come first, followed by IP-based
+virtual hosts, followed by any <SAMP>_default_</SAMP> virtual host</p>
+
+<li>Avoid <code>ServerPaths</code> which are prefixes of other
+<code>ServerPaths</code>.  If you cannot avoid this then you have to
+ensure that the longer (more specific) prefix vhost appears earlier in
+the configuration file than the shorter (less specific) prefix
+(<EM>i.e.</EM>, &quot;ServerPath /abc&quot; should appear after
+&quot;ServerPath /abcdef&quot;). </p>
+
+<li>Do not use <i>port-based</i> vhosts in the same server as
+name-based vhosts.  A loose definition for port-based is a vhost which
+is determined by the port on the server (<em>i.e.</em> one server with
+ports 8000, 8080, and 80 all of which have different configurations).</p>
+
+</ul>
+
+<!--#include virtual="footer.html" -->
+</BODY>
+</HTML>
diff --git a/APACHE_1_2_X/htdocs/manual/virtual-host.html b/APACHE_1_2_X/htdocs/manual/virtual-host.html
new file mode 100644 (file)
index 0000000..6bfa8fb
--- /dev/null
@@ -0,0 +1,204 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<title>Apache Server Virtual Host Support</title>
+</head>
+
+<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
+<BODY
+ BGCOLOR="#FFFFFF"
+ TEXT="#000000"
+ LINK="#0000FF"
+ VLINK="#000080"
+ ALINK="#FF0000"
+>
+<!--#include virtual="header.html" -->
+<h1 ALIGN="CENTER">Virtual Host Support</h1>
+
+<strong>See Also:</strong>
+<a href="host.html">Non-IP based virtual hosts</a>
+
+<h2>What are virtual hosts?</h2>
+This is the ability of a single machine to be a web server for multiple
+domains. For example, an Internet service provider might have a machine
+called <code>www.serve.com</code> which provides Web space for several
+organizations including, say, <em>smallco</em> and <em>baygroup</em>.
+Ordinarily, these groups would be given parts of the Web tree on www.serve.com.
+So smallco's home page would have the URL
+<blockquote>
+http://www.serve.com/smallco/
+</blockquote>
+and baygroup's home page would have the URL
+<blockquote>
+http://www.serve.com/baygroup/
+</blockquote>
+<p>
+For esthetic reasons, however, both organizations would rather their home
+pages appeared under their own names rather than that of the service
+provider's; but they do not want to set up their own Internet links and
+servers.
+<p>
+Virtual hosts are the solution to this problem. smallco and baygroup would
+have their own Internet name registrations, <code>www.smallco.com</code> and
+<code>www.baygroup.org</code> respectively. These hostnames would both
+correspond to the service provider's machine (www.serve.com). Thus
+smallco's home page would now have the URL
+<blockquote>
+http://www.smallco.com/
+</blockquote>
+and baygroup's home page would would have the URL
+<blockquote>
+http://www.baygroup.org/
+</blockquote>
+
+<h2>System requirements</h2>
+Due to limitations in the HTTP/1.0 protocol, the web server <strong>must have a
+different IP address for each virtual host</strong>. This can be achieved
+by the machine having several physical network connections, or by use
+of a <a href="misc/vif-info.html">virtual interface</a> on some operating systems.
+
+<h2>How to set up Apache</h2>
+There are two ways of configuring apache to support multiple hosts.
+Either by running a separate httpd daemon for each hostname, or by running a
+single daemon which supports all the virtual hosts.
+<p>
+Use multiple daemons when:
+<ul>
+<li>The different virtual hosts need very different httpd configurations, such
+   as different values for: <A HREF="mod/core.html#servertype">ServerType</A>,
+   <A HREF="mod/core.html#user">User</A>, 
+   <A HREF="mod/core.html#group">Group</A>,
+   <A HREF="mod/mod_mime.html#typesconfig">TypesConfig</A> or
+   <A HREF="mod/core.html#serverroot">ServerRoot</A>.
+<li>The machine does not process a very high request rate.
+</ul>
+Use a single daemon when:
+<ul>
+<li>Sharing of the httpd configuration between virtual hosts is acceptable.
+<li>The machine services a large number of requests, and so the performance
+   loss in running separate daemons may be significant.
+</ul>
+
+<h2>Setting up multiple daemons</h2>
+Create a separate httpd installation for each virtual host.
+For each installation, use the
+<A HREF="mod/core.html#bindaddress">BindAddress</A> directive in the configuration
+file to select which IP address (or virtual host) that daemon services.
+e.g.
+<blockquote><code>BindAddress www.smallco.com</code></blockquote>
+This hostname can also be given as an IP address.
+
+<h2>Setting up a single daemon</h2>
+For this case, a single httpd will service requests for all the virtual hosts.
+The <A HREF="mod/core.html#virtualhost">VirtualHost</A> directive in the
+ configuration file is used to set the values of
+<A HREF="mod/core.html#serveradmin">ServerAdmin</A>,
+<A HREF="mod/core.html#servername">ServerName</A>,
+<A HREF="mod/core.html#documentroot">DocumentRoot</A>,
+<A HREF="mod/core.html#errorlog">ErrorLog</A> and
+<A HREF="mod/mod_log_common.html#transferlog">TransferLog</A> configuration
+directives to different values for each virtual host.
+e.g.
+<blockquote><code>
+&lt;VirtualHost www.smallco.com&gt;<br>
+ServerAdmin webmaster@mail.smallco.com<br>
+DocumentRoot /groups/smallco/www<br>
+ServerName www.smallco.com<br>
+ErrorLog /groups/smallco/logs/error_log<br>
+TransferLog /groups/smallco/logs/access_log<br>
+&lt;/VirtualHost&gt;<br>
+<br>
+&lt;VirtualHost www.baygroup.org&gt;<br>
+ServerAdmin webmaster@mail.baygroup.org<br>
+DocumentRoot /groups/baygroup/www<br>
+ServerName www.baygroup.org<br>
+ErrorLog /groups/baygroup/logs/error_log<br>
+TransferLog /groups/baygroup/logs/access_log<br>
+&lt;/VirtualHost&gt;<br>
+</code></blockquote>
+
+This VirtualHost hostnames can also be given as IP addresses.
+
+<P>
+
+Almost <strong>ANY</strong> configuration directive can be put
+in the VirtualHost directive, with the exception of
+<A HREF="mod/core.html#servertype">ServerType</A>,
+<A HREF="mod/core.html#user">User</A>,
+<A HREF="mod/core.html#group">Group</A>,
+<A HREF="mod/core.html#startservers">StartServers</A>,
+<A HREF="mod/core.html#maxspareservers">MaxSpareServers</A>,
+<A HREF="mod/core.html#minspareservers">MinSpareServers</A>,
+<A HREF="mod/core.html#maxrequestsperchild">MaxRequestsPerChild</A>,
+<A HREF="mod/core.html#bindaddress">BindAddress</A>,
+<A HREF="mod/core.html#pidfile">PidFile</A>,
+<A HREF="mod/mod_mime.html#typesconfig">TypesConfig</A>, and
+<A HREF="mod/core.html#serverroot">ServerRoot</A>.
+
+<P>
+
+<EM>SECURITY:</EM> When specifying where to write log files, be aware
+of some security risks which are present if anyone other than the
+user that starts Apache has write access to the directory where they
+are written.  See the <A HREF="misc/security_tips.html">security
+tips</A> document for details.
+
+<P>
+
+<H2>File Handle/Resource Limits:</H2>
+When using a large number of Virtual Hosts, Apache may run out of available
+file descriptors if each Virtual Host specifies different log files.
+The total number of file descriptors used by Apache is one for each distinct
+error log file, one for every other log file directive, plus 10-20 for
+internal use. Unix operating systems limit the number of file descriptors that
+may be used by a process; the limit is typically 64, and may usually be
+increased up to a large hard-limit.
+<p>
+Although Apache attempts to increase the limit as required, this 
+may not work if:
+<ol>
+<li>Your system does not provide the setrlimit() system call.
+<li>The setrlimit(RLIMIT_NOFILE) call does not function on your system
+ (such as Solaris 2.3)
+<li>The number of file descriptors required exceeds the hard limit.
+<li>Your system imposes other limits on file descriptors, such as a limit
+on stdio streams only using file descriptors below 256. (Solaris 2)
+</ol>
+
+In the event of problems you can:
+<ul>
+<li>Reduce the number of log files; don't specify log files in the VirtualHost
+sections, but only log to the main log files.
+<li>If you system falls into 1 or 2 (above), then increase the file descriptor
+limit before starting Apache, using a script like
+<blockquote><code>
+#!/bin/sh <br>
+ulimit -S -n 100 <br>
+exec httpd</code></blockquote>
+</ul>
+
+The have been reports that Apache may start running out of resources allocated
+for the root process. This will exhibit itself as errors in the error log like
+"unable to fork". There are two ways you can bump this up:
+
+<OL> 
+<LI>Have a <code>csh</code> script wrapper around httpd which sets the
+"rlimit" to some large number, like 512.  
+<LI>Edit http_main.c to add calls to setrlimit() from main(), along the lines of
+<PRE>
+       struct rlimit rlp;
+
+       rlp.rlim_cur = rlp.rlim_max = 512;
+        if (setrlimit(RLIMIT_NPROC, &rlp)) {
+            fprintf(stderr, "setrlimit(RLIMIT_NPROC) failed.\n");
+            exit(1);
+        }
+</PRE>
+(thanks to "Aaron Gifford &lt;agifford@InfoWest.COM&gt;" for the patch)
+</OL>
+
+The latter will probably manifest itself in a later version of Apache.
+
+<!--#include virtual="footer.html" -->
+</body></html>
+
diff --git a/APACHE_1_2_X/icons/README b/APACHE_1_2_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/APACHE_1_2_X/icons/a.gif b/APACHE_1_2_X/icons/a.gif
new file mode 100644 (file)
index 0000000..bb23d97
Binary files /dev/null and b/APACHE_1_2_X/icons/a.gif differ
diff --git a/APACHE_1_2_X/icons/alert.black.gif b/APACHE_1_2_X/icons/alert.black.gif
new file mode 100644 (file)
index 0000000..eaecd21
Binary files /dev/null and b/APACHE_1_2_X/icons/alert.black.gif differ
diff --git a/APACHE_1_2_X/icons/alert.red.gif b/APACHE_1_2_X/icons/alert.red.gif
new file mode 100644 (file)
index 0000000..a423894
Binary files /dev/null and b/APACHE_1_2_X/icons/alert.red.gif differ
diff --git a/APACHE_1_2_X/icons/apache_pb.gif b/APACHE_1_2_X/icons/apache_pb.gif
new file mode 100644 (file)
index 0000000..3a1c139
Binary files /dev/null and b/APACHE_1_2_X/icons/apache_pb.gif differ
diff --git a/APACHE_1_2_X/icons/back.gif b/APACHE_1_2_X/icons/back.gif
new file mode 100644 (file)
index 0000000..a694ae1
Binary files /dev/null and b/APACHE_1_2_X/icons/back.gif differ
diff --git a/APACHE_1_2_X/icons/ball.gray.gif b/APACHE_1_2_X/icons/ball.gray.gif
new file mode 100644 (file)
index 0000000..eb84268
Binary files /dev/null and b/APACHE_1_2_X/icons/ball.gray.gif differ
diff --git a/APACHE_1_2_X/icons/ball.red.gif b/APACHE_1_2_X/icons/ball.red.gif
new file mode 100644 (file)
index 0000000..a8425cb
Binary files /dev/null and b/APACHE_1_2_X/icons/ball.red.gif differ
diff --git a/APACHE_1_2_X/icons/binary.gif b/APACHE_1_2_X/icons/binary.gif
new file mode 100644 (file)
index 0000000..9a15cba
Binary files /dev/null and b/APACHE_1_2_X/icons/binary.gif differ
diff --git a/APACHE_1_2_X/icons/binhex.gif b/APACHE_1_2_X/icons/binhex.gif
new file mode 100644 (file)
index 0000000..62d0363
Binary files /dev/null and b/APACHE_1_2_X/icons/binhex.gif differ
diff --git a/APACHE_1_2_X/icons/blank.gif b/APACHE_1_2_X/icons/blank.gif
new file mode 100644 (file)
index 0000000..0ccf01e
Binary files /dev/null and b/APACHE_1_2_X/icons/blank.gif differ
diff --git a/APACHE_1_2_X/icons/bomb.gif b/APACHE_1_2_X/icons/bomb.gif
new file mode 100644 (file)
index 0000000..270fdb1
Binary files /dev/null and b/APACHE_1_2_X/icons/bomb.gif differ
diff --git a/APACHE_1_2_X/icons/box1.gif b/APACHE_1_2_X/icons/box1.gif
new file mode 100644 (file)
index 0000000..65dcd00
Binary files /dev/null and b/APACHE_1_2_X/icons/box1.gif differ
diff --git a/APACHE_1_2_X/icons/box2.gif b/APACHE_1_2_X/icons/box2.gif
new file mode 100644 (file)
index 0000000..c43bc4f
Binary files /dev/null and b/APACHE_1_2_X/icons/box2.gif differ
diff --git a/APACHE_1_2_X/icons/broken.gif b/APACHE_1_2_X/icons/broken.gif
new file mode 100644 (file)
index 0000000..9f8cbe9
Binary files /dev/null and b/APACHE_1_2_X/icons/broken.gif differ
diff --git a/APACHE_1_2_X/icons/burst.gif b/APACHE_1_2_X/icons/burst.gif
new file mode 100644 (file)
index 0000000..fbdcf57
Binary files /dev/null and b/APACHE_1_2_X/icons/burst.gif differ
diff --git a/APACHE_1_2_X/icons/c.gif b/APACHE_1_2_X/icons/c.gif
new file mode 100644 (file)
index 0000000..7555b6c
Binary files /dev/null and b/APACHE_1_2_X/icons/c.gif differ
diff --git a/APACHE_1_2_X/icons/comp.blue.gif b/APACHE_1_2_X/icons/comp.blue.gif
new file mode 100644 (file)
index 0000000..f8d76a8
Binary files /dev/null and b/APACHE_1_2_X/icons/comp.blue.gif differ
diff --git a/APACHE_1_2_X/icons/comp.gray.gif b/APACHE_1_2_X/icons/comp.gray.gif
new file mode 100644 (file)
index 0000000..7664cd0
Binary files /dev/null and b/APACHE_1_2_X/icons/comp.gray.gif differ
diff --git a/APACHE_1_2_X/icons/compressed.gif b/APACHE_1_2_X/icons/compressed.gif
new file mode 100644 (file)
index 0000000..39e7327
Binary files /dev/null and b/APACHE_1_2_X/icons/compressed.gif differ
diff --git a/APACHE_1_2_X/icons/continued.gif b/APACHE_1_2_X/icons/continued.gif
new file mode 100644 (file)
index 0000000..b0ffb7e
Binary files /dev/null and b/APACHE_1_2_X/icons/continued.gif differ
diff --git a/APACHE_1_2_X/icons/dir.gif b/APACHE_1_2_X/icons/dir.gif
new file mode 100644 (file)
index 0000000..4826460
Binary files /dev/null and b/APACHE_1_2_X/icons/dir.gif differ
diff --git a/APACHE_1_2_X/icons/down.gif b/APACHE_1_2_X/icons/down.gif
new file mode 100644 (file)
index 0000000..a354c87
Binary files /dev/null and b/APACHE_1_2_X/icons/down.gif differ
diff --git a/APACHE_1_2_X/icons/dvi.gif b/APACHE_1_2_X/icons/dvi.gif
new file mode 100644 (file)
index 0000000..791be33
Binary files /dev/null and b/APACHE_1_2_X/icons/dvi.gif differ
diff --git a/APACHE_1_2_X/icons/f.gif b/APACHE_1_2_X/icons/f.gif
new file mode 100644 (file)
index 0000000..fbe353c
Binary files /dev/null and b/APACHE_1_2_X/icons/f.gif differ
diff --git a/APACHE_1_2_X/icons/folder.gif b/APACHE_1_2_X/icons/folder.gif
new file mode 100644 (file)
index 0000000..4826460
Binary files /dev/null and b/APACHE_1_2_X/icons/folder.gif differ
diff --git a/APACHE_1_2_X/icons/folder.open.gif b/APACHE_1_2_X/icons/folder.open.gif
new file mode 100644 (file)
index 0000000..30979cb
Binary files /dev/null and b/APACHE_1_2_X/icons/folder.open.gif differ
diff --git a/APACHE_1_2_X/icons/folder.sec.gif b/APACHE_1_2_X/icons/folder.sec.gif
new file mode 100644 (file)
index 0000000..75332d9
Binary files /dev/null and b/APACHE_1_2_X/icons/folder.sec.gif differ
diff --git a/APACHE_1_2_X/icons/forward.gif b/APACHE_1_2_X/icons/forward.gif
new file mode 100644 (file)
index 0000000..b2959b4
Binary files /dev/null and b/APACHE_1_2_X/icons/forward.gif differ
diff --git a/APACHE_1_2_X/icons/generic.gif b/APACHE_1_2_X/icons/generic.gif
new file mode 100644 (file)
index 0000000..de60b29
Binary files /dev/null and b/APACHE_1_2_X/icons/generic.gif differ
diff --git a/APACHE_1_2_X/icons/generic.red.gif b/APACHE_1_2_X/icons/generic.red.gif
new file mode 100644 (file)
index 0000000..9474398
Binary files /dev/null and b/APACHE_1_2_X/icons/generic.red.gif differ
diff --git a/APACHE_1_2_X/icons/generic.sec.gif b/APACHE_1_2_X/icons/generic.sec.gif
new file mode 100644 (file)
index 0000000..88d5240
Binary files /dev/null and b/APACHE_1_2_X/icons/generic.sec.gif differ
diff --git a/APACHE_1_2_X/icons/hand.right.gif b/APACHE_1_2_X/icons/hand.right.gif
new file mode 100644 (file)
index 0000000..5cdbc72
Binary files /dev/null and b/APACHE_1_2_X/icons/hand.right.gif differ
diff --git a/APACHE_1_2_X/icons/hand.up.gif b/APACHE_1_2_X/icons/hand.up.gif
new file mode 100644 (file)
index 0000000..85a5d68
Binary files /dev/null and b/APACHE_1_2_X/icons/hand.up.gif differ
diff --git a/APACHE_1_2_X/icons/icon.sheet.gif b/APACHE_1_2_X/icons/icon.sheet.gif
new file mode 100644 (file)
index 0000000..ad1686e
Binary files /dev/null and b/APACHE_1_2_X/icons/icon.sheet.gif differ
diff --git a/APACHE_1_2_X/icons/image1.gif b/APACHE_1_2_X/icons/image1.gif
new file mode 100644 (file)
index 0000000..01e442b
Binary files /dev/null and b/APACHE_1_2_X/icons/image1.gif differ
diff --git a/APACHE_1_2_X/icons/image2.gif b/APACHE_1_2_X/icons/image2.gif
new file mode 100644 (file)
index 0000000..751faee
Binary files /dev/null and b/APACHE_1_2_X/icons/image2.gif differ
diff --git a/APACHE_1_2_X/icons/image3.gif b/APACHE_1_2_X/icons/image3.gif
new file mode 100644 (file)
index 0000000..4f30484
Binary files /dev/null and b/APACHE_1_2_X/icons/image3.gif differ
diff --git a/APACHE_1_2_X/icons/index.gif b/APACHE_1_2_X/icons/index.gif
new file mode 100644 (file)
index 0000000..162478f
Binary files /dev/null and b/APACHE_1_2_X/icons/index.gif differ
diff --git a/APACHE_1_2_X/icons/layout.gif b/APACHE_1_2_X/icons/layout.gif
new file mode 100644 (file)
index 0000000..c96338a
Binary files /dev/null and b/APACHE_1_2_X/icons/layout.gif differ
diff --git a/APACHE_1_2_X/icons/left.gif b/APACHE_1_2_X/icons/left.gif
new file mode 100644 (file)
index 0000000..279e671
Binary files /dev/null and b/APACHE_1_2_X/icons/left.gif differ
diff --git a/APACHE_1_2_X/icons/link.gif b/APACHE_1_2_X/icons/link.gif
new file mode 100644 (file)
index 0000000..c5b6889
Binary files /dev/null and b/APACHE_1_2_X/icons/link.gif differ
diff --git a/APACHE_1_2_X/icons/movie.gif b/APACHE_1_2_X/icons/movie.gif
new file mode 100644 (file)
index 0000000..0035183
Binary files /dev/null and b/APACHE_1_2_X/icons/movie.gif differ
diff --git a/APACHE_1_2_X/icons/p.gif b/APACHE_1_2_X/icons/p.gif
new file mode 100644 (file)
index 0000000..7b917b4
Binary files /dev/null and b/APACHE_1_2_X/icons/p.gif differ
diff --git a/APACHE_1_2_X/icons/patch.gif b/APACHE_1_2_X/icons/patch.gif
new file mode 100644 (file)
index 0000000..39bc90e
Binary files /dev/null and b/APACHE_1_2_X/icons/patch.gif differ
diff --git a/APACHE_1_2_X/icons/pdf.gif b/APACHE_1_2_X/icons/pdf.gif
new file mode 100644 (file)
index 0000000..c88fd77
Binary files /dev/null and b/APACHE_1_2_X/icons/pdf.gif differ
diff --git a/APACHE_1_2_X/icons/pie0.gif b/APACHE_1_2_X/icons/pie0.gif
new file mode 100644 (file)
index 0000000..6f7a0ae
Binary files /dev/null and b/APACHE_1_2_X/icons/pie0.gif differ
diff --git a/APACHE_1_2_X/icons/pie1.gif b/APACHE_1_2_X/icons/pie1.gif
new file mode 100644 (file)
index 0000000..03aa6be
Binary files /dev/null and b/APACHE_1_2_X/icons/pie1.gif differ
diff --git a/APACHE_1_2_X/icons/pie2.gif b/APACHE_1_2_X/icons/pie2.gif
new file mode 100644 (file)
index 0000000..b04c5e0
Binary files /dev/null and b/APACHE_1_2_X/icons/pie2.gif differ
diff --git a/APACHE_1_2_X/icons/pie3.gif b/APACHE_1_2_X/icons/pie3.gif
new file mode 100644 (file)
index 0000000..4db9d02
Binary files /dev/null and b/APACHE_1_2_X/icons/pie3.gif differ
diff --git a/APACHE_1_2_X/icons/pie4.gif b/APACHE_1_2_X/icons/pie4.gif
new file mode 100644 (file)
index 0000000..93471fd
Binary files /dev/null and b/APACHE_1_2_X/icons/pie4.gif differ
diff --git a/APACHE_1_2_X/icons/pie5.gif b/APACHE_1_2_X/icons/pie5.gif
new file mode 100644 (file)
index 0000000..57aee93
Binary files /dev/null and b/APACHE_1_2_X/icons/pie5.gif differ
diff --git a/APACHE_1_2_X/icons/pie6.gif b/APACHE_1_2_X/icons/pie6.gif
new file mode 100644 (file)
index 0000000..0dc327b
Binary files /dev/null and b/APACHE_1_2_X/icons/pie6.gif differ
diff --git a/APACHE_1_2_X/icons/pie7.gif b/APACHE_1_2_X/icons/pie7.gif
new file mode 100644 (file)
index 0000000..8661337
Binary files /dev/null and b/APACHE_1_2_X/icons/pie7.gif differ
diff --git a/APACHE_1_2_X/icons/pie8.gif b/APACHE_1_2_X/icons/pie8.gif
new file mode 100644 (file)
index 0000000..59ddb34
Binary files /dev/null and b/APACHE_1_2_X/icons/pie8.gif differ
diff --git a/APACHE_1_2_X/icons/portal.gif b/APACHE_1_2_X/icons/portal.gif
new file mode 100644 (file)
index 0000000..0e6e506
Binary files /dev/null and b/APACHE_1_2_X/icons/portal.gif differ
diff --git a/APACHE_1_2_X/icons/ps.gif b/APACHE_1_2_X/icons/ps.gif
new file mode 100644 (file)
index 0000000..0f565bc
Binary files /dev/null and b/APACHE_1_2_X/icons/ps.gif differ
diff --git a/APACHE_1_2_X/icons/quill.gif b/APACHE_1_2_X/icons/quill.gif
new file mode 100644 (file)
index 0000000..818a5cd
Binary files /dev/null and b/APACHE_1_2_X/icons/quill.gif differ
diff --git a/APACHE_1_2_X/icons/right.gif b/APACHE_1_2_X/icons/right.gif
new file mode 100644 (file)
index 0000000..b256e5f
Binary files /dev/null and b/APACHE_1_2_X/icons/right.gif differ
diff --git a/APACHE_1_2_X/icons/screw1.gif b/APACHE_1_2_X/icons/screw1.gif
new file mode 100644 (file)
index 0000000..af6ba2b
Binary files /dev/null and b/APACHE_1_2_X/icons/screw1.gif differ
diff --git a/APACHE_1_2_X/icons/screw2.gif b/APACHE_1_2_X/icons/screw2.gif
new file mode 100644 (file)
index 0000000..06dccb3
Binary files /dev/null and b/APACHE_1_2_X/icons/screw2.gif differ
diff --git a/APACHE_1_2_X/icons/script.gif b/APACHE_1_2_X/icons/script.gif
new file mode 100644 (file)
index 0000000..d8a853b
Binary files /dev/null and b/APACHE_1_2_X/icons/script.gif differ
diff --git a/APACHE_1_2_X/icons/sound1.gif b/APACHE_1_2_X/icons/sound1.gif
new file mode 100644 (file)
index 0000000..8efb49f
Binary files /dev/null and b/APACHE_1_2_X/icons/sound1.gif differ
diff --git a/APACHE_1_2_X/icons/sound2.gif b/APACHE_1_2_X/icons/sound2.gif
new file mode 100644 (file)
index 0000000..48e6a7f
Binary files /dev/null and b/APACHE_1_2_X/icons/sound2.gif differ
diff --git a/APACHE_1_2_X/icons/sphere1.gif b/APACHE_1_2_X/icons/sphere1.gif
new file mode 100644 (file)
index 0000000..7067070
Binary files /dev/null and b/APACHE_1_2_X/icons/sphere1.gif differ
diff --git a/APACHE_1_2_X/icons/sphere2.gif b/APACHE_1_2_X/icons/sphere2.gif
new file mode 100644 (file)
index 0000000..a9e462a
Binary files /dev/null and b/APACHE_1_2_X/icons/sphere2.gif differ
diff --git a/APACHE_1_2_X/icons/tar.gif b/APACHE_1_2_X/icons/tar.gif
new file mode 100644 (file)
index 0000000..4032c1b
Binary files /dev/null and b/APACHE_1_2_X/icons/tar.gif differ
diff --git a/APACHE_1_2_X/icons/tex.gif b/APACHE_1_2_X/icons/tex.gif
new file mode 100644 (file)
index 0000000..45e4323
Binary files /dev/null and b/APACHE_1_2_X/icons/tex.gif differ
diff --git a/APACHE_1_2_X/icons/text.gif b/APACHE_1_2_X/icons/text.gif
new file mode 100644 (file)
index 0000000..4c62390
Binary files /dev/null and b/APACHE_1_2_X/icons/text.gif differ
diff --git a/APACHE_1_2_X/icons/transfer.gif b/APACHE_1_2_X/icons/transfer.gif
new file mode 100644 (file)
index 0000000..33697db
Binary files /dev/null and b/APACHE_1_2_X/icons/transfer.gif differ
diff --git a/APACHE_1_2_X/icons/unknown.gif b/APACHE_1_2_X/icons/unknown.gif
new file mode 100644 (file)
index 0000000..32b1ea2
Binary files /dev/null and b/APACHE_1_2_X/icons/unknown.gif differ
diff --git a/APACHE_1_2_X/icons/up.gif b/APACHE_1_2_X/icons/up.gif
new file mode 100644 (file)
index 0000000..6d6d6d1
Binary files /dev/null and b/APACHE_1_2_X/icons/up.gif differ
diff --git a/APACHE_1_2_X/icons/uu.gif b/APACHE_1_2_X/icons/uu.gif
new file mode 100644 (file)
index 0000000..4387d52
Binary files /dev/null and b/APACHE_1_2_X/icons/uu.gif differ
diff --git a/APACHE_1_2_X/icons/uuencoded.gif b/APACHE_1_2_X/icons/uuencoded.gif
new file mode 100644 (file)
index 0000000..4387d52
Binary files /dev/null and b/APACHE_1_2_X/icons/uuencoded.gif differ
diff --git a/APACHE_1_2_X/icons/world1.gif b/APACHE_1_2_X/icons/world1.gif
new file mode 100644 (file)
index 0000000..05b4ec2
Binary files /dev/null and b/APACHE_1_2_X/icons/world1.gif differ
diff --git a/APACHE_1_2_X/icons/world2.gif b/APACHE_1_2_X/icons/world2.gif
new file mode 100644 (file)
index 0000000..e3203f7
Binary files /dev/null and b/APACHE_1_2_X/icons/world2.gif differ
diff --git a/APACHE_1_2_X/src/.cvsignore b/APACHE_1_2_X/src/.cvsignore
new file mode 100644 (file)
index 0000000..1cc54bc
--- /dev/null
@@ -0,0 +1,5 @@
+Configuration
+Makefile
+modules.c
+httpd
+Makefile.config
diff --git a/APACHE_1_2_X/src/.indent.pro b/APACHE_1_2_X/src/.indent.pro
new file mode 100644 (file)
index 0000000..77b65f3
--- /dev/null
@@ -0,0 +1 @@
+-i4 -npsl -di0 -br -nce -d0 -cli0 -npcs
diff --git a/APACHE_1_2_X/src/CHANGES b/APACHE_1_2_X/src/CHANGES
new file mode 100644 (file)
index 0000000..5bddf6a
--- /dev/null
@@ -0,0 +1,1794 @@
+Changes with Apache 1.2
+
+Changes with Apache 1.2b11
+
+  *) Fixed open timestamp fd in proxy_cache.c [Chuck Murcko]
+
+  *) Added undocumented perl SSI mechanism for -DUSE_PERL_SSI and mod_perl.
+     [Rob Hartill]
+
+  *) Proxy needs to use hard_timeout instead of soft_timeout when it is
+     reading from one buffer and writing to another, at least until it has
+     a custom timeout handler.  [Roy Fielding and Petr Lampa]
+
+  *) Fixed problem on Irix with servers hanging in IdentityCheck,
+     apparently due to a mismatch between sigaction and setjmp.
+     [Roy Fielding] PR#502
+
+  *) Log correct status code if we timeout before receiving a request (408)
+     or if we received a request-line that was too long to process (414).
+     [Ed Korthof and Roy Fielding] PR#601
+
+  *) Virtual hosts with the same ServerName, but on different ports, were
+     not being selected properly.  [Ed Korthof]
+
+  *) Added code to return the requested IP address from proxy_host2addr()
+     if gethostbyaddr() fails due to reverse DNS lookup problems. Original
+     change submitted by Jozsef Hollosi <hollosi@sbcm.com>.
+     [Chuck Murcko] PR#614
+
+  *) If multiple requests on a single connection are used to retrieve
+     data from different virtual hosts, the virtual host list would be
+     scanned starting with the most recently used VH instead of the first,
+     causing most virtual hosts to be ignored.
+     [Paul Sutton and Martin Mares] PR#610
+
+  *) The OS/2 handling of process group was broken by a porting patch for
+     MPE, so restored prior code for OS/2.  [Roy Fielding and Garey Smiley]
+
+  *) Inherit virtual server port from main server if none (or "*") is
+     given for VirtualHost.  [Dean Gaudet] PR#576
+
+  *) If the lookup for a DirectoryIndex name with content negotiation
+     has found matching variants, but none are acceptable, return the
+     negotiation result if there are no more DirectoryIndex names to lookup.
+     [Petr Lampa and Roy Fielding]
+
+  *) If a soft_timeout occurs after keepalive is set, then the main child
+     loop would try to read another request even though the connection
+     has been aborted.  [Roy Fielding]
+
+  *) Configure changes: Allow for whitespace at the start of a
+     Module declaration. Also, be more understanding about the
+     CC=/OPTIM= format in Configuration. Finally, fix compiler
+     flags if using HP-UX's cc compiler. [Jim Jagielski]
+
+  *) Subrequests and internal redirects now inherit the_request from the
+     original request-line. [Roy Fielding]
+
+  *) Test for error conditions before creating output header fields, since
+     we don't want the error message to include those fields.  Likewise,
+     reset the content_language(s) and content_encoding of the response
+     before generating or redirecting to an error message, since the new
+     message will have its own Content-* definitions. [Dean Gaudet]
+
+  *) Restored the semantics of headers_out (headers sent only with 200..299
+     and 304 responses) and err_headers_out (headers sent with all responses).
+     Avoid the overhead of copying tables if err_headers_out is empty
+     (the usual case).  [Roy Fielding]
+
+  *) Fixed a couple places where a check for the default Content-Type was
+     not properly checking both the value configured by the DefaultType
+     directive and the DEFAULT_TYPE symbol in httpd.h.  Changed the value
+     of DEFAULT_TYPE to match the documented default (text/plain).
+     [Dean Gaudet] PR#506
+
+  *) Escape the HTML-sensitive characters in the Request-URI that is
+     output for each child by mod_status. [Dean Gaudet and Ken Coar] PR#501
+
+  *) Properly initialize the flock structures used by the mutex locking
+     around accept() when USE_FCNTL_SERIALIZED_ACCEPT is defined.
+     [Marc Slemko]
+
+  *) The method for determining PATH_INFO has been restored to the pre-1.2b
+     (and NCSA httpd) definition wherein it was the extra path info beyond
+     the CGI script filename.  The environment variable FILEPATH_INFO has
+     been removed, and instead we supply the original REQUEST_URI to any
+     script that wants to be Apache-specific and needs the real URI path.
+     This solves a problem with existing scripts that use extra path info
+     in the ScriptAlias directive to pass options to the CGI script.
+     [Roy Fielding]
+
+  *) The _default_ change in 1.2b10 will change the behaviour on configs
+     that use multiple Listen statements for listening on multiple ports.
+     But that change is necessary to make _default_ consistent with other
+     forms of <VirtualHost>.  It requires such configs to be modified
+     to use <VirtualHost _default_:*>.  The documentation has been
+     updated.  [Dean Gaudet] PR#530
+
+  *) If an ErrorDocument CGI script is used to respond to an error
+     generated by another CGI script which has already read the message
+     body of the request, the server would block trying to read the
+     message body again.  [Rob Hartill]
+
+  *) signal() replacement conflicted with a define on QNX (and potentially
+     other platforms). Fixed. [Ben Laurie] PR#512
+
+Changes with Apache 1.2b10
+
+  *) Allow HTTPD_ROOT, SERVER_CONFIG_FILE, DEFAULT_PATH, and SHELL_PATH
+     to be configured via -D in Configuration.  [Dean Gaudet] PR#449
+
+  *) <VirtualHost _default_:portnum> didn't work properly.  [Dean Gaudet]
+
+  *) Added prototype for mktemp() for SUNOS4 [Marc Slemko]
+
+  *) In mod_proxy.c, check return values for proxy_host2addr() when reading
+     config, in case the hostent struct returned is trash.
+     [Chuck Murcko] PR #491
+
+  *) Fixed the fix in 1.2b9 for parsing URL query info into args for CGI
+     scripts.  [Dean Gaudet, Roy Fielding, Marc Slemko]
+
+Changes with Apache 1.2b9  [never announced]
+
+  *) Reset the MODULE_MAGIC_NUMBER to account for the unsigned port
+     changes and in anticipation of 1.2 final release.  [Roy Fielding]
+
+  *) Fix problem with scripts not receiving a SIGPIPE when client drops
+     the connection (e.g., when user presses Stop).  Apache will now stop
+     trying to send a message body immediately after an error from write.
+     [Roy Fielding and Nathan Kurz] PR#335
+
+  *) Rearrange Configuration.tmpl so that mod_rewrite has higher priority
+     than mod_alias, and mod_alias has higher priority than mod_proxy;
+     rearranged other modules to enhance understanding of their purpose
+     and relative order (and maybe even reduce some overhead).
+     [Roy Fielding and Sameer Parekh]
+
+  *) Fix graceful restart.  Eliminate many signal-related race
+     conditions in both forms of restart, and in SIGTERM.  See
+     htdocs/manual/stopping.html for details on stopping and
+     restarting the parent.  [Dean Gaudet]
+
+  *) Fix memory leaks in mod_rewrite, mod_browser, mod_include.  Tune
+     memory allocator to avoid a behaviour that required extra blocks to
+     be allocated.  [Dean Gaudet]
+
+  *) Allow suexec to access files relative to current directory but not
+     above.  (Excluding leading / or any .. directory.)  [Ken Coar]
+     PR#269, 319, 395
+
+  *) Fix suexec segfault when group doesn't exist. [Gregory Neil Shapiro]
+     PR#367, 368, 354, 453
+
+  *) Fix the above fix: if suexec is enabled, avoid destroying r->url
+     while obtaining the /~user and save the username in a separate data
+     area so that it won't be overwritten by the call to getgrgid(), and
+     fix some misuse of the pool string allocation functions.  Also fixes
+     a general problem with parsing URL query info into args for CGI scripts.
+     [Roy Fielding] PR#339, 367, 354, 453
+
+  *) Fix IRIX warning about bzero undefined. [Marc Slemko]
+
+  *) Fix problem with <Directory proxy:...>. [Martin Kraemer] PR#271
+
+  *) Corrected spelling of "authoritative".  AuthDBAuthoratative became
+     AuthDBAuthoritative. [Marc Slemko] PR#420
+
+  *) MaxClients should be at least 1. [Lars Eilebrecht] PR#375
+
+  *) The default handler now logs invalid methods or URIs (i.e. PUT on an
+     object that can't be PUT, or FOOBAR for some method FOOBAR that
+     apache doesn't know about at all).  Log 404s that occur in mod_include.
+     [Paul Sutton, John Van Essen]
+
+  *) If a soft timeout (or lingerout) occurs while trying to flush a
+     buffer or write inside buff.c or fread'ing from a CGI's output,
+     then the timeout would be ignored. [Roy Fielding] PR#373
+
+  *) Work around a bug in Netscape Navigator versions 2.x, 3.x and 4.0b2's
+     parsing of headers.  If the terminating empty-line CRLF occurs starting
+     at the 256th or 257th byte of output, then Navigator will think a normal
+     image is invalid.  We are guessing that this is because their initial
+     read of a new request uses a 256 byte buffer. We check the bytes written
+     so far and, if we are about to tickle the bug, we instead insert a
+     padding header of eminent bogosity. [Roy Fielding and Dean Gaudet] PR#232
+
+  *) Fixed SIGSEGV problem when a DirectoryIndex file is also the source
+     of an external redirection.  [Roy Fielding and Paul Sutton]
+
+  *) Configure would create a broken Makefile if the configuration file
+     contained a commented-out Rule.  [Roy Fielding]
+
+  *) Promote per_dir_config and subprocess_env from the subrequest to the
+     main request in mod_negotiation.  In particular this fixes a bug
+     where <Files> sections wouldn't properly apply to negotiated content.
+     [Dean Gaudet]
+
+  *) Fix a potential deadlock in mod_cgi script_err handling.
+     [Ralf S. Engelschall]
+
+  *) rotatelogs zero-pads the logfile names to improve alphabetic sorting.
+     [Mitchell Blank Jr]
+
+  *) Updated mod_rewrite to 3.0.4: Fixes HTTP redirects from within
+     .htaccess files because the RewriteBase was not replaced correctly.
+     Updated mod_rewrite to 3.0.5: Fixes problem with rewriting inside
+     <Directory> sections missing a trailing /.  [Ralf S. Engelschall]
+
+  *) Clean up Linux settings in conf.h by detecting 2.x versus 1.x.  For
+     1.x the settings are those of pre-1.2b8.  For 2.x we include
+     HAVE_SHMGET (scoreboard in shared memory rather than file) and
+     HAVE_SYS_RESOURCE_H (enable the RLimit commands).
+     [Dean Gaudet] PR#336, PR#340
+
+  *) Redirect did not preserve ?query_strings when present in the client's
+     request.  [Dean Gaudet]
+
+  *) Configure was finding non-modules on EXTRA_LIBS. [Frank Cringle] PR#380
+
+  *) Use /bin/sh5 on ultrix.  [P. Alejandro Lopez-Valencia] PR#369
+
+  *) Add UnixWare compile/install instructions.  [Chuck Murcko]
+
+  *) Add mod_example (illustration of API techniques).  [Ken Coar]
+
+  *) Add macro for memmove to conf.h for SUNOS4. [Marc Slemko]
+
+  *) Improve handling of directories when filenames have spaces in them.
+     [Chuck Murcko]
+
+  *) For hosts with multiple IP addresses, try all additional addresses if
+     necessary to get a connect. Fail only if hostent address list is
+     exhausted. [Chuck Murcko]
+
+  *) More signed/unsigned port fixes.  [Dean Gaudet]
+
+  *) HARD_SERVER_LIMIT can be defined in the Configuration file now.
+     [Dean Gaudet]
+
+Changes with Apache 1.2b8
+
+  *) suexec.c doesn't close the log file, allowing CGIs to continue writing
+     to it.  [Marc Slemko]
+
+  *) The addition of <Location> and <File> directives made the
+     sub_req_lookup_simple() function bogus, so we now handle
+     the special cases directly.  [Dean Gaudet]
+
+  *) We now try to log where the server is dumping core when a fatal
+     signal is received.  [Ken Coar]
+
+  *) Improved lingering_close by adding a special timeout, removing the
+     spurious log messages, removing the nonblocking settings (they
+     are not needed with the better timeout), and adding commentary
+     about the NO_LINGCLOSE and USE_SO_LINGER issues.  NO_LINGCLOSE is
+     now the default for SunOS4, Unixware, NeXT, and Irix.  [Roy Fielding]
+
+  *) Send error messages about setsockopt failures to the server error
+     log instead of stderr.  [Roy Fielding]
+
+  *) Fix loopholes in proxy cache expiry vis a vis alarms. [Brian Moore]
+
+  *) Stopgap solution for CGI 3-second delay with server-side includes: if
+     processing a subrequest, allocate memory from r->main->pool instead
+     of r->pool so that we can avoid waiting for free_proc_chain to cleanup
+     in the middle of an SSI request.  [Dean Gaudet] PR #122
+
+  *) Fixed status of response when POST is received for a nonexistant URL
+     (was sending 405, now 404) and when any method is sent with a
+     full-URI that doesn't match the server and the server is not acting
+     as a proxy (was sending 501, now 403).  [Roy Fielding]
+
+  *) Host port changed to unsigned short. [Ken Coar] PR #276
+
+  *) Fix typo in command definition of AuthAuthoritative. [Ken Coar] PR #246
+
+  *) Defined HAVE_SHMGET for shared memory on Linux.  [Dean Gaudet]
+
+  *) Report extra info from errno with many errors that cause httpd to exit.
+     spawn_child, popenf, and pclosef now have valid errno returns in the
+     event of an error.  Correct problems where errno was stomped on
+     before being reported.  [Dean Gaudet]
+
+  *) In the proxy, if the cache filesystem was full, garbage_coll() was
+     never called, and thus the filesystem would remain full indefinitely.
+     We now also remove incomplete cache files left if the origin server
+     didn't send a Content-Length header and either the client has aborted
+     transfer or bwrite() to client has failed. [Petr Lampa]
+
+  *) Fixed the handling of module and script-added header fields.
+     Improved the interface for sending header fields and reduced
+     the duplication of code between sending okay responses and errors.
+     We now always send both headers_out and err_headers_out, and
+     ensure that the server-reserved fields are not being overridden,
+     while not overriding those that are not reserved.  [Roy Fielding]
+
+  *) Moved transparent content negotiation fields to err_headers_out
+     to reflect above changes.  [Petr Lampa]
+
+  *) Fixed the determination of whether or not we should make the
+     connection persistent for all of the cases where some other part
+     of the server has already indicated that we should not.  Also
+     improved the ordering of the test so that chunked encoding will
+     be set whenever it is desired instead of only when KeepAlive
+     is enabled. Added persistent connection capability for most error
+     responses (those that do not indicate a bad input stream) when
+     accessed by an HTTP/1.1 client. [Roy Fielding]
+
+  *) Added missing timeouts for sending header fields, error responses,
+     and the last chunk of chunked encoding, each of which could have
+     resulted in a process being stuck in write forever.  Using soft_timeout
+     requires that the sender check for an aborted connection rather than
+     continuing after an EINTR.  Timeouts that used to be initiated before
+     send_http_header (and never killed) are now initiated only within or
+     around the routines that actually do the sending, and not allowed to
+     propagate above the caller.  [Roy Fielding]
+
+  *) mod_auth_anon required an @ or a . in the email address, not both.
+     [Dirk vanGulik]
+
+  *) per_dir_defaults weren't set correctly until directory_walk for
+     name-based vhosts.  This fixes an obscure bug with the wrong config
+     info being used for vhosts that share the same ip as the server.
+     [Dean Gaudet]
+
+  *) Improved generation of modules/Makefile to be more generic for
+     new module directories. [Ken Coar, Chuck Murcko, Roy Fielding]
+
+  *) Generate makefile dependency for Configuration based on the actual
+     name given when running the Configure process.  [Dean Gaudet]
+
+  *) Fixed problem with vhost error log not being set prior to
+     initializing virtual hosts. [Dean Gaudet]
+
+  *) Fixed infinite loop when a trailing slash is included after a type map
+     file URL (extra path info). [Petr Lampa]
+
+  *) Fixed server status updating of per-connection counters. [Roy Fielding]
+
+  *) Add documentation for DNS issues (reliability and security), and try
+     to explain the virtual host matching process.  [Dean Gaudet]
+
+  *) Try to continue gracefully by disabling the vhost if a DNS lookup
+     fails while parsing the configuration file.  [Dean Gaudet]
+
+  *) Improved calls to setsockopt.  [Roy Fielding]
+
+  *) Negotiation changes: Don't output empty content-type in variant list;
+     Output charset in variant list; Return sooner from handle_multi() if
+     no variants found; Add handling of '*' wildcard in Accept-Charset.
+     [Petr Lampa and Paul Sutton]
+
+  *) Fixed overlaying of request/sub-request notes and headers in
+     mod_negotiation.  [Dean Gaudet]
+
+  *) If two variants' charset quality are equal and one is the default
+     charset (iso-8859-1), then prefer the variant that was specifically
+     listed in Accept-Charset instead of the default.  [Petr Lampa]
+
+  *) Memory allocation problem in push_array() -- it would corrupt memory
+     when nalloc==0.  [Kai Risku <krisku@tf.hut.fi> and Roy Fielding]
+
+  *) invoke_handler() doesn't handle mime arguments in content-type
+     [Petr Lampa] PR#160
+
+  *) Reduced IdentityCheck timeout to 30 seconds, as per RFC 1413 minimum.
+     [Ken Coar]
+
+  *) Fixed problem with ErrorDocument not working for virtual hosts
+     due to one of the performance changes in 1.2b7. [Dean Gaudet]
+
+  *) Log an error message if we get a request header that is too long,
+     since it may indicate a buffer overflow attack. [Marc Slemko]
+
+  *) Made is_url() allow "[-.+a-zA-Z0-9]+:" as a valid scheme and
+     not reject URLs without a double-slash, as per RFC2068 section 3.2.
+     [Ken Coar] PR #146, #187
+
+  *) Added table entry placeholder for new header_parser callback
+     in all of the distributed modules. [Ken Coar] PR #191
+
+  *) Allow for cgi files without the .EXE extension on them under OS/2.
+     [Garey Smiley] PR #59
+
+  *) Fixed error message when resource is not found and URL contains
+     path info. [Petr Lampa and Dean Gaudet] PR #40
+
+  *) Fixed user and server confusion over what should be a virtual host
+     and what is the main server, resulting in access to something
+     other than the name defined in the virtualhost directive (but
+     with the same IP address) failing. [Dean Gaudet]
+
+  *) Updated mod_rewrite to version 3.0.2, which: fixes compile error on
+     AIX; improves the redirection stuff to enable the users to generally
+     redirect to http, https, gopher and ftp; added TIME variable for
+     RewriteCond which expands to YYYYMMDDHHMMSS strings and added the
+     special patterns >STRING, <STRING and =STRING to RewriteCond, which
+     can be used in conjunction with %{TIME} or other variables to create
+     time-dependent rewriting rules. [Ralf S. Engelschall]
+
+  *) bpushfd() no longer notes cleanups for the file descriptors it is handed.
+     Module authors may need to adjust their code for proper cleanup to take
+     place (that is, call note_cleanups_for_fd()). This change fixes problems
+     with file descriptors being erroneously closed when the proxy module was
+     in use. [Ben Laurie]
+
+  *) Fix bug in suexec reintroduced by changes in 1.2b7 which allows
+     initgroups() to hose the group information needed for later
+     comparisons. [Randy Terbush]
+
+  *) Remove unnecessary call to va_end() in create_argv() which
+     caused a SEGV on some systems.
+
+  *) Use proper MAXHOSTNAMELEN symbol for limiting length of server name.
+     [Dean Gaudet]
+
+  *) Clear memory allocated for listeners. [Randy Terbush]
+
+  *) Improved handling of IP address as a virtualhost address and
+     introduced "_default_" as a synonym for the default vhost config.
+     [Dean Gaudet] PR #212
+
+Changes with Apache 1.2b7
+
+  *) Port to  UXP/DS(V20) [Toshiaki Nomura <nom@yk.fujitsu.co.jp>]
+
+  *) unset Content-Length if chunked (RFC-2068) [Petr Lampa]
+
+  *) mod_negotiation fixes [Petr Lampa] PR#157, PR#158, PR#159
+     - replace protocol response numbers with symbols
+     - save variant-list into main request notes
+     - free allocated memory from subrequests
+     - merge notes, headers_out and err_headers_out
+
+  *) changed status check mask in proxy_http.c from "HTTP/#.# ### *" to
+     "HTTP/#.# ###*" to be more lenient about what we accept.
+     [Chuck Murcko]
+
+  *) more proxy FTP bug fixes:
+     - Changed send_dir() to remove user/passwd from displayed URL.
+     - Changed login error messages to be more descriptive.
+     - remove setting of SO_DEBUG socket option
+     - Make ftp_getrc() more lenient about multiline responses,
+       specifically, 230 responses which don't have continuation 230-
+       on each line). These seem to be all NT FTP servers, and while
+       perhaps questionable, they appear to be legal by RFC 959.
+     - Add missing kill_timeout() after transfer to user completes.
+     [Chuck Murcko]
+
+  *) Fixed problem where a busy server could hang when restarting
+     after being sent a SIGHUP due to child processes not exiting.
+     [Marc Slemko]
+
+  *) Modify mod_include escaping so a '\' only signifies an escaped
+     character if the next character is one that needs
+     escaping.  [Ben Laurie]
+
+  *) Eliminated possible infinite loop in mod_imap when relative URLs are
+     used with a 'base' directive that does not have a '/' in it.
+     [Marc Slemko, reported by Onno Witvliet <onno@tc.hsa.nl>]
+
+  *) Reduced the default timeout from 1200 seconds to 300, and the
+     one in the sample configfile from 400 to 300.  [Marc Slemko]
+
+  *) Stop vbprintf from crashing if given a NULL string pointer;
+     print (null) instead.  [Ken Coar]
+
+  *) Don't disable Nagle algorithm if system doesn't have TCP_NODELAY.
+     [Marc Slemko and Roy Fielding]
+
+  *) Fixed problem with mod_cgi-generated internal redirects trying to
+     read the request message-body twice. [Archie Cobbs and Roy Fielding]
+
+  *) Reduced timeout on lingering close, removed possibility of a blocked
+     read causing the child to hang, and stopped logging of errors if
+     the socket is not connected (reset by client).  [Roy Fielding]
+
+  *) Rearranged main child loop to remove duplication of code in
+     select/accept and keep-alive requests, fixed several bugs regarding
+     checking scoreboard_image for exit indication and failure to
+     account for all success conditions and trap all error conditions,
+     prevented multiple flushes before closing the socket; close the entire
+     socket buffer instead of just one descriptor, prevent logging of
+     EPROTO and ECONNABORTED on platforms where supported, and generally
+     improved readability.  [Roy Fielding]
+
+  *) Extensive performance improvements. Cleaned up inefficient use of
+     auto initializers, multiple is_matchexp calls on a static string,
+     and excessive merging of response_code_strings. [Dean Gaudet]
+
+  *) Added double-buffering to mod_include to improve performance on
+     server-side includes. [Marc Slemko]
+
+  *) Several fixes for suexec wrapper. [Randy Terbush]
+     - Make wrapper work for files on NFS filesystem.
+     - Fix portability problem of MAXPATHLEN.
+     - Fix array overrun problem in clean_env().
+     - Fix allocation of PATH environment variable
+
+  *) Removed extraneous blank line is description of mod_status chars.
+     [Kurt Kohler]
+
+  *) Logging of errors from the call_exec routine simply went nowhere,
+     since the logfile fd has been closed, so now we send them to stderr.
+     [Harald T. Alvestrand]
+
+  *) Fixed core dump when DocumentRoot is a CGI.
+     [Ben Laurie, reported by geddis@tesserae.com]
+
+  *) Fixed potential file descriptor leak in mod_asis; updated it and
+     http_core to use pfopen/pfclose instead of fopen/fclose.
+     [Randy Terbush and Roy Fielding]
+
+  *) Fixed handling of unsigned ints in ap_snprintf() on some chips such
+     as the DEC Alpha which is 64-bit but uses 32-bit ints.
+     [Dean Gaudet and Ken Coar]
+
+  *) Return a 302 response code to the client when sending a redirect
+     due to a missing trailing '/' on a directory instead of a 301; now
+     it is cacheable. [Markus Gyger]
+
+  *) Fix condition where, if a bad directive occurs in .htaccess, and
+     sub_request() goes first to this directory, then log_reason() will
+     SIGSEGV because it doesn't have initialized r->per_dir_config.
+     [PR#162 from Petr Lampa, fix by Marc Slemko and Dean Gaudet]
+
+  *) Fix handling of lang_index in is_variant_better().  This was
+     causing problems which resulted in the server sending the
+     wrong language document in some cases. [Petr Lampa]
+
+  *) Remove free() from clean_env() in suexec wrapper. This was nuking
+     the clean environment on some systems.
+
+  *) Tweak byteserving code (e.g. serving PDF files) to work around
+     bugs in Netscape Navigator and Microsoft Internet Explorer.
+     Emit Content-Length header when sending multipart/byteranges.
+     [Alexei Kosut]
+
+  *) Port to HI-UX/WE2. [Nick Maclaren]
+
+  *) Port to HP MPE operating system for HP 3000 machines
+     [Mark Bixby <markb@cccd.edu>]
+
+  *) Fixed bug which caused a segmentation fault if only one argument
+     given to RLimit* directives. [Ed Korthof]
+
+  *) Continue persistent connection after 204 or 304 response. [Dean Gaudet]
+
+  *) Improved buffered output to the client by delaying the flush decision
+     until the BUFF code is actually about to read the next request.
+     This fixes a problem introduced in 1.2b5 with clients that send
+     an extra CRLF after a POST request. Also improved chunked output
+     performance by combining writes using writev() and removing as
+     many bflush() calls as possible.  NOTE: Platforms without writev()
+     must add -DNO_WRITEV to the compiler CFLAGS, either in Configuration
+     or Configure, unless we have already done so.  [Dean Gaudet]
+
+  *) Fixed mod_rewrite bug which truncated the rewritten URL [Marc Slemko]
+
+  *) Fixed mod_info output corruption bug introduced by buffer overflow
+     fixes. [Dean Gaudet]
+
+  *) Fixed http_protocol to correctly output all HTTP/1.1 headers, including
+     for the special case of a 304 response.  [Paul Sutton]
+
+  *) Improved handling of TRACE method by bypassing normal method handling
+     and header parsing routines; fixed Allow response to always allow TRACE.
+     [Dean Gaudet]
+
+  *) Fixed compiler warnings in the regex library. [Dean Gaudet]
+
+  *) Cleaned-up some of the generated HTML. [Ken Coar]
+
+Changes with Apache 1.2b6
+
+  *) Allow whitespace in imagemap mapfile coordinates. [Marc Slemko]
+
+  *) Fix typo introduced in fix for potential infinite loop around
+     accept() in child_main(). This change caused the rev to 1.2b6.
+     1.2b5 was never a public beta.
+
+Changes with Apache 1.2b5
+
+  *) Change KeepAlive semantics (On|Off instead of a number), add
+     MaxKeepAliveRequests directive. [Alexei Kosut]
+
+  *) Various NeXT compilation patches, as well as a change in
+     regex/regcomp.c since that file also used a NEXT define.
+     [Andreas Koenig]
+
+  *) Allow * to terminate the end of a directory match in mod_dir.
+     Allows /~* to match for both /~joe and /~joe/. [David Bronder]
+
+  *) Don't call can_exec() if suexec_enabled. Calling this requires
+     scripts executed by the suexec wrapper to be world executable, which
+     defeats one of the advantages of running the wrapper. [Randy Terbush]
+
+  *) Portability Fix: IRIX complained with 'make clean' about *pure* (removed)
+     [Jim Jagielski]
+
+  *) Migration from sprintf() to snprintf() to avoid buffer
+     overflows. [Marc Slemko]
+
+  *) Provide portable snprintf() implementation (ap_snprintf)
+     as well as *cvt family. [Jim Jagielski]
+
+  *) Portability Fix: NeXT lacks unistd.h so we wrap it's inclusion
+     [Jim Jagielski]
+
+  *) Remove mod_fastcgi.c from the distribution. This module appears
+     to be maintained more through the Open Market channels and should
+     continue to be easily available at http://www.fastcgi.com/
+
+  *) Fixed bug in modules/Makefile that wouldn't allow building in more
+     than one subdirectory (or cleaning, either). [Jeremy Laidman]
+
+  *) mod_info assumed that the config files were relative to ServerRoot.
+     [Ken the Rodent]
+
+  *) CGI scripts called as an error document resulting from failed
+     CGI execution would hang waiting for POST'ed data. [Rob Hartill]
+
+  *) Log reason when mod_dir returns access HTTP_FORBIDDEN
+     [Ken the Rodent]
+
+  *) Properly check errno to prevent display of a directory index
+     when server receives a long enough URL to confuse stat().
+     [Marc Slemko]
+
+  *) Several security enhancements to suexec wrapper. It is _highly_
+     recommended that previously installed versions of the wrapper
+     be replaced with this version.  [Randy Terbush, Jason Dour]
+
+       - ~user execution now properly restricted to ~user's home
+         directory and below.
+       - execution restricted to UID/GID > 100
+       - restrict passed environment to known variables
+       - call setgid() before initgroups() (portability fix)
+       - remove use of setenv() (portability fix)
+
+  *) Add HTTP/1.0 response forcing. [Ben Laurie]
+
+  *) Add access control via environment variables. [Ben Laurie]
+
+  *) Add rflush() function. [Alexei Kosut]
+
+  *) remove duplicate pcalloc() call in new_connection().
+
+  *) Fix incorrect comparison which could allow number of children =
+     MaxClients + 1 if less than HARD_SERVER_LIMIT. Also fix potential
+     problem if StartServers > HARD_SERVER_LIMIT. [Ed Korthof]
+
+  *) Updated support for OSes (MachTen, ULTRIX, Paragon, ISC, OpenBSD
+     AIX PS/2, CONVEXOS. [Jim Jagielski]
+
+  *) Replace instances of inet_ntoa() with inet_addr() for ProxyBlock.
+     It's more portable. [Martin Kraemer]
+
+  *) Replace references to make in Makefile.tmpl with $(MAKE).
+     [Chuck Murcko]
+
+  *) Add ProxyBlock directive w/IP address caching. Add IP address
+     caching to NoCache directive as well. ProxyBlock works with all
+     handlers; NoCache now also works with FTP for anonymous logins.
+     Still more code cleanup. [Chuck Murcko]
+
+  *) Add "header parse" API hook [Ben Laurie]
+
+  *) Fix byte ordering problems for REMOTE_PORT [Chuck Murcko]
+
+  *) suEXEC wrapper was freeing memory that had not been malloc'ed.
+
+  *) Correctly allow access and auth directives in <Files> sections in
+     server config files. [Alexei Kosut]
+
+  *) Fix bug with ServerPath that could cause certain files to be not
+     found by the server. [Alexei Kosut]
+
+  *) Fix handling of ErrorDocument so that it doesn't remove a trailing
+     double-quote from text and so that it properly checks for unsupported
+     status codes using the new index_of_response interface. [Roy Fielding]
+
+  *) Multiple fixes to the lingering_close code in order to avoid being
+     interrupted by a stray timeout, to avoid lingering on a connection
+     that has already been aborted or never really existed, to ensure that
+     we stop lingering as soon as any error condition is received, and to
+     prevent being stuck indefinitely if the read blocks.  Also improves
+     reporting of error conditions.  [Marc Slemko and Roy Fielding]
+
+  *) Fixed initialization of parameter structure for sigaction.
+     [mgyger@itr.ch, Adrian Filipi-Martin]
+
+  *) Fixed reinitializing the parameters before each call to accept and
+     select, and removed potential for infinite loop in accept.
+     [Roy Fielding, after useful PR from adrian@virginia.edu]
+
+  *) Fixed condition where, if a child fails to fork, the scoreboard would
+     continue to say SERVER_STARTING forever. Eventually, the main process
+     would refuse to start new children because count_idle_servers() will
+     count those SERVER_STARTING entries and will always report that there
+     are enough idle servers. [Phillip Vandry]
+
+  *) Fixed bug in bcwrite regarding failure to account for partial writes.
+     Avoided calling bflush() when the client is pipelining requests.
+     Removed unnecessary flushes from http_protocol. [Dean Gaudet]
+
+  *) Added description of "." mode in server-status [Jim Jagielski]
+
+
+Changes with Apache 1.2b4:
+
+  *) Fix possible race condition in accept_mutex_init() that
+     could leave a small security hole open allowing files to be
+     overwritten in cases where the server UID has write permissions.
+     [Marc Slemko]
+
+  *) Fix awk compatibilty problem in Configure. [Jim Jagielski]
+
+  *) Fix portablity problem in util_script where ARG_MAX may not be
+     defined for some systems.
+
+  *) Add changes to allow compilation on Machten 4.0.3 for PowerPC.
+     [Randal Schwartz]
+
+  *) OS/2 changes to support an MMAP style scoreboard file and UNIX
+     style magic #! token for better script portability. [Garey Smiley]
+
+  *) Fix bug in suexec wrapper introduced in b3 that would cause failed
+     execution for ~userdir CGI. [Jason Dour]
+
+  *) Fix initgroups() business in suexec wrapper. [Jason Dour]
+
+  *) Fix month off by one in suexec wrapper logging.
+
+Changes with Apache 1.2b3:
+
+  *) Fix error in mod_cgi which could cause resources not to be properly
+     freed, or worse. [Dean Gaudet]
+
+  *) Fix find_string() NULL pointer dereference. [Howard Fear]
+
+  *) Add set_flag_slot() at the request of Dirk and others.
+     [Dirk vanGulik]
+
+  *) Sync mod_rewrite with patch level 10. [Ralf Engelschall]
+
+  *) Add changes to improve the error message given for invalid
+     ServerName parameters. [Dirk vanGulik]
+
+  *) Add "Authoritative" directive for Auth modules that don't
+     currently have it. This gives admin control to assign authoritative
+     control to an authentication scheme and allow "fall through" for
+     those authentication modules that aren't "Authoritative" thereby
+     allowing multiple authentication mechanisms to be chained.
+     [Dirk vanGulik]
+
+  *) Remove requirement for ResourceConfig/AccessConfig if not using
+     the three config file layout. [Randy Terbush]
+
+  *) Add PASV mode to mod_proxy FTP handler. [Chuck Murcko]
+
+  *) Changes to suexec wrapper to fix the following problems:
+     1.  symlinked homedirs will kill ~userdirs.
+     2.  initgroups() on Linux 2.0.x clobbers gr->grid.
+     3.  CGI command lines paramters problems
+     4.  pw-pwdir for "docroot check" still the httpd user's pw record.
+    [Randy Terbush, Jason Dour]
+
+  *) Change create_argv() to accept variable arguments. This fixes
+     a problem where arguments were not getting passed to the CGI via
+     argv[] when the suexec wrapper was active. [Randy Terbush, Jake Buchholz]
+
+  *) Collapse multiple slashes in path URLs to properly apply
+     handlers defined by <Location>. [Alexei Kosut]
+
+  *) Define a sane set of DEFAULT_USER and DEFAULT_GROUP values for AIX.
+
+  *) Improve the accuracy of request duration timings by setting
+     r->request_time in read_request_line() instead of read_request().
+     [Dean Gaudet]
+
+  *) Reset timeout while reading via get_client_block() in mod_cgi.c
+     Fixes problem with timed out transfers of large files. [Rasmus Lerdorf]
+
+  *) Add the ability to pass different Makefile.tmpl files to Configure
+     using the -make flag. [Rob Hartill]
+
+  *) Fix coredump triggered when sending a SIGHUP to the server caused
+     by an assertion failure, in turn caused by an uninitialised field in a
+     listen_rec.
+     [Ben Laurie]
+
+  *) Add FILEPATH_INFO variable to CGI environment, which is equal to
+     PATH_INFO from previous versions of Apache (in certain situations,
+     Apache 1.2's PATH_INFO will be different than 1.1's). [Alexei Kosut]
+     [later removed in 1.2b11]
+
+  *) Add rwrite() function to API to allow for sending strings of
+     arbitrary length. [Doug MacEachern]
+
+  *) Remove rlim_t typedef for NetBSD. Do older versions need this?
+
+  *) Defined rlim_t and WANTHSREGEX=yes and fixed waitpid() substitute for
+     NeXT. [Jim Jagielski]
+
+  *) Removed recent modification to promote the status code on internal
+     redirects, since the correct fix was to change the default log format
+     in mod_log_config so that it outputs the original status. [Rob Hartill]
+
+Changes with Apache 1.2b2:
+
+  *) Update set_signals() to use sigaction() for setting handlers.
+     This appears to fix a re-entrant problem in the seg_fault()
+     bus_error() handlers. [Randy Terbush]
+
+  *) Changes to allow mod_status compile for OS/2 [Garey Smiley]
+
+  *) changes for DEC AXP running OSF/1 v3.0. [Marc Evans]
+
+  *) proxy_http.c bugfixes:  [Chuck Murcko]
+        1) fixes possible NULL pointer reference w/NoCache
+        2) fixes NoCache behavior when using ProxyRemote (ProxyRemote
+           host would cache nothing if it was in the local domain,
+           and the local domain was in the NoCache list)
+        3) Adds Host: header when not available
+        4) Some code cleanup and clarification
+
+  *) mod_include.c bugfixes:
+       1) Fixed an ommission that caused include variables to not
+          be parsed in config errmsg directives [Howard Fear]
+       2) Remove HAVE_POSIX_REGEX cruft [Alexei Kosut]
+       3) Patch to fix compiler warnings [perrot@lal.in2p3.fr]
+       4) Allow backslash-escaping to all quoted text
+          [Ben Yoshino <ben@wiliki.eng.hawaii.edu>]
+       5) Pass variable to command line if not set in XSSI's env
+          [Howard Fear]
+
+  *) Fix infinite loop when processing Content-language lines in
+     type-map files. [Alexei Kosut]
+
+  *) Closed file-globbing hole in test-cgi script. [Brian Behlendorf]
+
+  *) Fixed problem in set_[user|group] that prevented CGI execution
+     for non-virtualhosts when suEXEC was enabled. [Randy Terbush]
+
+  *) Added PORTING information file.  [Jim Jagielski]
+
+  *) Added definitions for S_IWGRP and S_IWOTH to conf.h [Ben Laurie]
+
+  *) Changed default group to "nogroup" instead of "nobody" [Randy Terbush]
+
+  *) Fixed define typo of FCNTL_SERIALIZED_ACCEPT where
+     USE_FCNTL_SERIALIZED_ACCEPT was intended.
+
+  *) Fixed additional uses of 0xffffffff where INADDR_NONE was intended,
+     which caused problems of systems where socket s_addr is >32bits.
+
+  *) Added comment to explain (r->chunked = 1) side-effect in
+     http_protocol.c [Roy Fielding]
+
+  *) Replaced use of index() in mod_expires.c with more appropriate
+     and portable isdigit() test.  [Ben Laurie]
+
+  *) Updated Configure for ...
+       OS/2          (DEF_WANTHSREGEX=yes, other code changes)
+        *-dg-dgux*    (bad pattern match)
+        QNX           (DEF_WANTHSREGEX=yes)
+        *-sunos4*     (DEF_WANTHSREGEX=yes, -DUSEBCOPY)
+        *-ultrix      (new)
+       *-unixware211 (new)
+     and added some user diagnostic info.  [Ben Laurie]
+
+  *) In helpers/CutRule, replaced "cut" invocation with "awk" invocation
+     for better portability. [Jim Jagielski]
+
+  *) Updated helpers/GuessOS for ...
+        SCO 5            (recognize minor releases)
+        SCO Unixware     (braindamaged uname, whatever-whatever-unixware2)
+       SCO UnixWare 2.1.1      (requires a separate set of #defines in conf.h)
+        IRIX64           (-sgi-irix64)
+        ULTRIX           (-unknown-ultrix)
+        SINIX            (-whatever-sysv4)
+        NCR Unix         (-ncr-sysv4)
+     and fixed something in helpers/PrintPath  [Ben Laurie]
+
+Changes with Apache 1.2b1:
+
+  *) Not listed. See <http://www.apache.org/docs/new_features_1_2.html>
+
+Changes with Apache 1.1.1:
+
+  *) Fixed bug where Cookie module would make two entries in the
+     logfile for each access [Mark Cox]
+
+  *) Fixed bug where Redirect in .htaccess files would cause memory
+     leak. [Nathan Neulinger]
+
+  *) MultiViews now works correctly with AddHandler [Alexei Kosut]
+
+  *) Problems with mod_auth_msql fixed [Dirk vanGulik]
+
+  *) Fix misspelling of "Anonymous_Authorative" directive in mod_auth_anon.
+
+Changes with Apache 1.1.0:
+
+  *) 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-cased to not merge multiple
+     instances, since certain popular browsers can not handle multiple
+     Set-Cookie instructions in a single header. [Paul Sutton]
+
+  *) 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:
+
+  *) Not listed. See <http://www.apache.org/docs/new_features_1_1.html>
+
+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 [Sameer 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 license. [David Robinson]
+
+Changes with Apache 1.0.0
+
+  *) Not listed. See <http://www.apache.org/docs/new_features_1_0.html>
+
+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 negotiation 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]
+
+  *) Clarified 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-compatibility, as the old
+     NCSA code did not check Options ExecCGI in ScriptAlias 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-compatibility.  (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-compatibility).  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 independent 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]                  10 Apr 1995
+
+  *) 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 ;-).
+
+Changes with 0.4                                          02 Apr 1995
+
+  *) Patches by Brian Behlendorf, Andrew Wilson, Robert Thau,
+     and Rob Hartill.
+
+Changes with 0.3                                          24 Mar 1995
+
+  *) Patches by Robert Thau, David Robinson, Rob Hartill, and
+     Carlos Varela
+
+Changes with 0.2                                          18 Mar 1995
+
+  *) Based on NCSA httpd 1.3 by Rob McCool and patches by CERT,
+     Roy Fielding, Robert Thau, Nicolas Pioch, David Robinson,
+     Brian Behlendorf, Rob Hartill, and Cliff Skolnick
diff --git a/APACHE_1_2_X/src/Configuration.tmpl b/APACHE_1_2_X/src/Configuration.tmpl
new file mode 100644 (file)
index 0000000..06446d7
--- /dev/null
@@ -0,0 +1,289 @@
+# Config file for the Apache httpd.
+
+# Configuration.tmpl is the template for Configuration. Configuration should
+# be edited to select the modules to be included as well as various flags
+# for Makefile.
+
+# The template should only be changed when a new system or module is added,
+# or an existing one modified. This will also most likely require some minor
+# changes to Configure to recognize those changes.
+
+# There are 5 types of lines here:
+
+# '#' comments, distinguished by having a '#' as the first non-blank character
+#
+# Makefile options, such as CC=gcc, etc...
+#
+# Rules, distinquished by having "Rule" at the front. These are used to
+# control Configure's behavior as far as how to create 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.
+#
+# Optional module selection lines, distinguished by having `%Module'
+# at the front.  These specify a module that is to be compiled in (but
+# not enabled).  The AddModule directive can be used to enable such a
+# module.  By default no such modules are defined.
+
+
+################################################################
+# Makefile configuration
+#
+# These are added to the general flags determined by Configure.
+# Edit these to work around Configure if needed. The EXTRA_* family
+# will be added to the regular Makefile flags. For example, if you
+# want to compile with -Wall, then add that to EXTRA_CFLAGS. These
+# will be added to whatever flags Configure determines as appropriate
+# and needed for your platform.
+#
+# You can also set the compiler and Optimization used here as well.
+# Settings here have priority; If not set, Configure will attempt to guess
+# the C compiler, and set OPTIM to '-O2'
+#
+EXTRA_CFLAGS=
+EXTRA_LFLAGS=
+EXTRA_LIBS=
+EXTRA_INCLUDES=
+
+#CC=
+#OPTIM=-O2
+#RANLIB=
+
+################################################################
+# Rules configuration
+#
+# These are used to let Configure know that we want certain
+# functions. The format is: Rule RULE=value
+#
+# At present, only the following RULES are known: WANTHSREGEX, SOCKS4,
+# STATUS, and IRIXNIS.
+#
+# For all Rules, if set to "yes", then Configure knows we want that
+# capability and does what is required to add it in. If set to "default"
+# then Configure makes a "best guess"; if set to anything else, or not
+# present, then nothing is done.
+#
+# SOCKS4:
+#  If SOCKS4 is set to 'yes', be sure that you add the sock library
+#  location to EXTRA_LIBS, otherwise Configure will assume
+#  "-L/usr/local/lib -lsocks"
+#
+# STATUS:
+#  If Configure determines that you are using the status_module,
+#  it will automatically enable full status information if set
+#  to 'yes'. If the status module is not included, having STATUS
+#  set to 'yes' has no impact.
+#
+# IRIXNIS:
+#  Only takes effect if Configure determines that you are running
+#  SGI IRIX. If you are, and you are using NIS, you should set this
+#  to 'yes'
+#
+
+Rule STATUS=yes
+Rule SOCKS4=no
+Rule IRIXNIS=no
+
+# The following rules should be set automatically by Configure. However, if
+# they are not set by Configure (because we don't know the correct value for
+# your platform), or are set incorrectly, you may override them here.
+# If you have to do this, please let us know what you set and what your
+# platform is, by filling out a problem report form at the Apache web site:
+# <http://www.apache.org/bugdb.cgi>.  If your browser is forms-incapable,
+# you can get the information to us by sending mail to apache-bugs@apache.org.
+#
+# WANTHSREGEX:
+#  Apache requires a POSIX regex implementation. Henry Spencer's
+#  excellent regex package is included with Apache and can be used
+#  if desired. If your OS has a decent regex, you can elect to
+#  not use this one by setting WANTHSREGEX to 'no' or commenting
+#  out the Rule. The "default" action is "no" unless overruled
+#  by OS specifics
+
+Rule WANTHSREGEX=default
+
+################################################################
+# 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.
+
+##
+## Config manipulation modules
+##
+## mod_env sets up additional or restricted environment variables to be
+## passed to CGI/SSI scripts.  It is listed first (lowest priority) since
+## it does not do per-request stuff.
+
+Module env_module          mod_env.o
+
+## mod_dld defines commands that allow other modules to be loaded
+## dynamically (at runtime).  This module is for experimental use only.
+
+# Module dld_module          mod_dld.o
+
+##
+## Request logging modules
+##
+
+Module config_log_module   mod_log_config.o
+
+## Optional modules for NCSA user-agent/referer logging compatibility
+## We recommend, however, that you just use the configurable access_log.
+
+# Module agent_log_module    mod_log_agent.o
+# Module referer_log_module  mod_log_referer.o
+
+##
+## Type checking modules
+##
+## mod_mime maps filename extensions to content types, encodings, and
+## magic type handlers (the latter is obsoleted by mod_actions).
+## mod_negotiation allows content selection based on the Accept* headers.
+
+Module mime_module         mod_mime.o
+Module negotiation_module  mod_negotiation.o
+
+##
+## Content delivery modules
+##
+## The status module allows the server to display current details about 
+## how well it is performing and what it is doing.  Consider also enabling 
+## STATUS=yes (see the Rules section near the start of this 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
+
+## mod_include translates server-side include (SSI) statements in text files.
+## mod_dir handles requests on directories and directory indexes.
+## mod_cgi handles CGI scripts.
+
+Module includes_module     mod_include.o
+Module dir_module          mod_dir.o
+Module cgi_module          mod_cgi.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
+
+##
+## URL translation modules.
+##
+## The UserDir module for selecting resource directories by user name
+## and a common prefix, e.g., /~<user> , /usr/web/<user> , etc.
+
+Module userdir_module      mod_userdir.o
+
+## The proxy module enables the server to act as a proxy for outside
+## http and ftp services. It's not as complete as it could be yet.
+## NOTE: You do not want this module UNLESS you are running a proxy;
+##       it is not needed for normal (origin server) operation.
+
+# Module proxy_module        modules/proxy/libproxy.a
+
+## The Alias module provides simple URL translation and redirection.
+
+Module alias_module        mod_alias.o
+
+## mod_rewrite allows for powerful URI-to-URI and URI-to-filename mapping,
+## using regular expressions.
+
+# Module rewrite_module      mod_rewrite.o
+
+##
+## Access control and authentication modules. 
+##
+Module access_module       mod_access.o
+Module auth_module         mod_auth.o
+
+## 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 and possibly adjust EXTRA_LIBS. (This may be
+## done by Configure at a later date)
+
+# 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 EXTRA_LIBS line, like
+##
+##  -lmsql -L/usr/local/lib -L/usr/local/Minerva/lib
+##
+## This depends on your installation of mSQL. (This may be done by Configure
+## at a later date)
+
+# 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
+
+## Optional response header manipulation modules. 
+##
+## cern_meta mimics the behavior of the CERN web server with regards to 
+## metainformation files.  
+
+# Module cern_meta_module    mod_cern_meta.o
+
+## The expires module can apply Expires: headers to resources,
+## as a function of access time or modification time.
+
+# Module expires_module      mod_expires.o
+
+## The headers module can set arbitrary HTTP response headers,
+## as configured in server, vhost, access.conf or .htaccess configs
+
+# Module headers_module      mod_headers.o
+
+## Miscellaneous modules
+##
+## mod_usertrack.c is the new name for mod_cookies.c.  This module
+## uses Netscape cookies to automatically construct and log
+## click-trails from Netscape cookies, or compatible clients who
+## aren't coming in via proxy.   
+##
+## You do not need this, or any other module to allow your site
+## to use Cookies.  This module is for user tracking only
+
+# Module usertrack_module      mod_usertrack.o
+
+## The example module, which demonstrates the use of the API.  See
+## the file modules/example/README for details.  This module should
+## only be used for testing -- DO NOT ENABLE IT on a production server.
+
+# Module example_module      modules/example/mod_example.o
+
+## mod_browser lets you set environment variables based on the User-Agent
+## string in the request; this is useful for conditional HTML, for example.
+## Since it is also used to detect buggy browsers for workarounds, it
+## should be the last (highest priority) module.
+
+Module browser_module      mod_browser.o
diff --git a/APACHE_1_2_X/src/Configure b/APACHE_1_2_X/src/Configure
new file mode 100755 (executable)
index 0000000..dc526ab
--- /dev/null
@@ -0,0 +1,645 @@
+#!/bin/sh
+trap 'rm -f $tmpfile; exit' 0 1 2 3 15
+
+# Apache configuration script, first cut --- rst.
+# Dont like it?  Inspired to do something better?  Go for it.
+
+# second cut --- jmj
+# At this point we change what Configuration contains. It maintain
+# contains comments, specific compiler flags, a list of included
+# modules and "rules". These rules are used to allow Configure to
+# be totally configured from Configuration
+#
+# Uses 3 supplemental scripts located in ./helpers: CutRule,
+# GuessOS and PrintPath
+#
+
+file=Configuration
+tmpfile=htconf.$$
+makefile_tmpl=Makefile.tmpl
+
+while [ "x$1" != "x" ]; do
+  if [ "x$1" = "x-file" ] ; then
+    shift 1; file=$1; shift 1
+    if [ ! -r $file ]; then
+      echo "$file does not exist or is not readable."
+      exit 1
+    fi
+  elif [ "x$1" = "x-make" ] ; then
+    shift 1; makefile_tmpl=$1; shift 1
+    if [ ! -r $makefile_tmpl ]; then
+      echo "$makefile_tmpl does not exist or is not readable."
+      exit 1
+    fi
+  else
+    echo "Ignoring command line option '$1'"
+    shift 1
+  fi
+done
+echo "Using config file: $file"
+echo "Using Makefile template file: $makefile_tmpl"
+
+if [ ! -r $file ]; then
+  echo "Can't see or read \"$file\""
+  exit 1
+fi
+
+# First, strip comments and blank lines and then change Rules to comments
+# and then remove whitespace before Module declarations
+
+sed 's/#.*//' $file | \
+ sed '/^[      ]*$/d' | \
+ sed 's/[      ]*$//' | \
+ sed 's/^Rule[         ]*/##Rule:/' | \
+ sed 's/^[     ]*Module/Module/' | \
+ sed 's/^[        ]*%Module/%Module/' > $tmpfile
+
+# Check for syntax errors...
+
+if egrep -v '^%?Module[        ]+[A-Za-z0-9_]+[        ]+[^    ]+$' $tmpfile \
+   | grep -v = > /dev/null
+then
+   echo "Syntax error --- The configuration file is used only to"
+   echo "define the list of included modules or to set Makefile"
+   echo "options or Configure rules, and I don't see that at all:"
+   egrep -v '^Module[  ]+[A-Za-z0-9_]+[        ]+[^    ]+$' $tmpfile | \
+     grep -v =
+   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
+
+sed -e 's/_module//' $tmpfile | awk >modules.c '\
+   BEGIN { modules[n++] = "core" ; pmodules[pn++] = "core"} \
+   /^Module/ { modules[n++] = $2 ; pmodules[pn++] = $2 } \
+   /^%Module/ { pmodules[pn++] = $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 < pn; ++i) { \
+            printf ("extern module %s_module;\n", pmodules[i]); \
+        } \
+        print ""; \
+        print "module *prelinked_modules[] = {"; \
+        for (i = 0; i < n; ++i) { \
+            printf "  &%s_module,\n", modules[i]; \
+        } \
+        print "  NULL"; \
+        print "};"; \
+        print "module *preloaded_modules[] = {"; \
+        for (i = 0; i < pn; ++i) { \
+            printf "  &%s_module,\n", pmodules[i]; \
+        } \
+        print "  NULL"; \
+        print "};"; \
+   }'
+
+#
+# Add module set only
+#
+echo "#" > Makefile
+echo "# Makefile automatically generated from $makefile_tmpl" >> Makefile
+echo "# and configuration file by Apache config script." >> Makefile
+echo "# Hand-edited changes will be lost if the config script" >> Makefile
+echo "# is re-run" >> Makefile
+echo "#" >> Makefile
+
+awk >>Makefile <$tmpfile '\
+   /^Module/ { modules[n++] = $3 } \
+   /^%Module/ { modules[n++] = $3 } \
+   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 "" \
+       }'
+#
+# Now add Makefile additions and Rules
+#
+awk >>Makefile <$tmpfile '\
+    BEGIN { print "# Makefile options inherited from Configure"; \
+           print "###############"; \
+         } \
+    /\=/ { print } \
+    END { print "###############"; }'
+
+#
+# Extract the rules.
+#
+RULE_WANTHSREGEX=`./helpers/CutRule WANTHSREGEX $file`
+RULE_STATUS=`./helpers/CutRule STATUS $file`
+RULE_SOCKS4=`./helpers/CutRule SOCKS4 $file`
+RULE_IRIXNIS=`./helpers/CutRule IRIXNIS $file`
+
+#
+# Now we determine the OS/Platform automagically, thanks to
+# GuessOS, a home-brewed OS-determiner ala config.guess
+#
+# We adjust CFLAGS, LIBS, LFLAGS and INCLUDES (and other Makefile
+# options) as required. Setting CC and OPTIM here has no effect
+# if they were set in Configure.
+#
+# Also, we set DEF_WANTHSREGEX and to the appropriate
+# value for each platform.
+#
+# As more PLATFORMs are added to Configuration.tmpl, be sure to
+# add the required lines below.
+#
+
+PLAT=`./helpers/GuessOS`
+
+# Preset DBM_LIB. Can be overridden on a per-platform basis.
+
+DBM_LIB="-ldbm"
+
+#
+# Look for ranlib. Do it early in case we want to override it below
+#
+if ./helpers/PrintPath -s ranlib; then
+    RANLIB="ranlib"
+else
+    RANLIB="true"
+fi
+
+#
+# We now look for popular compilers. As with ranlib, we
+# do this early because some options may depend
+# on which compiler we use/find
+#
+for compilers in "gcc" "cc" "acc" "c89"
+do
+    lookedfor="$lookedfor $compilers"
+    if ./helpers/PrintPath -s $compilers; then
+       COMPILER="$compilers"
+       break
+    fi
+done
+
+#
+SHELL="/bin/sh"
+
+case "$PLAT" in
+    *MPE/iX*)
+        OS='MPE/iX'
+       CFLAGS="$CFLAGS -DMPE -D_POSIX_SOURCE -D_SOCKET_SOURCE"
+       LIBS="$LIBS -lsocket"
+       LFLAGS="$LFLAGS -Xlinker \"-WL,cap=ia,ba,ph,pm;nmstack=1024000\""
+       ;;
+    *-apple-aux3*)
+       OS='A/UX 3.1.x'
+       CFLAGS="$CFLAGS -DAUX -D_POSIX_SOURCE"
+       LIBS="$LIBS -lposix -lbsd"
+       LFLAGS="$LFLAGS -s"
+       DEF_WANTHSREGEX=no
+       ;;
+    i386-ibm-aix*)
+       OS='IBM AIX PS/2'
+       CFLAGS="$CFLAGS -DAIX -U__STR__ -DUSEBCOPY"
+       DEF_WANTHSREGEX=no
+       ;;
+    *-ibm-aix*)
+       OS='IBM AIX'
+       CFLAGS="$CFLAGS -DAIX -U__STR__"
+       ;;
+    *-apollo-*)
+       OS='Apollo Domain'
+       CFLAGS="$CFLAGS -DAPOLLO"
+       ;;
+    *-dg-dgux*)
+       OS='DG/UX 5.4'
+       CFLAGS="$CFLAGS -DDGUX"
+       DEF_WANTHSREGEX=yes
+       ;;
+    *OS/2*)
+       DEF_WANTHSREGEX=yes
+       OS='EMX OS/2'
+       CFLAGS="$CFLAGS -Zbsd-signals -Zbin-files -DTCPIPV4 -g"
+       LIBS="$LIBS -lsocket -llibufc -lbsd"
+       DBM_LIB="-lgdbm"
+       ;;
+    *-hi-hiux)
+       OS='HI-UX'
+       CFLAGS="$CFLAGS -DHIUX"
+       # if we're using the HIUX compiler, add a few flags.
+       if [ "$CC" = "cc" ] || [ "$COMPILER" = "cc" ]; then
+           CFLAGS="$CFLAGS -Aa -D_HIUX_SOURCE"
+           OPTIM=" "
+       fi
+       ;;
+    *-hp-hpux10.*)
+       OS='HP-UX 10'
+       CFLAGS="$CFLAGS -DHPUX10"
+       # if we're using the HPUX compiler, add a few flags.
+       if [ "$CC" = "cc" ] || [ "$COMPILER" = "cc" ]; then
+           CFLAGS="$CFLAGS -Aa -D_HPUX_SOURCE"
+           OPTIM=" "
+       fi
+       ;;
+    *-hp-hpux*)
+       OS='HP-UX'
+       CFLAGS="$CFLAGS -DHPUX"
+       if [ "$CC" = "cc" ] || [ "$COMPILER" = "cc" ]; then
+           CFLAGS="$CFLAGS -Aa -D_HPUX_SOURCE"
+           OPTIM=" "
+       fi
+       ;;
+    *-sgi-irix64)
+# Note: We'd like to see patches to compile 64-bit, but for now...
+       echo "You are running 64-bit Irix. For now, we will compile 32-bit"
+       echo "but if you would care to port to 64-bit, send us the patches."
+       CFLAGS="$CFLAGS -n32"
+       LFLAGS="$LFLAGS -n32"
+       DEF_WANTHSREGEX=yes
+       DBM_LIB=""
+       if [ "$RULE_IRIXNIS" = "yes" ]; then
+           OS='SGI IRIX w/NIS'
+           CFLAGS="$CFLAGS -DIRIX"
+           LIBS="$LIBS -lsun"
+       else
+           OS='SGI IRIX'
+           CFLAGS="$CFLAGS -DIRIX"
+       fi
+       ;;
+    *-sgi-irix)
+       DEF_WANTHSREGEX=yes
+       DBM_LIB=""
+       if [ "$RULE_IRIXNIS" = "yes" ]; then
+           OS='SGI IRIX w/NIS'
+           CFLAGS="$CFLAGS -DIRIX"
+           LIBS="$LIBS -lsun"
+       else
+           OS='SGI IRIX'
+           CFLAGS="$CFLAGS -DIRIX"
+       fi
+       ;;
+    *-linux2)
+       DEF_WANTHSREGEX=yes
+       OS='Linux'
+       CFLAGS="$CFLAGS -DLINUX=2"
+       ;;
+    *-linux1)
+       DEF_WANTHSREGEX=yes
+       OS='Linux'
+       CFLAGS="$CFLAGS -DLINUX=1"
+       ;;
+    *-lynx-lynxos*)
+       OS='LynxOS'
+       CFLAGS="$CFLAGS -DLYNXOS"
+       LIBS="$LIBS -lbsd -ldes -lc_p"
+       ;;
+    *486-*-bsdi*)
+       OS='BSDI w/486'
+       CFLAGS="$CFLAGS -m486"
+       DBM_LIB=""
+       ;;
+    *-bsdi*)
+       OS='BSDI'
+       DBM_LIB=""
+       ;;
+    *486-*-freebsd*|*486-*-netbsd*)
+       OS='FreeBSD/NETBSD on 486'
+       LIBS="$LIBS -lcrypt"
+       DBM_LIB=""
+       ;;
+    *-freebsd*|*-netbsd*)
+       OS='FreeBSD/NetBSD'
+       LIBS="$LIBS -lcrypt"
+       DBM_LIB=""
+       ;;
+    *-openbsd*)
+       OS='OpenBSD'
+       ;;
+    *-next-nextstep*)
+       OS='NeXT'
+       CFLAGS="$CFLAGS -DNEXT"
+       DEF_WANTHSREGEX=yes
+       RANLIB="sleep 5; /bin/ranlib"
+       # ranlib on most NeXTs sets the time wrong. 5 secs wait does much good
+       ;;
+    *-dec-osf*)
+       OS='DEC OSF/1'
+       CFLAGS="$CFLAGS -DOSF1"
+       LIBS="$LIBS -lm"
+       ;;
+    *-qnx)
+       OS='QNX'
+       CFLAGS="$CFLAGS -DQNX"
+       LIBS="$LIBS -N128k -lsocket"
+       DEF_WANTHSREGEX=yes
+       ;;
+    *-qnx32)
+       OS='QNX32'
+       CFLAGS="$CFLAGS -DQNX -mf -3"
+       LIBS="$LIBS -N128k -lsocket"
+       DEF_WANTHSREGEX=yes
+       ;;
+    *-isc4*)
+       OS='ISC 4'
+       CC='gcc'
+       CFLAGS="$CFLAGS -posix -DISC"
+       LFLAGS="$LFLAGS -posix"
+       LIBS="$LIBS -linet"
+       DEF_WANTHSREGEX=yes
+       ;;
+    *-sco3*)
+       OS='SCO 3'
+       CFLAGS="$CFLAGS -DSCO -Oacgiltz"
+       LIBS="$LIBS -lPW -lsocket -lmalloc -lcrypt_i"
+       DEF_WANTHSREGEX=yes
+       ;;
+    *-sco5*)
+       OS='SCO 5'
+       CFLAGS="$CFLAGS -DSCO5"
+       LIBS="$LIBS -lsocket -lmalloc -lprot"
+       OSBPRINTF="-K noinline"
+       DEF_WANTHSREGEX=no
+       ;;
+    *-solaris2*)
+       OS='Solaris 2'
+       CFLAGS="$CFLAGS -DSOLARIS2"
+       LIBS="$LIBS -lsocket -lnsl"
+       DBM_LIB=""
+       DEF_WANTHSREGEX=yes
+       ;;
+    *-sunos4*)
+       OS='SunOS 4'
+       CFLAGS="$CFLAGS -DSUNOS4 -DUSEBCOPY"
+       DEF_WANTHSREGEX=yes
+       ;;
+    *-unixware1)
+       DEF_WANTHSREGEX=yes
+       OS='Unixware'
+       CFLAGS="$CFLAGS -DSVR4 -DNO_LINGCLOSE"
+       LIBS="$LIBS -lsocket -lnsl -lcrypt"
+       ;;
+    *-unixware2)
+       DEF_WANTHSREGEX=yes
+       OS='Unixware'
+       CFLAGS="$CFLAGS -DSVR4 -DNO_LINGCLOSE"
+       LIBS="$LIBS -lsocket -lnsl -lcrypt"
+       ;;
+    *-unixware211)
+       OS='Unixware 2.1.1'
+       CFLAGS="$CFLAGS -DUW"
+       LIBS="$LIBS -lsocket -lnsl -lcrypt"
+       ;;
+    *-sni-sysv4*)
+       OS='SVR4'
+       CFLAGS="$CFLAGS -DSVR4"
+       DEF_WANTHSREGEX=yes
+       LIBS="$LIBS -lsocket -lnsl -lc"
+       ;;
+    DS/90\ 7000-*-sysv4*)
+       OS='UXP/DS'
+       CFLAGS="$CFLAGS -DUXPDS"
+       LIBS="$LIBS -lsocket -lnsl"
+       DEF_WANTHSREGEX=yes
+       ;;
+    *-sysv4*)
+       OS='SVR4'
+       CFLAGS="$CFLAGS -DSVR4"
+       LIBS="$LIBS -lsocket -lnsl -lc"
+       ;;
+    *-uts*)
+       OS='Amdahl UTS'
+       CFLAGS="$CFLAGS -Xa -eft -DUTS21"
+       LIBS="$LIBS -lsocket -lbsd -la"
+       ;;
+    *-ultrix)
+       OS='ULTRIX'
+       CFLAGS="-DULTRIX"
+       DEF_WANTHSREGEX=yes
+       SHELL="/bin/sh5"
+       ;;
+    *powerpc-tenon-machten*)
+       OS='MachTen PPC'
+       LFLAGS="$LFLAGS -Xlstack=0x14000 -Xldelcsect"
+       ;;
+    *-machten*)
+       OS='MachTen 68K'
+       LFLAGS="$LFLAGS -stack 0x14000"
+       DEF_WANTHSREGEX=yes
+       ;;
+    *convex-v11*)
+       OS='CONVEXOS11'
+       CFLAGS="$CFLAGS -DCONVEXOS11"
+       CC='cc'
+       DEF_WANTHSREGEX=yes
+       ;;
+    i860-intel-osf1)
+       DEF_WANTHSREGEX=yes
+       OS='Paragon OSF/1'
+       CFLAGS="$CFLAGS -DPARAGON"
+       ;;
+    *) # default: Catch systems we don't know about
+       echo Sorry, but we cannot grok \"$PLAT\"
+       echo uname -m
+       uname -m
+       echo uname -r
+       uname -r
+       echo uname -s
+       uname -s
+       echo uname -v
+       uname -v
+       echo uname -X
+       uname -X
+       echo Ideally, read the file PORTING, do what it says, and send the
+       echo resulting patches to The Apache Group by filling out a report
+       echo form at http://www.apache.org/bugdb.cgi - or, if your browser
+       echo isn\'t forms-capable, you can send them via email to 
+       echo apache-bugs@apache.org.  If you don\'t wish to do the port
+       echo yourself, please submit this output rather than the patches.
+       echo Thank you
+       exit 1
+       ;;
+esac
+
+#
+# See if we need to override WANTHSREGEX
+#
+if [ "$RULE_WANTHSREGEX" = "default" ]; then
+       if [ "x$DEF_WANTHSREGEX" = "x" ]; then
+               RULE_WANTHSREGEX=no
+       else
+               RULE_WANTHSREGEX=$DEF_WANTHSREGEX
+       fi
+fi
+
+# Show the final values of the rules
+
+echo "###############" > Makefile.config
+echo "# Platform: $OS" >> Makefile.config
+echo "# Final Rules:" >> Makefile.config
+echo "#  Rule WANTHSREGEX=$RULE_WANTHSREGEX" >> Makefile.config
+echo "###############" >> Makefile.config
+
+#
+# Now that _that's_ done, get on with it
+#
+
+echo " + configured for $OS platform"
+
+#
+# Now we determine the C-compiler and optimization level
+# to use. Settings of CC and OPTIM in Configuration have
+# the highest precedence; next comes any settings from
+# the above "OS-specific" section. If still unset,
+# then we use the "found" location of COMPILERS above
+# and set a "safe" optimization level
+#
+
+if egrep "^CC[         ]*=" Makefile > /dev/null; then
+    CC=""      # clear it just in case
+else
+    if [ "x$CC" = "x" ]; then
+       if [ "x$COMPILER" = "x" ]; then
+           echo "Error: could not find any of these C compilers"
+           echo " anywhere in your PATH: $lookedfor"
+           echo "Configure terminated"
+           exit 1
+       fi
+       CC=$COMPILER
+    fi
+    echo " + setting C compiler to $CC"
+fi
+
+#
+# Ditto for optimization
+#
+if  egrep "^OPTIM[     ]*=" Makefile > /dev/null; then
+    OPTIM=""   # ditto
+else
+    if [ "x$OPTIM" = "x" ]; then
+       OPTIM="-O2"
+    fi
+    echo " + setting C compiler optimization-level to $OPTIM"
+fi
+
+#
+# Are they using the status monitor module? If so, check
+# for STATUS rule...
+#
+STAT_MOD="mod_status"
+if grep "$STAT_MOD" Makefile > /dev/null; then
+    if [ "$RULE_STATUS" = "yes" ]; then
+       CFLAGS="$CFLAGS -DSTATUS"
+    fi
+fi
+
+#
+# Are they using dbm auth? If so, add DBM library.
+#
+if grep mod_auth_dbm Makefile > /dev/null; then
+    LIBS="$LIBS $DBM_LIB"
+fi
+
+#
+# Now HS's POSIX regex implementation if needed/wanted
+#
+if [ "$RULE_WANTHSREGEX" = "yes" ]; then
+    REGLIB="regex/libregex.a"
+    INCLUDES="$INCLUDES -Iregex"
+fi
+
+#
+# Now SOCKS4.
+#  NOTE: We assume that if they are using SOCKS4, then they've
+#   adjusted EXTRA_LIBS and/or EXTRA_LFLAGS as required,
+#   otherwise we assume "-L/usr/local/lib -lsocks"
+#
+if [ "$RULE_SOCKS4" = "yes" ]; then
+    # Set flag and check Makefile for -lsocks line
+    CFLAGS="$CFLAGS -Dconnect=Rconnect -Dselect=Rselect"
+    CFLAGS="$CFLAGS -Dgethostbyname=Rgethostbyname"
+    if [ "$OS" = "Solaris 2" ]; then
+       LIBS="$LIBS -lresolv"
+    fi
+    if grep "EXTRA_" Makefile | grep "\-lsocks" > /dev/null; then : ;
+    else
+       LIBS="$LIBS -L/usr/local/lib -lsocks"
+    fi
+fi
+
+#
+# Good enough
+#
+echo  >> Makefile
+if [ "x$CC" != "x" ]; then
+    echo "CC=$CC" >> Makefile.config
+fi
+if [ "x$OPTIM" != "x" ]; then
+    echo "OPTIM=$OPTIM" >> Makefile.config
+fi
+echo "CFLAGS1=$CFLAGS">> Makefile.config
+echo "INCLUDES1=$INCLUDES">> Makefile.config
+echo "LIBS1=$LIBS">> Makefile.config
+echo "LFLAGS1=$LFLAGS">> Makefile.config
+echo "BROKEN_BPRINTF_FLAGS=$OSBPRINTF">> Makefile.config
+echo "REGLIB=$REGLIB">> Makefile.config
+echo "RANLIB=$RANLIB">> Makefile.config
+echo "SHELL=$SHELL">> Makefile.config
+echo >> Makefile.config
+echo "#### End of Configure created section ####">> Makefile.config
+
+
+# Now (finish) creating the makefiles
+cat Makefile.config >> Makefile
+sed -e "s#@@Configuration@@#$file#" "$makefile_tmpl" >>Makefile
+awk >>Makefile <$tmpfile \
+   '($1 == "Module" && $3 ~ /modules\//) { printf "%s: modules/last-built ; @cat /dev/null\n\n", $3, $3}'
+cat Makefile.config ../support/Makefile.tmpl > ../support/Makefile
+
+cat << EOF > modules/Makefile
+# 
+# Simple Makefile for modules in src/modules.
+# Generated by src/Configure according to rules in src/Configuration;
+# hand-edit at your own risk!
+# 
+
+SHELL=$SHELL
+EOF
+
+if [ "$RULE_WANTHSREGEX" = "yes" ]; then
+    INCLUDES2="-I../../regex"
+fi
+
+echo "INCLUDES2=$INCLUDES2">> modules/Makefile
+echo "MOD_CFLAGS=\$(INCLUDES2) \$(AUX_CFLAGS)">> modules/Makefile
+
+awk >> modules/Makefile < $tmpfile '\
+   BEGIN {printf "MODULES="} \
+   ($1 == "Module" && $3 ~ /modules\//) {split ($3, pp, "/"); printf "%s ", pp[2]} \
+   END {printf "\n"}'
+
+awk >> modules/Makefile < $tmpfile '\
+   BEGIN {printf "CLEANERS="} \
+   ($1 == "Module" && $3 ~ /modules\//) {split ($3, pp, "/"); printf "%s_clean ", pp[2]} \
+   END {printf "\n"}'
+
+cat << EOF >> modules/Makefile
+
+default: \$(MODULES)
+       @echo "Done building module subdirectories"
+
+clean: \$(CLEANERS)
+       @echo "Done cleaning module subdirectories"
+
+\$(MODULES): ForceMe
+       (cd \$@; \$(MAKE) CC=\$(CC) AUX_CFLAGS='\$(MOD_CFLAGS)' RANLIB='\$(RANLIB)')
+
+ForceMe:
+
+EOF
+
+awk >>modules/Makefile <$tmpfile \
+   '($1 == "Module" && $3 ~ /modules\//) { split ($3, pp, "/"); \
+   printf "%s_clean:\n\t(cd %s; $(MAKE) clean)\n\n", pp[2], pp[2]}'
+
diff --git a/APACHE_1_2_X/src/INSTALL b/APACHE_1_2_X/src/INSTALL
new file mode 100644 (file)
index 0000000..e5dcfa5
--- /dev/null
@@ -0,0 +1,71 @@
+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 list and settings of various
+   "Rules" and 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) Adjust the Rules and EXTRA_CFLAGS|LIBS|LFLAGS|INCLUDES if
+      you feel so inclined.
+
+   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 config file: Configuration
+      Using Makefile template file: Makefile.tmpl
+       + configured for <whatever> platform
+       + setting C compiler to <whatever> *
+       + setting C compiler optimization-level to <whatever> *
+      %
+
+   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 config file: Configuration.ai
+      Using Makefile template file: Makefile.tmpl
+       + configured for <whatever> platform
+       + setting C compiler to <whatever> *
+       + setting C compiler optimization-level to <whatever> *
+      % 
+
+   (*: Depending on Configuration and your system, Configure
+       make not print these lines. That's OK)
+
+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.
+
+If during compilation you get a warning about a missing 'regex.h', set
+WANTHSREGEX=yes in the 'Configuration', and let The Apache Group know
+you needed to do this for your OS by filling out a problem report form
+at <http://www.apache.org/bugdb.cgi>, or by sending a mail message to
+apache-bugs@apache.org.  Include the output of the command "uname -a".
+
+--------------------------------------------------------------------
+
+Now that you have compiled Apache, go back to the README file in the
+top-level directory of this distribution to continue the installation.
diff --git a/APACHE_1_2_X/src/Makefile.tmpl b/APACHE_1_2_X/src/Makefile.tmpl
new file mode 100644 (file)
index 0000000..54352ac
--- /dev/null
@@ -0,0 +1,126 @@
+# Apache makefile template (well, suffix).
+
+# This is combined with the information in the "Configuration" file
+# by the configure script to make the actual Makefile.
+
+CFLAGS=$(OPTIM) $(CFLAGS1) $(EXTRA_CFLAGS)
+LIBS=$(EXTRA_LIBS) $(LIBS1)
+INCLUDES=$(INCLUDES1) $(EXTRA_INCLUDES)
+LFLAGS=$(LFLAGS1) $(EXTRA_LFLAGS)
+
+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 util_date.o util_snprintf.o\
+  $(MODULES)
+
+.c.o:
+       $(CC) -c $(INCLUDES) $(CFLAGS) $(SPACER) $<
+
+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: $(REGLIB) $(OBJS)
+       $(CC) $(LFLAGS)  -o httpd $(OBJS) $(REGLIB) $(LIBS)
+
+regex/libregex.a:
+       (cd regex; $(MAKE) lib CC=$(CC) AUX_CFLAGS='$(CFLAGS)' RANLIB='$(RANLIB)')
+
+modules/last-built:
+       (cd modules; \
+       $(MAKE) CC=$(CC) AUX_CFLAGS='$(CFLAGS)' RANLIB='$(RANLIB)')
+
+clean:
+       rm -f httpd $(OBJS) 
+       cd regex; $(MAKE) clean
+       cd modules; $(MAKE) clean
+
+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 $(INCLUDES) $(CFLAGS) $(BROKEN_BPRINTF_FLAGS) http_bprintf.c
+
+#Dependencies
+
+$(OBJS): Makefile
+
+alloc.o: conf.h alloc.h
+buff.o: conf.h alloc.h buff.h
+explain.o: explain.h
+http_bprintf.o: conf.h alloc.h buff.h
+http_config.o: httpd.h http_config.h http_core.h http_log.h http_request.h \
+               http_conf_globals.h explain.h
+http_core.o: httpd.h http_config.h http_core.h http_protocol.h scoreboard.h \
+             http_conf_globals.h http_main.h http_log.h rfc1413.h util_md5.h
+http_log.o: httpd.h http_config.h http_core.h http_log.h
+http_main.o: httpd.h http_config.h http_core.h http_log.h http_request.h \
+             http_conf_globals.h http_protocol.h http_main.h scoreboard.h \
+             explain.h
+http_protocol.o: httpd.h http_config.h http_core.h http_protocol.h \
+                 http_main.h http_log.h util_date.h
+http_request.o: httpd.h http_config.h http_request.h http_core.h \
+                http_protocol.h http_log.h http_main.h scoreboard.h
+md5c.o: md5.h
+mod_access.o: httpd.h http_core.h http_config.h http_log.h
+mod_actions.o: httpd.h http_config.h http_request.h http_core.h \
+               http_protocol.h http_main.h http_log.h util_script.h
+mod_alias.o: httpd.h http_config.h
+mod_asis.o: httpd.h http_config.h http_protocol.h http_log.h util_script.h \
+            http_main.h http_request.h
+mod_auth.o: httpd.h http_config.h http_core.h http_log.h http_protocol.h
+mod_auth_anon.o: httpd.h http_config.h http_core.h http_log.h http_protocol.h
+mod_auth_db.o: httpd.h http_config.h http_core.h http_log.h http_protocol.h
+mod_auth_dbm.o: httpd.h http_config.h http_core.h http_log.h http_protocol.h
+mod_auth_msql.o: httpd.h http_config.h http_core.h http_log.h http_protocol.h
+mod_browser.o: httpd.h http_config.h
+mod_cern_meta.o: httpd.h http_config.h util_script.h http_log.h
+mod_cgi.o: httpd.h http_config.h http_request.h http_core.h http_protocol.h \
+           http_main.h http_log.h util_script.h
+mod_digest.o: httpd.h http_config.h http_core.h http_log.h http_protocol.h \
+              util_md5.h
+mod_dir.o: httpd.h http_config.h http_core.h http_request.h http_protocol.h \
+           http_log.h http_main.h util_script.h
+mod_dld.o: httpd.h http_config.h http_conf_globals.h
+mod_env.o: httpd.h http_config.h
+mod_expires.o: httpd.h http_config.h http_log.h
+mod_headers.o: httpd.h http_config.h
+mod_imap.o: httpd.h http_config.h http_request.h http_core.h http_protocol.h \
+            http_main.h http_log.h util_script.h
+mod_include.o: httpd.h http_config.h http_request.h http_core.h http_log.h \
+               http_protocol.h http_main.h util_script.h
+mod_info.o: httpd.h http_config.h http_core.h http_log.h http_main.h \
+            http_protocol.h util_script.h
+mod_log_agent.o: httpd.h http_config.h
+mod_log_config.o: httpd.h http_config.h http_core.h
+mod_log_referer.o: httpd.h http_config.h
+mod_mime.o: httpd.h http_config.h
+mod_negotiation.o: httpd.h http_config.h http_request.h http_core.h http_log.h
+mod_rewrite.o: httpd.h http_config.h http_request.h http_core.h http_log.h \
+               mod_rewrite.h
+mod_status.o: httpd.h http_config.h http_core.h http_protocol.h http_main.h \
+              util_script.h scoreboard.h
+mod_userdir.o: httpd.h http_config.h
+mod_usertrack.o: httpd.h http_config.h http_core.h
+modules.o: httpd.h http_config.h
+rfc1413.o: httpd.h http_log.h rfc1413.h
+util.o: httpd.h http_conf_globals.h
+util_date.o: util_date.h
+util_md5.o: httpd.h util_md5.h
+util_script.o: httpd.h http_config.h http_conf_globals.h http_main.h \
+               http_log.h http_protocol.h http_core.h http_request.h \
+               util_script.h
+util_snprintf.o: httpd.h
+
+httpd.h: conf.h alloc.h buff.h
+util_md5.h: md5.h
diff --git a/APACHE_1_2_X/src/PORTING b/APACHE_1_2_X/src/PORTING
new file mode 100644 (file)
index 0000000..97fccdb
--- /dev/null
@@ -0,0 +1,254 @@
+The Semi-Official Guide to Porting Apache
+
+-------------
+Introduction:
+-------------
+Apache has been ported to a wide variety of platforms, from multiple
+UNIX varients to OS/2. Nonetheless, there are most likely a few
+platforms out there that currently are not "officially" supported
+under Apache. Porting Apache to these platforms can be quite simple
+depending on the "genericness" of the OS. This doc will provide
+some basic guidelines to help the potential porter.
+
+-------------
+Requirements:
+-------------
+One of the basic requirements for a potential Apache platform is
+a robust TCP/IP implementation. Just about any UNIX out there
+nowadays, even some ancient ones, have a TCP/IP stack that will
+work. In particular, the UNIX should provide for sockets and the
+basic controlling functions for them (like accept(), bind(), etc).
+
+The source for Apache is written in ANSI-C, so an ANSI-C compiler
+is required. However, Apache does not use or require ANSI-only
+functions or options (eg: the "%n" parameter in the scanf()
+family); the source basically uses ANSI function prototyping but
+no other specific ANSIisms. Thus, an ANSI-to-K&R filter _may_
+work, although as far as I know it has not yet been tried. If you
+attempt this, let the Apache team know (mailto: new-httpd@hyperreal.com).
+
+-------------------
+The Starting Point:
+-------------------
+The first thing to look at is the output of the ./helpers/GuessOS
+script. This is a simple script that attempts to determine the
+platform and OS you are running on. The output of this script
+is used by Configure to set some basic compilation parameters.
+
+The output of ./helpers/GuessOS was designed to be GNUconfig.guess
+compatible (from GNU/autoconf). The format of the output string
+is:
+
+   machine-vendor-OS
+
+This string is returned to the main Configure script as the
+shell variable $PLAT. If Configure is not "aware" of that platform
+(or cannot correctly parse it), it will complain and die.
+
+----------------------
+Configure cannot Grok:
+----------------------
+If this happens to you, then it means that Configure doesn't
+know how to configure and compile Apache for your OS. The first
+course of action is the easiest: Look in Configure and see if
+there are any OSs which is similar to yours.
+
+For example, let's say that your OS is similar to HP-UX, but that
+GuessOS returns "foobar-intel-hubble". You would then edit
+Configure as follows:
+
+    *-hp-hpux*|*-*-hubble)
+       OS='HP-UX'
+       CFLAGS="$CFLAGS -DHPUX"
+       ;;
+
+The '|*-*-hubble' was added to the switch statement for HP-UX.
+
+Another fix may involve editing the GuessOS helper script. Let's
+say, for example, that your system is SysV4-based, but that
+GuessOS does not return that info. You could then add a switch
+to the script that does something like:
+
+       *WeirdSystem*)
+           echo "${MACHINE}-whatever-sysv4"; exit 0
+           ;;
+
+In this case, we force GuessOS to return a string that includes
+the "sysv4" cookie for Configure to recognize.
+
+Unfortunately, unless you are running a very generic BSD or SysV
+system, no "supported" OS will be close enough in all aspects to
+allow for a clear (and possibly workable) build of Apache. If this
+is the case, you will need to port Apache to your OS.
+
+-------------------
+Porting for Apache:
+-------------------
+When all else fails, it's time to hack some code. The source itself
+is generic enough that most ports are incredibly easy. No matter
+what, however, there are 2 source files that need to be updated
+for the port:
+
+   Configure
+   conf.h
+
+Configure:
+ ==========
+Configure concerns itself with determining the OS-type for the
+build and setting up a few Makefile variables for the build. The
+most important is 'OS' and 'CFLAGS'. For example, when Configure
+determines a build for A/UX, it runs the following lines:
+
+  case "$PLAT" in
+    *-apple-aux3*)
+       OS='A/UX 3.1.x'
+       CFLAGS="$CFLAGS -DAUX -D_POSIX_SOURCE"
+       LIBS="$LIBS -lposix -lbsd"
+       LFLAGS="$LFLAGS -s"
+       DEF_WANTHSREGEX=no
+       ;;
+
+The 'OS' variable is used to define the system Apache is being built
+for. You will also note that 'CFLAGS' defines "-DAUX". In this case,
+'AUX' is a magic cookie used by the Apache code (mainly conf.h [see
+below]) to handle OS-specific code. Each code that has and requires
+such OS-specific code will require a unique "system cookie" defined
+in 'CFLAGS'. You will also note that Configure also goes ahead and
+predefines the LIBS and LFLAGS Makefile variables (DEF_WANTHSREGEX is
+explained below).
+
+conf.h:
+ =======
+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
+supported OS. One of the hardest parts about the porting process is
+determining which of the following are applicable for your system and
+setup. This time using the example of AIX, we see:
+
+   #elif defined(AIX)
+   #undef HAVE_GMTOFF
+   #undef NO_KILLPG
+   #undef NO_SETSID
+   #define HAVE_SYS_SELECT_H
+   #define JMP_BUF sigjmp_buf
+   #define HAVE_MMAP
+   typedef int rlim_t;
+
+The above lines describe which functions,  capabilities and specifics
+are required for Apache to build and run under IBM AIX (the #undefs
+are not strictly required, but are a Good Idea anyway).
+
+The following several lines provide a list and short description
+of these #defines. By correcting #defining the ones you need in conf.h
+(wrapped by the above mentioned "system cookie"), you can fine tune the
+build for your OS.
+
+--
+
+ 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:
+--
+
+ HAVE_*:
+  Does this OS have/support this capability?
+
+    HAVE_GMTOFF:
+      Define if the OS's tm struct has the tm_gmtoff element
+
+    HAVE_RESOURCE:
+      Define 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.
+
+    HAVE_SYS_SELECT_H:
+      Define if the OS has the <sys/select.h> header file.
+
+    HAVE_SYS_RESOURCE_H:
+      Define if the OS has and supports the getrlimit/setrlimit
+      family. Apache uses this to determine if RLIMIT_CPU|VMEM|DATA|RLIMIT
+      is found and used.
+
+    HAVE_SNPRINTF:
+      Apache makes extensive use of the snprintf() function. many
+      platforms do not provide this function. If your platform
+      does provide it _and_ it's reliable (most are not) then
+      define this to use the OS version. Otherwise, Apache will
+      use it's own.
+--
+
+ USE_*:
+  These #defines are used for functions and ability that aren't exactly
+  required but should be used.
+
+     USE_FCNTL_SERIALIZED_ACCEPT:
+      Define if the OS requires a mutex "lock" around the socket accept()
+      call. Use fcntl() locking.
+
+     USE_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).
+
+     USE_LONGJMP:
+      use the longjmp() call instead of siglongjmp()
+      (as well as setjmp() instead of sigsetjmp())
+
+--
+
+  NO_*:
+   These are defined if the OS does NOT have the specified function or if
+   we should not use it.
+
+      NO_UNISTD_H:
+      NO_KILLPG:
+      NO_SETSID:
+      NO_USE_SIGACTION:
+       Do not use the sigaction() call, even if we have it.
+      NO_LINGCLOSE:
+       Do not use Apache's soft, "lingering" close feature to
+       terminate connections.
+--
+
+  MISC #DEFINES:
+   Various other #defines used in the code.
+
+      JMP_BUF:
+       The variable-type for siglongjmp() or longjmp() call.
+
+      MOVEBREAK:
+       Amount to move sbrk() breakpoint, if required, before attaching
+       shared-memory segment.
+
+-----------
+Conclusion:
+-----------
+The above hints, and a good understanding of your OS and Apache, will
+go a LONG way in helping you get Apache built and running on your
+OS. If you have a port, PLEASE send Email to 'new-httpd@hyperreal.com'
+with the patches so that we may add them to the official version.
+If you hit a rough spot in the porting process, you can also try
+sending Email to that address as well and, if you are lucky, someone
+will respond. Another good source is the 'comp.infosystems.www.servers.unix'
+Usenet group as well.
+
+Good luck and happy porting!
diff --git a/APACHE_1_2_X/src/README b/APACHE_1_2_X/src/README
new file mode 100644 (file)
index 0000000..9aefdca
--- /dev/null
@@ -0,0 +1,147 @@
+The following document was written by Robert S. Thau (rst@ai.mit.edu) on the
+release of Apache 1.0.  Some details may have changed since then regarding the
+functions and names of modules, but the basic ideas are still intact.
+ =================================================
+
+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_log_config.c --- logging in configurable or 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.
+
diff --git a/APACHE_1_2_X/src/ap/ap_md5c.c b/APACHE_1_2_X/src/ap/ap_md5c.c
new file mode 100644 (file)
index 0000000..fd42bcb
--- /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,1997 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/APACHE_1_2_X/src/ap/ap_snprintf.c b/APACHE_1_2_X/src/ap/ap_snprintf.c
new file mode 100644 (file)
index 0000000..d37c634
--- /dev/null
@@ -0,0 +1,949 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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 code is based on, and used with the permission of, the
+ * SIO stdio-replacement strx_* functions by Panos Tsirigotis
+ * <panos@alumni.cs.colorado.edu> for xinetd.
+ */
+
+#include "conf.h"
+
+#ifndef HAVE_SNPRINTF
+
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+
+#ifdef HAVE_CVT
+
+# define ap_ecvt ecvt
+# define ap_fcvt fcvt
+# define ap_gcvt gcvt
+
+#else
+
+/*
+ * cvt.c - IEEE floating point formatting routines for FreeBSD
+ * from GNU libc-4.6.27
+ */
+
+/*
+ *    ap_ecvt converts to decimal
+ *      the number of digits is specified by ndigit
+ *      decpt is set to the position of the decimal point
+ *      sign is set to 0 for positive, 1 for negative
+ */
+
+#define        NDIG    80
+
+static char *
+     ap_cvt(double arg, int ndigits, int *decpt, int *sign, int eflag)
+{
+    register int r2;
+    double fi, fj;
+    register char *p, *p1;
+    static char buf[NDIG];
+
+    if (ndigits >= NDIG - 1)
+       ndigits = NDIG - 2;
+    r2 = 0;
+    *sign = 0;
+    p = &buf[0];
+    if (arg < 0) {
+       *sign = 1;
+       arg = -arg;
+    }
+    arg = modf(arg, &fi);
+    p1 = &buf[NDIG];
+    /*
+     * Do integer part
+     */
+    if (fi != 0) {
+       p1 = &buf[NDIG];
+       while (fi != 0) {
+           fj = modf(fi / 10, &fi);
+           *--p1 = (int) ((fj + .03) * 10) + '0';
+           r2++;
+       }
+       while (p1 < &buf[NDIG])
+           *p++ = *p1++;
+    }
+    else if (arg > 0) {
+       while ((fj = arg * 10) < 1) {
+           arg = fj;
+           r2--;
+       }
+    }
+    p1 = &buf[ndigits];
+    if (eflag == 0)
+       p1 += r2;
+    *decpt = r2;
+    if (p1 < &buf[0]) {
+       buf[0] = '\0';
+       return (buf);
+    }
+    while (p <= p1 && p < &buf[NDIG]) {
+       arg *= 10;
+       arg = modf(arg, &fj);
+       *p++ = (int) fj + '0';
+    }
+    if (p1 >= &buf[NDIG]) {
+       buf[NDIG - 1] = '\0';
+       return (buf);
+    }
+    p = p1;
+    *p1 += 5;
+    while (*p1 > '9') {
+       *p1 = '0';
+       if (p1 > buf)
+           ++ * --p1;
+       else {
+           *p1 = '1';
+           (*decpt)++;
+           if (eflag == 0) {
+               if (p > buf)
+                   *p = '0';
+               p++;
+           }
+       }
+    }
+    *p = '\0';
+    return (buf);
+}
+
+static char *
+     ap_ecvt(double arg, int ndigits, int *decpt, int *sign)
+{
+    return (ap_cvt(arg, ndigits, decpt, sign, 1));
+}
+
+static char *
+     ap_fcvt(double arg, int ndigits, int *decpt, int *sign)
+{
+    return (ap_cvt(arg, ndigits, decpt, sign, 0));
+}
+
+/*
+ * ap_gcvt  - Floating output conversion to
+ * minimal length string
+ */
+
+static char *
+     ap_gcvt(double number, int ndigit, char *buf)
+{
+    int sign, decpt;
+    register char *p1, *p2;
+    register i;
+
+    p1 = ap_ecvt(number, ndigit, &decpt, &sign);
+    p2 = buf;
+    if (sign)
+       *p2++ = '-';
+    for (i = ndigit - 1; i > 0 && p1[i] == '0'; i--)
+       ndigit--;
+    if ((decpt >= 0 && decpt - ndigit > 4)
+       || (decpt < 0 && decpt < -3)) {         /* use E-style */
+       decpt--;
+       *p2++ = *p1++;
+       *p2++ = '.';
+       for (i = 1; i < ndigit; i++)
+           *p2++ = *p1++;
+       *p2++ = 'e';
+       if (decpt < 0) {
+           decpt = -decpt;
+           *p2++ = '-';
+       }
+       else
+           *p2++ = '+';
+       if (decpt / 100 > 0)
+           *p2++ = decpt / 100 + '0';
+       if (decpt / 10 > 0)
+           *p2++ = (decpt % 100) / 10 + '0';
+       *p2++ = decpt % 10 + '0';
+    }
+    else {
+       if (decpt <= 0) {
+           if (*p1 != '0')
+               *p2++ = '.';
+           while (decpt < 0) {
+               decpt++;
+               *p2++ = '0';
+           }
+       }
+       for (i = 1; i <= ndigit; i++) {
+           *p2++ = *p1++;
+           if (i == decpt)
+               *p2++ = '.';
+       }
+       if (ndigit < decpt) {
+           while (ndigit++ < decpt)
+               *p2++ = '0';
+           *p2++ = '.';
+       }
+    }
+    if (p2[-1] == '.')
+       p2--;
+    *p2 = '\0';
+    return (buf);
+}
+
+#endif /* HAVE_CVT */
+
+typedef enum {
+    NO = 0, YES = 1
+} boolean_e;
+
+#define FALSE                  0
+#define TRUE                   1
+#define NUL                    '\0'
+#define INT_NULL               ((int *)0)
+#define WIDE_INT               long
+
+typedef WIDE_INT               wide_int;
+typedef unsigned WIDE_INT      u_wide_int;
+typedef int                    bool_int;
+
+#define S_NULL                 "(null)"
+#define S_NULL_LEN             6
+
+#define FLOAT_DIGITS           6
+#define EXPONENT_LENGTH                10
+
+/*
+ * NUM_BUF_SIZE is the size of the buffer used for arithmetic conversions
+ *
+ * XXX: this is a magic number; do not decrease it
+ */
+#define NUM_BUF_SIZE           512
+
+
+/*
+ * Descriptor for buffer area
+ */
+struct buf_area {
+    char *buf_end;
+    char *nextb;               /* pointer to next byte to read/write   */
+};
+
+typedef struct buf_area buffy;
+
+/*
+ * The INS_CHAR macro inserts a character in the buffer and writes
+ * the buffer back to disk if necessary
+ * It uses the char pointers sp and bep:
+ *      sp points to the next available character in the buffer
+ *      bep points to the end-of-buffer+1
+ * While using this macro, note that the nextb pointer is NOT updated.
+ *
+ * NOTE: Evaluation of the c argument should not have any side-effects
+ */
+#define INS_CHAR( c, sp, bep, cc )     \
+           {                           \
+               if ( sp < bep )         \
+               {                       \
+                   *sp++ = c ;         \
+                   cc++ ;              \
+               }                       \
+           }
+
+#define NUM( c )                       ( c - '0' )
+
+#define STR_TO_DEC( str, num )         \
+    num = NUM( *str++ ) ;              \
+    while ( isdigit( *str ) )          \
+    {                                  \
+       num *= 10 ;                     \
+       num += NUM( *str++ ) ;          \
+    }
+
+/*
+ * This macro does zero padding so that the precision
+ * requirement is satisfied. The padding is done by
+ * adding '0's to the left of the string that is going
+ * to be printed.
+ */
+#define FIX_PRECISION( adjust, precision, s, s_len )   \
+    if ( adjust )                                      \
+       while ( s_len < precision )                     \
+       {                                               \
+           *--s = '0' ;                                \
+           s_len++ ;                                   \
+       }
+
+/*
+ * Macro that does padding. The padding is done by printing
+ * the character ch.
+ */
+#define PAD( width, len, ch )  do              \
+       {                                       \
+           INS_CHAR( ch, sp, bep, cc ) ;       \
+           width-- ;                           \
+       }                                       \
+       while ( width > len )
+
+/*
+ * Prefix the character ch to the string str
+ * Increase length
+ * Set the has_prefix flag
+ */
+#define PREFIX( str, length, ch )       *--str = ch ; length++ ; has_prefix = YES
+
+
+/*
+ * Convert num to its decimal format.
+ * Return value:
+ *   - a pointer to a string containing the number (no sign)
+ *   - len contains the length of the string
+ *   - is_negative is set to TRUE or FALSE depending on the sign
+ *     of the number (always set to FALSE if is_unsigned is TRUE)
+ *
+ * The caller provides a buffer for the string: that is the buf_end argument
+ * which is a pointer to the END of the buffer + 1 (i.e. if the buffer
+ * is declared as buf[ 100 ], buf_end should be &buf[ 100 ])
+ */
+static char *
+     conv_10(register wide_int num, register bool_int is_unsigned,
+         register bool_int * is_negative, char *buf_end, register int *len)
+{
+    register char *p = buf_end;
+    register u_wide_int magnitude;
+
+    if (is_unsigned) {
+       magnitude = (u_wide_int) num;
+       *is_negative = FALSE;
+    }
+    else {
+       *is_negative = (num < 0);
+
+       /*
+        * On a 2's complement machine, negating the most negative integer 
+        * results in a number that cannot be represented as a signed integer.
+        * Here is what we do to obtain the number's magnitude:
+        *      a. add 1 to the number
+        *      b. negate it (becomes positive)
+        *      c. convert it to unsigned
+        *      d. add 1
+        */
+       if (*is_negative) {
+           wide_int t = num + 1;
+
+           magnitude = ((u_wide_int) - t) + 1;
+       }
+       else
+           magnitude = (u_wide_int) num;
+    }
+
+    /*
+     * We use a do-while loop so that we write at least 1 digit 
+     */
+    do {
+       register u_wide_int new_magnitude = magnitude / 10;
+
+       *--p = magnitude - new_magnitude * 10 + '0';
+       magnitude = new_magnitude;
+    }
+    while (magnitude);
+
+    *len = buf_end - p;
+    return (p);
+}
+
+
+
+/*
+ * Convert a floating point number to a string formats 'f', 'e' or 'E'.
+ * The result is placed in buf, and len denotes the length of the string
+ * The sign is returned in the is_negative argument (and is not placed
+ * in buf).
+ */
+static char *
+     conv_fp(register char format, register double num,
+boolean_e add_dp, int precision, bool_int * is_negative, char *buf, int *len)
+{
+    register char *s = buf;
+    register char *p;
+    int decimal_point;
+
+    if (format == 'f')
+       p = ap_fcvt(num, precision, &decimal_point, is_negative);
+    else                       /* either e or E format */
+       p = ap_ecvt(num, precision + 1, &decimal_point, is_negative);
+
+    /*
+     * Check for Infinity and NaN
+     */
+    if (isalpha(*p)) {
+       *len = strlen(strcpy(buf, p));
+       *is_negative = FALSE;
+       return (buf);
+    }
+
+    if (format == 'f')
+       if (decimal_point <= 0) {
+           *s++ = '0';
+           if (precision > 0) {
+               *s++ = '.';
+               while (decimal_point++ < 0)
+                   *s++ = '0';
+           }
+           else if (add_dp)
+               *s++ = '.';
+       }
+       else {
+           while (decimal_point-- > 0)
+               *s++ = *p++;
+           if (precision > 0 || add_dp)
+               *s++ = '.';
+       }
+    else {
+       *s++ = *p++;
+       if (precision > 0 || add_dp)
+           *s++ = '.';
+    }
+
+    /*
+     * copy the rest of p, the NUL is NOT copied
+     */
+    while (*p)
+       *s++ = *p++;
+
+    if (format != 'f') {
+       char temp[EXPONENT_LENGTH];     /* for exponent conversion */
+       int t_len;
+       bool_int exponent_is_negative;
+
+       *s++ = format;          /* either e or E */
+       decimal_point--;
+       if (decimal_point != 0) {
+           p = conv_10((wide_int) decimal_point, FALSE, &exponent_is_negative,
+                       &temp[EXPONENT_LENGTH], &t_len);
+           *s++ = exponent_is_negative ? '-' : '+';
+
+           /*
+            * Make sure the exponent has at least 2 digits
+            */
+           if (t_len == 1)
+               *s++ = '0';
+           while (t_len--)
+               *s++ = *p++;
+       }
+       else {
+           *s++ = '+';
+           *s++ = '0';
+           *s++ = '0';
+       }
+    }
+
+    *len = s - buf;
+    return (buf);
+}
+
+
+/*
+ * Convert num to a base X number where X is a power of 2. nbits determines X.
+ * For example, if nbits is 3, we do base 8 conversion
+ * Return value:
+ *      a pointer to a string containing the number
+ *
+ * The caller provides a buffer for the string: that is the buf_end argument
+ * which is a pointer to the END of the buffer + 1 (i.e. if the buffer
+ * is declared as buf[ 100 ], buf_end should be &buf[ 100 ])
+ */
+static char *
+     conv_p2(register u_wide_int num, register int nbits,
+            char format, char *buf_end, register int *len)
+{
+    register int mask = (1 << nbits) - 1;
+    register char *p = buf_end;
+    static char low_digits[] = "0123456789abcdef";
+    static char upper_digits[] = "0123456789ABCDEF";
+    register char *digits = (format == 'X') ? upper_digits : low_digits;
+
+    do {
+       *--p = digits[num & mask];
+       num >>= nbits;
+    }
+    while (num);
+
+    *len = buf_end - p;
+    return (p);
+}
+
+
+/*
+ * Do format conversion placing the output in buffer
+ */
+static int format_converter(register buffy * odp, const char *fmt,
+                             va_list ap)
+{
+    register char *sp;
+    register char *bep;
+    register int cc = 0;
+    register int i;
+
+    register char *s = NULL;
+    char *q;
+    int s_len;
+
+    register int min_width = 0;
+    int precision = 0;
+    enum {
+       LEFT, RIGHT
+    } adjust;
+    char pad_char;
+    char prefix_char;
+
+    double fp_num;
+    wide_int i_num = (wide_int) 0;
+    u_wide_int ui_num;
+
+    char num_buf[NUM_BUF_SIZE];
+    char char_buf[2];          /* for printing %% and %<unknown> */
+
+    /*
+     * Flag variables
+     */
+    boolean_e is_long;
+    boolean_e alternate_form;
+    boolean_e print_sign;
+    boolean_e print_blank;
+    boolean_e adjust_precision;
+    boolean_e adjust_width;
+    bool_int is_negative;
+
+    sp = odp->nextb;
+    bep = odp->buf_end;
+
+    while (*fmt) {
+       if (*fmt != '%') {
+           INS_CHAR(*fmt, sp, bep, cc);
+       }
+       else {
+           /*
+            * Default variable settings
+            */
+           adjust = RIGHT;
+           alternate_form = print_sign = print_blank = NO;
+           pad_char = ' ';
+           prefix_char = NUL;
+
+           fmt++;
+
+           /*
+            * Try to avoid checking for flags, width or precision
+            */
+           if (isascii(*fmt) && !islower(*fmt)) {
+               /*
+                * Recognize flags: -, #, BLANK, +
+                */
+               for (;; fmt++) {
+                   if (*fmt == '-')
+                       adjust = LEFT;
+                   else if (*fmt == '+')
+                       print_sign = YES;
+                   else if (*fmt == '#')
+                       alternate_form = YES;
+                   else if (*fmt == ' ')
+                       print_blank = YES;
+                   else if (*fmt == '0')
+                       pad_char = '0';
+                   else
+                       break;
+               }
+
+               /*
+                * Check if a width was specified
+                */
+               if (isdigit(*fmt)) {
+                   STR_TO_DEC(fmt, min_width);
+                   adjust_width = YES;
+               }
+               else if (*fmt == '*') {
+                   min_width = va_arg(ap, int);
+                   fmt++;
+                   adjust_width = YES;
+                   if (min_width < 0) {
+                       adjust = LEFT;
+                       min_width = -min_width;
+                   }
+               }
+               else
+                   adjust_width = NO;
+
+               /*
+                * Check if a precision was specified
+                *
+                * XXX: an unreasonable amount of precision may be specified
+                * resulting in overflow of num_buf. Currently we
+                * ignore this possibility.
+                */
+               if (*fmt == '.') {
+                   adjust_precision = YES;
+                   fmt++;
+                   if (isdigit(*fmt)) {
+                       STR_TO_DEC(fmt, precision);
+                   }
+                   else if (*fmt == '*') {
+                       precision = va_arg(ap, int);
+                       fmt++;
+                       if (precision < 0)
+                           precision = 0;
+                   }
+                   else
+                       precision = 0;
+               }
+               else
+                   adjust_precision = NO;
+           }
+           else
+               adjust_precision = adjust_width = NO;
+
+           /*
+            * Modifier check
+            */
+           if (*fmt == 'l') {
+               is_long = YES;
+               fmt++;
+           }
+           else
+               is_long = NO;
+
+           /*
+            * Argument extraction and printing.
+            * First we determine the argument type.
+            * Then, we convert the argument to a string.
+            * On exit from the switch, s points to the string that
+            * must be printed, s_len has the length of the string
+            * The precision requirements, if any, are reflected in s_len.
+            *
+            * NOTE: pad_char may be set to '0' because of the 0 flag.
+            *   It is reset to ' ' by non-numeric formats
+            */
+           switch (*fmt) {
+           case 'u':
+               if (is_long)
+                   i_num = va_arg(ap, u_wide_int);
+               else
+                   i_num = (wide_int) va_arg(ap, unsigned int);
+               /*
+                * The rest also applies to other integer formats, so fall
+                * into that case.
+                */
+           case 'd':
+           case 'i':
+               /*
+                * Get the arg if we haven't already.
+                */
+               if ((*fmt) != 'u') {
+                   if (is_long)
+                       i_num = va_arg(ap, wide_int);
+                   else
+                       i_num = (wide_int) va_arg(ap, int);
+               };
+               s = conv_10(i_num, (*fmt) == 'u', &is_negative,
+                           &num_buf[NUM_BUF_SIZE], &s_len);
+               FIX_PRECISION(adjust_precision, precision, s, s_len);
+
+               if (*fmt != 'u') {
+                   if (is_negative)
+                       prefix_char = '-';
+                   else if (print_sign)
+                       prefix_char = '+';
+                   else if (print_blank)
+                       prefix_char = ' ';
+               }
+               break;
+
+
+           case 'o':
+               if (is_long)
+                   ui_num = va_arg(ap, u_wide_int);
+               else
+                   ui_num = (u_wide_int) va_arg(ap, unsigned int);
+               s = conv_p2(ui_num, 3, *fmt,
+                           &num_buf[NUM_BUF_SIZE], &s_len);
+               FIX_PRECISION(adjust_precision, precision, s, s_len);
+               if (alternate_form && *s != '0') {
+                   *--s = '0';
+                   s_len++;
+               }
+               break;
+
+
+           case 'x':
+           case 'X':
+               if (is_long)
+                   ui_num = (u_wide_int) va_arg(ap, u_wide_int);
+               else
+                   ui_num = (u_wide_int) va_arg(ap, unsigned int);
+               s = conv_p2(ui_num, 4, *fmt,
+                           &num_buf[NUM_BUF_SIZE], &s_len);
+               FIX_PRECISION(adjust_precision, precision, s, s_len);
+               if (alternate_form && i_num != 0) {
+                   *--s = *fmt;        /* 'x' or 'X' */
+                   *--s = '0';
+                   s_len += 2;
+               }
+               break;
+
+
+           case 's':
+               s = va_arg(ap, char *);
+               if (s != NULL) {
+                   s_len = strlen(s);
+                   if (adjust_precision && precision < s_len)
+                       s_len = precision;
+               }
+               else {
+                   s = S_NULL;
+                   s_len = S_NULL_LEN;
+               }
+               pad_char = ' ';
+               break;
+
+
+           case 'f':
+           case 'e':
+           case 'E':
+               fp_num = va_arg(ap, double);
+
+               s = conv_fp(*fmt, fp_num, alternate_form,
+                       (adjust_precision == NO) ? FLOAT_DIGITS : precision,
+                           &is_negative, &num_buf[1], &s_len);
+               if (is_negative)
+                   prefix_char = '-';
+               else if (print_sign)
+                   prefix_char = '+';
+               else if (print_blank)
+                   prefix_char = ' ';
+               break;
+
+
+           case 'g':
+           case 'G':
+               if (adjust_precision == NO)
+                   precision = FLOAT_DIGITS;
+               else if (precision == 0)
+                   precision = 1;
+               /*
+                * * We use &num_buf[ 1 ], so that we have room for the sign
+                */
+               s = ap_gcvt(va_arg(ap, double), precision, &num_buf[1]);
+               if (*s == '-')
+                   prefix_char = *s++;
+               else if (print_sign)
+                   prefix_char = '+';
+               else if (print_blank)
+                   prefix_char = ' ';
+
+               s_len = strlen(s);
+
+               if (alternate_form && (q = strchr(s, '.')) == NULL)
+                   s[s_len++] = '.';
+               if (*fmt == 'G' && (q = strchr(s, 'e')) != NULL)
+                   *q = 'E';
+               break;
+
+
+           case 'c':
+               char_buf[0] = (char) (va_arg(ap, int));
+               s = &char_buf[0];
+               s_len = 1;
+               pad_char = ' ';
+               break;
+
+
+           case '%':
+               char_buf[0] = '%';
+               s = &char_buf[0];
+               s_len = 1;
+               pad_char = ' ';
+               break;
+
+
+           case 'n':
+               *(va_arg(ap, int *)) = cc;
+               break;
+
+               /*
+                * Always extract the argument as a "char *" pointer. We 
+                * should be using "void *" but there are still machines 
+                * that don't understand it.
+                * If the pointer size is equal to the size of an unsigned
+                * integer we convert the pointer to a hex number, otherwise 
+                * we print "%p" to indicate that we don't handle "%p".
+                */
+           case 'p':
+               ui_num = (u_wide_int) va_arg(ap, char *);
+
+               if (sizeof(char *) <= sizeof(u_wide_int))
+                        s = conv_p2(ui_num, 4, 'x',
+                                    &num_buf[NUM_BUF_SIZE], &s_len);
+               else {
+                   s = "%p";
+                   s_len = 2;
+               }
+               pad_char = ' ';
+               break;
+
+
+           case NUL:
+               /*
+                * The last character of the format string was %.
+                * We ignore it.
+                */
+               continue;
+
+
+               /*
+                * The default case is for unrecognized %'s.
+                * We print %<char> to help the user identify what
+                * option is not understood.
+                * This is also useful in case the user wants to pass
+                * the output of format_converter to another function
+                * that understands some other %<char> (like syslog).
+                * Note that we can't point s inside fmt because the
+                * unknown <char> could be preceded by width etc.
+                */
+           default:
+               char_buf[0] = '%';
+               char_buf[1] = *fmt;
+               s = char_buf;
+               s_len = 2;
+               pad_char = ' ';
+               break;
+           }
+
+           if (prefix_char != NUL) {
+               *--s = prefix_char;
+               s_len++;
+           }
+
+           if (adjust_width && adjust == RIGHT && min_width > s_len) {
+               if (pad_char == '0' && prefix_char != NUL) {
+                   INS_CHAR(*s, sp, bep, cc)
+                       s++;
+                   s_len--;
+                   min_width--;
+               }
+               PAD(min_width, s_len, pad_char);
+           }
+
+           /*
+            * Print the string s. 
+            */
+           for (i = s_len; i != 0; i--) {
+               INS_CHAR(*s, sp, bep, cc);
+               s++;
+           }
+
+           if (adjust_width && adjust == LEFT && min_width > s_len)
+               PAD(min_width, s_len, pad_char);
+       }
+       fmt++;
+    }
+    odp->nextb = sp;
+    return (cc);
+}
+
+
+/*
+ * This is the general purpose conversion function.
+ */
+static void strx_printv(int *ccp, char *buf, size_t len, const char *format,
+                       va_list ap)
+{
+    buffy od;
+    int cc;
+
+    /*
+     * First initialize the descriptor
+     * Notice that if no length is given, we initialize buf_end to the
+     * highest possible address.
+     */
+    od.buf_end = len ? &buf[len] : (char *) ~0;
+    od.nextb = buf;
+
+    /*
+     * Do the conversion
+     */
+    cc = format_converter(&od, format, ap);
+    if (len == 0 || od.nextb <= od.buf_end)
+       *(od.nextb) = '\0';
+    if (ccp)
+       *ccp = cc;
+}
+
+
+int ap_snprintf(char *buf, size_t len, const char *format,...)
+{
+    int cc;
+    va_list ap;
+
+    va_start(ap, format);
+    strx_printv(&cc, buf, (len - 1), format, ap);
+    va_end(ap);
+    return (cc);
+}
+
+
+int ap_vsnprintf(char *buf, size_t len, const char *format, va_list ap)
+{
+    int cc;
+
+    strx_printv(&cc, buf, (len - 1), format, ap);
+    return (cc);
+}
+
+#endif /* HAVE_SNPRINTF */
diff --git a/APACHE_1_2_X/src/helpers/CutRule b/APACHE_1_2_X/src/helpers/CutRule
new file mode 100755 (executable)
index 0000000..740a336
--- /dev/null
@@ -0,0 +1,7 @@
+# Helper script for Configure - cut a rule from Configuration.
+# note that there is a tab and a space in the character groups.
+# Map to lowercase to make tests easier
+
+egrep "^[       ]*Rule[         ]+$1[   ]*=" $2 | \
+awk 'BEGIN {FS="="}{print $2}' | \
+sed 's/[        ]//g' | tr "A-Z" "a-z"
diff --git a/APACHE_1_2_X/src/helpers/GuessOS b/APACHE_1_2_X/src/helpers/GuessOS
new file mode 100755 (executable)
index 0000000..0890b81
--- /dev/null
@@ -0,0 +1,224 @@
+#!/bin/sh
+#
+# Simple OS/Platform guesser. Similar to config.guess but
+# much, much smaller. Since it was developed for use with
+# Apache, it follows under Apache's regular licensing
+# with one specific addition: Any changes or additions
+# to this script should be Emailed to the Apache
+# group (apache@apache.org) in general and to
+# Jim Jagielski (jim@jaguNET.com) in specific.
+#
+# Be as similar to the output of config.guess/config.sub
+# as possible.
+
+# First get uname entries that we use below
+
+MACHINE=`(uname -m) 2>/dev/null` || MACHINE="unknown"
+RELEASE=`(uname -r) 2>/dev/null` || RELEASE="unknown"
+SYSTEM=`(uname -s) 2>/dev/null`  || SYSTEM="unknown"
+VERSION=`(uname -v) 2>/dev/null` || VERSION="unknown"
+
+
+# Now test for ISC and SCO, since it is has a braindamaged uname.
+#
+# We need to work around FreeBSD 1.1.5.1 
+XREL=`uname -X 2>/dev/null | grep "^Release" | awk '{print $3}'`
+if [ "x$XREL" != "x" ]; then
+    if [ -f /etc/kconfig ]; then
+       case "$XREL" in
+           4.0|4.1)
+                   echo "${MACHINE}-whatever-isc4"; exit 0
+               ;;
+       esac
+    else
+       case "$XREL" in
+           3.2v4.2)
+               echo "whatever-whatever-sco3"; exit 0
+               ;;
+           3.2v5.0*)
+               echo "whatever-whatever-sco5"; exit 0
+               ;;
+           4.2MP)
+               if [ "x$VERSION" = "x2.1.1" ]; then
+                   echo "${MACHINE}-whatever-unixware211"; exit 0
+               else
+                   echo "${MACHINE}-whatever-unixware2"; exit 0
+               fi
+               ;;
+           4.2)
+               echo "whatever-whatever-unixware1"; exit 0
+               ;;
+       esac
+    fi
+fi
+# Now we simply scan though... In most cases, the SYSTEM info is enough
+#
+case "${SYSTEM}:${RELEASE}:${VERSION}:${MACHINE}" in
+    A/UX:*)
+       echo "m68k-apple-aux3"; exit 0
+       ;;
+
+    AIX:*)
+       echo "${MACHINE}-ibm-aix"; exit 0
+       ;;
+
+    dgux:*)
+       echo "${MACHINE}-dg-dgux"; exit 0
+       ;;
+
+    HI-UX:*)
+       echo "${MACHINE}-hi-hiux"; exit 0
+       ;;
+
+    HP-UX:*)
+       HPUXVER=`echo ${RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+       case "$HPUXVER" in
+           10.*)
+               echo "${MACHINE}-hp-hpux10."; exit 0
+               ;;
+           *)
+               echo "${MACHINE}-hp-hpux"; exit 0
+               ;;
+       esac
+       ;;
+
+    IRIX:*)
+       echo "${MACHINE}-sgi-irix"; exit 0
+       ;;
+
+    IRIX64:*)
+       echo "${MACHINE}-sgi-irix64"; exit 0
+       ;;
+
+    Linux:[2-9].*)
+       echo "${MACHINE}-whatever-linux2"; exit 0
+       ;;
+
+    Linux:1.*)
+       echo "${MACHINE}-whatever-linux1"; exit 0
+       ;;
+
+    LynxOS:*)
+       echo "${MACHINE}-lynx-lynxos"; exit 0
+       ;;
+
+    BSD/386:*:*:*486*|BSD/OS:*:*:*:*486*)
+       echo "i486-whatever-bsdi"; exit 0
+       ;;
+
+    BSD/386:*|BSD/OS:*)
+       echo "${MACHINE}-whatever-bsdi"; exit 0
+       ;;
+
+    FreeBSD:*:*:*486*)
+       echo "i486-whatever-freebsd"; exit 0
+       ;;
+
+    FreeBSD:*)
+       echo "${MACHINE}-whatever-freebsd"; exit 0
+       ;;
+
+    NetBSD:*:*:*486*)
+       echo "i486-whatever-netbsd"; exit 0
+       ;;
+
+    NetBSD:*)
+       echo "${MACHINE}-whatever-netbsd"; exit 0
+       ;;
+
+    OpenBSD:*)
+       echo "${MACHINE}-whatever-openbsd"; exit 0
+       ;;
+
+    OSF1:*:*:*alpha*)
+       echo "${MACHINE}-dec-osf"; exit 0
+       ;;
+
+    QNX:*)
+       case "$VERSION" in
+           423)
+               echo "${MACHINE}-qssl-qnx32"
+               ;;
+           *)
+               echo "${MACHINE}-qssl-qnx"
+               ;;
+       esac
+       exit 0
+       ;;
+
+    Paragon*:*:*:*)
+       echo "i860-intel-osf1"; exit 0
+       ;;
+
+    SunOS:5.*)
+       echo "${MACHINE}-sun-solaris2"; exit 0
+       ;;
+
+    SunOS:*)
+       echo "${MACHINE}-sun-sunos4"; exit 0
+       ;;
+
+    UNIX_System_V:4.*:*)
+       echo "${MACHINE}-whatever-sysv4"; exit 0
+       ;;
+
+    *:4*:R4*:m88k)
+       echo "${MACHINE}-whatever-sysv4"; exit 0
+       ;;
+
+    DYNIX/ptx:4*:*)
+       echo "${MACHINE}-whatever-sysv4"; exit 0
+       ;;
+
+    *:4.0:3.0:3[34]?? | *:4.0:3.0:3[34]??,*)
+       echo "i486-ncr-sysv4"; exit 0
+       ;;
+
+    ULTRIX:*)
+       echo "${MACHINE}-unknown-ultrix"; exit 0
+       ;;
+
+    SINIX*)
+       echo "${MACHINE}-sni-sysv4"; exit 0
+       ;;
+
+    machten:*)
+       echo "${MACHINE}-tenon-${SYSTEM}"; exit 0;
+       ;;
+
+    library:*)
+       echo "${MACHINE}-ncr-sysv4"; exit 0
+       ;;
+
+    ConvexOS:*:11.0:*)
+       echo "${MACHINE}-v11-${SYSTEM}"; exit 0;
+       ;;
+
+esac
+
+#
+# Ugg. These are all we can determine by what we know about
+# the output of uname. Be more creative:
+#
+
+# Do the Apollo stuff first. Here, we just simply assume
+# that the existance of the /usr/apollo directory is proof
+# enough
+if [ -d /usr/apollo ]; then
+    echo "whatever-apollo-whatever"
+    exit 0
+fi
+
+# Now NeXT
+ISNEXT=`hostinfo 2>/dev/null`
+case "$ISNEXT" in
+    *NeXT*)
+       echo "whatever-next-nextstep"; exit 0
+       ;;
+esac
+
+# At this point we gone through all the one's
+# we know of: Punt
+
+echo "${MACHINE}-whatever-${SYSTEM}|${RELEASE}|${VERSION}" 
+exit 0
diff --git a/APACHE_1_2_X/src/helpers/PrintPath b/APACHE_1_2_X/src/helpers/PrintPath
new file mode 100755 (executable)
index 0000000..9ec0e0c
--- /dev/null
@@ -0,0 +1,46 @@
+#!/bin/sh
+# Look for $1 somewhere in $PATH
+#  will print out the full pathname unless
+#  called with the '-s' option
+#
+# We do some funny stuff to check to see
+# if test/[] knows about -x
+#
+testfile="pp.t.$$"
+
+cat > $testfile <<ENDTEST
+#!/bin/sh
+if [ -x / ] || [ -x /bin ] || [ -x /bin/ls ]; then
+ exit 0
+fi
+exit 1
+ENDTEST
+
+if `/bin/sh $testfile 2>/dev/null`; then
+    test_exec_flag="-x"
+else
+    test_exec_flag="-r"
+fi
+rm -f $testfile
+
+if [ "x$1" = "x-s" ]; then
+    shift
+else
+    echo="yes"
+fi
+
+for path in `echo $PATH |
+ sed 's/^:/.:/
+      s/::/:.:/g
+      s/:$/:./
+      s/:/ /g' `
+do
+    if [ $test_exec_flag $path/$1 ] && [ ! -d $path/$1 ]; then
+        if [ "$echo" = "yes" ]; then
+           echo $path/$1
+       fi
+       exit 0
+    fi
+done
+exit 1
+
diff --git a/APACHE_1_2_X/src/include/alloc.h b/APACHE_1_2_X/src/include/alloc.h
new file mode 100644 (file)
index 0000000..858bf2c
--- /dev/null
@@ -0,0 +1,252 @@
+
+/* ====================================================================
+ * Copyright (c) 1995-1997 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, const array_header *src);
+array_header *append_arrays (pool *, const array_header *,
+                            const 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, const array_header *src);
+array_header *copy_array_hdr (pool *p, const 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, const table *);     
+void clear_table (table *);     
+char *table_get (const table *, const char *);
+void table_set (table *, const char *name, const char *val);
+void table_merge (table *, const char *name, const char *more_val);
+void table_unset (table *, const char *key);
+void table_add (table *, const char *name, const char *val);
+void table_do (int (*comp)(void *, const char *, const char *), void *rec,
+               const table *t, ...);
+
+table *overlay_tables (pool *p, const table *overlay, const table *base);     
+
+array_header *table_elts (table *);     
+
+#define is_empty_table(t) (((t) == NULL)||((t)->nelts == 0))
+
+/* 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 *));
+void run_cleanup (pool *p, void *data, void (*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 *, const char *name, const char *fmode);
+FILE *pfdopen(struct pool *, int fd, const char *fmode);
+int popenf(struct pool *, const char *name, int flg, int mode); 
+
+void note_cleanups_for_file (pool *, FILE *);
+void note_cleanups_for_fd (pool *, int);
+void kill_cleanups_for_fd (pool *p, int fd);
+
+regex_t *pregcomp (pool *p, const char *pattern, int cflags);
+void pregfree (pool *p, regex_t *reg);
+
+/* 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_err (pool *, void (*)(void *), void *,
+                enum kill_conditions, FILE **pipe_in, FILE **pipe_out,
+                 FILE **pipe_err);
+#define spawn_child(p,f,v,k,in,out) spawn_child_err(p,f,v,k,in,out,NULL)
+
+/* magic numbers --- min free bytes to consider a free pool block useable,
+ * and the min amount to allocate if we have to go to malloc() */
+
+#define BLOCK_MINFREE 4096
+#define BLOCK_MINALLOC 8192
+
+/* Finally, some accounting */
+
+long bytes_in_pool(pool *p);
+long bytes_in_free_blocks();
diff --git a/APACHE_1_2_X/src/include/ap_config.h b/APACHE_1_2_X/src/include/ap_config.h
new file mode 100644 (file)
index 0000000..fd7869c
--- /dev/null
@@ -0,0 +1,752 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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
+ */
+
+#if !defined(QNX) && !defined(MPE)
+#include <sys/param.h>
+#endif
+
+/* Define one of these according to your system. */
+#if defined(MPE)
+#include <sys/times.h>
+#define JMP_BUF sigjmp_buf
+#define NO_SETSID
+#define NO_KILLPG
+#define NO_WRITEV
+#define NEED_INITGROUPS
+#define NEED_STRCASECMP
+#define NEED_STRDUP
+#define NEED_STRNCASECMP
+extern void GETPRIVMODE();
+extern void GETUSERMODE();
+extern char *inet_ntoa();
+
+#elif defined(SUNOS4)
+#define HAVE_GMTOFF
+#define HAVE_SYS_RESOURCE_H
+#undef NO_KILLPG
+#undef NO_SETSID
+char *crypt(const char *pw, const char *salt);
+char *mktemp(char *template);
+#define JMP_BUF sigjmp_buf
+#define HAVE_MMAP
+#include <sys/time.h>     
+#define NEED_STRERROR
+typedef int rlim_t;
+#define memmove(a,b,c) bcopy(b,a,c)
+#define NO_LINGCLOSE
+
+#elif defined(SOLARIS2)
+#undef HAVE_GMTOFF
+#define NO_KILLPG
+#undef NO_SETSID
+#define HAVE_SYS_RESOURCE_H
+#define bzero(a,b) memset(a,0,b)
+#define JMP_BUF sigjmp_buf
+#define USE_FCNTL_SERIALIZED_ACCEPT
+#define HAVE_MMAP
+#define HAVE_CRYPT_H
+int gethostname(char *name, int namelen);
+
+#elif defined(IRIX)
+#undef HAVE_GMTOFF
+/* IRIX has killpg, but it's only in _BSD_COMPAT, so don't use it in case
+ * there's some weird conflict with non-BSD signals */
+#define NO_KILLPG
+#undef NO_SETSID
+#define JMP_BUF sigjmp_buf
+#define USE_FCNTL_SERIALIZED_ACCEPT
+#define HAVE_SHMGET
+#define HAVE_CRYPT_H
+#define NO_LONG_DOUBLE
+#define HAVE_BSTRING_H
+#define NO_LINGCLOSE
+
+#elif defined(HIUX)
+#define HAVE_SYS_RESOURCE_H
+#undef HAVE_GMTOFF
+#define NO_KILLPG
+#undef NO_SETSID
+#ifndef _HIUX_SOURCE
+#define _HIUX_SOURCE
+#endif
+#define JMP_BUF sigjmp_buf
+#define HAVE_SHMGET
+#define SELECT_NEEDS_CAST
+
+#elif defined(HPUX) || defined(HPUX10)
+#define HAVE_SYS_RESOURCE_H
+#undef HAVE_GMTOFF
+#define NO_KILLPG
+#undef NO_SETSID
+#ifndef _HPUX_SOURCE
+#define _HPUX_SOURCE
+#endif
+#define JMP_BUF sigjmp_buf
+#define HAVE_SHMGET
+#ifndef HPUX10
+#define SELECT_NEEDS_CAST
+typedef int rlim_t;
+#endif
+
+#elif defined(AIX)
+#undef HAVE_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+#define HAVE_SYS_SELECT_H
+#define JMP_BUF sigjmp_buf
+#ifndef __ps2__
+#define HAVE_MMAP
+#define DEFAULT_GROUP "nobody"
+#endif
+#define DEFAULT_USER "nobody"
+typedef int rlim_t;
+
+#elif defined(ULTRIX)
+#define HAVE_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 HAVE_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+#define JMP_BUF sigjmp_buf
+#define HAVE_MMAP
+#define HAVE_CRYPT_H
+#define NO_LONG_DOUBLE
+
+#elif defined(PARAGON)
+#define HAVE_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+#define JMP_BUF sigjmp_buf
+#define HAVE_MMAP
+#define HAVE_CRYPT_H
+#define NO_LONG_DOUBLE
+typedef int rlim_t;
+
+#elif defined(SEQUENT)
+#define HAVE_GMTOFF
+#undef NO_KILLPG
+#define NO_SETSID
+#define NEED_STRDUP
+#define tolower(c) (isupper(c) ? tolower(c) : c)
+
+#elif defined(NEXT)
+typedef unsigned short mode_t;
+#define HAVE_GMTOFF
+#undef NO_KILLPG
+#define NO_SETSID
+#define NEED_STRDUP
+#define NO_LINGCLOSE
+#define NO_UNISTD_H
+#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
+#ifndef S_IWGRP
+#define S_IWGRP        000020
+#endif
+#ifndef S_IWOTH
+#define S_IWOTH 000002
+#ifndef rlim_t
+typedef int rlim_t;
+#endif
+typedef u_long  n_long;
+#endif
+
+#define STDIN_FILENO  0
+#define STDOUT_FILENO 1
+#define STDERR_FILENO 2
+#define waitpid(a,b,c) wait4((a) == -1 ? 0 : (a),(union wait *)(b),c,NULL)
+typedef int pid_t;
+#define JMP_BUF jmp_buf
+#define USE_LONGJMP
+#define NO_USE_SIGACTION
+
+#elif defined(LINUX)
+#if LINUX > 1
+#define HAVE_SHMGET
+#define HAVE_SYS_RESOURCE_H
+typedef int rlim_t;
+#endif
+#define USE_FCNTL_SERIALIZED_ACCEPT
+#undef HAVE_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+#undef NEED_STRDUP
+#define JMP_BUF sigjmp_buf
+#include <sys/time.h>     
+
+#elif defined(SCO)
+#undef HAVE_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+#define NEED_INITGROUPS
+#define NO_WRITEV
+#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. */
+#include <sys/time.h>     
+
+#elif defined(SCO5)
+
+#define JMP_BUF sigjmp_buf
+#define SIGURG SIGUSR1
+#define HAVE_SYS_SELECT_H
+#define USE_FCNTL_SERIALIZED_ACCEPT
+#define HAVE_MMAP
+#define HAVE_SYS_RESOURCE_H
+#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 HAVE_GMTOFF
+#define NEED_STRDUP
+
+#elif defined(AUX)
+/* These are to let -Wall compile more cleanly */
+extern int strcasecmp(const char *, const char *);
+extern int strncasecmp(const char *,const char *,unsigned);
+extern int set42sig(), getopt(), getpeername(), bzero();
+extern int listen(), bind(), socket(), getsockname();
+extern int accept(), gethostname(), connect(), lstat();
+extern int select(), killpg(), shutdown();
+extern int initgroups(), setsockopt();
+extern char *shmat();
+extern int  shmctl();
+extern int  shmget();
+extern char *sbrk();
+extern char *crypt();
+#include <sys/time.h>
+#undef HAVE_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+#define NEED_STRDUP
+#define JMP_BUF sigjmp_buf
+/* fcntl() locking is expensive with NFS */
+#undef USE_FLOCK_SERIALIZED_ACCEPT
+#define HAVE_SHMGET
+#define MOVEBREAK              0x4000000
+/*
+ * NOTE: If when you run Apache under A/UX and you get a warning
+ * that httpd couldn't move break, then the above value for
+ * MOVEBREAK (64megs) is too large for your setup. Try reducing
+ * to 0x2000000 which is still PLENTY of space. I doubt if
+ * even on heavy systems sbrk() would be called at all...
+ */
+#define NO_LINGCLOSE
+
+#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
+/* A lot of SVR4 systems need this */
+#define USE_FCNTL_SERIALIZED_ACCEPT
+
+#elif defined(UW)
+#define NO_LINGCLOSE
+#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 HAVE_RESOURCE
+#define HAVE_MMAP
+#define HAVE_SHMGET
+#define HAVE_CRYPT_H
+#define HAVE_SYS_SELECT_H
+#define HAVE_SYS_RESOURCE_H
+#include <sys/time.h>
+#define _POSIX_SOURCE
+
+#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
+/* A lot of SVR4 systems need this */
+#define USE_FCNTL_SERIALIZED_ACCEPT
+
+#elif defined(__NetBSD__) || defined(__OpenBSD__)
+#define HAVE_SYS_RESOURCE_H
+#define HAVE_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+#define JMP_BUF sigjmp_buf
+#define DEFAULT_USER "nobody"
+#define DEFAULT_GROUP "nogroup"
+
+#elif defined(UTS21)
+#undef HAVE_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 HAVE_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+
+#elif defined(__FreeBSD__) || defined(__bsdi__)
+#if defined(__FreeBSD__)
+#include <osreldate.h>
+#endif
+#define HAVE_SYS_RESOURCE_H
+#define HAVE_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+#define JMP_BUF sigjmp_buf
+#define HAVE_MMAP
+#define DEFAULT_USER "nobody"
+#define DEFAULT_GROUP "nogroup"
+#if defined(__bsdi__) || \
+(defined(__FreeBSD_version) && (__FreeBSD_version < 220000))
+typedef quad_t rlim_t;
+#endif
+
+#elif defined(QNX)
+#ifndef crypt
+char *crypt(const char *pw, const char *salt);
+#endif
+#ifndef initgroups
+int initgroups (char *, int);     
+#endif
+#ifndef strncasecmp
+#define strncasecmp strnicmp
+#endif
+#undef NO_KILLPG
+#undef NO_SETSID
+#define NEED_INITGROUPS
+#define NEED_SELECT_H
+#define NEED_PROCESS_H
+#define HAVE_SYS_SELECT_H
+#include <unix.h>
+#define JMP_BUF sigjmp_buf
+
+#elif defined(LYNXOS)
+#undef NO_KILLPG
+#undef NO_SETSID
+#define NEED_STRCASECMP
+#define NEED_STRNCASECMP
+#define NEED_INITGROUPS
+#define JMP_BUF jmp_buf
+
+#elif defined(UXPDS)
+#undef NEED_STRCASECMP
+#undef NEED_STRNCASECMP
+#undef NEED_STRDUP
+#undef HAVE_GMTOFF
+#define NO_KILLPG
+#undef NO_SETSID
+#define HAVE_RESOURCE 1
+#define bzero(a,b) memset(a,0,b)
+#define JMP_BUF sigjmp_buf
+#define USE_FCNTL_SERIALIZED_ACCEPT
+#define HAVE_MMAP
+#define HAVE_CRYPT_H
+#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
+#include <sys/time.h>     
+#define MAXSOCKETS 4096
+#define HAVE_MMAP
+    
+#elif defined(__MACHTEN__)
+typedef int rlim_t;
+#define JMP_BUF sigjmp_buf
+#undef NO_KILLPG
+#define NO_SETSID
+#define HAVE_GMTOFF
+#ifndef __MACHTEN_PPC__
+#ifndef __MACHTEN_68K__
+#define __MACHTEN_68K__
+#endif
+#define USE_FLOCK_SERIALIZED_ACCEPT
+#define NO_USE_SIGACTION
+#define USE_LONGJMP
+#undef NEED_STRDUP
+#else
+#define HAVE_SHMGET
+#define USE_FCNTL_SERIALIZED_ACCEPT
+#endif
+
+/* Convex OS v11 */
+#elif defined(CONVEXOS11)
+#define NO_TIMEZONE
+#include <stdio.h>
+#include <sys/types.h>
+#define JMP_BUF jmp_buf
+typedef int rlim_t;
+
+#elif defined(ISC)
+#include <net/errno.h>     
+#define NO_KILLPG
+#undef NO_SETSID
+#define HAVE_SHMGET
+#define SIGURG SIGUSR1
+#define JMP_BUF sigjmp_buf
+#define USE_FCNTL_SERIALIZED_ACCEPT
+
+/* Unknown system - Edit these to match */
+#else
+#ifdef BSD
+#define HAVE_GMTOFF
+#else
+#undef HAVE_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_SYS_RESOURCE_H
+#ifdef BSD
+#define HAVE_SYS_RESOURCE_H
+#endif
+#endif /* HAVE_SYS_RESOURCE_H */
+
+/*
+ * 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>
+#include <stdarg.h>
+/*
+ * We use snprintf() to avoid overflows, but we include
+ * our own version (ap_snprintf). Allow for people to use their
+ * snprintf() if they want
+ */
+#ifdef HAVE_SNPRINTF
+#define ap_snprintf     snprintf
+#define ap_vsnprintf    vsnprintf
+#else
+int ap_snprintf(char *buf, size_t len, const char *format,...);
+int ap_vsnprintf(char *buf, size_t len, const char *format, va_list ap);
+#endif
+
+#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>
+#ifndef MPE
+#include <sys/file.h>
+#endif
+#include <sys/socket.h>
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#include <ctype.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <sys/ioctl.h>
+#ifndef MPE
+#include <arpa/inet.h>  /* for inet_ntoa */
+#endif
+#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>
+#if !defined(QNX) && !defined(CONVEXOS11) && !defined(NEXT)
+#include <memory.h>
+#endif
+#ifdef NEED_PROCESS_H
+#include <process.h>
+#endif
+
+#include <regex.h>
+
+#ifdef HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#ifdef SUNOS4
+int getrlimit( int, struct rlimit *);
+int setrlimit( int, struct rlimit *);
+#endif
+#endif
+#ifdef HAVE_MMAP
+#ifndef __EMX__
+/* This file is not needed for OS/2 */
+#include <sys/mman.h>
+#endif
+#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
+#ifndef __EMX__
+/* Don't define this for OS/2 */
+#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
+#endif
+#endif
+
+#ifndef INADDR_NONE
+#define INADDR_NONE ((unsigned long) -1)
+#endif
+
+/*
+ * Replace signal function with sigaction equivalent
+ */
+#ifndef NO_USE_SIGACTION
+typedef void Sigfunc(int);
+
+#if defined(SIG_IGN) && !defined(SIG_ERR)
+#define SIG_ERR ((Sigfunc *)-1)
+#endif
+
+/*
+ * For some strange reason, QNX defines signal to signal. Eliminate it.
+ */
+#ifdef signal
+#undef signal
+#endif
+#define signal(s,f)    ap_signal(s,f)
+Sigfunc *signal(int signo, Sigfunc *func);
+#endif
+
+#include <setjmp.h>
+
+#if defined(USE_LONGJMP)
+#define ap_longjmp(x, y)        longjmp((x), (y))
+#define ap_setjmp(x)            setjmp(x)
+#else
+#define ap_longjmp(x, y)        siglongjmp((x), (y))
+#define ap_setjmp(x)            sigsetjmp((x), 1)
+#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);
+#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 *);
+     
+long vfprintf (FILE *, char *, va_list);
+     
+#endif
diff --git a/APACHE_1_2_X/src/include/buff.h b/APACHE_1_2_X/src/include/buff.h
new file mode 100644 (file)
index 0000000..593b68b
--- /dev/null
@@ -0,0 +1,137 @@
+/* ====================================================================
+ * Copyright (c) 1996,1997 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)
+/* Use chunked writing */
+#define B_CHUNK (64)
+/* bflush() if a read would block */
+#define B_SAFEREAD (128)
+
+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 outchunk;         /* location of chunk header when chunking */
+    int outchunk_header_size; /* how long the header is */
+    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 bsetflag(BUFF *fb, int flag, int value);
+extern int bclose(BUFF *fb);
+
+#define bgetflag(fb, flag)     ((fb)->flags & (flag))
+
+/* 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 blookc(char *buff, 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/APACHE_1_2_X/src/include/conf.h b/APACHE_1_2_X/src/include/conf.h
new file mode 100644 (file)
index 0000000..fd7869c
--- /dev/null
@@ -0,0 +1,752 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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
+ */
+
+#if !defined(QNX) && !defined(MPE)
+#include <sys/param.h>
+#endif
+
+/* Define one of these according to your system. */
+#if defined(MPE)
+#include <sys/times.h>
+#define JMP_BUF sigjmp_buf
+#define NO_SETSID
+#define NO_KILLPG
+#define NO_WRITEV
+#define NEED_INITGROUPS
+#define NEED_STRCASECMP
+#define NEED_STRDUP
+#define NEED_STRNCASECMP
+extern void GETPRIVMODE();
+extern void GETUSERMODE();
+extern char *inet_ntoa();
+
+#elif defined(SUNOS4)
+#define HAVE_GMTOFF
+#define HAVE_SYS_RESOURCE_H
+#undef NO_KILLPG
+#undef NO_SETSID
+char *crypt(const char *pw, const char *salt);
+char *mktemp(char *template);
+#define JMP_BUF sigjmp_buf
+#define HAVE_MMAP
+#include <sys/time.h>     
+#define NEED_STRERROR
+typedef int rlim_t;
+#define memmove(a,b,c) bcopy(b,a,c)
+#define NO_LINGCLOSE
+
+#elif defined(SOLARIS2)
+#undef HAVE_GMTOFF
+#define NO_KILLPG
+#undef NO_SETSID
+#define HAVE_SYS_RESOURCE_H
+#define bzero(a,b) memset(a,0,b)
+#define JMP_BUF sigjmp_buf
+#define USE_FCNTL_SERIALIZED_ACCEPT
+#define HAVE_MMAP
+#define HAVE_CRYPT_H
+int gethostname(char *name, int namelen);
+
+#elif defined(IRIX)
+#undef HAVE_GMTOFF
+/* IRIX has killpg, but it's only in _BSD_COMPAT, so don't use it in case
+ * there's some weird conflict with non-BSD signals */
+#define NO_KILLPG
+#undef NO_SETSID
+#define JMP_BUF sigjmp_buf
+#define USE_FCNTL_SERIALIZED_ACCEPT
+#define HAVE_SHMGET
+#define HAVE_CRYPT_H
+#define NO_LONG_DOUBLE
+#define HAVE_BSTRING_H
+#define NO_LINGCLOSE
+
+#elif defined(HIUX)
+#define HAVE_SYS_RESOURCE_H
+#undef HAVE_GMTOFF
+#define NO_KILLPG
+#undef NO_SETSID
+#ifndef _HIUX_SOURCE
+#define _HIUX_SOURCE
+#endif
+#define JMP_BUF sigjmp_buf
+#define HAVE_SHMGET
+#define SELECT_NEEDS_CAST
+
+#elif defined(HPUX) || defined(HPUX10)
+#define HAVE_SYS_RESOURCE_H
+#undef HAVE_GMTOFF
+#define NO_KILLPG
+#undef NO_SETSID
+#ifndef _HPUX_SOURCE
+#define _HPUX_SOURCE
+#endif
+#define JMP_BUF sigjmp_buf
+#define HAVE_SHMGET
+#ifndef HPUX10
+#define SELECT_NEEDS_CAST
+typedef int rlim_t;
+#endif
+
+#elif defined(AIX)
+#undef HAVE_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+#define HAVE_SYS_SELECT_H
+#define JMP_BUF sigjmp_buf
+#ifndef __ps2__
+#define HAVE_MMAP
+#define DEFAULT_GROUP "nobody"
+#endif
+#define DEFAULT_USER "nobody"
+typedef int rlim_t;
+
+#elif defined(ULTRIX)
+#define HAVE_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 HAVE_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+#define JMP_BUF sigjmp_buf
+#define HAVE_MMAP
+#define HAVE_CRYPT_H
+#define NO_LONG_DOUBLE
+
+#elif defined(PARAGON)
+#define HAVE_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+#define JMP_BUF sigjmp_buf
+#define HAVE_MMAP
+#define HAVE_CRYPT_H
+#define NO_LONG_DOUBLE
+typedef int rlim_t;
+
+#elif defined(SEQUENT)
+#define HAVE_GMTOFF
+#undef NO_KILLPG
+#define NO_SETSID
+#define NEED_STRDUP
+#define tolower(c) (isupper(c) ? tolower(c) : c)
+
+#elif defined(NEXT)
+typedef unsigned short mode_t;
+#define HAVE_GMTOFF
+#undef NO_KILLPG
+#define NO_SETSID
+#define NEED_STRDUP
+#define NO_LINGCLOSE
+#define NO_UNISTD_H
+#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
+#ifndef S_IWGRP
+#define S_IWGRP        000020
+#endif
+#ifndef S_IWOTH
+#define S_IWOTH 000002
+#ifndef rlim_t
+typedef int rlim_t;
+#endif
+typedef u_long  n_long;
+#endif
+
+#define STDIN_FILENO  0
+#define STDOUT_FILENO 1
+#define STDERR_FILENO 2
+#define waitpid(a,b,c) wait4((a) == -1 ? 0 : (a),(union wait *)(b),c,NULL)
+typedef int pid_t;
+#define JMP_BUF jmp_buf
+#define USE_LONGJMP
+#define NO_USE_SIGACTION
+
+#elif defined(LINUX)
+#if LINUX > 1
+#define HAVE_SHMGET
+#define HAVE_SYS_RESOURCE_H
+typedef int rlim_t;
+#endif
+#define USE_FCNTL_SERIALIZED_ACCEPT
+#undef HAVE_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+#undef NEED_STRDUP
+#define JMP_BUF sigjmp_buf
+#include <sys/time.h>     
+
+#elif defined(SCO)
+#undef HAVE_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+#define NEED_INITGROUPS
+#define NO_WRITEV
+#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. */
+#include <sys/time.h>     
+
+#elif defined(SCO5)
+
+#define JMP_BUF sigjmp_buf
+#define SIGURG SIGUSR1
+#define HAVE_SYS_SELECT_H
+#define USE_FCNTL_SERIALIZED_ACCEPT
+#define HAVE_MMAP
+#define HAVE_SYS_RESOURCE_H
+#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 HAVE_GMTOFF
+#define NEED_STRDUP
+
+#elif defined(AUX)
+/* These are to let -Wall compile more cleanly */
+extern int strcasecmp(const char *, const char *);
+extern int strncasecmp(const char *,const char *,unsigned);
+extern int set42sig(), getopt(), getpeername(), bzero();
+extern int listen(), bind(), socket(), getsockname();
+extern int accept(), gethostname(), connect(), lstat();
+extern int select(), killpg(), shutdown();
+extern int initgroups(), setsockopt();
+extern char *shmat();
+extern int  shmctl();
+extern int  shmget();
+extern char *sbrk();
+extern char *crypt();
+#include <sys/time.h>
+#undef HAVE_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+#define NEED_STRDUP
+#define JMP_BUF sigjmp_buf
+/* fcntl() locking is expensive with NFS */
+#undef USE_FLOCK_SERIALIZED_ACCEPT
+#define HAVE_SHMGET
+#define MOVEBREAK              0x4000000
+/*
+ * NOTE: If when you run Apache under A/UX and you get a warning
+ * that httpd couldn't move break, then the above value for
+ * MOVEBREAK (64megs) is too large for your setup. Try reducing
+ * to 0x2000000 which is still PLENTY of space. I doubt if
+ * even on heavy systems sbrk() would be called at all...
+ */
+#define NO_LINGCLOSE
+
+#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
+/* A lot of SVR4 systems need this */
+#define USE_FCNTL_SERIALIZED_ACCEPT
+
+#elif defined(UW)
+#define NO_LINGCLOSE
+#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 HAVE_RESOURCE
+#define HAVE_MMAP
+#define HAVE_SHMGET
+#define HAVE_CRYPT_H
+#define HAVE_SYS_SELECT_H
+#define HAVE_SYS_RESOURCE_H
+#include <sys/time.h>
+#define _POSIX_SOURCE
+
+#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
+/* A lot of SVR4 systems need this */
+#define USE_FCNTL_SERIALIZED_ACCEPT
+
+#elif defined(__NetBSD__) || defined(__OpenBSD__)
+#define HAVE_SYS_RESOURCE_H
+#define HAVE_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+#define JMP_BUF sigjmp_buf
+#define DEFAULT_USER "nobody"
+#define DEFAULT_GROUP "nogroup"
+
+#elif defined(UTS21)
+#undef HAVE_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 HAVE_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+
+#elif defined(__FreeBSD__) || defined(__bsdi__)
+#if defined(__FreeBSD__)
+#include <osreldate.h>
+#endif
+#define HAVE_SYS_RESOURCE_H
+#define HAVE_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+#define JMP_BUF sigjmp_buf
+#define HAVE_MMAP
+#define DEFAULT_USER "nobody"
+#define DEFAULT_GROUP "nogroup"
+#if defined(__bsdi__) || \
+(defined(__FreeBSD_version) && (__FreeBSD_version < 220000))
+typedef quad_t rlim_t;
+#endif
+
+#elif defined(QNX)
+#ifndef crypt
+char *crypt(const char *pw, const char *salt);
+#endif
+#ifndef initgroups
+int initgroups (char *, int);     
+#endif
+#ifndef strncasecmp
+#define strncasecmp strnicmp
+#endif
+#undef NO_KILLPG
+#undef NO_SETSID
+#define NEED_INITGROUPS
+#define NEED_SELECT_H
+#define NEED_PROCESS_H
+#define HAVE_SYS_SELECT_H
+#include <unix.h>
+#define JMP_BUF sigjmp_buf
+
+#elif defined(LYNXOS)
+#undef NO_KILLPG
+#undef NO_SETSID
+#define NEED_STRCASECMP
+#define NEED_STRNCASECMP
+#define NEED_INITGROUPS
+#define JMP_BUF jmp_buf
+
+#elif defined(UXPDS)
+#undef NEED_STRCASECMP
+#undef NEED_STRNCASECMP
+#undef NEED_STRDUP
+#undef HAVE_GMTOFF
+#define NO_KILLPG
+#undef NO_SETSID
+#define HAVE_RESOURCE 1
+#define bzero(a,b) memset(a,0,b)
+#define JMP_BUF sigjmp_buf
+#define USE_FCNTL_SERIALIZED_ACCEPT
+#define HAVE_MMAP
+#define HAVE_CRYPT_H
+#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
+#include <sys/time.h>     
+#define MAXSOCKETS 4096
+#define HAVE_MMAP
+    
+#elif defined(__MACHTEN__)
+typedef int rlim_t;
+#define JMP_BUF sigjmp_buf
+#undef NO_KILLPG
+#define NO_SETSID
+#define HAVE_GMTOFF
+#ifndef __MACHTEN_PPC__
+#ifndef __MACHTEN_68K__
+#define __MACHTEN_68K__
+#endif
+#define USE_FLOCK_SERIALIZED_ACCEPT
+#define NO_USE_SIGACTION
+#define USE_LONGJMP
+#undef NEED_STRDUP
+#else
+#define HAVE_SHMGET
+#define USE_FCNTL_SERIALIZED_ACCEPT
+#endif
+
+/* Convex OS v11 */
+#elif defined(CONVEXOS11)
+#define NO_TIMEZONE
+#include <stdio.h>
+#include <sys/types.h>
+#define JMP_BUF jmp_buf
+typedef int rlim_t;
+
+#elif defined(ISC)
+#include <net/errno.h>     
+#define NO_KILLPG
+#undef NO_SETSID
+#define HAVE_SHMGET
+#define SIGURG SIGUSR1
+#define JMP_BUF sigjmp_buf
+#define USE_FCNTL_SERIALIZED_ACCEPT
+
+/* Unknown system - Edit these to match */
+#else
+#ifdef BSD
+#define HAVE_GMTOFF
+#else
+#undef HAVE_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_SYS_RESOURCE_H
+#ifdef BSD
+#define HAVE_SYS_RESOURCE_H
+#endif
+#endif /* HAVE_SYS_RESOURCE_H */
+
+/*
+ * 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>
+#include <stdarg.h>
+/*
+ * We use snprintf() to avoid overflows, but we include
+ * our own version (ap_snprintf). Allow for people to use their
+ * snprintf() if they want
+ */
+#ifdef HAVE_SNPRINTF
+#define ap_snprintf     snprintf
+#define ap_vsnprintf    vsnprintf
+#else
+int ap_snprintf(char *buf, size_t len, const char *format,...);
+int ap_vsnprintf(char *buf, size_t len, const char *format, va_list ap);
+#endif
+
+#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>
+#ifndef MPE
+#include <sys/file.h>
+#endif
+#include <sys/socket.h>
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#include <ctype.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <sys/ioctl.h>
+#ifndef MPE
+#include <arpa/inet.h>  /* for inet_ntoa */
+#endif
+#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>
+#if !defined(QNX) && !defined(CONVEXOS11) && !defined(NEXT)
+#include <memory.h>
+#endif
+#ifdef NEED_PROCESS_H
+#include <process.h>
+#endif
+
+#include <regex.h>
+
+#ifdef HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#ifdef SUNOS4
+int getrlimit( int, struct rlimit *);
+int setrlimit( int, struct rlimit *);
+#endif
+#endif
+#ifdef HAVE_MMAP
+#ifndef __EMX__
+/* This file is not needed for OS/2 */
+#include <sys/mman.h>
+#endif
+#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
+#ifndef __EMX__
+/* Don't define this for OS/2 */
+#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
+#endif
+#endif
+
+#ifndef INADDR_NONE
+#define INADDR_NONE ((unsigned long) -1)
+#endif
+
+/*
+ * Replace signal function with sigaction equivalent
+ */
+#ifndef NO_USE_SIGACTION
+typedef void Sigfunc(int);
+
+#if defined(SIG_IGN) && !defined(SIG_ERR)
+#define SIG_ERR ((Sigfunc *)-1)
+#endif
+
+/*
+ * For some strange reason, QNX defines signal to signal. Eliminate it.
+ */
+#ifdef signal
+#undef signal
+#endif
+#define signal(s,f)    ap_signal(s,f)
+Sigfunc *signal(int signo, Sigfunc *func);
+#endif
+
+#include <setjmp.h>
+
+#if defined(USE_LONGJMP)
+#define ap_longjmp(x, y)        longjmp((x), (y))
+#define ap_setjmp(x)            setjmp(x)
+#else
+#define ap_longjmp(x, y)        siglongjmp((x), (y))
+#define ap_setjmp(x)            sigsetjmp((x), 1)
+#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);
+#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 *);
+     
+long vfprintf (FILE *, char *, va_list);
+     
+#endif
diff --git a/APACHE_1_2_X/src/include/explain.h b/APACHE_1_2_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/APACHE_1_2_X/src/include/hsregex.h b/APACHE_1_2_X/src/include/hsregex.h
new file mode 100644 (file)
index 0000000..dde954d
--- /dev/null
@@ -0,0 +1,73 @@
+#ifndef _REGEX_H_
+#define        _REGEX_H_       /* never again */
+/* ========= begin header generated by ./mkh ========= */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* === regex2.h === */
+typedef off_t regoff_t;
+typedef struct {
+       int re_magic;
+       size_t re_nsub;         /* number of parenthesized subexpressions */
+       const char *re_endp;    /* end pointer for REG_PEND */
+       struct re_guts *re_g;   /* none of your business :-) */
+} regex_t;
+typedef struct {
+       regoff_t rm_so;         /* start of match */
+       regoff_t rm_eo;         /* end of match */
+} regmatch_t;
+
+
+/* === regcomp.c === */
+extern int regcomp(regex_t *, const char *, int);
+#define        REG_BASIC       0000
+#define        REG_EXTENDED    0001
+#define        REG_ICASE       0002
+#define        REG_NOSUB       0004
+#define        REG_NEWLINE     0010
+#define        REG_NOSPEC      0020
+#define        REG_PEND        0040
+#define        REG_DUMP        0200
+
+
+/* === regerror.c === */
+#define        REG_NOMATCH      1
+#define        REG_BADPAT       2
+#define        REG_ECOLLATE     3
+#define        REG_ECTYPE       4
+#define        REG_EESCAPE      5
+#define        REG_ESUBREG      6
+#define        REG_EBRACK       7
+#define        REG_EPAREN       8
+#define        REG_EBRACE       9
+#define        REG_BADBR       10
+#define        REG_ERANGE      11
+#define        REG_ESPACE      12
+#define        REG_BADRPT      13
+#define        REG_EMPTY       14
+#define        REG_ASSERT      15
+#define        REG_INVARG      16
+#define        REG_ATOI        255     /* convert name to number (!) */
+#define        REG_ITOA        0400    /* convert number to name (!) */
+extern size_t regerror(int, const regex_t *, char *, size_t);
+
+
+/* === regexec.c === */
+extern int regexec(const regex_t *, const char *, size_t, regmatch_t [], int);
+#define        REG_NOTBOL      00001
+#define        REG_NOTEOL      00002
+#define        REG_STARTEND    00004
+#define        REG_TRACE       00400   /* tracing of execution */
+#define        REG_LARGE       01000   /* force large representation */
+#define        REG_BACKR       02000   /* force use of backref code */
+
+
+/* === regfree.c === */
+extern void regfree(regex_t *);
+
+#ifdef __cplusplus
+}
+#endif
+/* ========= end header generated by ./mkh ========= */
+#endif
diff --git a/APACHE_1_2_X/src/include/http_conf_globals.h b/APACHE_1_2_X/src/include/http_conf_globals.h
new file mode 100644 (file)
index 0000000..0596ab4
--- /dev/null
@@ -0,0 +1,85 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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;
+#ifdef MULTIPLE_GROUPS
+extern gid_t group_id_list[NGROUPS_MAX];
+#endif
+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 int suexec_enabled;
+
+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/APACHE_1_2_X/src/include/http_config.h b/APACHE_1_2_X/src/include/http_config.h
new file mode 100644 (file)
index 0000000..148ab69
--- /dev/null
@@ -0,0 +1,297 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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> */
+  TAKE12,                      /* one or two arguments */
+  TAKE3,                       /* three arguments only */
+  TAKE23,                      /* two or three arguments */
+  TAKE123,                     /* one, two or three arguments */
+  TAKE13                       /* one or three arguments */
+};
+
+typedef struct command_struct {
+  char *name;                  /* Name of this command */
+  const 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;
+
+/* The allowed locations for a configuration directive are the union of
+ * those indicated by each set bit in the req_override mask.
+ *
+ * (req_override & RSRC_CONF)   => *.conf outside <Directory> or <Location>
+ * (req_override & ACCESS_CONF) => *.conf inside <Directory> or <Location>
+ * (req_override & OR_AUTHCFG)  => *.conf inside <Directory> or <Location>
+ *                                 and .htaccess when AllowOverride AuthConfig
+ * (req_override & OR_LIMIT)    => *.conf inside <Directory> or <Location>
+ *                                 and .htaccess when AllowOverride Limit
+ * (req_override & OR_OPTIONS)  => *.conf anywhere
+ *                                 and .htaccess when AllowOverride Options
+ * (req_override & OR_FILEINFO) => *.conf anywhere
+ *                                 and .htaccess when AllowOverride FileInfo
+ * (req_override & OR_INDEXES)  => *.conf anywhere
+ *                                 and .htaccess when AllowOverride Indexes
+ */
+#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
+#define RSRC_CONF 128
+#define OR_ALL (OR_LIMIT|OR_OPTIONS|OR_FILEINFO|OR_AUTHCFG|OR_INDEXES)
+
+/* This can be returned by a function if they don't wish to handle
+ * a command. Make it something not likely someone will actually use
+ * as an error code.
+ */
+
+#define DECLINE_CMD "\a\b"
+
+/*
+ * 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.
+                                */
+    const command_rec *cmd;    /* configuration command */
+} cmd_parms;
+
+/* This structure records the existence of handlers in a module... */
+
+typedef struct {
+    char *content_type;
+    int (*handler) (request_rec *);
+} 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.
+                                */
+
+    const char *name;
+
+    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 *);
+    int (*header_parser)(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 19970526
+#define STANDARD_MODULE_STUFF MODULE_MAGIC_NUMBER, -1, __FILE__, 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... */
+
+const char *set_string_slot (cmd_parms *, char *, char *);
+const char *set_flag_slot (cmd_parms *, char *, int);
+
+/* 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);
+int add_named_module (const char *name);
+void clear_module_list ();
+const char *find_module_name (module *m);
+module *find_linked_module (const char *name);
+
+#ifdef CORE_PRIVATE
+
+/* For http_main.c... */
+
+server_rec *read_config (pool *conf_pool, pool *temp_pool, char *config_name);
+void setup_prelinked_modules();
+void show_directives();
+void show_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);
+const char *srm_command_loop (cmd_parms *parms, void *config);
+
+server_rec *init_virtual_host (pool *p, const char *hostname, server_rec *main_server);
+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);
+int header_parse (request_rec *);
+
+#endif
diff --git a/APACHE_1_2_X/src/include/http_core.h b/APACHE_1_2_X/src/include/http_core.h
new file mode 100644 (file)
index 0000000..8454b81
--- /dev/null
@@ -0,0 +1,205 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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)
+#define REMOTE_NOLOOKUP (2)
+
+#define SATISFY_ALL 0
+#define SATISFY_ANY 1
+#define SATISFY_NOSPEC 2
+
+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 *);     
+int satisfies (request_rec *r);
+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;
+    /* since is_matchexp(conf->d) was being called so frequently in
+     * directory_walk() and its relatives, this field was created and
+     * is set to the result of that call.
+     */
+    int d_is_matchexp;
+
+    allow_options_t opts;
+    allow_options_t opts_add;
+    allow_options_t opts_remove;
+    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... */
+    
+    int satisfy;
+    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.
+     * if response_code_strings is NULL then there are none in the config,
+     * if it's not null then it's allocated to sizeof(char*)*RESPONSE_CODES.
+     * This lets us do quick merges in merge_core_dir_configs().
+     */
+  
+    char **response_code_strings;
+
+    /* Hostname resolution etc */
+    int hostname_lookups;
+    int do_rfc1413;   /* See if client is advertising a username? */
+
+    /* System Resource Control */
+#ifdef RLIMIT_CPU
+    struct rlimit *limit_cpu;
+#endif
+#if defined (RLIMIT_DATA) || defined (RLIMIT_VMEM)
+    struct rlimit *limit_mem;
+#endif
+#ifdef RLIMIT_NPROC
+    struct rlimit *limit_nproc;
+#endif
+
+    /* Access control */
+    array_header *sec;
+    regex_t *r;
+
+} 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/APACHE_1_2_X/src/include/http_log.h b/APACHE_1_2_X/src/include/http_log.h
new file mode 100644 (file)
index 0000000..e30324d
--- /dev/null
@@ -0,0 +1,62 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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(const char *reason, const char *fname, request_rec *r);
+
diff --git a/APACHE_1_2_X/src/include/http_main.h b/APACHE_1_2_X/src/include/http_main.h
new file mode 100644 (file)
index 0000000..7d3c2f5
--- /dev/null
@@ -0,0 +1,99 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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 keepalive_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/APACHE_1_2_X/src/include/http_protocol.h b/APACHE_1_2_X/src/include/http_protocol.h
new file mode 100644 (file)
index 0000000..85687b4
--- /dev/null
@@ -0,0 +1,190 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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 a single HTTP header field */
+
+int send_header_field (request_rec *r, const char *fieldname,
+                                       const char *fieldval);
+
+/* Send the Status-Line and header fields for HTTP response */
+
+void send_http_header (request_rec *l);     
+
+/* Send the response to special method requests */
+
+int send_http_trace (request_rec *r);
+int send_http_options (request_rec *r);
+
+/* Finish up stuff after a request */
+
+void finalize_request_protocol (request_rec *r);
+     
+/* 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);
+
+/* 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);
+long send_fd_length(FILE *f, request_rec *r, long length);
+     
+/* Hmmm... could macrofy these for now, and maybe forever, though the
+ * definitions of the macros would get a whole lot hairier.
+ */
+     
+int rputc (int c, request_rec *r);     
+int rputs(const char *str, request_rec *r);
+int rwrite(const void *buf, int nbyte, request_rec *r);
+int rvputs(request_rec *r, ...);
+int rprintf(request_rec *r,const char *fmt,...);
+int rflush(request_rec *r);
+     
+/*
+ * 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) */
+     
+int setup_client_block (request_rec *r, int read_policy);
+int should_client_block (request_rec *r);
+long get_client_block (request_rec *r, char *buffer, int bufsiz);
+
+/* Sending a byterange */
+
+int set_byterange (request_rec *r);
+int each_byterange (request_rec *r, long *offset, long *length);
+     
+/* 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, const 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, const char *uri);     
diff --git a/APACHE_1_2_X/src/include/http_request.h b/APACHE_1_2_X/src/include/http_request.h
new file mode 100644 (file)
index 0000000..f20d494
--- /dev/null
@@ -0,0 +1,92 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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 (const char *new_file, const request_rec *r);
+request_rec *sub_req_lookup_file (const char *new_file, const 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 (const char *new_uri, request_rec *);     
+void internal_redirect_handler (const char *new_uri, request_rec *);
+int some_auth_required (request_rec *r);
+
+#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/APACHE_1_2_X/src/include/httpd.h b/APACHE_1_2_X/src/include/httpd.h
new file mode 100644 (file)
index 0000000..3f15afd
--- /dev/null
@@ -0,0 +1,713 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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.
+ */
+#ifndef HTTPD_ROOT
+#ifdef __EMX__
+/* Set default for OS/2 file system */ 
+#define HTTPD_ROOT "/os2httpd"
+#else
+#define HTTPD_ROOT "/usr/local/etc/httpd"
+#endif
+#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 --- */
+
+#ifndef DEFAULT_USER
+#define DEFAULT_USER "#-1"
+#endif
+#ifndef DEFAULT_GROUP
+#define DEFAULT_GROUP "#-1"
+#endif
+
+/* 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/plain"
+
+/* 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 */
+#ifndef SERVER_CONFIG_FILE
+#define SERVER_CONFIG_FILE "conf/httpd.conf"
+#endif
+
+/* 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 */
+#ifndef DEFAULT_PATH
+#define DEFAULT_PATH "/bin:/usr/bin:/usr/ucb:/usr/bsd:/usr/local/bin"
+#endif
+
+/* The path to the Bourne shell, for parsed docs */
+#ifndef SHELL_PATH
+#ifdef __EMX__
+/* Set default for OS/2 file system */ 
+#define SHELL_PATH "CMD.EXE"
+#else
+#define SHELL_PATH "/bin/sh"
+#endif
+#endif
+
+/* The path to the suExec wrapper, can be overridden in Configuration */
+#ifndef SUEXEC_BIN
+#define SUEXEC_BIN "/usr/local/etc/httpd/sbin/suexec"
+#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 300
+
+/* 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 100
+
+/* The size of the server's internal read-write buffers */
+#define IOBUFSIZE 8192
+
+/* 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.  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.
+ */
+#ifndef HARD_SERVER_LIMIT
+#define HARD_SERVER_LIMIT 256
+#endif
+
+/* 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
+ * identifier below, please keep to the HTTP 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, by adding
+ * their product tokens to EXTRA_CFLAGS in the Configuration file like so.
+ *
+ * EXTRA_CFLAGS="-DSERVER_SUBVERSION="MrWidget/0.1-alpha"
+ *
+ * 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.1.0 MrWidget/0.1-alpha" 
+ */
+
+#define SERVER_BASEVERSION "Apache/1.2.1-dev" /* SEE COMMENTS ABOVE */
+#ifdef SERVER_SUBVERSION
+#define SERVER_VERSION SERVER_BASEVERSION " " SERVER_SUBVERSION
+#else
+#define SERVER_VERSION SERVER_BASEVERSION
+#endif
+
+#define SERVER_PROTOCOL "HTTP/1.1"
+#define SERVER_SUPPORT "http://www.apache.org/"
+
+#define DECLINED -1            /* Module declines to handle */
+#define OK 0                   /* Module has handled this stage. */
+
+/* ----------------------- HTTP Status Codes  ------------------------- */
+
+#define RESPONSE_CODES 38
+
+#define HTTP_CONTINUE                      100
+#define HTTP_SWITCHING_PROTOCOLS           101
+#define HTTP_OK                            200
+#define HTTP_CREATED                       201
+#define HTTP_ACCEPTED                      202
+#define HTTP_NON_AUTHORITATIVE             203
+#define HTTP_NO_CONTENT                    204
+#define HTTP_RESET_CONTENT                 205
+#define HTTP_PARTIAL_CONTENT               206
+#define HTTP_MULTIPLE_CHOICES              300
+#define HTTP_MOVED_PERMANENTLY             301
+#define HTTP_MOVED_TEMPORARILY             302
+#define HTTP_SEE_OTHER                     303
+#define HTTP_NOT_MODIFIED                  304
+#define HTTP_USE_PROXY                     305
+#define HTTP_BAD_REQUEST                   400
+#define HTTP_UNAUTHORIZED                  401
+#define HTTP_PAYMENT_REQUIRED              402
+#define HTTP_FORBIDDEN                     403
+#define HTTP_NOT_FOUND                     404
+#define HTTP_METHOD_NOT_ALLOWED            405
+#define HTTP_NOT_ACCEPTABLE                406
+#define HTTP_PROXY_AUTHENTICATION_REQUIRED 407
+#define HTTP_REQUEST_TIME_OUT              408
+#define HTTP_CONFLICT                      409
+#define HTTP_GONE                          410
+#define HTTP_LENGTH_REQUIRED               411
+#define HTTP_PRECONDITION_FAILED           412
+#define HTTP_REQUEST_ENTITY_TOO_LARGE      413
+#define HTTP_REQUEST_URI_TOO_LARGE         414
+#define HTTP_UNSUPPORTED_MEDIA_TYPE        415
+#define HTTP_INTERNAL_SERVER_ERROR         500
+#define HTTP_NOT_IMPLEMENTED               501
+#define HTTP_BAD_GATEWAY                   502
+#define HTTP_SERVICE_UNAVAILABLE           503
+#define HTTP_GATEWAY_TIME_OUT              504
+#define HTTP_VERSION_NOT_SUPPORTED         505
+#define HTTP_VARIANT_ALSO_VARIES           506
+
+#define DOCUMENT_FOLLOWS    HTTP_OK
+#define PARTIAL_CONTENT     HTTP_PARTIAL_CONTENT
+#define MULTIPLE_CHOICES    HTTP_MULTIPLE_CHOICES
+#define MOVED               HTTP_MOVED_PERMANENTLY
+#define REDIRECT            HTTP_MOVED_TEMPORARILY
+#define USE_LOCAL_COPY      HTTP_NOT_MODIFIED
+#define BAD_REQUEST         HTTP_BAD_REQUEST
+#define AUTH_REQUIRED       HTTP_UNAUTHORIZED
+#define FORBIDDEN           HTTP_FORBIDDEN
+#define NOT_FOUND           HTTP_NOT_FOUND
+#define METHOD_NOT_ALLOWED  HTTP_METHOD_NOT_ALLOWED
+#define NOT_ACCEPTABLE      HTTP_NOT_ACCEPTABLE
+#define LENGTH_REQUIRED     HTTP_LENGTH_REQUIRED
+#define PRECONDITION_FAILED HTTP_PRECONDITION_FAILED
+#define SERVER_ERROR        HTTP_INTERNAL_SERVER_ERROR
+#define NOT_IMPLEMENTED     HTTP_NOT_IMPLEMENTED
+#define BAD_GATEWAY         HTTP_BAD_GATEWAY
+#define VARIANT_ALSO_VARIES HTTP_VARIANT_ALSO_VARIES
+
+#define is_HTTP_INFO(x)         (((x) >= 100)&&((x) < 200))
+#define is_HTTP_SUCCESS(x)      (((x) >= 200)&&((x) < 300))
+#define is_HTTP_REDIRECT(x)     (((x) >= 300)&&((x) < 400))
+#define is_HTTP_ERROR(x)        (((x) >= 400)&&((x) < 600))
+#define is_HTTP_CLIENT_ERROR(x) (((x) >= 400)&&((x) < 500))
+#define is_HTTP_SERVER_ERROR(x) (((x) >= 500)&&((x) < 600))
+
+#define status_drops_connection(x) (((x) == HTTP_BAD_REQUEST)           || \
+                                    ((x) == HTTP_REQUEST_TIME_OUT)      || \
+                                    ((x) == HTTP_LENGTH_REQUIRED)       || \
+                                    ((x) == HTTP_REQUEST_ENTITY_TOO_LARGE) || \
+                                    ((x) == HTTP_REQUEST_URI_TOO_LARGE) || \
+                                    ((x) == HTTP_INTERNAL_SERVER_ERROR) || \
+                                    ((x) == HTTP_SERVICE_UNAVAILABLE))
+
+
+#define METHODS 8
+#define M_GET 0
+#define M_PUT 1
+#define M_POST 2
+#define M_DELETE 3
+#define M_CONNECT 4
+#define M_OPTIONS 5
+#define M_TRACE 6
+#define M_INVALID 7
+
+#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
+
+/* Possible values for request_rec.read_body (set by handling module):
+ *    REQUEST_NO_BODY          Send 413 error if message has any body
+ *    REQUEST_CHUNKED_ERROR    Send 411 error if body without Content-Length
+ *    REQUEST_CHUNKED_DECHUNK  If chunked, remove the chunks for me.
+ *    REQUEST_CHUNKED_PASS     Pass the chunks to me without removal.
+ */
+#define REQUEST_NO_BODY          0
+#define REQUEST_CHUNKED_ERROR    1
+#define REQUEST_CHUNKED_DECHUNK  2
+#define REQUEST_CHUNKED_PASS     3
+
+/* 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 */
+
+  time_t request_time;         /* When the request started */
+
+  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 allowed;                 /* Allowed methods - for 405, OPTIONS, etc */
+
+  int sent_bodyct;             /* byte count in stream is for body */
+  long bytes_sent;             /* body byte count, for easy access */
+
+  /* HTTP/1.1 connection-level features */
+
+  int chunked;                 /* sending chunked transfer-coding */
+  int byterange;               /* number of byte ranges */
+  char *boundary;              /* multipart/byteranges boundary */
+  char *range;                 /* The Range: header */
+  long clength;                        /* The "real" content length */
+
+  long remaining;              /* bytes left to read */
+  long read_length;            /* bytes that have been read */
+  int read_body;               /* how the request body should be read */
+  int read_chunked;            /* reading chunked transfer-coding */
+
+  /* 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;      /* for back-compat. only -- do not use */
+  array_header *content_languages; /* array of (char*) */
+  
+  int no_cache;
+  int no_local_copy;
+  
+  /* 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;
+  server_rec *base_server;      /* Physical vhost this conn come in on */
+  
+  /* 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 rfc1413 lookups.
+                                 * 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... */
+
+/* The address 255.255.255.255, when used as a virtualhost address,
+ * will become the "default" server when the ip doesn't match other vhosts.
+ */
+#define DEFAULT_VHOST_ADDR 0xfffffffful
+
+typedef struct server_addr_rec server_addr_rec;
+struct server_addr_rec {
+    server_addr_rec *next;
+    struct in_addr host_addr;  /* The bound address, for this server */
+    unsigned short host_port;  /* The bound port, for this server */   
+    char *virthost;            /* The name given in <VirtualHost> */
+};
+
+
+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;
+    unsigned 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 */
+
+    server_addr_rec *addrs;
+    int timeout;               /* Timeout, in seconds, before we give up */
+    int keep_alive_timeout;    /* Seconds we'll wait for another request */
+    int keep_alive_max;                /* Maximum requests per connection */
+    int keep_alive;            /* Use persistent connections? */
+    int send_buffer_size;       /* size of TCP send buffer (in bytes) */
+
+    char *path;                        /* Pathname for ServerPath */
+    int pathlen;               /* Length of path */
+
+    char *names;               /* Wildcarded names for ServerAlias servers */
+
+    uid_t server_uid;          /* effective user id when calling exec wrapper */
+    gid_t server_gid;          /* effective group id when calling exec wrapper */
+};
+
+/* 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 */
+    int fd;
+    int used;  /* Only used during restart */
+/* 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(int *tz);
+char *get_time();
+char *ht_time (pool *p, time_t t, const char *fmt, int gmt);     
+char *gm_timestr_822(pool *p, time_t t);
+     
+/* String handling. The *_nc variants allow you to use non-const char **s as
+arguments (unfortunately C won't automatically convert a char ** to a const
+char **) */     
+     
+char *getword(pool *p, const char **line, char stop);
+char *getword_nc(pool *p, char **line, char stop);
+char *getword_white(pool *p, const char **line);
+char *getword_white_nc(pool *p, char **line);
+char *getword_nulls (pool *p, const char **line, char stop);
+char *getword_nulls_nc (pool *p, char **line, char stop);
+char *getword_conf (pool *p, const char **line);      
+char *getword_conf_nc (pool *p, char **line);      
+
+char *get_token (pool *p, char **accept_line, int accept_white);
+int find_token (pool *p, const char *line, const char *tok);
+int find_last_token (pool *p, const char *line, const char *tok);
+     
+int is_url(const 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);
+#define escape_uri(ppool,path) os_escape_path(ppool,path,1)
+extern char *escape_html(pool *p, const char *s);
+char *construct_server(pool *p, const char *hostname, unsigned port);
+char *construct_url (pool *p, const char *path, const server_rec *s);     
+char *escape_shell_cmd (pool *p, const char *s);
+     
+int count_dirs(const char *path);
+char *make_dirstr(pool *a, const char *s, int n);
+char *make_full_path(pool *a, const char *dir, const char *f);
+     
+int is_matchexp(const char *str);
+int strcmp_match(const char *str, const char *exp);
+int strcasecmp_match(const char *str, const char *exp);
+char *uudecode (pool *, const char *);
+
+char *pregsub(pool *p, const char *input, const char *source,
+             size_t nmatch, regmatch_t pmatch[]);
+
+void str_tolower (char *);
+int ind (const char *, char);  /* Sigh... */
+int rind (const char *, char);     
+
+int cfg_getline(char *s, int n, FILE *f);
+
+#ifdef NEED_STRERROR
+char *strerror (int err);
+#endif
+
+/* Misc system hackery */
+     
+uid_t uname2id(const char *name);
+gid_t gname2id(const char *name);
+int is_directory(const char *name);
+int can_exec(const struct stat *);     
+void chdir_file(const char *file);
+     
+char *get_local_host(pool *);
+unsigned long get_virthost_addr (const char *hostname, unsigned short *port);
+
+extern time_t restart_time;
diff --git a/APACHE_1_2_X/src/include/md5.h b/APACHE_1_2_X/src/include/md5.h
new file mode 100644 (file)
index 0000000..a8ff86c
--- /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,1997 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/APACHE_1_2_X/src/include/regex.h b/APACHE_1_2_X/src/include/regex.h
new file mode 100644 (file)
index 0000000..dde954d
--- /dev/null
@@ -0,0 +1,73 @@
+#ifndef _REGEX_H_
+#define        _REGEX_H_       /* never again */
+/* ========= begin header generated by ./mkh ========= */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* === regex2.h === */
+typedef off_t regoff_t;
+typedef struct {
+       int re_magic;
+       size_t re_nsub;         /* number of parenthesized subexpressions */
+       const char *re_endp;    /* end pointer for REG_PEND */
+       struct re_guts *re_g;   /* none of your business :-) */
+} regex_t;
+typedef struct {
+       regoff_t rm_so;         /* start of match */
+       regoff_t rm_eo;         /* end of match */
+} regmatch_t;
+
+
+/* === regcomp.c === */
+extern int regcomp(regex_t *, const char *, int);
+#define        REG_BASIC       0000
+#define        REG_EXTENDED    0001
+#define        REG_ICASE       0002
+#define        REG_NOSUB       0004
+#define        REG_NEWLINE     0010
+#define        REG_NOSPEC      0020
+#define        REG_PEND        0040
+#define        REG_DUMP        0200
+
+
+/* === regerror.c === */
+#define        REG_NOMATCH      1
+#define        REG_BADPAT       2
+#define        REG_ECOLLATE     3
+#define        REG_ECTYPE       4
+#define        REG_EESCAPE      5
+#define        REG_ESUBREG      6
+#define        REG_EBRACK       7
+#define        REG_EPAREN       8
+#define        REG_EBRACE       9
+#define        REG_BADBR       10
+#define        REG_ERANGE      11
+#define        REG_ESPACE      12
+#define        REG_BADRPT      13
+#define        REG_EMPTY       14
+#define        REG_ASSERT      15
+#define        REG_INVARG      16
+#define        REG_ATOI        255     /* convert name to number (!) */
+#define        REG_ITOA        0400    /* convert number to name (!) */
+extern size_t regerror(int, const regex_t *, char *, size_t);
+
+
+/* === regexec.c === */
+extern int regexec(const regex_t *, const char *, size_t, regmatch_t [], int);
+#define        REG_NOTBOL      00001
+#define        REG_NOTEOL      00002
+#define        REG_STARTEND    00004
+#define        REG_TRACE       00400   /* tracing of execution */
+#define        REG_LARGE       01000   /* force large representation */
+#define        REG_BACKR       02000   /* force use of backref code */
+
+
+/* === regfree.c === */
+extern void regfree(regex_t *);
+
+#ifdef __cplusplus
+}
+#endif
+/* ========= end header generated by ./mkh ========= */
+#endif
diff --git a/APACHE_1_2_X/src/include/rfc1413.h b/APACHE_1_2_X/src/include/rfc1413.h
new file mode 100644 (file)
index 0000000..91bf42e
--- /dev/null
@@ -0,0 +1,53 @@
+/* ====================================================================
+ * Copyright (c) 1996,1997 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/APACHE_1_2_X/src/include/scoreboard.h b/APACHE_1_2_X/src/include/scoreboard.h
new file mode 100644 (file)
index 0000000..1485a45
--- /dev/null
@@ -0,0 +1,110 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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 */
+#define SERVER_GRACEFUL 8      /* server is gracefully finishing request */
+
+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... */
+    char vhost[32];     /* What virtual host is being accessed? */
+#endif
+} short_score;
+
+typedef struct
+    {
+    int exit_generation;       /* Set by the main process if a graceful
+                                  restart is required */
+    } global_score;
+
+typedef struct
+    {
+    short_score servers[HARD_SERVER_LIMIT];
+    global_score global;
+    } scoreboard;
+
+#define SCOREBOARD_SIZE                sizeof(scoreboard)
+
+extern void sync_scoreboard_image(void);
+short_score get_scoreboard_info(int x);
+
diff --git a/APACHE_1_2_X/src/include/util_date.h b/APACHE_1_2_X/src/include/util_date.h
new file mode 100644 (file)
index 0000000..edfd34a
--- /dev/null
@@ -0,0 +1,63 @@
+/* ====================================================================
+ * Copyright (c) 1996,1997 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/>.
+ *
+ */
+
+/*
+ * util_date.h: prototypes for date parsing utility routines
+ */
+
+#include <time.h>
+
+#define BAD_DATE (time_t)0
+
+int checkmask (const char *data, const char *mask);
+time_t tm2sec (const struct tm *t);
+time_t parseHTTPdate (const char *date);
diff --git a/APACHE_1_2_X/src/include/util_md5.h b/APACHE_1_2_X/src/include/util_md5.h
new file mode 100644 (file)
index 0000000..63e2c37
--- /dev/null
@@ -0,0 +1,58 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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/APACHE_1_2_X/src/include/util_script.h b/APACHE_1_2_X/src/include/util_script.h
new file mode 100644 (file)
index 0000000..2825876
--- /dev/null
@@ -0,0 +1,69 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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/>.
+ *
+ */
+
+#ifndef APACHE_ARG_MAX
+#ifdef _POSIX_ARG_MAX
+#define APACHE_ARG_MAX _POSIX_ARG_MAX
+#else
+#define APACHE_ARG_MAX 512
+#endif
+#endif
+
+char **create_environment(pool *p, table *t);
+int find_path_info(char *uri, char *path_info);
+void add_cgi_vars(request_rec *r);
+void add_common_vars(request_rec *r);
+#define scan_script_header(a1,a2) scan_script_header_err(a1,a2,NULL)
+int scan_script_header_err(request_rec *r, FILE *f, char *buffer);
+void send_size(size_t size, request_rec *r);
+void call_exec (request_rec *r, char *argv0, char **env, int shellcmd);
+
diff --git a/APACHE_1_2_X/src/main/alloc.c b/APACHE_1_2_X/src/main/alloc.c
new file mode 100644 (file)
index 0000000..2557c07
--- /dev/null
@@ -0,0 +1,1130 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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. Note that we rely on
+malloc() to provide aligned memory. */
+
+union block_hdr *malloc_block (int size)
+{
+  union block_hdr *blok =
+    (union block_hdr *)malloc(size + sizeof(union block_hdr));
+
+  if (blok == NULL) {
+      fprintf (stderr, "Ouch!  malloc failed in malloc_block()\n");
+      exit (1);
+  }
+  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...
+   */
+
+  while (blok != NULL) {
+    if (min_size + BLOCK_MINFREE <= 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. */
+
+  min_size += BLOCK_MINFREE;
+  return malloc_block((min_size > BLOCK_MINALLOC) ? min_size : BLOCK_MINALLOC);
+}
+
+
+
+/* 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(reqsize <= 0)
+      return NULL;
+  
+  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) {
+    int new_size = (arr->nalloc <= 0) ? 1 : arr->nalloc * 2;
+    char *new_data;
+    
+    new_data = pcalloc (arr->pool, arr->elt_size * new_size);
+
+    memcpy (new_data, arr->elts, arr->nalloc * arr->elt_size);
+    arr->elts = new_data;
+    arr->nalloc = new_size;
+  }
+
+  ++arr->nelts;
+  return arr->elts + (arr->elt_size * (arr->nelts - 1));
+}
+
+void array_cat (array_header *dst, const array_header *src)
+{
+  int elt_size = dst->elt_size;
+  
+  if (dst->nelts + src->nelts > dst->nalloc) {
+    int new_size = (dst->nalloc <= 0) ? 1 : dst->nalloc * 2;
+    char *new_data;
+
+    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, const 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, const 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,
+                            const array_header *first,
+                            const 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, const table *t) {
+    return copy_array (p, t);
+}
+
+void clear_table (table *t)
+{
+    t->nelts = 0;
+}
+
+array_header *table_elts (table *t) { return t; }
+
+char *table_get (const table *t, const 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)
+{
+    register int i, j, k;
+    table_entry *elts = (table_entry *)t->elts;
+    int done = 0;
+
+    for (i = 0; i < t->nelts; ++i)
+       if (!strcasecmp (elts[i].key, key)) {
+           if (!done) {
+               elts[i].val = pstrdup(t->pool, val);
+               done = 1;
+           }
+           else {     /* delete an extraneous element */
+                for (j = i, k = i + 1; k < t->nelts; ++j, ++k) {
+                    elts[j].key = elts[k].key;
+                    elts[j].val = elts[k].val;
+                }
+                --t->nelts;
+           }
+       }
+
+    if (!done) {
+        elts = (table_entry *)push_array(t);
+        elts->key = pstrdup (t->pool, key);
+        elts->val = pstrdup (t->pool, val);
+    }
+}
+
+void table_unset( table *t, const char *key ) 
+{
+    register int i, j, k;   
+    table_entry *elts = (table_entry *)t->elts;
+    for (i = 0; i < t->nelts; ++i)
+        if (!strcasecmp (elts[i].key, key)) {
+            /* found an 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*...
+             */
+            for (j = i, k = i + 1; k < t->nelts; ++j, ++k) {
+                elts[j].key = elts[k].key;
+                elts[j].val = elts[k].val;
+            }
+            --t->nelts;
+        }
+}     
+
+void table_merge (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 = 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, const char *key, const 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, const table *overlay, const table *base)
+{
+    return append_arrays (p, overlay, base);
+}
+
+/* And now for something completely abstract ...
+ *
+ * For each key value given as a vararg:
+ *   run the function pointed to as
+ *     int comp(void *r, char *key, char *value);
+ *   on each valid key-value pair in the table t that matches the vararg key,
+ *   or once for every valid key-value pair if the vararg list is empty,
+ *   until the function returns false (0) or we finish the table.
+ *
+ * Note that we restart the traversal for each vararg, which means that
+ * duplicate varargs will result in multiple executions of the function
+ * for each matching key.  Note also that if the vararg list is empty,
+ * only one traversal will be made and will cut short if comp returns 0.
+ *
+ * Note that the table_get and table_merge functions assume that each key in
+ * the table is unique (i.e., no multiple entries with the same key).  This
+ * function does not make that assumption, since it (unfortunately) isn't
+ * true for some of Apache's tables.
+ *
+ * Note that rec is simply passed-on to the comp function, so that the
+ * caller can pass additional info for the task.
+ */
+void table_do (int (*comp)(void *, const char *, const char *), void *rec,
+               const table *t, ...)
+{
+    va_list vp;
+    char *argp;
+    table_entry *elts = (table_entry *)t->elts;
+    int rv, i;
+  
+    va_start(vp, t);
+
+    argp = va_arg(vp, char *);
+
+    do {
+        for (rv = 1, i = 0; rv && (i < t->nelts); ++i) {
+            if (elts[i].key && (!argp || !strcasecmp(elts[i].key, argp))) {
+                rv = (*comp)(rec, elts[i].key, elts[i].val);
+            }
+        }
+    } while (argp && ((argp = va_arg(vp, char *)) != NULL));
+
+    va_end(vp);
+}
+
+/*****************************************************************
+ *
+ * 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);
+}
+
+void kill_cleanups_for_fd(pool *p,int fd)
+    {
+    kill_cleanup(p,(void *)fd,fd_cleanup);
+    }
+
+int popenf(pool *a, const char *name, int flg, int mode)
+{
+  int fd;
+  int save_errno;
+
+  block_alarms();
+  fd = open(name, flg, mode);
+  save_errno = errno;
+  if (fd >= 0) note_cleanups_for_fd (a, fd);
+  unblock_alarms();
+  errno = save_errno;
+  return fd;
+}
+
+int pclosef(pool *a, int fd)
+{
+  int res;
+  int save_errno;
+  
+  block_alarms();
+  res = close(fd);
+  save_errno = errno;
+  kill_cleanup(a, (void *)fd, fd_cleanup);
+  unblock_alarms();
+  errno = save_errno;
+  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 (pool *p, FILE *fp) {
+  register_cleanup (p, (void *)fp, file_cleanup, file_child_cleanup);
+}
+
+FILE *pfopen(pool *a, const char *name, const char *mode)
+{
+  FILE *fd = NULL;
+  int baseFlag, desc;
+
+  block_alarms();
+
+  if (*mode == 'a') {
+    /* Work around faulty implementations of fopen */
+    baseFlag = (*(mode+1) == '+') ? O_RDWR : O_WRONLY;
+    desc = open(name, baseFlag | O_APPEND | O_CREAT,
+               S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
+    if (desc >= 0) {
+      fd = fdopen(desc, mode);
+    }
+  } else {
+    fd = fopen(name, mode);
+  }
+
+  if (fd != NULL) note_cleanups_for_file (a, fd);
+  unblock_alarms();
+  return fd;
+}
+
+FILE *pfdopen(pool *a,int fd, const 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(pool *a, FILE *fd)
+{
+  int res;
+  
+  block_alarms();
+  res = fclose(fd);
+  kill_cleanup(a, (void *)fd, file_cleanup);
+  unblock_alarms();
+  return res;
+}
+
+/*
+ * Here's a pool-based interface to POSIX regex's regcomp().
+ * Note that we return regex_t instead of being passed one.
+ * The reason is that if you use an already-used regex_t structure,
+ * the memory that you've already allocated gets forgotten, and
+ * regfree() doesn't clear it. So we don't allow it.
+ */
+
+static void regex_cleanup (void *preg) { regfree ((regex_t *)preg); }
+
+regex_t *pregcomp(pool *p, const char *pattern, int cflags) {
+    regex_t *preg = palloc(p, sizeof(regex_t));
+
+    if (regcomp(preg, pattern, cflags))
+       return NULL;
+
+    register_cleanup (p, (void *)preg, regex_cleanup, regex_cleanup);
+
+    return preg;
+}
+
+
+void pregfree(pool *p, regex_t *reg)
+{
+    block_alarms();
+    regfree (reg);
+    kill_cleanup (p, (void *)reg, regex_cleanup);
+    unblock_alarms();
+}
+
+/*****************************************************************
+ *
+ * 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_err (pool *p, void (*func)(void *), void *data,
+                    enum kill_conditions kill_how,
+                    FILE **pipe_in, FILE **pipe_out, FILE **pipe_err)
+{
+  int pid;
+  int in_fds[2];
+  int out_fds[2];
+  int err_fds[2];
+  int save_errno;
+
+  block_alarms();
+  
+  if (pipe_in && pipe (in_fds) < 0)
+  {
+      save_errno = errno;
+      unblock_alarms();
+      errno = save_errno;
+      return 0;
+  }
+  
+  if (pipe_out && pipe (out_fds) < 0) {
+    save_errno = errno;
+    if (pipe_in) {
+      close (in_fds[0]); close (in_fds[1]);
+    }
+    unblock_alarms();
+    errno = save_errno;
+    return 0;
+  }
+
+  if (pipe_err && pipe (err_fds) < 0) {
+    save_errno = errno;
+    if (pipe_in) {
+      close (in_fds[0]); close (in_fds[1]);
+    }
+    if (pipe_out) {
+      close (out_fds[0]); close (out_fds[1]);
+    }
+    unblock_alarms();
+    errno = save_errno;
+    return 0;
+  }
+
+  if ((pid = fork()) < 0) {
+    save_errno = errno;
+    if (pipe_in) {
+      close (in_fds[0]); close (in_fds[1]);
+    }
+    if (pipe_out) {
+      close (out_fds[0]); close (out_fds[1]);
+    }
+    if (pipe_err) {
+      close (err_fds[0]); close (err_fds[1]);
+    }
+    unblock_alarms();
+    errno = save_errno;
+    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]);
+    }
+
+    if (pipe_err) {
+      close (err_fds[0]);
+      dup2 (err_fds[1], STDERR_FILENO);
+      close (err_fds[1]);
+    }
+
+    /* 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);
+  }
+
+  if (pipe_err) {
+    close (err_fds[1]);
+#ifdef __EMX__
+    /* Need binary mode set for OS/2. */
+    *pipe_err = fdopen (err_fds[0], "rb");
+#else
+    *pipe_err = fdopen (err_fds[0], "r");
+#endif
+  
+    if (*pipe_err) note_cleanups_for_file (p, *pipe_err);
+  }
+
+  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);
+  }
+}
+
diff --git a/APACHE_1_2_X/src/main/buff.c b/APACHE_1_2_X/src/main/buff.c
new file mode 100644 (file)
index 0000000..97c0002
--- /dev/null
@@ -0,0 +1,975 @@
+/* ====================================================================
+ * Copyright (c) 1996,1997 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 "conf.h"
+#include "alloc.h"
+#include "buff.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#ifndef NO_UNISTD_H
+#include <unistd.h>
+#endif
+#ifndef NO_WRITEV
+#include <sys/types.h>
+#include <sys/uio.h>
+#endif
+
+#ifdef HAVE_BSTRING_H
+#include <bstring.h>           /* for IRIX, FD_SET calls bzero() */
+#endif
+
+#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)
+{
+    int errsave = errno;  /* Save errno to prevent overwriting it below */
+
+    if (err == B_RD)
+       fb->flags |= B_RDERR;
+    else
+       fb->flags |= B_WRERR;
+    if (fb->error != NULL) (*fb->error)(fb, err, fb->error_data);
+
+    errno = errsave;
+}
+
+/* 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;
+
+    /* overallocate so that we can put a chunk trailer of CRLF into this
+     * buffer */
+    if (flags & B_WR) fb->outbase = palloc(p, fb->bufsiz + 2);
+    else fb->outbase = NULL;
+
+    fb->inptr = fb->inbase;
+
+    fb->incnt = 0;
+    fb->outcnt = 0;
+    fb->outchunk = -1;
+    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;
+}
+
+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;
+    }
+}
+
+/*
+ * start chunked encoding
+ */
+static void
+start_chunk( BUFF *fb )
+{
+    char chunksize[16];        /* Big enough for practically anything */
+    int chunk_header_size;
+
+    if (fb->outchunk != -1) {
+       /* already chunking */
+       return;
+    }
+    if (!(fb->flags & B_WR) || (fb->flags & (B_WRERR|B_EOUT))) {
+       /* unbuffered writes */
+       return;
+    }
+
+    /* we know that the chunk header is going to take at least 3 bytes... */
+    chunk_header_size = ap_snprintf( chunksize, sizeof(chunksize),
+       "%x\015\012", fb->bufsiz - fb->outcnt - 3 );
+    /* we need at least the header_len + at least 1 data byte
+     * remember that we've overallocated fb->outbase so that we can always
+     * fit the two byte CRLF trailer
+     */
+    if( fb->bufsiz - fb->outcnt < chunk_header_size + 1 ) {
+       bflush(fb);
+    }
+    /* assume there's enough space now */
+    memcpy( &fb->outbase[fb->outcnt], chunksize, chunk_header_size );
+    fb->outchunk = fb->outcnt;
+    fb->outcnt += chunk_header_size;
+    fb->outchunk_header_size = chunk_header_size;
+}
+
+
+/*
+ * end a chunk -- tweak the chunk_header from start_chunk, and add a trailer
+ */
+static void
+end_chunk( BUFF *fb )
+{
+    int i;
+
+    if( fb->outchunk == -1 ) {
+       /* not chunking */
+       return;
+    }
+
+    if( fb->outchunk + fb->outchunk_header_size == fb->outcnt ) {
+       /* nothing was written into this chunk, and we can't write a 0 size
+        * chunk because that signifies EOF, so just erase it
+        */
+       fb->outcnt = fb->outchunk;
+       fb->outchunk = -1;
+       return;
+    }
+
+    /* we know this will fit because of how we wrote it in start_chunk() */
+    i = ap_snprintf( (char *)&fb->outbase[fb->outchunk],
+       fb->outchunk_header_size,
+       "%x", fb->outcnt - fb->outchunk - fb->outchunk_header_size );
+
+    /* we may have to tack some trailing spaces onto the number we just wrote
+     * in case it was smaller than our estimated size.  We've also written
+     * a \0 into the buffer with ap_snprintf so we might have to put a
+     * \r back in.
+     */
+    i += fb->outchunk;
+    while( fb->outbase[i] != '\015' && fb->outbase[i] != '\012' ) {
+       fb->outbase[i++] = ' ';
+    }
+    if( fb->outbase[i] == '\012' ) {
+       /* we overwrote the \r, so put it back */
+       fb->outbase[i-1] = '\015';
+    }
+
+    /* tack on the trailing CRLF, we've reserved room for this */
+    fb->outbase[fb->outcnt++] = '\015';
+    fb->outbase[fb->outcnt++] = '\012';
+
+    fb->outchunk = -1;
+}
+
+
+/*
+ * Set a flag on (1) or off (0).
+ */
+int bsetflag(BUFF *fb, int flag, int value)
+{
+    if (value) {
+       fb->flags |= flag;
+       if( flag & B_CHUNK ) {
+           start_chunk(fb);
+       }
+    } else {
+       fb->flags &= ~flag;
+       if( flag & B_CHUNK ) {
+           end_chunk(fb);
+       }
+    }
+    return value;
+}
+
+
+/*
+ * This is called instead of read() everywhere in here.  It implements
+ * the B_SAFEREAD functionality -- which is to force a flush() if a read()
+ * would block.  It also deals with the EINTR errno result from read().
+ * return code is like read() except EINTR is eliminated.
+ */
+static int
+saferead( BUFF *fb, void *buf, int nbyte )
+{
+    int rv;
+
+    if( fb->flags & B_SAFEREAD ) {
+       fd_set fds;
+       struct timeval tv;
+
+       /* test for a block */
+       do {
+           FD_ZERO( &fds );
+           FD_SET( fb->fd_in, &fds );
+           tv.tv_sec = 0;
+           tv.tv_usec = 0;
+#ifdef SELECT_NEEDS_CAST
+           rv = select( fb->fd_in + 1, (int *)&fds, NULL, NULL, &tv );
+#else
+           rv = select( fb->fd_in + 1, &fds, NULL, NULL, &tv );
+#endif
+       } while( rv < 0 && errno == EINTR );
+       /* treat any error as if it would block as well */
+       if( rv != 1 ) {
+           bflush(fb);
+       }
+    }
+    do {
+       rv = read( fb->fd_in, buf, nbyte );
+    } while (rv == -1 && errno == EINTR && !(fb->flags & B_EOUT));
+    return( rv );
+}
+
+
+/*
+ * 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 */
+       i = saferead( fb, buf, nbyte );
+       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 */
+       i = saferead( fb, buf, nbyte );
+       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;
+       i = saferead( fb, fb->inptr, fb->bufsiz );
+       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;
+           i = saferead( fb, fb->inptr, fb->bufsiz );
+           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;
+}
+
+/*
+ * Looks at the stream fb and places the first character into buff
+ * without removing it from the stream buffer.
+ *
+ * Returns 1 on success, zero on end of transmission, or -1 on an error.
+ *
+ */
+int blookc(char *buff, BUFF *fb)
+{
+    int i;
+
+    *buff = '\0';
+    
+    if (!(fb->flags & B_RD)) {   /* Can't do blookc on an unbuffered stream */
+        errno = EINVAL;
+        return -1;
+    }
+    if (fb->flags & B_RDERR) return -1;
+
+    if (fb->incnt == 0) {        /* no characters left in stream buffer */
+        fb->inptr = fb->inbase;
+        if (fb->flags & B_EOF)
+            return 0;
+
+       i = saferead( fb, fb->inptr, fb->bufsiz );
+
+        if (i == -1) {
+            if (errno != EAGAIN)
+                doerror(fb, B_RD);
+            return -1;
+        }
+        if (i == 0) {
+            fb->flags |= B_EOF;
+            return 0; /* EOF */
+        }
+        else fb->incnt = i;
+    }
+
+    *buff = fb->inptr[0];
+    return 1;
+}
+
+/*
+ * 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 = (unsigned char *)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;
+       i = saferead( fb, fb->inptr, fb->bufsiz );
+       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];
+}
+
+
+/*
+ * When doing chunked encodings we really have to write everything in the
+ * chunk before proceeding onto anything else.  This routine either writes
+ * nbytes and returns 0 or returns -1 indicating a failure.
+ *
+ * This is *seriously broken* if used on a non-blocking fd.  It will poll.
+ */
+static int
+write_it_all(BUFF *fb, const void *buf, int nbyte)
+{
+    int i;
+
+    if (fb->flags & (B_WRERR|B_EOUT))
+       return -1;
+
+    while (nbyte > 0) {
+       i = write(fb->fd, buf, nbyte);
+       if (i < 0) {
+           if (errno != EAGAIN && errno != EINTR) {
+               return -1;
+           }
+       }
+       else {
+           nbyte -= i;
+           buf = i + (const char *)buf;
+       }
+       if (fb->flags & B_EOUT)
+           return -1;
+    }
+    return 0;
+}
+
+
+/*
+ * A hook to write() that deals with chunking. This is really a protocol-
+ * level issue, but we deal with it here because it's simpler; this is
+ * an interim solution pending a complete rewrite of all this stuff in
+ * 2.0, using something like sfio stacked disciplines or BSD's funopen().
+ */
+static int
+bcwrite(BUFF *fb, const void *buf, int nbyte)
+{
+    char chunksize[16];        /* Big enough for practically anything */
+#ifndef NO_WRITEV
+    struct iovec vec[3];
+    int i, rv;
+#endif
+
+    if (fb->flags & (B_WRERR|B_EOUT))
+       return -1;
+
+    if (!(fb->flags & B_CHUNK))
+       return write(fb->fd, buf, nbyte);
+
+#ifdef NO_WRITEV
+    /* without writev() this has poor performance, too bad */
+
+    ap_snprintf(chunksize, sizeof(chunksize), "%x\015\012", nbyte);
+    if (write_it_all(fb, chunksize, strlen(chunksize)) == -1)
+       return -1;
+    if (write_it_all(fb, buf, nbyte) == -1)
+       return -1;
+    if (write_it_all(fb, "\015\012", 2) == -1)
+       return -1;
+    return nbyte;
+#else
+
+#define NVEC   (sizeof(vec)/sizeof(vec[0]))
+
+    vec[0].iov_base = chunksize;
+    vec[0].iov_len = ap_snprintf(chunksize, sizeof(chunksize), "%x\015\012",
+       nbyte);
+    vec[1].iov_base = (void *)buf;     /* cast is to avoid const warning */
+    vec[1].iov_len = nbyte;
+    vec[2].iov_base = "\r\n";
+    vec[2].iov_len = 2;
+    /* while it's nice an easy to build the vector and crud, it's painful
+     * to deal with a partial writev()
+     */
+    for( i = 0; i < NVEC; ) {
+       do rv = writev( fb->fd, &vec[i], NVEC - i );
+       while (rv == -1 && errno == EINTR && !(fb->flags & B_EOUT));
+       if (rv == -1)
+           return -1;
+       /* recalculate vec to deal with partial writes */
+       while (rv > 0) {
+           if( rv <= vec[i].iov_len ) {
+               vec[i].iov_base = (char *)vec[i].iov_base + rv;
+               vec[i].iov_len -= rv;
+               rv = 0;
+               if( vec[i].iov_len == 0 ) {
+                   ++i;
+               }
+           } else {
+               rv -= vec[i].iov_len;
+               ++i;
+           }
+       }
+       if (fb->flags & B_EOUT)
+           return -1;
+    }
+    /* if we got here, we wrote it all */
+    return nbyte;
+#undef NVEC
+#endif
+}
+
+
+/*
+ * Write nbyte bytes.
+ * Only returns fewer than nbyte if an error ocurred.
+ * Returns -1 if no bytes were written before the error ocurred.
+ * It is worth noting that if an error occurs, the buffer is in an unknown
+ * state.
+ */
+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 -- have to use bcwrite since we aren't taking care
+ * of chunking any other way */
+       do i = bcwrite(fb, buf, nbyte);
+       while (i == -1 && errno == EINTR && !(fb->flags & B_EOUT));
+       if (i == 0) {  /* return of 0 means non-blocking */
+           errno = EAGAIN;
+           return -1;
+       }
+       else if (i < 0) {
+           if (errno != EAGAIN)
+               doerror(fb, B_WR);
+           return -1;
+       }
+       fb->bytes_sent += i;
+       if (fb->flags & B_EOUT)
+           return -1;
+       else
+           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 */
+       if (fb->flags & B_CHUNK) {
+           end_chunk(fb);
+           /* it is just too painful to try to re-cram the buffer while
+            * chunking
+            */
+           i = (write_it_all(fb, fb->outbase, fb->outcnt) == -1) ?
+                   -1 : fb->outcnt;
+       }
+       else {
+           do i = write(fb->fd, fb->outbase, fb->outcnt);
+           while (i == -1 && errno == EINTR && !(fb->flags & B_EOUT));
+       }
+       if (i <= 0) {
+           if (i == 0) /* return of 0 means non-blocking */
+               errno = EAGAIN;
+           if (nwr == 0) {
+               if (errno != EAGAIN) doerror(fb, B_WR);
+               return -1;
+           }
+           else return nwr;
+       }
+       fb->bytes_sent += i;
+
+       /* deal with a partial write */
+       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;
+       }
+       else
+           fb->outcnt = 0;
+
+       if (fb->flags & B_EOUT)
+           return -1;
+    }
+/* we have emptied the file buffer. Now try to write the data from the
+ * original buffer until there is less than bufsiz left.  Note that we
+ * use bcwrite() to do this for us, it will do the chunking so that
+ * we don't have to dink around building a chunk in our own buffer.
+ */
+    while (nbyte >= fb->bufsiz)
+    {
+       do i = bcwrite(fb, buf, nbyte);
+       while (i == -1 && errno == EINTR && !(fb->flags & B_EOUT));
+       if (i <= 0) {
+           if (i == 0) /* return of 0 means non-blocking */
+               errno = EAGAIN;
+           if (nwr == 0) {
+               if (errno != EAGAIN) doerror(fb, B_WR);
+               return -1;
+           }
+           else return nwr;
+       }
+       fb->bytes_sent += i;
+
+       buf = i + (const char *)buf;
+       nwr += i;
+       nbyte -= i;
+
+       if (fb->flags & B_EOUT)
+           return -1;
+    }
+/* copy what's left to the file buffer */
+    fb->outcnt = 0;
+    if( fb->flags & B_CHUNK ) start_chunk( fb );
+    if (nbyte > 0) memcpy(fb->outbase + fb->outcnt, 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;
+
+    if (!(fb->flags & B_WR) || (fb->flags & B_EOUT)) return 0;
+
+    if (fb->flags & B_WRERR) return -1;
+    
+    if (fb->flags & B_CHUNK) end_chunk(fb);
+
+    while (fb->outcnt > 0)
+    {
+       /* the buffer must be full */
+       do i = write(fb->fd, fb->outbase, fb->outcnt);
+       while (i == -1 && errno == EINTR && !(fb->flags & B_EOUT));
+       if (i == 0) {
+           errno = EAGAIN;
+           return -1;  /* return of 0 means non-blocking */
+       }
+       else if (i < 0) {
+           if (errno != EAGAIN) doerror(fb, B_WR);
+           return -1;
+       }
+       fb->bytes_sent += i;
+
+       /*
+        * We should have written all the data, but 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;
+
+       /* If a soft timeout occurs while flushing, the handler should
+        * have set the buffer flag B_EOUT.
+        */
+       if (fb->flags & B_EOUT)
+           return -1;
+    }
+    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/APACHE_1_2_X/src/main/explain.c b/APACHE_1_2_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/APACHE_1_2_X/src/main/http_bprintf.c b/APACHE_1_2_X/src/main/http_bprintf.c
new file mode 100644 (file)
index 0000000..712af06
--- /dev/null
@@ -0,0 +1,599 @@
+/*
+ * 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 <assert.h>
+#include <math.h>
+#include "conf.h"
+#include "alloc.h"
+#include "buff.h"
+
+#if !defined(max)
+#define max(a,b)       (a > b ? a : b)
+#endif
+
+#ifdef NO_LONG_DOUBLE
+#define LONG_DOUBLE    double
+#else
+#define LONG_DOUBLE    long double
+#endif
+
+#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
+     */
+#define NULL_STRING "(null)"
+    /*
+     * String displayed if given a NULL pointer.
+     */
+
+/*
+ * 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 (charPtrArg == NULL) {
+                       charPtrArg = NULL_STRING;
+                   };
+                   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 *);
+                       if (buffPtr == NULL) {
+                           buffPtr = NULL_STRING;
+                       };
+                       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/APACHE_1_2_X/src/main/http_config.c b/APACHE_1_2_X/src/main/http_config.c
new file mode 100644 (file)
index 0000000..51c0ec6
--- /dev/null
@@ -0,0 +1,1198 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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 Apache... 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
+ * Apache 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... */
+#include "explain.h"
+
+DEF_Explain
+
+/****************************************************************
+ *
+ * We begin with the functions which deal with the linked list
+ * of modules which control just about all of the server operation.
+ */
+
+/* num_modules is the number of currently active modules.  */
+static int num_modules = 0;    
+/* total_modules is the number of modules linked in.  */
+static int total_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*) * total_modules);
+   return (void *)conf_vector;
+}
+
+void *
+create_default_per_dir_config (pool *p)
+{
+   void **conf_vector = (void **)pcalloc(p, sizeof(void*) * (total_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*) * total_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*) * (total_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);
+}
+
+#ifdef EXPLAIN
+
+struct
+    {
+    int offset;
+    char *method;
+    } aMethods[]=
+    {
+#define m(meth)        { XtOffsetOf(module,meth),#meth }
+    m(translate_handler),
+    m(check_user_id),
+    m(auth_checker),
+    m(type_checker),
+    m(fixer_upper),
+    m(logger),
+    { -1,"?" },
+#undef m
+    };
+
+char *ShowMethod(module *modp,int offset)
+    {
+    int n;
+    static char buf[200];
+
+    for(n=0 ; aMethods[n].offset >= 0 ; ++n)
+       if(aMethods[n].offset == offset)
+           break;
+    ap_snprintf(buf, sizeof(buf), "%s:%s",modp->name,aMethods[n].method);
+    return buf;
+    }
+#else
+#define ShowMethod(modp,offset)
+#endif
+
+/****************************************************************
+ *
+ * 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;
+
+           Explain1("Run %s",ShowMethod(modp,offset));
+          result = (*mod_handler)(r);
+
+          Explain2("%s returned %d",ShowMethod(modp,offset),result);
+          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);
+}
+
+int header_parse (request_rec *r) {
+    return run_method (r, XtOffsetOf (module, header_parser), 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, *p; 
+
+   if ((p = strchr(content_type, ';')) != NULL) {  /* MIME type arguments */
+       while (p > content_type && p[-1] == ' ') --p; /* strip trailing spaces */
+       content_type = pstrndup(r->pool, content_type, p - content_type);
+   }
+   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...
+     */
+
+    /* At some point, we may want to offer back-compatibility for
+     * loading modules that are for older versions of Apache. For now,
+     * though, we don't.
+     */
+
+    if (m->version != MODULE_MAGIC_NUMBER) {
+       fprintf(stderr, "httpd: module \"%s\" is not compatible with this "
+                       "version of Apache.\n", m->name);
+       fprintf(stderr, "Please contact the author for the correct version.\n");
+       exit(1);
+    }
+
+    if (m->next == NULL) {
+        m->next = top_module;
+       top_module = m;
+    }
+    if (m->module_index == -1) {
+       m->module_index = num_modules++;
+    }
+}
+
+void setup_prelinked_modules ()
+{
+    extern module *prelinked_modules[], *preloaded_modules[];
+    module **m;
+
+    /* First, set all module indices, and init total_modules.  */
+    total_modules = 0;
+    for (m = preloaded_modules; *m; ++m, ++total_modules) {
+        (*m)->module_index = total_modules;
+    }
+
+    for (m = prelinked_modules; *m; ++m) {
+        add_module (*m);
+    }
+}
+
+const char *find_module_name (module *m)
+{
+    return m->name;
+}
+
+module *find_linked_module (const char *name)
+{
+    module *modp;
+
+    for (modp = top_module; modp; modp = modp->next) {
+        if (strcmp(modp->name, name) == 0)
+            return modp;
+    }
+    return NULL;
+}
+
+/* Add a named module.  Returns 1 if module found, 0 otherwise.  */
+int add_named_module (const char *name)
+{
+    extern module *preloaded_modules[];
+    module *modp;
+    int i = 0;
+
+    for (modp = preloaded_modules[i]; modp; modp = preloaded_modules[++i]) {
+        if (strcmp(modp->name, name) == 0) {
+           /* Only add modules that are not already enabled.  */
+           if (modp->next == NULL) {
+               add_module(modp);
+           }
+           return 1;
+       }
+    }
+
+    return 0;
+}
+
+/* Clear the internal list of modules, in preparation for starting over. */
+void clear_module_list ()
+{
+    module **m = &top_module;
+    module **next_m;
+
+    while (*m) {
+       next_m = &((*m)->next);
+       *m = NULL;
+       m = next_m;
+    }
+
+    num_modules = 0;
+
+    /* This is required; so we add it always.  */
+    add_named_module ("http_core.c");
+}
+
+/*****************************************************************
+ *
+ * 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...
+ */
+
+const char *invoke_cmd(const command_rec *cmd, cmd_parms *parms, void *mconfig,
+                const char *args)
+{
+    char *w, *w2, *w3;
+    const char *errmsg;
+
+    if ((parms->override & cmd->req_override) == 0)
+        return pstrcat (parms->pool, cmd->name, " not allowed here", NULL);
+    
+    parms->info = cmd->cmd_data;
+    parms->cmd = cmd;
+    
+    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 TAKE12:
+
+       w = getword_conf (parms->pool, &args);
+       w2 = getword_conf (parms->pool, &args);
+       
+       if (*w == '\0' || *args != 0) 
+           return pstrcat (parms->pool, cmd->name, " takes 1-2 arguments",
+                           cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL);
+
+       return (*cmd->func) (parms, mconfig, w, *w2 ? w2 : NULL);
+       
+    case TAKE3:
+
+       w = getword_conf (parms->pool, &args);
+       w2 = getword_conf (parms->pool, &args);
+       w3 = getword_conf (parms->pool, &args);
+       
+       if (*w == '\0' || *w2 == '\0' || *w3 == '\0' || *args != 0) 
+           return pstrcat (parms->pool, cmd->name, " takes three arguments",
+                           cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL);
+
+       return (*cmd->func) (parms, mconfig, w, w2, w3);
+       
+    case TAKE23:
+
+       w = getword_conf (parms->pool, &args);
+       w2 = getword_conf (parms->pool, &args);
+       w3 = *args ? getword_conf (parms->pool, &args) : NULL;
+       
+       if (*w == '\0' || *w2 == '\0' || *args != 0) 
+           return pstrcat (parms->pool, cmd->name, " takes two or three arguments",
+                           cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL);
+
+       return (*cmd->func) (parms, mconfig, w, w2, w3);
+       
+    case TAKE123:
+
+       w = getword_conf (parms->pool, &args);
+       w2 = *args ? getword_conf (parms->pool, &args) : NULL;
+       w3 = *args ? getword_conf (parms->pool, &args) : NULL;
+       
+       if (*w == '\0' || *args != 0) 
+           return pstrcat (parms->pool, cmd->name, " takes one, two or three arguments",
+                           cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL);
+
+       return (*cmd->func) (parms, mconfig, w, w2, w3);
+       
+    case TAKE13:
+
+       w = getword_conf (parms->pool, &args);
+       w2 = *args ? getword_conf (parms->pool, &args) : NULL;
+       w3 = *args ? getword_conf (parms->pool, &args) : NULL;
+       
+       if (*w == '\0' || (*w2 && !w3) || *args != 0) 
+           return pstrcat (parms->pool, cmd->name, " takes one or three arguments",
+                           cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL);
+
+       return (*cmd->func) (parms, mconfig, w, w2, w3);
+       
+    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);
+    }
+}
+
+const command_rec *find_command (const char *name, const command_rec *cmds)
+{
+    while (cmds->name) 
+        if (!strcasecmp (name, cmds->name))
+           return cmds;
+       else
+           ++cmds;
+
+    return NULL;
+}
+    
+const command_rec *find_command_in_modules (const char *cmd_name, module **mod)
+{
+   const command_rec *cmdp;
+   module *modp;
+
+   for (modp = *mod; modp; modp = modp->next) 
+       if (modp->cmds && (cmdp = find_command (cmd_name, modp->cmds))) {
+          *mod = modp;
+          return cmdp;
+       }
+
+   return NULL;
+}
+
+const char *handle_command (cmd_parms *parms, void *config, const char *l)
+{
+    const char *args, *cmd_name, *retval;
+    const command_rec *cmd;
+    module *mod = top_module;
+
+    ++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;
+       
+    do {
+       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);
+           }
+           
+           retval = invoke_cmd (cmd, parms, mconfig, args);
+           mod = mod->next;    /* Next time around, skip this one */
+       }
+    } while (retval && !strcmp(retval, DECLINE_CMD));
+
+    return retval;
+}
+
+const char *srm_command_loop (cmd_parms *parms, void *config)
+{
+    char l[MAX_STRING_LEN];
+    
+    while (!(cfg_getline (l, MAX_STRING_LEN, parms->infile))) {
+       const char *errmsg = handle_command (parms, config, l);
+       if (errmsg) return errmsg;
+    }
+
+    return NULL;
+}
+
+/*
+ * Generic command functions...
+ */
+
+const 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;
+}
+
+const char *set_flag_slot (cmd_parms *cmd, char *struct_ptr, int arg)
+{
+    /* This one's pretty generic too... */
+  
+    int offset = (int)cmd->info; 
+    *(int *)(struct_ptr + offset) = arg ? 1 : 0;
+    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;
+    const char *errmsg;
+    cmd_parms parms;
+    struct stat finfo;
+    
+    fname = server_root_relative (p, fname);
+
+    if (!(strcmp(fname, server_root_relative(p, RESOURCE_CONFIG_FILE))) ||
+       !(strcmp(fname, server_root_relative(p, ACCESS_CONFIG_FILE)))) {
+       if (stat(fname, &finfo) == -1)
+           return;
+    }
+    
+    /* 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"))) {
+        perror("fopen");
+        fprintf(stderr,"httpd: could not open document config file %s\n",
+                fname);
+        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;
+    const 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.
+ */
+
+/*
+ * Parses a host of the form <address>[:port]
+ * paddr is used to create a list in the order of input
+ * **paddr is the ->next pointer of the last entry (or s->addrs)
+ * *paddr is the variable used to keep track of **paddr between calls
+ * port is the default port to assume
+ */
+static void get_addresses (pool *p, char *w, server_addr_rec ***paddr, unsigned port)
+{
+    struct hostent *hep;
+    unsigned long my_addr;
+    server_addr_rec *sar;
+    char *t;
+    int i, is_an_ip_addr;
+
+    if( *w == 0 ) return;
+
+    t = strchr(w, ':');
+    if (t) {
+       if( strcmp(t+1,"*") == 0 ) {
+           port = 0;
+       } else if( (i = atoi(t+1)) ) {
+           port = i;
+       } else {
+           fprintf( stderr, "Port must be numeric\n" );
+       }
+       *t = 0;
+    }
+
+    is_an_ip_addr = 0;
+    if (strcmp(w, "*") == 0) {
+       my_addr = htonl(INADDR_ANY);
+       is_an_ip_addr = 1;
+    } else if( strcmp(w, "_default_") == 0
+           || strcmp(w, "255.255.255.255") == 0 ) {
+       my_addr = DEFAULT_VHOST_ADDR;
+       is_an_ip_addr = 1;
+    } else if(
+#ifdef DGUX
+           ( my_addr = inet_network(w) )
+#else
+           ( my_addr = inet_addr(w) )
+#endif
+           != INADDR_NONE ) {
+       is_an_ip_addr = 1;
+    }
+    if( is_an_ip_addr ) {
+       sar = pcalloc( p, sizeof( server_addr_rec ) );
+       **paddr = sar;
+       *paddr = &sar->next;
+       sar->host_addr.s_addr = my_addr;
+       sar->host_port = port;
+       sar->virthost = pstrdup(p, w);
+       if (t != NULL) *t = ':';
+       return;
+    }
+
+    hep = gethostbyname(w);
+
+    if ((!hep) || (hep->h_addrtype != AF_INET || !hep->h_addr_list[0])) {
+       fprintf (stderr, "Cannot resolve host name %s --- ignoring!\n", w);
+       if (t != NULL) *t = ':';
+       return;
+    }
+
+    for( i = 0; hep->h_addr_list[i]; ++i ) {
+       sar = pcalloc( p, sizeof( server_addr_rec ) );
+       **paddr = sar;
+       *paddr = &sar->next;
+       sar->host_addr = *(struct in_addr *)hep->h_addr_list[i];
+       sar->host_port = port;
+       sar->virthost = pstrdup(p, w);
+    }
+
+    if (t != NULL) *t = ':';
+}
+
+server_rec *init_virtual_host (pool *p, const char *hostname,
+                               server_rec *main_server)
+{
+    server_rec *s = (server_rec *)pcalloc (p, sizeof (server_rec));
+    server_addr_rec **addrs;
+
+#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 ) {
+       perror ("setrlimit(RLIMIT_NOFILE)");
+       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->keep_alive_max = -1;
+    s->error_log = main_server->error_log;
+    /* start the list of addreses */
+    addrs = &s->addrs;
+    while( hostname[0] ) {
+       get_addresses( p, getword_conf( p, &hostname ), &addrs,
+           main_server->port );
+    }
+    /* terminate the list */
+    *addrs = NULL;
+    if( s->addrs ) {
+       if (s->addrs->host_port) {
+           s->port = s->addrs->host_port;  /* set them the same, by default */
+       } else {
+           /* otherwise we get a port of 0 on redirects */
+           s->port = main_server->port;
+       }
+    }
+    s->next = NULL;
+
+    s->is_virtual = 1;
+    s->names = NULL;
+
+    s->module_config = create_empty_config (p);
+    s->lookup_defaults = create_per_dir_config (p);
+    
+    s->server_uid = user_id;
+    s->server_gid = group_id;
+
+    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->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;
+
+       if (virt->keep_alive_max == -1)
+           virt->keep_alive_max = main_server->keep_alive_max;
+
+       if (virt->send_buffer_size == 0)
+               virt->send_buffer_size = main_server->send_buffer_size;
+    }
+}
+
+/*****************************************************************
+ *
+ * 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->error_log = stderr;
+    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_max = DEFAULT_KEEPALIVE;
+    s->keep_alive = 1;
+    s->next = NULL;
+    s->addrs = pcalloc(p, sizeof (server_addr_rec));
+    s->addrs->host_addr.s_addr = htonl (INADDR_ANY); /* NOT virtual host;
+                                              * don't match any real network
+                                              * interface.
+                                              */
+    s->addrs->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;
+}
+
+/********************************************************************
+ * Configuration directives are restricted in terms of where they may
+ * appear in the main configuration files and/or .htaccess files according
+ * to the bitmask req_override in the command_rec structure.
+ * If any of the overrides set in req_override are also allowed in the
+ * context in which the command is read, then the command is allowed.
+ * The context is determined as follows:
+ *
+ *    inside *.conf --> override = (RSRC_CONF|OR_ALL)&~(OR_AUTHCFG|OR_LIMIT);
+ *    within <Directory> or <Location> --> override = OR_ALL|ACCESS_CONF;
+ *    within .htaccess --> override = AllowOverride for current directory;
+ *
+ * the result is, well, a rather confusing set of possibilities for when
+ * a particular directive is allowed to be used.  This procedure prints
+ * in English where the given (pc) directive can be used.
+ */
+void show_overrides(command_rec *pc, module *pm)
+{
+    int n = 0;
+    
+    printf("\tAllowed in *.conf ");
+    if ((pc->req_override & (OR_OPTIONS|OR_FILEINFO|OR_INDEXES)) ||
+        ((pc->req_override & RSRC_CONF) &&
+         ((pc->req_override & (ACCESS_CONF|OR_AUTHCFG|OR_LIMIT)))))
+        printf("anywhere");
+    else if (pc->req_override & RSRC_CONF)
+        printf("only outside <Directory> or <Location>");
+    else 
+        printf("only inside <Directory> or <Location>");
+
+    /* Warn if the directive is allowed inside <Directory> or .htaccess
+     * but module doesn't support per-dir configuration */
+
+    if ((pc->req_override & (OR_ALL|ACCESS_CONF)) && !pm->create_dir_config)
+        printf(" [no per-dir config]");
+
+    if (pc->req_override & OR_ALL) {
+        printf(" and in .htaccess\n\twhen AllowOverride");
+
+        if ((pc->req_override & OR_ALL) == OR_ALL)
+            printf(" isn't None");
+        else {
+            printf(" includes ");
+
+            if (pc->req_override & OR_AUTHCFG) {
+                if (n++) printf(" or ");
+                printf("AuthConfig");
+            }
+            if (pc->req_override & OR_LIMIT) {
+                if (n++) printf(" or ");
+                printf("Limit");
+            }
+            if (pc->req_override & OR_OPTIONS) {
+                if (n++) printf(" or ");
+                printf("Options");
+            }
+            if (pc->req_override & OR_FILEINFO) {
+                if (n++) printf(" or ");
+                printf("FileInfo");
+            }
+            if (pc->req_override & OR_INDEXES) {
+                if (n++) printf(" or ");
+                printf("Indexes");
+            }
+        }
+    }
+    printf("\n");
+}
+
+/* Show the preloaded configuration directives, the help string explaining
+ * the directive arguments, in what module they are handled, and in
+ * what parts of the configuration they are allowed.  Used for httpd -h.
+ */
+void show_directives()
+{
+    extern module *preloaded_modules[];
+    command_rec *pc;
+    int n;
+    
+    for (n = 0; preloaded_modules[n]; ++n)
+        for (pc = preloaded_modules[n]->cmds; pc && pc->name; ++pc) {
+            printf("%s\n", pc->name);
+            if (pc->errmsg)
+                printf("\t%s\n", pc->errmsg);
+            printf("\t%s\n", preloaded_modules[n]->name);
+            show_overrides(pc, preloaded_modules[n]);
+        }
+}
+
+/* Show the preloaded module names.  Used for httpd -l. */
+void show_modules()
+{
+    extern module *preloaded_modules[];
+    int n;
+    printf ("Compiled-in modules:\n");
+    for (n = 0; preloaded_modules[n]; ++n)
+        printf ("  %s\n", preloaded_modules[n]->name);
+}
+
diff --git a/APACHE_1_2_X/src/main/http_core.c b/APACHE_1_2_X/src/main/http_core.c
new file mode 100644 (file)
index 0000000..0bc6ece
--- /dev/null
@@ -0,0 +1,1387 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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 if (strncmp(dir,"proxy:",6)==0) conf->d = pstrdup (a, dir);
+    else conf->d = pstrcat (a, dir, "/", NULL);
+    conf->d_is_matchexp = conf->d ? is_matchexp( conf->d ) : 0;
+
+
+    conf->opts = dir ? OPT_UNSET : OPT_ALL;
+    conf->opts_add = conf->opts_remove = OPT_NONE;
+    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 */
+    conf->satisfy = SATISFY_NOSPEC;
+
+#ifdef RLIMIT_CPU
+    conf->limit_cpu = NULL;
+#endif
+#if defined(RLIMIT_DATA) || defined(RLIMIT_VMEM)
+    conf->limit_mem = NULL;
+#endif
+#ifdef RLIMIT_NPROC
+    conf->limit_nproc = NULL;
+#endif
+
+    conf->sec = make_array (a, 2, sizeof(void *));
+
+    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));
+    if( base->response_code_strings ) {
+       conf->response_code_strings = palloc(a,
+           sizeof(*conf->response_code_strings) * RESPONSE_CODES );
+       memcpy( conf->response_code_strings, base->response_code_strings,
+           sizeof(*conf->response_code_strings) * RESPONSE_CODES );
+    }
+    
+    conf->d = new->d;
+    conf->d_is_matchexp = new->d_is_matchexp;
+    conf->r = new->r;
+    
+    if (new->opts != OPT_UNSET) conf->opts = new->opts;
+    if (new->opts_add) conf->opts |= new->opts_add;
+    if (new->opts_remove) conf->opts &= ~(new->opts_remove);
+
+    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;
+
+    if( new->response_code_strings ) {
+       if( conf->response_code_strings == NULL ) {
+           conf->response_code_strings = palloc(a,
+               sizeof(*conf->response_code_strings) * RESPONSE_CODES );
+           memcpy( conf->response_code_strings, new->response_code_strings,
+               sizeof(*conf->response_code_strings) * RESPONSE_CODES );
+       } else {
+           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;
+
+#ifdef RLIMIT_CPU
+    if (new->limit_cpu) conf->limit_cpu = new->limit_cpu;
+#endif
+#if defined(RLIMIT_DATA) || defined(RLIMIT_VMEM)
+    if (new->limit_mem) conf->limit_mem = new->limit_mem;
+#endif
+#ifdef RLIMIT_NPROC    
+    if (new->limit_nproc) conf->limit_nproc = new->limit_nproc;
+#endif
+
+    conf->sec = append_arrays (a, base->sec, new->sec);
+
+    if (new->satisfy != SATISFY_NOSPEC) conf->satisfy = new->satisfy;
+    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;
+}
+
+void add_file_conf (core_dir_config *conf, void *url_config)
+{
+    void **new_space = (void **) push_array (conf->sec);
+    
+    *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;
+}
+
+int satisfies (request_rec *r)
+{
+    core_dir_config *conf =
+      (core_dir_config *)get_module_config(r->per_dir_config, &core_module);
+
+    return conf->satisfy;
+}
+
+/* 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); 
+
+    if( conf->response_code_strings == NULL ) {
+       return NULL;
+    }
+    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 = NULL;
+
+/* If we haven't checked the host name, and we want to */
+    if (dir_config) 
+       dir_conf = (core_dir_config *)get_module_config(dir_config, &core_module);
+
+   if ((!dir_conf) || (type != REMOTE_NOLOOKUP && 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.
+ */
+
+const 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;
+}
+
+const 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;
+}
+
+const char *set_error_document (cmd_parms *cmd, core_dir_config *conf,
+                               char *line)
+{
+    int error_number, index_number, idx500;
+    char *w;
+                
+    /* 1st parameter should be a 3 digit number, which we recognize;
+     * convert it into an array index
+     */
+  
+    w = getword_conf_nc (cmd->pool, &line);
+    error_number = atoi(w);
+
+    idx500 = index_of_response(HTTP_INTERNAL_SERVER_ERROR);
+
+    if (error_number == HTTP_INTERNAL_SERVER_ERROR)
+        index_number = idx500;
+    else if ((index_number = index_of_response(error_number)) == idx500)
+        return pstrcat(cmd->pool, "Unsupported HTTP response code ", w, NULL);
+                
+    /* Store it... */
+
+    if( conf->response_code_strings == NULL ) {
+       conf->response_code_strings = pcalloc(cmd->pool,
+           sizeof(*conf->response_code_strings) * RESPONSE_CODES );
+    }
+    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.
+ */
+
+const char *set_override (cmd_parms *cmd, core_dir_config *d, const 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;
+}
+
+const char *set_options (cmd_parms *cmd, core_dir_config *d, const char *l)
+{
+    char opt;
+    int first = 1;
+    char action;
+
+    while(l[0]) {
+        char *w = getword_conf(cmd->pool, &l);
+       action = '\0';
+
+       if (*w == '+' || *w == '-')
+           action = *(w++);
+       else if (first) {
+           d->opts = OPT_NONE;
+            first = 0;
+        }
+           
+       if(!strcasecmp(w,"Indexes"))
+           opt = OPT_INDEXES;
+       else if(!strcasecmp(w,"Includes"))
+           opt = OPT_INCLUDES;
+       else if(!strcasecmp(w,"IncludesNOEXEC"))
+           opt = (OPT_INCLUDES | OPT_INCNOEXEC);
+       else if(!strcasecmp(w,"FollowSymLinks"))
+           opt = OPT_SYM_LINKS;
+       else if(!strcasecmp(w,"SymLinksIfOwnerMatch"))
+           opt = OPT_SYM_OWNER;
+       else if(!strcasecmp(w,"execCGI"))
+           opt = OPT_EXECCGI;
+       else if (!strcasecmp(w,"MultiViews"))
+           opt = OPT_MULTI;
+       else if (!strcasecmp(w,"RunScripts")) /* AI backcompat. Yuck */
+           opt = OPT_MULTI|OPT_EXECCGI;
+       else if(!strcasecmp(w,"None")) 
+           opt = OPT_NONE;
+       else if(!strcasecmp(w,"All")) 
+           opt = OPT_ALL;
+       else 
+           return pstrcat (cmd->pool, "Illegal option ", w, NULL);
+
+       if (action == '-')
+           d->opts_remove |= opt;
+       else if (action == '+')
+           d->opts_add |= opt;
+       else
+         d->opts |= opt;
+    }
+
+    return NULL;
+}
+
+const char *satisfy (cmd_parms *cmd, core_dir_config *c, char *arg)
+{
+    if(!strcasecmp(arg,"all"))
+        c->satisfy = SATISFY_ALL;
+    else if(!strcasecmp(arg,"any"))
+        c->satisfy = SATISFY_ANY;
+    else
+        return "Satisfy either 'any' or 'all'.";
+    return NULL;
+}
+
+const 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;
+}
+
+const char *limit (cmd_parms *cmd, void *dummy, const char *arg)
+{
+    const 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 if(!strcasecmp(method,"OPTIONS")) limited |= (1 << M_OPTIONS);
+       else return "unknown method in <Limit>";
+    }
+
+    cmd->limited = limited;
+    return NULL;
+}
+
+const char *endlimit (cmd_parms *cmd, void *dummy, void *dummy2)
+{
+    if (cmd->limited == -1) return "</Limit> unexpected";
+    
+    cmd->limited = -1;
+    return NULL;
+}
+
+static const char end_dir_magic[] = "</Directory> outside of any <Directory> section";
+
+const char *end_dirsection (cmd_parms *cmd, void *dummy) {
+    return end_dir_magic;
+}
+
+const char *dirsection (cmd_parms *cmd, void *dummy, const char *arg)
+{
+    const char *errmsg;
+    char *endp = strrchr (arg, '>');
+    int old_overrides = cmd->override;
+    char *old_path = cmd->path;
+    core_dir_config *conf;
+    void *new_dir_conf = create_per_dir_config (cmd->pool);
+    regex_t *r = NULL;
+
+    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);
+#ifdef __EMX__
+    /* Fix OS/2 HPFS filename case problem. */
+    cmd->path = strlwr(cmd->path);
+#endif    
+    cmd->override = OR_ALL|ACCESS_CONF;
+
+    if (!strcmp(cmd->path, "~")) {
+       cmd->path = getword_conf (cmd->pool, &arg);
+       r = pregcomp(cmd->pool, cmd->path, REG_EXTENDED);
+    }
+
+    errmsg = srm_command_loop (cmd, new_dir_conf);
+    if (errmsg != end_dir_magic) return errmsg;
+
+    conf = (core_dir_config *)get_module_config(new_dir_conf, &core_module);
+    conf->r = r;
+
+    add_per_dir_conf (cmd->server, new_dir_conf);
+    cmd->path = old_path;
+    cmd->override = old_overrides;
+
+    return NULL;
+}
+
+static const char end_url_magic[] = "</Location> outside of any <Location> section";
+
+const char *end_urlsection (cmd_parms *cmd, void *dummy) {
+    return end_url_magic;
+}
+
+const char *urlsection (cmd_parms *cmd, void *dummy, const char *arg)
+{
+    const char *errmsg;
+    char *endp = strrchr (arg, '>');
+    int old_overrides = cmd->override;
+    char *old_path = cmd->path;
+    core_dir_config *conf;
+    regex_t *r = NULL;
+
+    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;
+
+    if (!strcmp(cmd->path, "~")) {
+       cmd->path = getword_conf (cmd->pool, &arg);
+       r = pregcomp(cmd->pool, cmd->path, REG_EXTENDED);
+    }
+
+    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 */
+    conf->d_is_matchexp = is_matchexp( conf->d );
+    conf->r = r;
+
+    add_per_url_conf (cmd->server, new_url_conf);
+    
+    cmd->path = old_path;
+    cmd->override = old_overrides;
+
+    return NULL;
+}
+
+static char *end_file_magic = "</Files> outside of any <Files> section";
+
+const char *end_filesection (cmd_parms *cmd, void *dummy) {
+    return end_file_magic;
+}
+
+const char *filesection (cmd_parms *cmd, core_dir_config *c, const char *arg)
+{
+    const char *errmsg;
+    char *endp = strrchr (arg, '>');
+    int old_overrides = cmd->override;
+    char *old_path = cmd->path;
+    core_dir_config *conf;
+    regex_t *r = NULL;
+
+    void *new_file_conf = create_per_dir_config (cmd->pool);
+
+    if (endp) *endp = '\0';
+
+    if (cmd->limited != -1) return "Can't have <Files> within <Limit>";
+
+    cmd->path = getword_conf (cmd->pool, &arg);
+    /* Only if not an .htaccess file */
+    if (cmd->path)
+       cmd->override = OR_ALL|ACCESS_CONF;
+
+    if (!strcmp(cmd->path, "~")) {
+       cmd->path = getword_conf (cmd->pool, &arg);
+       if (old_path && cmd->path[0] != '/' && cmd->path[0] != '^')
+           cmd->path = pstrcat(cmd->pool, "^", old_path, cmd->path, NULL);
+       r = pregcomp(cmd->pool, cmd->path, REG_EXTENDED);
+    }
+    else if (old_path && cmd->path[0] != '/')
+       cmd->path = pstrcat(cmd->pool, old_path, cmd->path, NULL);
+
+    errmsg = srm_command_loop (cmd, new_file_conf);
+    if (errmsg != end_file_magic) return errmsg;
+
+    conf = (core_dir_config *)get_module_config(new_file_conf, &core_module);
+    conf->d = pstrdup(cmd->pool, cmd->path);
+    conf->d_is_matchexp = is_matchexp( conf->d );
+    conf->r = r;
+
+    add_file_conf (c, new_file_conf);
+    
+    cmd->path = old_path;
+    cmd->override = old_overrides;
+
+    return NULL;
+}
+
+const char *end_ifmod (cmd_parms *cmd, void *dummy) {
+    return NULL;
+}
+
+const char *start_ifmod (cmd_parms *cmd, void *dummy, char *arg)
+{
+    char *endp = strrchr (arg, '>');
+    char l[MAX_STRING_LEN];
+    int not = (arg[0] == '!');
+    module *found;
+    int nest = 1;
+
+    if (endp) *endp = '\0';
+    if (not) arg++;
+
+    found = find_linked_module(arg);
+
+    if ((!not && found) || (not && !found))
+      return NULL;
+
+    while (nest && !(cfg_getline (l, MAX_STRING_LEN, cmd->infile))) {
+        if (!strncasecmp(l, "<IfModule", 9))
+         nest++;
+       if (!strcasecmp(l, "</IfModule>"))
+         nest--;
+    }
+
+    return NULL;
+}
+
+/* httpd.conf commands... beginning with the <VirtualHost> business */
+
+const char end_virthost_magic[] = "</Virtualhost> out of place";
+
+const char *end_virtualhost_section (cmd_parms *cmd, void *dummy)
+{
+    return end_virthost_magic;
+}
+
+const char *virtualhost_section (cmd_parms *cmd, void *dummy, char *arg)
+{
+    server_rec *main_server = cmd->server, *s;
+    const char *errmsg;
+    char *endp = strrchr (arg, '>');
+    pool *p = cmd->pool, *ptemp = cmd->temp_pool;
+
+    if (endp) *endp = '\0';
+    
+    /* FIXME: There's another feature waiting to happen here -- since you
+       can now put multiple addresses/names on a single <VirtualHost>
+       you might want to use it to group common definitions and then
+       define other "subhosts" with their individual differences.  But
+       personally I'd rather just do it with a macro preprocessor. -djg */
+    if (main_server->is_virtual)
+       return "<VirtualHost> doesn't nest!";
+    
+    s = init_virtual_host (p, arg, main_server);
+    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;
+}
+
+const char *add_module_command (cmd_parms *cmd, void *dummy, char *arg)
+{
+    if (add_named_module (arg))
+        return NULL;
+    return "required module not found";
+}
+
+const char *clear_module_list_command (cmd_parms *cmd, void *dummy)
+{
+    clear_module_list ();
+    return NULL;
+}
+
+const 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;
+}
+
+const 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;
+}
+
+const char *server_port (cmd_parms *cmd, void *dummy, char *arg) {
+    cmd->server->port = atoi (arg);
+    return NULL;
+}
+
+const char *set_send_buffer_size (cmd_parms *cmd, void *dummy, char *arg) {
+    int s = atoi (arg);
+    if (s < 512 && s != 0) {
+        return "SendBufferSize must be >= 512 bytes, or 0 for system default.";
+    }
+    cmd->server->send_buffer_size = s;
+    return NULL;
+}
+
+const char *set_user (cmd_parms *cmd, void *dummy, char *arg)
+{
+    if (!cmd->server->is_virtual) {
+       user_name = pstrdup (cmd->pool, arg);
+       cmd->server->server_uid = user_id = uname2id(arg);
+    }
+    else {
+       if (suexec_enabled)
+           cmd->server->server_uid = uname2id(arg);
+       else {
+           cmd->server->server_uid = user_id;
+           fprintf(stderr,
+                   "Warning: User directive in <VirtualHost> requires SUEXEC wrapper.\n");
+       }
+    }
+
+    return NULL;
+}
+
+const char *set_group (cmd_parms *cmd, void *dummy, char *arg)
+{
+    if (!cmd->server->is_virtual)
+       cmd->server->server_gid = group_id = gname2id(arg);
+    else {
+       if (suexec_enabled)
+           cmd->server->server_gid = gname2id(arg);
+       else {
+           cmd->server->server_gid = group_id;
+           fprintf(stderr,
+                   "Warning: Group directive in <VirtualHost> requires SUEXEC wrapper.\n");
+       }
+    }
+
+    return NULL;
+}
+
+const char *set_server_root (cmd_parms *cmd, void *dummy, char *arg) {
+    if (!is_directory (arg)) return "ServerRoot must be a valid directory";
+    strncpy (server_root, arg, sizeof(server_root)-1);
+    server_root[sizeof(server_root)-1] = '\0';
+    return NULL;
+}
+
+const char *set_timeout (cmd_parms *cmd, void *dummy, char *arg) {
+    cmd->server->timeout = atoi (arg);
+    return NULL;
+}
+
+const char *set_keep_alive_timeout (cmd_parms *cmd, void *dummy, char *arg) {
+    cmd->server->keep_alive_timeout = atoi (arg);
+    return NULL;
+}
+
+const char *set_keep_alive (cmd_parms *cmd, void *dummy, char *arg) {
+    /* We've changed it to On/Off, but used to use numbers
+     * so we accept anything but "Off" or "0" as "On"
+     */
+    if (!strcasecmp(arg, "off") || !strcmp(arg, "0"))
+       cmd->server->keep_alive = 0;
+    else
+       cmd->server->keep_alive = 1;
+    return NULL;
+}
+
+const char *set_keep_alive_max (cmd_parms *cmd, void *dummy, char *arg) {
+    cmd->server->keep_alive_max = atoi (arg);
+    return NULL;
+}
+
+const char *set_pidfile (cmd_parms *cmd, void *dummy, char *arg) {
+    pid_fname = pstrdup (cmd->pool, arg);
+    return NULL;
+}
+
+const char *set_scoreboard (cmd_parms *cmd, void *dummy, char *arg) {
+    scoreboard_fname = pstrdup (cmd->pool, arg);
+    return NULL;
+}
+
+const char *set_idcheck (cmd_parms *cmd, core_dir_config *d, int arg) {
+    d->do_rfc1413 = arg;
+    return NULL;
+}
+
+const char *set_hostname_lookups (cmd_parms *cmd, core_dir_config *d, int arg)
+{
+    d->hostname_lookups = arg;
+    return NULL;
+}
+
+const char *set_serverpath (cmd_parms *cmd, void *dummy, char *arg) {
+    cmd->server->path = pstrdup (cmd->pool, arg);
+    cmd->server->pathlen = strlen (arg);
+    return NULL;
+}
+
+const char *set_content_md5 (cmd_parms *cmd, core_dir_config *d, int arg) {
+    d->content_md5 = arg;
+    return NULL;
+}
+
+const char *set_daemons_to_start (cmd_parms *cmd, void *dummy, char *arg) {
+    daemons_to_start = atoi (arg);
+    return NULL;
+}
+
+const 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;
+}
+
+const char *set_max_free_servers (cmd_parms *cmd, void *dummy, char *arg) {
+    daemons_max_free = atoi (arg);
+    return NULL;
+}
+
+const char *set_server_limit (cmd_parms *cmd, void *dummy, char *arg) {
+    daemons_limit = atoi (arg);
+    if (daemons_limit > HARD_SERVER_LIMIT) {
+       fprintf(stderr, "WARNING: Compile-time limit of %d servers\n",
+        HARD_SERVER_LIMIT);
+       fprintf(stderr, " Adjusting as required (to increase, please read\n");
+       fprintf(stderr, " the documentation)\n");
+       daemons_limit = HARD_SERVER_LIMIT;
+    } else if (daemons_limit < 1) {
+       fprintf (stderr, "WARNING: Require MaxClients > 0, setting to 1\n");
+       daemons_limit = 1;
+    }
+    return NULL;
+}
+
+const char *set_max_requests (cmd_parms *cmd, void *dummy, char *arg) {
+    max_requests_per_child = atoi (arg);
+    return NULL;
+}
+
+#if defined(RLIMIT_CPU) || defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_NPROC)
+static void set_rlimit(cmd_parms *cmd, struct rlimit **plimit, const char *arg,
+                       const char * arg2, int type)
+{
+    char *str;
+    struct rlimit *limit;
+    /* If your platform doesn't define rlim_t then typedef it in conf.h */
+    rlim_t cur = 0;
+    rlim_t max = 0;
+
+    *plimit=(struct rlimit *)pcalloc(cmd->pool,sizeof **plimit);
+    limit=*plimit;
+    if ((getrlimit(type, limit)) != 0)
+       {
+       *plimit = NULL;
+       log_unixerr("getrlimit",cmd->cmd->name,"failed",cmd->server);
+       return;
+       }
+
+    if ((str = getword_conf(cmd->pool, &arg)))
+       if (!strcasecmp(str, "max"))
+           cur = limit->rlim_max;
+       else
+           cur = atol(str);
+    else {
+       log_printf(cmd->server, "Invalid parameters for %s", cmd->cmd->name);
+       return;
+    }
+    
+    if (arg2 && (str = getword_conf(cmd->pool, &arg2)))
+       max = atol(str);
+
+    /* if we aren't running as root, cannot increase max */
+    if (geteuid()) {
+       limit->rlim_cur = cur;
+       if (max)
+           log_printf(cmd->server, "Must be uid 0 to raise maximum %s",
+                     cmd->cmd->name);
+    }
+    else {
+       if (cur)
+           limit->rlim_cur = cur;
+       if (max)
+           limit->rlim_max = max;
+    }
+}
+#endif
+
+#if !defined (RLIMIT_CPU) || !(defined (RLIMIT_DATA) || defined (RLIMIT_VMEM)) || !defined (RLIMIT_NPROC)
+static const char *no_set_limit (cmd_parms *cmd, core_dir_config *conf,
+                                char *arg, char *arg2)
+{
+    log_printf(cmd->server, "%s not supported on this platform",
+              cmd->cmd->name);
+    return NULL;
+}
+#endif
+
+#ifdef RLIMIT_CPU
+const char *set_limit_cpu (cmd_parms *cmd, core_dir_config *conf, char *arg, char *arg2)
+{
+    set_rlimit(cmd,&conf->limit_cpu,arg,arg2,RLIMIT_CPU);
+    return NULL;
+}
+#endif
+
+#if defined (RLIMIT_DATA) || defined (RLIMIT_VMEM)
+const char *set_limit_mem (cmd_parms *cmd, core_dir_config *conf, char *arg, char * arg2)
+{
+#ifdef RLIMIT_DATA
+    set_rlimit(cmd,&conf->limit_mem,arg,arg2,RLIMIT_DATA);
+#else
+    set_rlimit(cmd,&conf->limit_mem,arg,arg2,RLIMIT_VMEM);
+#endif
+    return NULL;
+}
+#endif
+
+#ifdef RLIMIT_NPROC
+const char *set_limit_nproc (cmd_parms *cmd, core_dir_config *conf, char *arg, char * arg2)
+{
+    set_rlimit(cmd,&conf->limit_nproc,arg,arg2,RLIMIT_NPROC);
+    return NULL;
+}
+#endif
+
+const char *set_bind_address (cmd_parms *cmd, void *dummy, char *arg) {
+    bind_address.s_addr = get_virthost_addr (arg, NULL);
+    return NULL;
+}
+
+const char *set_listener(cmd_parms *cmd, void *dummy, char *ips)
+{
+    listen_rec *new;
+    char *ports;
+    unsigned port;
+
+    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=pcalloc(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);
+    port=atoi(ports);
+    if(!port)
+       return "Port must be numeric";
+    new->local_addr.sin_port = htons(port);
+    new->fd = -1;
+    new->used = 0;
+    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, "Container for directives affecting resources located in the specified directories" },
+{ "</Directory>", end_dirsection, NULL, ACCESS_CONF, NO_ARGS, NULL },
+{ "<Location", urlsection, NULL, RSRC_CONF, RAW_ARGS, "Container for directives affecting resources accessed through the specified URL paths" },
+{ "</Location>", end_urlsection, NULL, ACCESS_CONF, NO_ARGS, NULL },
+{ "<VirtualHost", virtualhost_section, NULL, RSRC_CONF, RAW_ARGS, "Container to map directives to a particular virtual host" },
+{ "</VirtualHost>", end_virtualhost_section, NULL, RSRC_CONF, NO_ARGS, NULL },
+{ "<Files", filesection, NULL, OR_ALL, RAW_ARGS, "Container for directives affecting files matching specified patterns" },
+{ "</Files>", end_filesection, NULL, OR_ALL, NO_ARGS, NULL },
+{ "<Limit", limit, NULL, OR_ALL, RAW_ARGS, "Container for authentication directives when accessed using specified HTTP methods" },
+{ "</Limit>", endlimit, NULL, OR_ALL, RAW_ARGS, NULL },
+{ "<IfModule", start_ifmod, NULL, OR_ALL, RAW_ARGS, "Container for directives based on existance of specified modules" },
+{ "</IfModule>", end_ifmod, NULL, OR_ALL, NO_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, "The authentication realm (e.g. \"Members Only\")" },
+{ "Require", require, NULL, OR_AUTHCFG, RAW_ARGS, "Selects which authenticated users or groups may access a protected space" },
+{ "Satisfy", satisfy, NULL, OR_AUTHCFG, TAKE1,
+    "access policy if both allow and require used ('all' or 'any')" },    
+
+/* Old resource config file commands */
+  
+{ "AccessFileName", set_access_name, NULL, RSRC_CONF, TAKE1, "Name of per-directory config files (default: .htaccess)" },
+{ "DocumentRoot", set_document_root, NULL, RSRC_CONF, TAKE1, "Root directory of the document tree"  },
+{ "ErrorDocument", set_error_document, NULL, OR_FILEINFO, RAW_ARGS, "Change responses for HTTP errors" },
+{ "AllowOverride", set_override, NULL, ACCESS_CONF, RAW_ARGS, "Controls what groups of directives can be configured by per-directory config files" },
+{ "Options", set_options, NULL, OR_OPTIONS, RAW_ARGS, "Set a number of attributes for a given directory" },
+{ "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, "\"on\" to enable or \"off\" to disable reverse DNS lookups" },
+{ "User", set_user, NULL, RSRC_CONF, TAKE1, "Effective user id for this server"},
+{ "Group", set_group, NULL, RSRC_CONF, TAKE1, "Effective group id for this server"},
+{ "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, "Common directory of server-related files (logs, confs, etc)" },
+{ "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)"},
+{ "MaxKeepAliveRequests", set_keep_alive_max, NULL, RSRC_CONF, TAKE1, "Maximum number of Keep-Alive requests per connection, or 0 for infinite" },
+{ "KeepAlive", set_keep_alive, NULL, RSRC_CONF, TAKE1, "Whether persistent connections should be On or Off" },
+{ "IdentityCheck", set_idcheck, NULL, RSRC_CONF|ACCESS_CONF, FLAG, "Enable identd (RFC 1413) user lookups - SLOW" },
+{ "ContentDigest", set_content_md5, NULL, RSRC_CONF|ACCESS_CONF|OR_AUTHCFG, FLAG, "whether or not to send a Content-MD5 header with each request" },
+{ "StartServers", set_daemons_to_start, NULL, RSRC_CONF, TAKE1, "Number of child processes launched at server startup" },
+{ "MinSpareServers", set_min_free_servers, NULL, RSRC_CONF, TAKE1, "Minimum number of idle children, to handle request spikes" },
+{ "MaxSpareServers", set_max_free_servers, NULL, RSRC_CONF, TAKE1, "Maximum number of idle children" },
+{ "MaxServers", set_max_free_servers, NULL, RSRC_CONF, TAKE1, "Deprecated equivalent to MaxSpareServers" },
+{ "ServersSafetyLimit", set_server_limit, NULL, RSRC_CONF, TAKE1, "Deprecated equivalent to MaxClients" },
+{ "MaxClients", set_server_limit, NULL, RSRC_CONF, TAKE1, "Maximum number of children alive at the same time" },
+{ "MaxRequestsPerChild", set_max_requests, NULL, RSRC_CONF, TAKE1, "Maximum number of requests a particular child serves before dying." },
+{ "RLimitCPU",
+#ifdef RLIMIT_CPU
+ set_limit_cpu, (void*)XtOffsetOf(core_dir_config, limit_cpu),
+#else
+ no_set_limit, NULL,
+#endif
+      OR_ALL, TAKE12, "soft/hard limits for max CPU usage in seconds" },
+{ "RLimitMEM",
+#if defined (RLIMIT_DATA) || defined (RLIMIT_VMEM)
+ set_limit_mem, (void*)XtOffsetOf(core_dir_config, limit_mem),
+#else
+ no_set_limit, NULL,
+#endif
+      OR_ALL, TAKE12, "soft/hard limits for max memory usage per process" },
+{ "RLimitNPROC",
+#ifdef RLIMIT_NPROC
+ set_limit_nproc, (void*)XtOffsetOf(core_dir_config, limit_nproc),
+#else
+ no_set_limit, NULL,
+#endif
+      OR_ALL, TAKE12, "soft/hard limits for max number of processes per uid" },
+{ "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"},
+{ "SendBufferSize", set_send_buffer_size, NULL, RSRC_CONF, TAKE1, "send buffer size in bytes"},
+{ "AddModule", add_module_command, NULL, RSRC_CONF, ITERATE,
+  "the name of a module" },
+{ "ClearModuleList", clear_module_list_command, 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 HTTP_FORBIDDEN;
+    if ((r->uri[0] != '/') && strcmp(r->uri, "*")) {
+       log_printf(r->server, "Invalid URI in request %s", r->the_request);
+       return BAD_REQUEST;
+    }
+    
+    if (r->server->path &&
+       !strncmp(r->uri, r->server->path, r->server->pathlen) &&
+       (r->server->path[r->server->pathlen - 1] == '/' ||
+        r->uri[r->server->pathlen] == '/' ||
+        r->uri[r->server->pathlen] == '\0'))
+      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
+ * and OPTIONS 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... So, for now, we assume that this will always be
+ * the last handler called and return 405 or 501.
+ */
+
+int default_handler (request_rec *r)
+{
+    core_dir_config *d =
+      (core_dir_config *)get_module_config(r->per_dir_config, &core_module);
+    int rangestatus, errstatus;
+    FILE *f;
+    
+    r->allowed |= (1 << M_GET);
+    r->allowed |= (1 << M_TRACE);
+    r->allowed |= (1 << M_OPTIONS);
+
+    if (r->method_number == M_INVALID) {
+       log_printf(r->server, "Invalid method in request %s", r->the_request);
+       return NOT_IMPLEMENTED;
+    }
+    if (r->method_number == M_OPTIONS) return send_http_options(r);
+    if (r->method_number == M_PUT) return METHOD_NOT_ALLOWED;
+
+    if (r->finfo.st_mode == 0 || (r->path_info && *r->path_info)) {
+       log_reason("File does not exist",
+           r->path_info ? pstrcat(r->pool, r->filename, r->path_info, NULL)
+               : r->filename, r);
+       return NOT_FOUND;
+    }
+    if (r->method_number != M_GET) return METHOD_NOT_ALLOWED;
+    
+#ifdef __EMX__
+    /* Need binary mode for OS/2 */
+    f = pfopen (r->pool, r->filename, "rb");
+#else
+    f = pfopen (r->pool, r->filename, "r");
+#endif
+
+    if (f == NULL) {
+        log_reason("file permissions deny server access", r->filename, r);
+        return FORBIDDEN;
+    }
+       
+    if ((errstatus = set_last_modified (r, r->finfo.st_mtime))
+       || (errstatus = set_content_length (r, r->finfo.st_size)))
+        return errstatus;
+
+    if (d->content_md5 & 1) {
+      table_set (r->headers_out, "Content-MD5", md5digest(r->pool, f));
+    }
+
+    rangestatus = set_byterange(r);
+    send_http_header (r);
+    
+    if (!r->header_only) {
+       if (!rangestatus)
+           send_fd (f, r);
+       else {
+           long offset, length;
+           while (each_byterange(r, &offset, &length)) {
+               fseek(f, offset, SEEK_SET);
+               send_fd_length(f, r, length);
+           }
+       }
+    }
+
+    pfclose(r->pool, 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 */
+   NULL                                /* header parser */
+};
diff --git a/APACHE_1_2_X/src/main/http_log.c b/APACHE_1_2_X/src/main/http_log.c
new file mode 100644 (file)
index 0000000..896c0a8
--- /dev/null
@@ -0,0 +1,197 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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);
+#ifdef __EMX__
+    /* For OS/2 we need to use a '/' */
+    execl (SHELL_PATH, SHELL_PATH, "/c", (char *)cmd, NULL);
+#else    
+    execl (SHELL_PATH, SHELL_PATH, "-c", (char *)cmd, NULL);
+#endif    
+    exit (1);
+}
+
+void open_error_log(server_rec *s, pool *p)
+{
+    char *fname;
+  
+    fname = server_root_relative (p, s->error_fname);
+
+    if (*s->error_fname == '|') {
+      FILE *dummy;
+
+      if (!spawn_child (p, error_log_child, (void *)(s->error_fname+1),
+                    kill_after_timeout, &dummy, NULL)) {
+       perror ("spawn_child");
+       fprintf (stderr, "Couldn't fork child for ErrorLog process\n");
+       exit (1);
+      }
+
+      s->error_log = dummy;
+    } else {
+        if(!(s->error_log = pfopen(p, fname, "a"))) {
+            perror("fopen");
+            fprintf(stderr,"httpd: could not open error log file %s.\n", fname);
+            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(const char *reason, const 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/APACHE_1_2_X/src/main/http_main.c b/APACHE_1_2_X/src/main/http_main.c
new file mode 100644 (file)
index 0000000..20ef2bb
--- /dev/null
@@ -0,0 +1,2518 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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 Apache.
+ */
+
+#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 <assert.h>
+#include <sys/stat.h>
+#ifdef HAVE_SHMGET
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#endif
+#ifdef SecureWare
+#include <sys/security.h>
+#include <sys/audit.h>
+#include <prot.h>
+#endif
+#include <netinet/tcp.h>
+
+#ifdef HAVE_BSTRING_H
+#include <bstring.h>           /* for IRIX, FD_SET calls bzero() */
+#endif
+
+#include "explain.h"
+
+#if !defined(max)
+#define max(a,b)        (a > b ? a : b)
+#endif
+
+#ifdef __EMX__
+    /* Add MMAP style functionality to OS/2 */
+    #ifdef HAVE_MMAP
+        #define INCL_DOSMEMMGR
+        #include <os2.h>
+        #include <umalloc.h>
+        #include <stdio.h>
+        caddr_t create_shared_heap (const char *, size_t);
+        caddr_t get_shared_heap (const char *);
+    #endif
+#endif
+
+
+DEF_Explain
+
+/*
+ * 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;
+#ifdef MULTIPLE_GROUPS
+gid_t group_id_list[NGROUPS_MAX];
+#endif
+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;
+int suexec_enabled = 0;
+
+char server_root[MAX_STRING_LEN];
+char server_confname[MAX_STRING_LEN];
+
+/* *Non*-shared http_main globals... */
+
+server_rec *server_conf;
+JMP_BUF jmpbuffer;
+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 --- Apache doesn't keep track of their pids, it just sends
+ * SIGHUP to the process group, ignoring it in the root process.
+ * Continue through and you'll be fine.).
+ */
+
+int one_process = 0;
+
+/* small utility macros to make things easier to read */
+
+#ifdef NO_KILLPG
+#define ap_killpg(x, y)                (kill (-(x), (y)))
+#else
+#define ap_killpg(x, y)                (killpg ((x), (y)))
+#endif
+
+#if defined(USE_FCNTL_SERIALIZED_ACCEPT)
+static struct flock lock_it;
+static struct flock unlock_it;
+
+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[256];
+
+    lock_it.l_whence = SEEK_SET;   /* from current point */
+    lock_it.l_start  = 0;          /* -"- */
+    lock_it.l_len    = 0;          /* until end of file */
+    lock_it.l_type   = F_WRLCK;    /* set exclusive/write lock */
+    lock_it.l_pid    = 0;          /* pid not actually interesting */
+    unlock_it.l_whence = SEEK_SET; /* from current point */
+    unlock_it.l_start  = 0;        /* -"- */
+    unlock_it.l_len    = 0;        /* until end of file */
+    unlock_it.l_type   = F_UNLCK;  /* set exclusive/write lock */
+    unlock_it.l_pid    = 0;        /* pid not actually interesting */
+
+#ifdef __MACHTEN__
+    strncpy(lock_fname, "/var/tmp/htlock.XXXXXX", sizeof(lock_fname)-1);
+#else
+    strncpy(lock_fname, "/usr/tmp/htlock.XXXXXX", sizeof(lock_fname)-1);
+#endif
+    lock_fname[sizeof(lock_fname)-1] = '\0';
+
+    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 | O_EXCL, 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(USE_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[256];
+
+    strncpy(lock_fname, "/usr/tmp/htlock.XXXXXX", sizeof(lock_fname)-1);
+    lock_fname[sizeof(lock_fname)-1] = '\0';
+    
+    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 | O_EXCL, 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] [-h] [-l]\n",bin);
+    fprintf(stderr,"-d directory : specify an alternate initial ServerRoot\n");
+    fprintf(stderr,"-f file : specify an alternate ServerConfigFile\n");
+    fprintf(stderr,"-v : show version number\n");
+    fprintf(stderr,"-h : list directives\n");
+    fprintf(stderr,"-l : list modules\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;
+
+#ifndef NO_USE_SIGACTION
+/*
+ * Replace standard signal() with the more reliable sigaction equivalent
+ * from W. Richard Stevens' "Advanced Programming in the UNIX Environment"
+ * (the version that does not automatically restart system calls).
+ */
+Sigfunc *signal(int signo, Sigfunc *func)
+{
+    struct sigaction act, oact;
+
+    act.sa_handler = func;
+    sigemptyset(&act.sa_mask);
+    act.sa_flags = 0;
+#ifdef  SA_INTERRUPT    /* SunOS */
+    act.sa_flags |= SA_INTERRUPT;
+#endif
+    if (sigaction(signo, &act, &oact) < 0)
+       return SIG_ERR;
+    return oact.sa_handler;
+}
+#endif
+
+void timeout(int sig)                  /* Also called on SIGPIPE */
+{
+    char errstr[MAX_STRING_LEN];
+    void *dirconf;
+
+    signal(SIGPIPE, SIG_IGN);          /* Block SIGPIPE */
+    if (alarms_blocked) {
+       alarm_pending = 1;
+       return;
+    }
+    
+    if (!current_conn) {
+       ap_longjmp (jmpbuffer, 1);
+    }
+    
+    if (timeout_req != NULL) dirconf = timeout_req->per_dir_config;
+    else dirconf = current_conn->server->lookup_defaults;
+    if (sig == SIGPIPE) {
+        ap_snprintf(errstr, sizeof(errstr), "%s lost connection to client %s",
+           timeout_name ? timeout_name : "request",
+           get_remote_host(current_conn, dirconf, REMOTE_NAME));
+    } else {
+        ap_snprintf(errstr, sizeof(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);
+
+       bsetflag(timeout_req->connection->client, B_EOUT, 1);
+       bclose(timeout_req->connection->client);
+    
+       if (!standalone) exit(0);
+
+       ap_longjmp (jmpbuffer, 1);
+    }
+    else {   /* abort the connection */
+        bsetflag(current_conn->client, B_EOUT, 1);
+        current_conn->aborted = 1;
+    }
+}
+
+/*
+ * 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 keepalive_timeout (char *name, request_rec *r)
+{
+    timeout_req = r;
+    timeout_name = name;
+    
+    signal(SIGALRM, timeout);
+    if (r->connection->keptalive) 
+       alarm (r->server->keep_alive_timeout);
+    else
+       alarm (r->server->timeout);
+}
+
+void hard_timeout (char *name, request_rec *r)
+{
+    timeout_req = r;
+    timeout_name = name;
+    
+    signal(SIGALRM, timeout);
+    alarm (r->server->timeout);
+}
+
+void soft_timeout (char *name, request_rec *r)
+{
+    timeout_name = name;
+    
+    signal(SIGALRM, 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);
+    }
+}
+
+/*
+ * More machine-dependent networking gooo... on some systems,
+ * you've got to be *really* sure that all the packets are acknowledged
+ * before closing the connection, since the client will not be able
+ * to see the last response if their TCP buffer is flushed by a RST
+ * packet from us, which is what the server's TCP stack will send
+ * if it receives any request data after closing the connection.
+ *
+ * In an ideal world, this function would be accomplished by simply
+ * setting the socket option SO_LINGER and handling it within the
+ * server's TCP stack while the process continues on to the next request.
+ * Unfortunately, it seems that most (if not all) operating systems
+ * block the server process on close() when SO_LINGER is used.
+ * For those that don't, see USE_SO_LINGER below.  For the rest,
+ * we have created a home-brew lingering_close.
+ *
+ * Many operating systems tend to block, puke, or otherwise mishandle
+ * calls to shutdown only half of the connection.  You should define
+ * NO_LINGCLOSE in conf.h if such is the case for your system.
+ */
+#ifndef MAX_SECS_TO_LINGER
+#define MAX_SECS_TO_LINGER 30
+#endif
+
+#ifdef USE_SO_LINGER
+#define NO_LINGCLOSE    /* The two lingering options are exclusive */
+
+static void sock_enable_linger (int s)
+{
+    struct linger li;
+
+    li.l_onoff = 1;
+    li.l_linger = MAX_SECS_TO_LINGER;
+
+    if (setsockopt(s, SOL_SOCKET, SO_LINGER,
+                   (char *)&li, sizeof(struct linger)) < 0) {
+        log_unixerr("setsockopt", "(SO_LINGER)", NULL, server_conf);
+        /* not a fatal error */
+    }
+}
+
+#else
+#define sock_enable_linger(s) /* NOOP */
+#endif  /* USE_SO_LINGER */
+
+#ifndef NO_LINGCLOSE
+
+/* Special version of timeout for lingering_close */
+
+static void lingerout(sig)
+int sig;
+{
+    if (alarms_blocked) {
+       alarm_pending = 1;
+       return;
+    }
+    
+    if (!current_conn) {
+       ap_longjmp (jmpbuffer, 1);
+    }
+    bsetflag(current_conn->client, B_EOUT, 1);
+    current_conn->aborted = 1;
+}
+    
+static void linger_timeout ()
+{
+    timeout_name = "lingering close";
+    
+    signal(SIGALRM, lingerout);
+    alarm(MAX_SECS_TO_LINGER);
+}
+
+/* Since many clients will abort a connection instead of closing it,
+ * attempting to log an error message from this routine will only
+ * confuse the webmaster.  There doesn't seem to be any portable way to
+ * distinguish between a dropped connection and something that might be
+ * worth logging.
+ */
+static void lingering_close (request_rec *r)
+{
+    int dummybuf[512];
+    struct timeval tv;
+    fd_set lfds, fds_read, fds_err;
+    int select_rv = 0, read_rv = 0;
+    int lsd;
+
+    /* Prevent a slow-drip client from holding us here indefinitely */
+
+    linger_timeout();
+
+    /* Send any leftover data to the client, but never try to again */
+
+    if (bflush(r->connection->client) == -1) {
+        kill_timeout(r);
+        bclose(r->connection->client);
+        return;
+    }
+    bsetflag(r->connection->client, B_EOUT, 1);
+
+    /* Close our half of the connection --- send the client a FIN */
+
+    lsd = r->connection->client->fd;
+
+    if ((shutdown(lsd, 1) != 0) || r->connection->aborted) {
+       kill_timeout(r);
+       bclose(r->connection->client);
+       return;
+    }
+
+    /* Set up to wait for readable data on socket... */
+
+    FD_ZERO(&lfds);
+    FD_SET(lsd, &lfds);
+
+    /* Wait for readable data or error condition on socket;
+     * slurp up any data that arrives...  We exit when we go for 
+     * an interval of tv length without getting any more data, get an
+     * error from select(), get an exception on lsd, get an error or EOF
+     * on a read, or the timer expires.
+     */
+
+    do {
+        /* We use a 2 second timeout because current (Feb 97) browsers
+         * fail to close a connection after the server closes it.  Thus,
+         * to avoid keeping the child busy, we are only lingering long enough
+         * for a client that is actively sending data on a connection.
+         * This should be sufficient unless the connection is massively
+         * losing packets, in which case we might have missed the RST anyway.
+         * These parameters are reset on each pass, since they might be
+         * changed by select.
+         */
+        tv.tv_sec  = 2;
+        tv.tv_usec = 0;
+        read_rv    = 0;
+        fds_read   = lfds;
+        fds_err    = lfds;
+    
+#ifdef SELECT_NEEDS_CAST
+        select_rv = select(lsd+1, (int*)&fds_read, NULL, (int*)&fds_err, &tv);
+#else
+        select_rv = select(lsd+1, &fds_read, NULL, &fds_err, &tv);
+#endif
+    } while ((select_rv > 0) &&            /* Something to see on socket    */
+             !FD_ISSET(lsd, &fds_err) &&   /* that isn't an error condition */
+             FD_ISSET(lsd, &fds_read) &&   /* and is worth trying to read   */
+             ((read_rv = read(lsd, dummybuf, sizeof dummybuf)) > 0));
+
+    /* Should now have seen final ack.  Safe to finally kill socket */
+
+    bclose(r->connection->client);
+
+    kill_timeout(r);
+}
+#endif /* ndef NO_LINGCLOSE */
+
+/*****************************************************************
+ *
+ * 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 scoreboard *scoreboard_image=NULL;
+
+static void setup_shared_mem(void)
+{
+    caddr_t m;
+
+#ifdef __EMX__
+    char errstr[MAX_STRING_LEN];
+    int rc;
+
+    m = (caddr_t)create_shared_heap("\\SHAREMEM\\SCOREBOARD", HARD_SERVER_LIMIT*sizeof(short_score));
+    if(m == 0) {
+       fprintf(stderr, "httpd: Could not create OS/2 Shared memory pool.\n");
+       exit(1);
+    }
+
+    rc = _uopen((Heap_t)m);
+    if(rc != 0) {
+       fprintf(stderr, "httpd: Could not uopen() newly created OS/2 Shared memory pool.\n");
+    }
+
+#elif defined(MAP_ANON) || defined(MAP_FILE)
+/* BSD style */
+    m = mmap((caddr_t)0, SCOREBOARD_SIZE,
+            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, SCOREBOARD_SIZE,
+            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 = (scoreboard *)m;
+    scoreboard_image->global.exit_generation=0;
+}
+
+#elif defined(HAVE_SHMGET)
+static scoreboard *scoreboard_image=NULL;
+static key_t shmkey = IPC_PRIVATE;
+static int shmid = -1;
+
+static void setup_shared_mem(void)
+{
+    char errstr[MAX_STRING_LEN];
+    struct shmid_ds shmbuf;
+#ifdef MOVEBREAK
+    char *obrk;
+#endif
+
+    if ((shmid = shmget(shmkey, SCOREBOARD_SIZE, IPC_CREAT|SHM_R|SHM_W)) == -1)
+    {
+       perror("shmget");
+       fprintf(stderr, "httpd: Could not call shmget\n");
+       exit(1);
+    }
+
+    ap_snprintf(errstr, sizeof(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       ((scoreboard *)(-1))
+    if ((scoreboard_image = (scoreboard *)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);
+       ap_snprintf(errstr, sizeof(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
+    scoreboard_image->global.exit_generation=0;
+}
+
+#else
+#define SCOREBOARD_FILE
+static scoreboard _scoreboard_image;
+static scoreboard *scoreboard_image=&_scoreboard_image;
+static int scoreboard_fd;
+
+/* XXX: things are seriously screwed if we ever have to do a partial
+ * read or write ... we could get a corrupted scoreboard
+ */
+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) || (rv == -1 && errno == EINTR));
+
+    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) || (rv == -1 && errno == EINTR));
+    
+    return rv < 0? rv : orig_sz - bufsz;
+}
+#endif
+
+/* Called by parent process */
+void reinit_scoreboard (pool *p)
+{
+    int exit_gen=0;
+    if(scoreboard_image)
+       exit_gen=scoreboard_image->global.exit_generation;
+       
+#ifndef SCOREBOARD_FILE
+    if (scoreboard_image == NULL)
+    {
+       setup_shared_mem();
+    }
+    memset(scoreboard_image, 0, SCOREBOARD_SIZE);
+    scoreboard_image->global.exit_generation=exit_gen;
+#else
+    scoreboard_fname = server_root_relative (p, scoreboard_fname);
+
+#ifdef __EMX__
+    /* OS/2 needs binary mode set. */
+    scoreboard_fd = popenf(p, scoreboard_fname, O_CREAT|O_BINARY|O_RDWR, 0644);
+#else
+    scoreboard_fd = popenf(p, scoreboard_fname, O_CREAT|O_RDWR, 0644);
+#endif
+    if (scoreboard_fd == -1)
+    {
+       perror (scoreboard_fname);
+       fprintf (stderr, "Cannot open scoreboard file:\n");
+       exit (1);
+    }
+
+    memset ((char*)scoreboard_image, 0, sizeof(*scoreboard_image));
+    scoreboard_image->global.exit_generation=exit_gen;
+    force_write (scoreboard_fd, (char*)scoreboard_image,
+                sizeof(*scoreboard_image));
+#endif
+}
+
+/* called by child */
+void reopen_scoreboard (pool *p)
+{
+#ifdef SCOREBOARD_FILE
+    if (scoreboard_fd != -1) pclosef (p, scoreboard_fd);
+    
+#ifdef __EMX__    
+    /* OS/2 needs binary mode set. */
+    scoreboard_fd = popenf(p, scoreboard_fname, O_CREAT|O_BINARY|O_RDWR, 0666);
+#else
+    scoreboard_fd = popenf(p, scoreboard_fname, O_CREAT|O_RDWR, 0666);
+#endif
+    if (scoreboard_fd == -1)
+    {
+       perror (scoreboard_fname);
+       fprintf (stderr, "Cannot open scoreboard file:\n");
+       exit (1);
+    }
+#else
+#ifdef __EMX__
+#ifdef HAVE_MMAP
+    caddr_t m;
+    int rc;
+
+    m = (caddr_t)get_shared_heap("\\SHAREMEM\\SCOREBOARD");
+    if(m == 0) {
+        fprintf(stderr, "httpd: Could not find existing OS/2 Shared memory pool.\n");
+        exit(1);
+    }
+
+    rc = _uopen((Heap_t)m);
+    scoreboard_image = (scoreboard *)m;
+#endif
+#endif
+#endif
+}
+
+void cleanup_scoreboard ()
+{
+#ifdef SCOREBOARD_FILE
+    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 ()
+{
+#ifdef SCOREBOARD_FILE
+    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)
+{
+    int old_status;
+    short_score new_score_rec;
+
+    if (child_num < 0)
+       return -1;
+    
+    sync_scoreboard_image();
+    new_score_rec = scoreboard_image->servers[child_num];
+    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_READY || status == SERVER_DEAD) {
+       /*
+        * Reset individual counters
+        */
+       if (status == SERVER_DEAD) {
+           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_NOLOOKUP), 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';
+       slot_size = sizeof(new_score_rec.vhost) - 1;
+       strncpy(new_score_rec.vhost,r->server->server_hostname, slot_size);
+       new_score_rec.vhost[slot_size] = '\0';
+    }
+#endif
+
+#ifndef SCOREBOARD_FILE
+    memcpy(&scoreboard_image->servers[child_num], &new_score_rec, sizeof new_score_rec);
+#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;
+}
+
+void update_scoreboard_global()
+    {
+#ifdef SCOREBOARD_FILE
+    lseek(scoreboard_fd,
+         (char *)&scoreboard_image->global-(char *)scoreboard_image,0);
+    force_write(scoreboard_fd,(char *)&scoreboard_image->global,
+               sizeof scoreboard_image->global);
+#endif
+    }
+
+int get_child_status (int child_num)
+{
+    if (child_num<0 || child_num>=HARD_SERVER_LIMIT)
+       return -1;
+    else
+       return scoreboard_image->servers[child_num].status;
+}
+
+int count_busy_servers ()
+{
+    int i;
+    int res = 0;
+
+    for (i = 0; i < HARD_SERVER_LIMIT; ++i)
+      if (scoreboard_image->servers[i].status == SERVER_BUSY_READ ||
+              scoreboard_image->servers[i].status == SERVER_BUSY_WRITE ||
+              scoreboard_image->servers[i].status == SERVER_BUSY_KEEPALIVE ||
+              scoreboard_image->servers[i].status == SERVER_BUSY_LOG ||
+              scoreboard_image->servers[i].status == SERVER_BUSY_DNS)
+          ++res;
+    return res;
+}
+
+int count_live_servers()
+    {
+    int i;
+    int res = 0;
+
+    for (i = 0; i < HARD_SERVER_LIMIT; ++i)
+      if (scoreboard_image->servers[i].status != SERVER_DEAD)
+         ++res;
+    return res;
+    }
+
+short_score get_scoreboard_info(int i)
+{
+    return (scoreboard_image->servers[i]);
+}
+
+#if defined(STATUS)
+static void increment_counts (int child_num, request_rec *r)
+{
+    long int bs=0;
+    short_score new_score_rec;
+
+    sync_scoreboard_image();
+    new_score_rec = scoreboard_image->servers[child_num];
+    if (r->sent_bodyct)
+        bgetopt(r->connection->client, BO_BYTECT, &bs);
+
+    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);
+
+
+#ifndef SCOREBOARD_FILE
+    memcpy(&scoreboard_image->servers[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->servers[i].status == SERVER_READY)
+           ++res;
+
+    return res;
+}
+
+int find_free_child_num ()
+{
+    int i;
+
+    for (i = 0; i < HARD_SERVER_LIMIT; ++i)
+       if (scoreboard_image->servers[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->servers[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->servers[i].pid;
+
+       if (pid != my_pid && pid != 0) { 
+           int waitret = 0,
+               tries = 1;
+
+           while (waitret == 0 && tries <= 4) {
+               long int waittime = 4096; /* in usecs */
+               struct timeval tv;
+           
+               /* don't want to hold up progress any more than 
+                * necessary, so keep checking to see if the child
+                * has exited with an exponential backoff.
+                * Currently set for a maximum wait of a bit over
+                * four seconds.
+                */
+               while (((waitret = waitpid(pid, &status, WNOHANG)) == 0) &&
+                        waittime < 3000000) {
+                      tv.tv_sec = waittime / 1000000;
+                      tv.tv_usec = waittime % 1000000;
+                      waittime = waittime * 2;
+                      select(0, NULL, NULL, NULL, &tv);
+               }
+               if (waitret == 0) {
+                   switch (tries) {
+                   case 1:
+                       /* perhaps it missed the SIGHUP, lets try again */
+                       log_printf(server_conf, "child process %d did not exit, sending another SIGHUP", pid);
+                       kill(pid, SIGHUP);
+                       break;
+                   case 2:
+                       /* ok, now it's being annoying */
+                       log_printf(server_conf, "child process %d still did not exit, sending a SIGTERM", pid);
+                       kill(pid, SIGTERM);
+                       break;
+                   case 3:
+                       /* die child scum */
+                       log_printf(server_conf, "child process %d still did not exit, sending a SIGKILL", pid);
+                       kill(pid, SIGKILL);
+                       break;
+                   case 4:
+                       /* gave it our best shot, but alas...  If this really 
+                        * is a child we are trying to kill and it really hasn't
+                        * exited, we will likely fail to bind to the port
+                        * after the restart.
+                        */
+                       log_printf(server_conf, "could not make child process %d exit, attempting to continue anyway", pid);
+                       break;
+                   }
+               }
+               tries++;
+           }
+       }
+    }
+}
+
+#if defined(BROKEN_WAIT) || defined(NEED_WAITPID)
+/*
+Some systems appear to fail to deliver dead children to wait() at times.
+This sorts them out. In fact, this may have been caused by a race condition
+in wait_or_timeout(). But this routine is still useful for systems with no
+waitpid().
+*/
+int reap_children ()
+{
+    int status, n;
+    int ret = 0;
+
+    for (n = 0; n < HARD_SERVER_LIMIT; ++n) {
+       if (scoreboard_image->servers[n].status != SERVER_DEAD
+               && waitpid (scoreboard_image->servers[n].pid, &status, WNOHANG)
+                   == -1
+               && errno == ECHILD) {
+           sync_scoreboard_image ();
+           update_child_status (n, SERVER_DEAD, NULL);
+           ret = 1;
+       }
+    }
+    return ret;
+}
+#endif
+
+/* Finally, this routine is used by the caretaker process to wait for
+ * a while...
+ */
+
+static int wait_or_timeout ()
+{
+#ifndef NEED_WAITPID
+    int ret;
+
+    ret = waitpid (-1, NULL, WNOHANG);
+    if (ret == -1 && errno == EINTR) {
+       return -1;
+    }
+    if (ret <= 0) {
+       sleep (1);
+       return -1;
+    }
+    return ret;
+#else
+    if (!reap_children ()) {
+       sleep(1);
+    }
+    return -1;
+#endif
+}
+
+
+void sig_term() {
+    log_error("httpd: caught SIGTERM, shutting down", server_conf);
+    cleanup_scoreboard();
+    ap_killpg (pgrp, SIGKILL);
+    close(sd);
+    exit(1);
+}
+
+void bus_error(void) {
+    char emsg[256];
+
+    ap_snprintf
+       (
+           emsg,
+           sizeof(emsg) - 1,
+           "httpd: caught SIGBUS, attempting to dump core in %s",
+           server_root
+       );
+    log_error(emsg, server_conf);
+    chdir(server_root);
+    abort();         
+    exit(1);
+}
+
+void seg_fault() {
+    char emsg[256];
+
+    ap_snprintf
+       (
+           emsg,
+           sizeof(emsg) - 1,
+           "httpd: caught SIGSEGV, attempting to dump core in %s",
+           server_root
+       );
+    log_error(emsg, server_conf);
+    chdir(server_root);
+    abort();
+    exit(1);
+}
+
+void just_die()                        /* SIGHUP to child process??? */
+{
+    exit (0);
+}
+
+static int deferred_die;
+
+static void deferred_die_handler ()
+{
+    deferred_die = 1;
+}
+
+/* volatile just in case */
+static volatile int restart_pending;
+static volatile int is_graceful;
+static volatile int generation;
+
+static void restart (int sig)
+{
+    is_graceful = (sig == SIGUSR1);
+    restart_pending = 1;
+}
+
+
+void set_signals()
+{
+#ifndef NO_USE_SIGACTION
+    struct sigaction sa;
+
+    sigemptyset(&sa.sa_mask);
+    sa.sa_flags = 0;
+
+    if (!one_process) {
+       sa.sa_handler = (void (*)())seg_fault;
+       if (sigaction (SIGSEGV, &sa, NULL) < 0)
+           log_unixerr ("sigaction(SIGSEGV)", NULL, NULL, server_conf);
+       sa.sa_handler = (void (*)())bus_error;
+       if (sigaction (SIGBUS, &sa, NULL) < 0)
+           log_unixerr ("sigaction(SIGBUS)", NULL, NULL, server_conf);
+    }
+    sa.sa_handler = (void (*)())sig_term;
+    if (sigaction (SIGTERM, &sa, NULL) < 0)
+       log_unixerr ("sigaction(SIGTERM)", NULL, NULL, server_conf);
+
+    /* wait_or_timeout uses sleep() which could deliver a SIGALRM just as we're
+     * trying to process the restart requests.  That's not good.  restart
+     * cleans out the SIGALRM handler, but this totally avoids the race
+     * condition between when the restart request is made and when the handler
+     * is invoked.
+     *
+     * We also don't want to ignore HUPs and USR1 while we're busy processing
+     * one.
+     */
+    sigaddset (&sa.sa_mask, SIGALRM);
+    sigaddset (&sa.sa_mask, SIGHUP);
+    sigaddset (&sa.sa_mask, SIGUSR1);
+    sa.sa_handler = (void (*)())restart;
+    if (sigaction (SIGHUP, &sa, NULL) < 0)
+       log_unixerr ("sigaction(SIGHUP)", NULL, NULL, server_conf);
+    if (sigaction (SIGUSR1, &sa, NULL) < 0)
+       log_unixerr ("sigaction(SIGUSR1)", NULL, NULL, server_conf);
+#else
+    if(!one_process) {
+       signal (SIGSEGV, (void (*)())seg_fault);
+       signal (SIGBUS, (void (*)())bus_error);
+    }
+
+    signal (SIGTERM, (void (*)())sig_term);
+    signal (SIGHUP, (void (*)())restart);
+    signal (SIGUSR1, (void (*)())restart);
+#endif
+}
+
+
+/*****************************************************************
+ * Here follows a long bunch of generic server bookkeeping stuff...
+ */
+
+void detach()
+{
+    int x;
+
+    chdir("/");
+#ifndef MPE
+/* Don't detach for MPE because child processes can't survive the death of
+   the parent. */
+    if((x = fork()) > 0)
+        exit(0);
+    else if(x == -1) {
+        perror("fork");
+        fprintf(stderr,"httpd: unable to fork new process\n");
+        exit(1);
+    }
+#endif
+#ifndef NO_SETSID
+    if((pgrp=setsid()) == -1) {
+        perror("setsid");
+        fprintf(stderr,"httpd: setsid failed\n");
+        exit(1);
+    }
+#elif defined(NEXT)
+    if(setpgrp(0,getpid()) == -1 || (pgrp = getpgrp(0)) == -1) {
+        perror("setpgrp");
+        fprintf(stderr,"httpd: setpgrp or getpgrp failed\n");
+        exit(1);
+    }
+#elif defined(__EMX__)
+    /* OS/2 doesn't support process group IDs */
+    pgrp=getpid();
+#elif defined(MPE)
+    /* MPE uses negative pid for process group */
+    pgrp=-getpid();
+#else
+    if((pgrp=setpgrp(getpid(),0)) == -1) {
+        perror("setpgrp");
+        fprintf(stderr,"httpd: setpgrp failed\n");
+        exit(1);
+    }
+#endif
+}
+
+/* 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);
+    }
+#ifdef MULTIPLE_GROUPS
+    if (getgroups(NGROUPS_MAX, group_id_list) == -1) {
+       log_unixerr("getgroups", NULL, "unable to get group list", server_conf);
+       exit (1);
+    }
+#endif
+    if (setgid(group_id) == -1) {
+       log_unixerr("setgid", NULL, "unable to set group id", server_conf);
+       exit (1);
+    }
+#endif 
+  }
+}
+
+/* check to see if we have the 'suexec' setuid wrapper installed */
+int init_suexec ()
+{
+    struct stat wrapper;
+    
+    if ((stat(SUEXEC_BIN, &wrapper)) != 0)
+      return (suexec_enabled);
+    
+    if ((wrapper.st_mode & S_ISUID) && wrapper.st_uid == 0) {
+      suexec_enabled = 1;
+      fprintf(stderr, "Configuring Apache for use with suexec wrapper.\n");
+    }
+
+    return (suexec_enabled);
+}
+
+/*****************************************************************
+ * 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 */
+
+static server_rec *find_virtual_server (struct in_addr server_ip,
+                               unsigned port, server_rec *server)
+{
+    server_rec *virt;
+    server_addr_rec *sar;
+    server_rec *def;
+
+    def = server;
+    for (virt = server->next; virt; virt = virt->next) {
+       for (sar = virt->addrs; sar; sar = sar->next) {
+           if ((virt->is_virtual == 1) &&      /* VirtualHost */
+               (sar->host_addr.s_addr == htonl(INADDR_ANY) ||
+               sar->host_addr.s_addr == server_ip.s_addr) &&
+               (sar->host_port == 0 || sar->host_port == port)) {
+               return virt;
+           } else if ( sar->host_addr.s_addr == DEFAULT_VHOST_ADDR
+               && (sar->host_port == 0 || sar->host_port == port)) {
+               /* this is so that you can build a server that is the
+                   "default" for any interface which isn't explicitly
+                   specified.  So that you can implement "deny anything
+                   which isn't expressly permitted" -djg */
+               def = virt;
+           }
+       }
+    }
+
+    return def;
+}
+
+void default_server_hostnames(server_rec *s)
+{
+    struct hostent *h;
+    struct in_addr *main_addr;
+    int num_addr;
+    char *def_hostname;
+    int n;
+    server_addr_rec *sar;
+    int has_default_vhost_addr;
+    unsigned mainport = s->port;
+    int from_local=0;  
+
+    /* Main host first */
+    
+    if (!s->server_hostname) {
+       s->server_hostname = get_local_host(pconf);
+       from_local = 1;
+    }
+
+    def_hostname = s->server_hostname;
+    h = gethostbyname(def_hostname);
+    if( h == NULL ) {
+       fprintf(stderr,"httpd: cannot determine the IP address of ");
+       if (from_local) {
+          fprintf(stderr,"the local host (%s). Use ServerName to set it manually.\n",
+               s->server_hostname ? s->server_hostname : "<NULL>");
+       } else {
+          fprintf(stderr,"the specified ServerName (%s).\n",
+               s->server_hostname ? s->server_hostname : "<NULL>");
+       };
+       exit(1);
+    }
+    /* we need to use gethostbyaddr below... and since it shares a static
+       area with gethostbyname it'd clobber the value we just got.  So
+       we need to make a copy.  -djg */
+    for (num_addr = 0; h->h_addr_list[num_addr] != NULL; num_addr++) {
+       /* nop */
+    }
+    main_addr = palloc( pconf, sizeof( *main_addr ) * num_addr );
+    for (n = 0; n < num_addr; n++) {
+       main_addr[n] = *(struct in_addr *)h->h_addr_list[n];
+    }
+
+    /* 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 */
+       has_default_vhost_addr = 0;
+       for (n = 0; n < num_addr; n++) {
+           for(sar = s->addrs; sar; sar = sar->next) {
+               if (sar->host_addr.s_addr == main_addr[n].s_addr &&
+                   s->port == mainport)
+                   s->is_virtual = 2;
+               if( sar->host_addr.s_addr == DEFAULT_VHOST_ADDR ) {
+                   has_default_vhost_addr = 1;
+               }
+           }
+       }
+
+       /* FIXME: some of this decision doesn't make a lot of sense in
+           the presence of multiple addresses on the <VirtualHost>
+           directive.  It should issue warnings here perhaps. -djg */
+        if (!s->server_hostname) {
+           if (s->is_virtual == 2) {
+               if (s->addrs) {
+                   s->server_hostname = s->addrs->virthost;
+               } else {
+                   /* what else can we do?  at this point this vhost has
+                       no configured name, probably because they used
+                       DNS in the VirtualHost statement.  It's disabled
+                       anyhow by the host matching code.  -djg */
+                   s->server_hostname = "bogus_host_without_forward_dns";
+               }
+           } else if (has_default_vhost_addr) {
+               s->server_hostname = def_hostname;
+           } else {
+               if (s->addrs
+                   && (h = gethostbyaddr ((char *)&(s->addrs->host_addr),
+                                  sizeof (struct in_addr), AF_INET))) {
+                   s->server_hostname = pstrdup (pconf, (char *)h->h_name);
+               } else {
+                   /* again, what can we do?  They didn't specify a
+                       ServerName, and their DNS isn't working. -djg */
+                   if (s->addrs) {
+                       fprintf(stderr, "Failed to resolve server name "
+                           "for %s (check DNS)\n",
+                           inet_ntoa(s->addrs->host_addr));
+                   }
+                   s->server_hostname = "bogus_host_without_reverse_dns";
+               }
+           }
+       }
+    }
+}
+
+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));
+    
+    /* Got a connection structure, so initialize what fields we can
+     * (the rest are zeroed out by pcalloc).
+     */
+    
+    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->base_server = conn->server;
+    conn->client = inout;
+    
+    conn->remote_addr = *remaddr;
+    conn->remote_ip = pstrdup (conn->pool,
+                              inet_ntoa(conn->remote_addr.sin_addr));
+
+    return conn;
+}
+
+#if defined(TCP_NODELAY) && !defined(MPE)
+static void sock_disable_nagle (int s)
+{
+    /* The Nagle algorithm says that we should delay sending partial
+     * packets in hopes of getting more data.  We don't want to do
+     * this; we are not telnet.  There are bad interactions between
+     * persistent connections and Nagle's algorithm that have very severe
+     * performance penalties.  (Failing to disable Nagle is not much of a
+     * problem with simple HTTP.)
+     *
+     * In spite of these problems, failure here is not a shooting offense.
+     */
+    int just_say_no = 1;
+
+    if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char*)&just_say_no,
+                   sizeof(int)) < 0) {
+        log_unixerr("setsockopt", "(TCP_NODELAY)", NULL, server_conf);
+    }
+}
+#else
+#define sock_disable_nagle(s) /* NOOP */
+#endif
+
+/*****************************************************************
+ * Child process main loop.
+ * The following vars are static to avoid getting clobbered by longjmp();
+ * they are really private to child_main.
+ */
+
+static int srv;
+static int csd;
+static int dupped_csd;
+static int requests_this_child;
+static int child_num;
+static fd_set main_fds;
+
+void child_main(int child_num_arg)
+{
+#if defined(UW)
+    size_t clen;
+#else
+    int clen;
+#endif
+    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);
+
+#ifdef MPE
+    /* Only try to switch if we're running as MANAGER.SYS */
+    if (geteuid() == 1 && user_id > 1) {
+        GETPRIVMODE();
+        if (setuid(user_id) == -1) {
+            GETUSERMODE();
+#else
+    /* Only try to switch if we're running as root */
+    if (!geteuid() && setuid(user_id) == -1) {
+#endif
+        log_unixerr("setuid", NULL, "unable to change uid", server_conf);
+       exit (1);
+    }
+#ifdef MPE
+        GETUSERMODE();
+    }
+#endif
+
+    /*
+     * Setup the jump buffers so that we can return here after
+     * a signal or a timeout (yeah, I know, same thing).
+     */
+    ap_setjmp (jmpbuffer);
+#ifndef __EMX__
+    signal(SIGURG, timeout);
+#endif    
+
+    while (1) {
+       int errsave;
+       BUFF *conn_io;
+       request_rec *r;
+      
+       /* Prepare to receive a SIGUSR1 due to graceful restart so that
+        * we can exit cleanly.  Since we're between connections right
+        * now it's the right time to exit, but we might be blocked in a
+        * system call when the graceful restart request is made. */
+       signal (SIGUSR1, (void (*)())just_die);
+
+        /*
+         * (Re)initialize this child to a pre-connection state.
+         */
+
+        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 (scoreboard_image->global.exit_generation >= generation)
+           exit(0);
+       
+       if ((count_idle_servers() >= daemons_max_free)
+           || (max_requests_per_child > 0
+               && ++requests_this_child >= max_requests_per_child))
+       {
+           exit(0);
+       }
+
+       (void)update_child_status(child_num, SERVER_READY, (request_rec*)NULL);
+
+        if (listeners == NULL) {
+            FD_ZERO(&listenfds);
+            FD_SET(sd, &listenfds);
+            listenmaxfd = sd;
+        }
+
+        /*
+         * Wait for an acceptable connection to arrive.
+         */
+
+        accept_mutex_on();  /* Lock around "accept", if necessary */
+
+        for (;;) {
+            memcpy(&main_fds, &listenfds, sizeof(fd_set));
+#ifdef SELECT_NEEDS_CAST
+            srv = select(listenmaxfd+1, (int*)&main_fds, NULL, NULL, NULL);
+#else
+            srv = select(listenmaxfd+1, &main_fds, NULL, NULL, NULL);
+#endif
+            errsave = errno;
+
+            sync_scoreboard_image();
+            if (scoreboard_image->global.exit_generation >= generation)
+                exit(0);
+
+            errno = errsave;
+            if (srv < 0 && errno != EINTR)
+                log_unixerr("select", "(listen)", NULL, server_conf);
+
+            if (srv <= 0)
+                continue;
+
+            if (listeners != NULL) {
+                for (sd = listenmaxfd; sd >= 0; sd--)
+                    if (FD_ISSET(sd, &main_fds)) break;
+                if (sd < 0)
+                    continue;
+            }
+
+           /* if we accept() something we don't want to die, so we have to
+            * defer the exit
+            */
+           deferred_die = 0;
+           signal (SIGUSR1, (void (*)())deferred_die_handler);
+            for (;;) {
+                clen = sizeof(sa_client);
+                csd  = accept(sd, &sa_client, &clen);
+               if (csd >= 0 || errno != EINTR) break;
+               if (deferred_die) {
+                   /* we didn't get a socket, and we were told to die */
+                   exit (0);
+               }
+           }
+
+            if (csd >= 0)
+                break;      /* We have a socket ready for reading */
+            else {
+
+#if defined(EPROTO) && defined(ECONNABORTED)
+              if ((errno != EPROTO) && (errno != ECONNABORTED))
+#elif defined(EPROTO)
+              if (errno != EPROTO)
+#elif defined(ECONNABORTED)
+              if (errno != ECONNABORTED)
+#endif
+                log_unixerr("accept", "(client socket)", NULL, server_conf);
+            }
+
+           /* go around again, safe to die */
+           signal (SIGUSR1, (void (*)())just_die);
+           if (deferred_die) {
+               /* ok maybe not, see ya later */
+               exit (0);
+           }
+        }
+
+        accept_mutex_off(); /* unlock after "accept" */
+
+       /* We've got a socket, let's at least process one request off the
+        * socket before we accept a graceful restart request.
+        */
+       signal (SIGUSR1, SIG_IGN);
+
+       note_cleanups_for_fd(ptrans,csd);
+
+        /*
+         * We now have a connection, so set it up with the appropriate
+         * socket options, file descriptors, and read/write buffers.
+         */
+
+       clen = sizeof(sa_server);
+       if (getsockname(csd, &sa_server, &clen) < 0) {
+           log_unixerr("getsockname", NULL, NULL, server_conf);
+           continue;
+       }
+
+       sock_disable_nagle(csd);
+
+       (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... */
+       }
+       note_cleanups_for_fd(ptrans,dupped_csd);
+#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);
+
+        /*
+         * Read and process each request found on our connection
+         * until no requests are left or we decide to close.
+         */
+
+        while ((r = read_request(current_conn)) != NULL) {
+
+           /* ok we've read the request... it's a little too late
+            * to do a graceful restart, so ignore them for now.
+            */
+           signal (SIGUSR1, SIG_IGN);
+
+            (void)update_child_status(child_num, SERVER_BUSY_WRITE, r);
+
+            process_request(r);
+#if defined(STATUS)
+            increment_counts(child_num, r);
+#endif
+            if (!current_conn->keepalive || current_conn->aborted)
+                break;
+
+            destroy_pool(r->pool);
+            (void)update_child_status(child_num, SERVER_BUSY_KEEPALIVE,
+                                      (request_rec*)NULL);
+
+            sync_scoreboard_image();
+            if (scoreboard_image->global.exit_generation >= generation) {
+                bclose(conn_io);
+                exit(0);
+            }
+
+           /* In case we get a graceful restart while we're blocked
+            * waiting for the request.
+            *
+            * XXX: This isn't perfect, we might actually read the
+            * request and then just die without saying anything to
+            * the client.  This can be fixed by using deferred_die
+            * but you have to teach buff.c about it so that it can handle
+            * the EINTR properly.
+            *
+            * In practice though browsers (have to) expect keepalive
+            * connections to close before receiving a response because
+            * of network latencies and server timeouts.
+            */
+           signal (SIGUSR1, (void (*)())just_die);
+        }
+
+        /*
+         * Close the connection, being careful to send out whatever is still
+         * in our buffers.  If possible, try to avoid a hard close until the
+         * client has ACKed our FIN and/or has stopped sending us data.
+         */
+
+#ifdef NO_LINGCLOSE
+        bclose(conn_io);        /* just close it */
+#else
+        if (r &&  r->connection
+              && !r->connection->aborted
+              &&  r->connection->client
+              && (r->connection->client->fd >= 0)) {
+
+            lingering_close(r);
+        }
+        else {
+            bsetflag(conn_io, B_EOUT, 1);
+            bclose(conn_io);
+        }
+#endif
+    }    
+}
+
+int 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);
+    }
+
+    Explain1 ("Starting new child in slot %d", child_num);
+    (void)update_child_status (child_num, SERVER_STARTING, (request_rec *)NULL);
+
+    if ((pid = fork()) == -1) {
+       log_unixerr("fork", NULL, "Unable to fork new process", server_conf);
+
+       /* fork didn't succeed. Fix the scoreboard or else
+        * it will say SERVER_STARTING forever and ever
+        */
+       (void)update_child_status (child_num, SERVER_DEAD, (request_rec*)NULL);
+
+       /* In case system resources are maxxed out, we don't want
+           Apache running away with the CPU trying to fork over and
+           over and over again. */
+       sleep(10);
+
+       return -1;
+    } 
+    
+    if (!pid) {
+       /* Disable the restart signal handlers and enable the just_die stuff.
+        * Note that since restart() just notes that a restart has been
+        * requested there's no race condition here.
+        */
+       signal (SIGHUP, (void (*)())just_die);
+       signal (SIGUSR1, (void (*)())just_die);
+       signal (SIGTERM, (void (*)())just_die);
+       child_main (child_num);
+    }
+
+    /* If the parent proceeds with a restart before the child has written
+     * their pid into the scoreboard we'll end up "forgetting" about the
+     * child.  So we write the child pid into the scoreboard now.  (This
+     * is safe, because the child is going to be writing the same value
+     * to the same word.)
+     * XXX: this needs to be sync'd to disk in the non shared memory stuff
+     */
+    scoreboard_image->servers[child_num].pid = pid;
+
+    return 0;
+}
+
+static int make_sock(pool *pconf, const struct sockaddr_in *server)
+{
+    int s;
+    int one = 1;
+
+    if ((s = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)) == -1) {
+        log_unixerr("socket", NULL, "Failed to get a socket, exiting child",
+                    server_conf);
+        exit(1);
+    }
+
+    note_cleanups_for_fd(pconf, s); /* arrange to close on exec or restart */
+    
+#ifndef MPE
+/* MPE does not support SO_REUSEADDR and SO_KEEPALIVE */
+    if (setsockopt(s, SOL_SOCKET,SO_REUSEADDR,(char *)&one,sizeof(int)) < 0) {
+        log_unixerr("setsockopt", "(SO_REUSEADDR)", NULL, server_conf);
+        exit(1);
+    }
+    one = 1;
+    if (setsockopt(s, SOL_SOCKET,SO_KEEPALIVE,(char *)&one,sizeof(int)) < 0) {
+        log_unixerr("setsockopt", "(SO_KEEPALIVE)", NULL, server_conf);
+        exit(1);
+    }
+#endif
+
+    sock_disable_nagle(s);
+    sock_enable_linger(s);
+    
+    /*
+     * To send data over high bandwidth-delay connections at full
+     * speed we must force the TCP window to open wide enough to keep the
+     * pipe full.  The default window size on many systems
+     * is only 4kB.  Cross-country WAN connections of 100ms
+     * at 1Mb/s are not impossible for well connected sites.
+     * If we assume 100ms cross-country latency,
+     * a 4kB buffer limits throughput to 40kB/s.
+     *
+     * To avoid this problem I've added the SendBufferSize directive
+     * to allow the web master to configure send buffer size.
+     *
+     * The trade-off of larger buffers is that more kernel memory
+     * is consumed.  YMMV, know your customers and your network!
+     *
+     * -John Heidemann <johnh@isi.edu> 25-Oct-96
+     *
+     * If no size is specified, use the kernel default.
+     */
+    if (server_conf->send_buffer_size) {
+        if (setsockopt(s, SOL_SOCKET, SO_SNDBUF,
+              (char *)&server_conf->send_buffer_size, sizeof(int)) < 0) {
+            log_unixerr("setsockopt", "(SO_SNDBUF)",
+                        "Failed to set SendBufferSize, using default",
+                        server_conf);
+           /* not a fatal error */
+       }
+    }
+
+#ifdef MPE
+/* MPE requires CAP=PM and GETPRIVMODE to bind to ports less than 1024 */
+    if (ntohs(server->sin_port) < 1024) GETPRIVMODE();
+#endif
+    if(bind(s, (struct sockaddr *)server,sizeof(struct sockaddr_in)) == -1)
+    {
+        perror("bind");
+#ifdef MPE
+        if (ntohs(server->sin_port) < 1024) GETUSERMODE();
+#endif
+       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);
+    }
+#ifdef MPE
+    if (ntohs(server->sin_port) < 1024) GETUSERMODE();
+#endif
+    listen(s, 512);
+    return s;
+}
+
+static listen_rec *old_listeners;
+
+static void copy_listeners(pool *p)
+    {
+    listen_rec *lr;
+
+    assert(old_listeners == NULL);
+    for(lr=listeners ; lr ; lr=lr->next)
+       {
+       listen_rec *nr=malloc(sizeof *nr);
+       if (nr == NULL) {
+         fprintf (stderr, "Ouch!  malloc failed in copy_listeners()\n");
+         exit (1);
+       }
+       *nr=*lr;
+       kill_cleanups_for_fd(p,nr->fd);
+       nr->next=old_listeners;
+       assert(!nr->used);
+       old_listeners=nr;
+       }
+    }
+
+static int find_listener(listen_rec *lr)
+    {
+    listen_rec *or;
+
+    for(or=old_listeners ; or ; or=or->next)
+       if(!memcmp(&or->local_addr,&lr->local_addr,sizeof or->local_addr))
+           {
+           or->used=1;
+           return or->fd;
+           }
+    return -1;
+    }
+
+static void close_unused_listeners()
+    {
+    listen_rec *or,*next;
+
+    for(or=old_listeners ; or ; or=next)
+       {
+       next=or->next;
+       if(!or->used)
+           close(or->fd);
+       free(or);
+       }
+    old_listeners=NULL;
+    }
+
+/*****************************************************************
+ * Executive routines.
+ */
+
+void standalone_main(int argc, char **argv)
+{
+    struct sockaddr_in sa_server;
+    int saved_sd;
+    int remaining_children_to_start;
+
+    standalone = 1;
+    sd = listenmaxfd = -1;
+
+    is_graceful = 0;
+    ++generation;
+
+    if (!one_process) detach (); 
+
+    do {
+       copy_listeners(pconf);
+       saved_sd = sd;
+       if (!is_graceful) {
+           restart_time = time(NULL);
+       }
+#ifdef SCOREBOARD_FILE
+       else {
+           kill_cleanups_for_fd (pconf, scoreboard_fd);
+       }
+#endif
+       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);
+       if (!is_graceful) {
+           reinit_scoreboard(pconf);
+       }
+#ifdef SCOREBOARD_FILE
+       else {
+           scoreboard_fname = server_root_relative (pconf, scoreboard_fname);
+           note_cleanups_for_fd (pconf, scoreboard_fd);
+       }
+#endif
+
+       default_server_hostnames (server_conf);
+
+       if (listeners == NULL) {
+           if (!is_graceful) {
+               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 {
+               sd = saved_sd;
+               note_cleanups_for_fd(pconf, sd);
+           }
+       }
+       else {
+           listen_rec *lr;
+           int fd;
+
+           listenmaxfd = -1;
+           FD_ZERO (&listenfds);
+           for (lr = listeners; lr != NULL; lr = lr->next)
+           {
+               fd = find_listener (lr);
+               if (fd < 0) {
+                   fd = make_sock (pconf, &lr->local_addr);
+               }
+               FD_SET (fd, &listenfds);
+               if (fd > listenmaxfd) listenmaxfd = fd;
+               lr->fd = fd;
+           }
+           close_unused_listeners ();
+           sd = -1;
+       }
+
+       set_signals ();
+       log_pid (pconf, pid_fname);
+
+       if (daemons_max_free < daemons_min_free + 1) /* Don't thrash... */
+           daemons_max_free = daemons_min_free + 1;
+
+       /* If we're doing a graceful_restart then we're going to see a lot
+        * of children exiting immediately when we get into the main loop
+        * below (because we just sent them SIGUSR1).  This happens pretty
+        * rapidly... and for each one that exits we'll start a new one until
+        * we reach at least daemons_min_free.  But we may be permitted to
+        * start more than that, so we'll just keep track of how many we're
+        * supposed to start up without the 1 second penalty between each fork.
+        */
+       remaining_children_to_start = daemons_to_start;
+       if( remaining_children_to_start > daemons_limit ) {
+           remaining_children_to_start = daemons_limit;
+       }
+       if (!is_graceful) {
+           while (remaining_children_to_start) {
+               --remaining_children_to_start;
+               make_child (server_conf, remaining_children_to_start);
+           }
+       }
+
+       log_error ("Server configured -- resuming normal operations",
+           server_conf);
+       restart_pending = 0;
+
+       while (!restart_pending) {
+           int child_slot;
+           int pid = wait_or_timeout ();
+
+           /* XXX: if it takes longer than 1 second for all our children
+            * to start up and get into IDLE state then we may spawn an
+            * extra child
+            */
+           if (pid >= 0) {
+               /* Child died... note that it's gone in the scoreboard. */
+               sync_scoreboard_image ();
+               child_slot = find_child_by_pid (pid);
+               Explain2 ("Reaping child %d slot %d", pid, child_slot);
+               if (child_slot >= 0) {
+                   (void)update_child_status (child_slot, SERVER_DEAD,
+                       (request_rec *)NULL);
+               } else if (is_graceful) {
+                   /* Great, we've probably just lost a slot in the
+                    * scoreboard.  Somehow we don't know about this
+                    * child.
+                    */
+                   log_printf (server_conf,
+                       "long lost child came home! (pid %d)", pid );
+               }
+           } else if (remaining_children_to_start) {
+               /* we hit a 1 second timeout in which none of the previous
+                * generation of children needed to be reaped... so assume
+                * they're all done, and pick up the slack if any is left.
+                */
+               while (remaining_children_to_start > 0) {
+                   child_slot = find_free_child_num ();
+                   if (child_slot < 0 || child_slot >= daemons_limit) {
+                       remaining_children_to_start = 0;
+                       break;
+                   }
+                   if (make_child (server_conf, child_slot) < 0) {
+                       remaining_children_to_start = 0;
+                       break;
+                   }
+                   --remaining_children_to_start;
+               }
+               /* In any event we really shouldn't do the code below because
+                * few of the servers we just started are in the IDLE state
+                * yet, so we'd mistakenly create an extra server.
+                */
+               continue;
+           }
+
+           sync_scoreboard_image ();
+           if ((remaining_children_to_start
+                   || (count_idle_servers () < daemons_min_free))
+               && (child_slot = find_free_child_num ()) >= 0
+               && child_slot < daemons_limit) {
+               make_child (server_conf, child_slot);
+           }
+           if (remaining_children_to_start) {
+               --remaining_children_to_start;
+           }
+       }
+
+       /* we've been told to restart */
+
+       if (one_process) {
+           /* not worth thinking about */
+           exit (0);
+       }
+
+       if (is_graceful) {
+#ifndef SCOREBOARD_FILE
+           int i;
+#endif
+
+           /* USE WITH CAUTION:  Graceful restarts are not known to work
+           * in various configurations on the architectures we support. */
+           scoreboard_image->global.exit_generation = generation;
+           update_scoreboard_global ();
+
+           log_error ("SIGUSR1 received.  Doing graceful restart",server_conf);
+           kill_cleanups_for_fd (pconf, sd);
+           /* kill off the idle ones */
+           if (ap_killpg(pgrp, SIGUSR1) < 0) {
+               log_unixerr ("killpg SIGUSR1", NULL, NULL, server_conf);
+           }
+#ifndef SCOREBOARD_FILE
+           /* This is mostly for debugging... so that we know what is still
+            * gracefully dealing with existing request.  But we can't really
+            * do it if we're in a SCOREBOARD_FILE because it'll cause
+            * corruption too easily.
+            */
+           sync_scoreboard_image();
+           for (i = 0; i < daemons_limit; ++i ) {
+               if (scoreboard_image->servers[i].status != SERVER_DEAD) {
+                   scoreboard_image->servers[i].status = SERVER_GRACEFUL;
+               }
+           }
+#endif
+       }
+       else {
+           /* Kill 'em off */
+           if (ap_killpg (pgrp, SIGHUP) < 0) {
+               log_unixerr ("killpg SIGHUP", NULL, NULL, server_conf);
+           }
+           reclaim_child_processes(); /* Not when just starting up */
+           log_error ("SIGHUP received.  Attempting to restart", server_conf);
+       }
+       ++generation;
+
+    } while (restart_pending);
+
+} /* 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];
+    strncpy (server_root, HTTPD_ROOT, sizeof(server_root)-1);
+    server_root[sizeof(server_root)-1] = '\0';
+    strncpy (server_confname, SERVER_CONFIG_FILE, sizeof(server_root)-1);
+    server_confname[sizeof(server_confname)-1] = '\0';
+
+    while((c = getopt(argc,argv,"Xd:f:vhl")) != -1) {
+        switch(c) {
+          case 'd':
+            strncpy (server_root, optarg, sizeof(server_root)-1);
+            server_root[sizeof(server_root)-1] = '\0';
+            break;
+          case 'f':
+            strncpy (server_confname, optarg, sizeof(server_confname)-1);
+            server_confname[sizeof(server_confname)-1] = '\0';
+            break;
+          case 'v':
+            printf("Server version %s.\n",SERVER_VERSION);
+            exit(0);
+          case 'h':
+           show_directives();
+           exit(0);
+         case 'l':
+           show_modules();
+           exit(0);
+         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();
+
+    suexec_enabled = init_suexec();
+    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);
+
+#ifdef MPE
+      /* Only try to switch if we're running as MANAGER.SYS */
+      if (geteuid() == 1 && user_id > 1) {
+          GETPRIVMODE();
+          if (setuid(user_id) == -1) {
+              GETUSERMODE();
+#else
+      /* Only try to switch if we're running as root */
+      if(!geteuid() && setuid(user_id) == -1) {
+#endif
+          log_unixerr("setuid", NULL, "unable to change uid", server_conf);
+          exit (1);
+      }
+#ifdef MPE
+          GETUSERMODE();
+      }
+#endif
+
+       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);
+#ifdef MPE
+/* HP MPE 5.5 inetd only passes the incoming socket as stdin (fd 0), whereas
+   HPUX inetd passes the incoming socket as stdin (fd 0) and stdout (fd 1).
+   Go figure.  SR 5003355016 has been submitted to request that the existing
+   functionality be documented, and then to enhance the functionality to be
+   like HPUX. */
+
+        cio->fd = fileno(stdin);
+#else
+       cio->fd = fileno(stdout);
+#endif
+       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 && !conn->aborted) {
+           destroy_pool(r->pool);
+            r = read_request (conn);
+            if (r) process_request (r);
+        }
+
+       bclose(cio);
+    }
+    exit (0);
+}
+
+#ifdef __EMX__
+#ifdef HAVE_MMAP
+/* The next two routines are used to access shared memory under OS/2.  */
+/* This requires EMX v09c to be installed.                           */
+
+caddr_t create_shared_heap (const char *name, size_t size)
+{
+    ULONG rc;
+    void *mem;
+    Heap_t h;
+
+    rc = DosAllocSharedMem (&mem, name, size,
+                          PAG_COMMIT | PAG_READ | PAG_WRITE);
+    if (rc != 0)
+        return NULL;
+    h = _ucreate (mem, size, !_BLOCK_CLEAN, _HEAP_REGULAR | _HEAP_SHARED,
+                NULL, NULL);
+    if (h == NULL)
+        DosFreeMem (mem);
+    return (caddr_t)h;
+}
+
+caddr_t get_shared_heap (const char *Name)
+{
+
+    PVOID    BaseAddress;     /* Pointer to the base address of
+                              the shared memory object */
+    ULONG    AttributeFlags;  /* Flags describing characteristics
+                              of the shared memory object */
+    APIRET   rc;              /* Return code */
+
+    /* Request read and write access to */
+    /*   the shared memory object       */
+    AttributeFlags = PAG_WRITE | PAG_READ;
+
+    rc = DosGetNamedSharedMem(&BaseAddress, Name, AttributeFlags);
+
+    if(rc != 0) {
+        printf("DosGetNamedSharedMem error: return code = %ld", rc);
+        return 0;
+    }
+
+    return BaseAddress;
+}
+#endif
+#endif
+
diff --git a/APACHE_1_2_X/src/main/http_protocol.c b/APACHE_1_2_X/src/main/http_protocol.c
new file mode 100644 (file)
index 0000000..9b7c4da
--- /dev/null
@@ -0,0 +1,1915 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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 Robert S. Thau
+ * and the Apache Group.
+ */
+
+#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 "util_date.h"          /* For parseHTTPdate and BAD_DATE */
+#include <stdarg.h>
+
+#define SET_BYTES_SENT(r) \
+  do { if (r->sent_bodyct) \
+         bgetopt (r->connection->client, BO_BYTECT, &r->bytes_sent); \
+  } while (0)
+
+
+static int parse_byterange (char *range, long clength, long *start, long *end)
+{
+    char *dash = strchr(range, '-');
+
+    if (!dash)
+       return 0;
+
+    if ((dash == range)) {
+       /* In the form "-5" */
+       *start = clength - atol(dash + 1);
+       *end = clength - 1;
+    }
+    else {
+       *dash = '\0';
+       dash++;
+       *start = atol(range);
+       if (*dash)
+           *end = atol(dash);
+       else    /* "5-" */
+           *end = clength -1;
+    }
+
+    if (*start > *end)
+       return 0;
+
+    if (*end >= clength)
+       *end = clength - 1;
+
+    return 1;
+}
+
+static int internal_byterange(int, long*, request_rec*, char**, long*, long*);
+
+int set_byterange (request_rec *r)
+{
+    char *range, *if_range, *match;
+    char ts[MAX_STRING_LEN];
+    long range_start, range_end;
+
+    if (!r->clength || r->assbackwards) return 0;
+
+    /* Check for Range request-header (HTTP/1.1) or Request-Range for
+     * backwards-compatibility with second-draft Luotonen/Franks
+     * byte-ranges (e.g. Netscape Navigator 2-3).
+     *
+     * We support this form, with Request-Range, and (farther down) we
+     * send multipart/x-byteranges instead of multipart/byteranges for
+     * Request-Range based requests to work around a bug in Netscape
+     * Navigator 2-3 and MSIE 3.
+     */
+
+    if (!(range = table_get(r->headers_in, "Range")))
+          range = table_get(r->headers_in, "Request-Range");
+
+    if (!range || strncmp(range, "bytes=", 6)) {
+       table_set (r->headers_out, "Accept-Ranges", "bytes");
+       return 0;
+    }
+
+    /* Check the If-Range header for Etag or Date */
+
+    if ((if_range = table_get(r->headers_in, "If-Range"))) {
+        if (if_range[0] == '"') {
+            if (!(match = table_get(r->headers_out, "Etag")) ||
+                (strcasecmp(if_range, match) != 0))
+                return 0;
+        }
+        else if (!(match = table_get(r->headers_out, "Last-Modified")) ||
+                 (strcasecmp(if_range, match) != 0))
+            return 0;
+    }
+    
+    if (!strchr(range, ',')) {
+       /* A single range */
+       if (!parse_byterange(pstrdup(r->pool, range + 6), r->clength,
+                            &range_start, &range_end))
+           return 0;
+
+       r->byterange = 1;
+
+       ap_snprintf(ts, sizeof(ts), "bytes %ld-%ld/%ld",
+                   range_start, range_end, r->clength);
+       table_set(r->headers_out, "Content-Range", ts);
+       ap_snprintf(ts, sizeof(ts), "%ld", range_end - range_start + 1);
+       table_set(r->headers_out, "Content-Length", ts);
+    }
+    else {
+       /* a multiple range */
+       char boundary[33];      /* Long enough */
+       char *r_range = pstrdup(r->pool, range + 6);
+       long tlength = 0;
+       
+       r->byterange = 2;
+       ap_snprintf(boundary, sizeof(boundary), "%lx%lx",
+                   r->request_time, (long)getpid());
+       r->boundary = pstrdup(r->pool, boundary);
+       while (internal_byterange(0, &tlength, r, &r_range, NULL, NULL));
+       ap_snprintf(ts, sizeof(ts), "%ld", tlength);
+       table_set(r->headers_out, "Content-Length", ts);
+    }
+    
+    r->status = PARTIAL_CONTENT;
+    r->range = range + 6;
+
+    return 1;
+}
+
+int each_byterange (request_rec *r, long *offset, long *length)
+{
+    return internal_byterange(1, NULL, r, &r->range, offset, length);
+}
+
+/* If this function is called with realreq=1, it will spit out
+ * the correct headers for a byterange chunk, and set offset and
+ * length to the positions they should be.
+ *
+ * If it is called with realreq=0, it will add to tlength the length
+ * it *would* have used with realreq=1.
+ *
+ * Either case will return 1 if it should be called again, and 0
+ * when done.
+ *
+ */
+
+static int internal_byterange(int realreq, long *tlength, request_rec *r,
+                             char **r_range, long *offset, long *length)
+{
+    long range_start, range_end;
+    char *range;
+
+    if (!**r_range) {
+       if (r->byterange > 1) {
+           if (realreq)
+               rvputs(r, "\015\012--", r->boundary, "--\015\012", NULL);
+           else
+               *tlength += 4 + strlen(r->boundary) + 4;
+       }
+       return 0;
+    }
+
+    range = getword_nc(r->pool, r_range, ',');
+    if (!parse_byterange(range, r->clength, &range_start, &range_end))
+       /* Skip this one */
+       return internal_byterange(realreq, tlength, r, r_range, offset,
+                                 length);
+
+    if (r->byterange > 1) {
+       char *ct = r->content_type ? r->content_type : default_type(r);
+       char ts[MAX_STRING_LEN];
+       
+       ap_snprintf(ts, sizeof(ts), "%ld-%ld/%ld", range_start, range_end, r->clength);
+       if (realreq)
+           rvputs(r, "\015\012--", r->boundary, "\015\012Content-type: ",
+              ct, "\015\012Content-range: bytes ", ts, "\015\012\015\012",
+              NULL);
+       else
+           *tlength += 4 + strlen(r->boundary) + 16 + strlen(ct) + 23 +
+               strlen(ts) + 4;
+    }
+
+    if (realreq) {
+       *offset = range_start;
+       *length = range_end - range_start + 1;
+    }
+    else {
+       *tlength += range_end - range_start + 1;
+    }
+    return 1;
+}
+
+int set_content_length (request_rec *r, long clength)
+{
+    char ts[MAX_STRING_LEN];
+
+    r->clength = clength;
+
+    ap_snprintf (ts, sizeof(ts), "%ld", clength);
+    table_set (r->headers_out, "Content-Length", ts);
+
+    return 0;
+}
+
+int set_keepalive(request_rec *r)
+{
+    int ka_sent = 0;
+    int wimpy   = find_token(r->pool,
+                             table_get(r->headers_out, "Connection"), "close");
+    char *conn  = table_get(r->headers_in, "Connection");
+
+    /* The following convoluted conditional determines whether or not
+     * the current connection should remain persistent after this response
+     * (a.k.a. HTTP Keep-Alive) and whether or not the output message
+     * body should use the HTTP/1.1 chunked transfer-coding.  In English,
+     *
+     *   IF  we have not marked this connection as errored;
+     *   and the response body has a defined length due to the status code
+     *       being 304 or 204, the request method being HEAD, already
+     *       having defined Content-Length or Transfer-Encoding: chunked, or
+     *       the request version being HTTP/1.1 and thus capable of being set
+     *       as chunked [we know the (r->chunked = 1) side-effect is ugly];
+     *   and the server configuration enables keep-alive;
+     *   and the server configuration has a reasonable inter-request timeout;
+     *   and there is no maximum # requests or the max hasn't been reached;
+     *   and the response status does not require a close;
+     *   and the response generator has not already indicated close;
+     *   and the client did not request non-persistence (Connection: close);
+     *   and    the client is requesting an HTTP/1.0-style keep-alive
+     *          and we haven't been configured to ignore the buggy twit,
+     *       or the client claims to be HTTP/1.1 compliant (perhaps a proxy);
+     *   THEN we can be persistent, which requires more headers be output.
+     *
+     * Note that the condition evaluation order is extremely important.
+     */
+    if ((r->connection->keepalive != -1) &&
+        ((r->status == HTTP_NOT_MODIFIED) ||
+         (r->status == HTTP_NO_CONTENT) ||
+         r->header_only ||
+         table_get(r->headers_out, "Content-Length") ||
+         find_last_token(r->pool,
+                         table_get(r->headers_out, "Transfer-Encoding"),
+                         "chunked") ||
+         ((r->proto_num >= 1001) && (r->chunked = 1))) &&
+        r->server->keep_alive &&
+        (r->server->keep_alive_timeout > 0) &&
+        ((r->server->keep_alive_max == 0) ||
+         (r->server->keep_alive_max > r->connection->keepalives)) &&
+        !status_drops_connection(r->status) &&
+        !wimpy &&
+        !find_token(r->pool, conn, "close") &&
+        (((ka_sent = find_token(r->pool, conn, "keep-alive")) &&
+          !table_get(r->subprocess_env, "nokeepalive")) ||
+         (r->proto_num >= 1001))
+       ) {
+       char header[256];
+       int left = r->server->keep_alive_max - r->connection->keepalives;
+       
+       r->connection->keepalive = 1;
+       r->connection->keepalives++;
+       
+       /* If they sent a Keep-Alive token, send one back */
+       if (ka_sent) {
+           if (r->server->keep_alive_max)
+               ap_snprintf(header, sizeof(header), "timeout=%d, max=%d",
+                           r->server->keep_alive_timeout, left);
+           else
+               ap_snprintf(header, sizeof(header), "timeout=%d",
+                           r->server->keep_alive_timeout);
+           table_set(r->headers_out, "Keep-Alive", header);
+           table_merge(r->headers_out, "Connection", "Keep-Alive");
+       }
+
+       return 1;
+    }
+
+    /* Otherwise, we need to indicate that we will be closing this
+     * connection immediately after the current response.
+     *
+     * We only really need to send "close" to HTTP/1.1 clients, but we
+     * always send it anyway, because a broken proxy may identify itself
+     * as HTTP/1.0, but pass our request along with our HTTP/1.1 tag
+     * to a HTTP/1.1 client. Better safe than sorry.
+     */
+    table_merge(r->headers_out, "Connection", "close");
+
+    r->connection->keepalive = 0;
+
+    return 0;
+}
+
+int set_last_modified(request_rec *r, time_t mtime)
+{
+    char *etag, weak_etag[MAX_STRING_LEN];
+    char *if_match, *if_modified_since, *if_unmodified, *if_nonematch;
+    time_t now = time(NULL);
+
+    if (now < 0)
+        now = r->request_time;
+
+    table_set(r->headers_out, "Last-Modified",
+              gm_timestr_822(r->pool, (mtime > now) ? now : mtime));
+
+    /* Make an ETag header out of various pieces of information. We use
+     * the last-modified date and, if we have a real file, the
+     * length and inode number - note that this doesn't have to match
+     * the content-length (i.e. includes), it just has to be unique
+     * for the file.
+     *
+     * If the request was made within a second of the last-modified date,
+     * we send a weak tag instead of a strong one, since it could
+     * be modified again later in the second, and the validation
+     * would be incorrect.
+     */
+
+    if (r->finfo.st_mode != 0)
+        ap_snprintf(weak_etag, sizeof(weak_etag), "W/\"%lx-%lx-%lx\"", 
+               (unsigned long)r->finfo.st_ino,
+               (unsigned long)r->finfo.st_size, (unsigned long)mtime);
+    else
+        ap_snprintf(weak_etag, sizeof(weak_etag), "W/\"%lx\"",
+               (unsigned long)mtime);
+
+    etag = weak_etag + ((r->request_time - mtime > 1) ? 2 : 0);
+    table_set(r->headers_out, "ETag", etag);
+
+    /* Check for conditional requests --- note that we only want to do
+     * this if we are successful so far and we are not processing a
+     * subrequest or an ErrorDocument.
+     *
+     * The order of the checks is important, since etag checks are supposed
+     * to be more accurate than checks relative to the modification time.
+     */
+    
+    if (!is_HTTP_SUCCESS(r->status) || r->no_local_copy)
+        return OK;
+
+    /* If an If-Match request-header field was given and
+     * if our ETag does not match any of the entity tags in that field
+     * and the field value is not "*" (meaning match anything), then
+     *    respond with a status of 412 (Precondition Failed).
+     */
+
+    if ((if_match = table_get(r->headers_in, "If-Match")) != NULL) {
+        if ((if_match[0] != '*') && !find_token(r->pool, if_match, etag))
+            return HTTP_PRECONDITION_FAILED;
+    }
+
+    /* Else if a valid If-Unmodified-Since request-header field was given
+     * and the requested resource has been modified since the time
+     * specified in this field, then the server MUST
+     *    respond with a status of 412 (Precondition Failed).
+     */
+
+    else if ((if_unmodified = table_get(r->headers_in, "If-Unmodified-Since"))
+             != NULL) {
+        time_t ius = parseHTTPdate(if_unmodified);
+
+        if ((ius != BAD_DATE) && (mtime > ius))
+            return HTTP_PRECONDITION_FAILED;
+    }
+
+    /* If an If-None-Match request-header field was given and
+     * if our ETag matches any of the entity tags in that field or
+     * if the field value is "*" (meaning match anything), then
+     *    if the request method was GET or HEAD, the server SHOULD
+     *       respond with a 304 (Not Modified) response.
+     *    For all other request methods, the server MUST
+     *       respond with a status of 412 (Precondition Failed).
+     */
+
+    if ((if_nonematch = table_get(r->headers_in, "If-None-Match")) != NULL) {
+        if ((if_nonematch[0] == '*') || find_token(r->pool,if_nonematch,etag))
+            return (r->method_number == M_GET) ? HTTP_NOT_MODIFIED
+                                               : HTTP_PRECONDITION_FAILED;
+    }
+
+    /* Else if a valid If-Modified-Since request-header field was given
+     * and it is a GET or HEAD request
+     * and the requested resource has not been modified since the time
+     * specified in this field, then the server MUST
+     *    respond with a status of 304 (Not Modified).
+     * A date later than the server's current request time is invalid.
+     */
+
+    else if ((r->method_number == M_GET) && ((if_modified_since =
+              table_get(r->headers_in, "If-Modified-Since")) != NULL)) {
+        time_t ims = parseHTTPdate(if_modified_since);
+
+        if ((ims >= mtime) && (ims <= r->request_time))
+            return HTTP_NOT_MODIFIED;
+    }
+
+    return OK;
+}
+
+/* Get a line of protocol input, including any continuation lines
+ * caused by MIME folding (or broken clients) if fold != 0, and place it
+ * in the buffer s, of size n bytes, without the ending newline.
+ *
+ * Returns -1 on error, or the length of s.
+ *
+ * Note: Because bgets uses 1 char for newline and 1 char for NUL,
+ *       the most we can get is (n - 2) actual characters if it
+ *       was ended by a newline, or (n - 1) characters if the line
+ *       length exceeded (n - 1).  So, if the result == (n - 1),
+ *       then the actual input line exceeded the buffer length,
+ *       and it would be a good idea for the caller to puke 400 or 414.
+ */
+static int getline(char *s, int n, BUFF *in, int fold)
+{
+    char *pos, next;
+    int retval;
+    int total = 0;
+
+    pos = s;
+
+    do {
+        retval = bgets(pos, n, in);    /* retval == -1 if error, 0 if EOF */
+
+        if (retval <= 0)
+            return ((retval < 0) && (total == 0)) ? -1 : total;
+
+        /* retval is the number of characters read, not including NUL     */
+
+        n     -= retval;      /* Keep track of how much of s is full      */
+        pos   += (retval-1);  /*               and where s ends           */
+        total += retval;      /*               and how long s has become  */
+
+        if (*pos == '\n') {   /* Did we get a full line of input?         */
+            *pos = '\0';
+            --total; ++n;
+        }
+        else return total;    /* if not, input line exceeded buffer size  */
+
+    /* Continue appending if line folding is desired and
+     * the last line was not empty and we have room in the buffer and
+     * the next line begins with a continuation character.
+     */
+    } while (fold && (retval != 1) && (n > 1) &&
+             (blookc(&next, in) == 1) &&
+             ((next == ' ') || (next == '\t')));
+
+    return total;
+}
+
+void parse_uri (request_rec *r, const char *uri)
+{
+    const char *s;
+
+#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 = pstrdup(r->pool, uri);
+       r->args = NULL;
+    }
+    else if (r->method && !strcmp(r->method, "TRACE")) {
+       r->proxyreq = 0;
+       r->uri = pstrdup(r->pool, 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] = '/';
+    };
+    
+    /* Fix OS/2 HPFS filename case problem. */
+    r->uri = strlwr(r->uri);
+#endif
+
+       if (*uri) r->args= pstrdup(r->pool, uri);
+       else r->args = NULL;
+    }
+}
+
+const char *check_fulluri (request_rec *r, const char *uri) {
+  char *name, *host;
+  int i;
+  unsigned 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_nc(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];
+    const char *ll = l, *uri;
+    conn_rec *conn = r->connection;
+    int major = 1, minor = 0;  /* Assume HTTP/1.0 if non-"HTTP" protocol*/
+    int len;
+    
+    /* Read past empty lines until we get a real request line,
+     * a read error, the connection closes (EOF), or we timeout.
+     *
+     * We skip empty lines because browsers have to tack a CRLF on to the end
+     * of POSTs to support old CERN webservers.  But note that we may not
+     * have flushed any previous response completely to the client yet.
+     * We delay the flush as long as possible so that we can improve
+     * performance for clients that are pipelining requests.  If a request
+     * is pipelined then we won't block during the (implicit) read() below.
+     * If the requests aren't pipelined, then the client is still waiting
+     * for the final buffer flush from us, and we will block in the implicit
+     * read().  B_SAFEREAD ensures that the BUFF layer flushes if it will
+     * have to block during a read.
+     */
+    bsetflag( conn->client, B_SAFEREAD, 1 );
+    while ((len = getline(l, HUGE_STRING_LEN, conn->client, 0)) <= 0) {
+        if ((len < 0) || bgetflag(conn->client, B_EOF)) {
+           bsetflag( conn->client, B_SAFEREAD, 0 );
+            return 0;
+       }
+    }
+    /* we've probably got something to do, ignore graceful restart requests */
+    signal (SIGUSR1, SIG_IGN);
+    bsetflag( conn->client, B_SAFEREAD, 0 );
+    if (len == (HUGE_STRING_LEN - 1)) {
+        log_printf(r->server, "request failed for %s, reason: URI too long",
+            get_remote_host(r->connection, r->per_dir_config, REMOTE_NAME));
+        r->status = HTTP_REQUEST_URI_TOO_LARGE;
+        return 0;
+    }
+
+    r->request_time = time(NULL);
+    r->the_request = pstrdup (r->pool, l);
+    r->method = getword_white(r->pool, &ll);
+    uri = getword_white(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)
+{
+    conn_rec *c = r->connection;
+    int len;
+    char *value;
+    char field[MAX_STRING_LEN];
+
+    /* Read header lines until we get the empty separator line,
+     * a read error, the connection closes (EOF), or we timeout.
+     * Should we also check for overflow (len == MAX_STRING_LEN-1)?
+     */
+    while ((len = getline(field, MAX_STRING_LEN, c->client, 1)) > 0) {
+
+        if (!(value = strchr(field,':')))     /* Find the colon separator */
+            continue;                         /*  or should puke 400 here */
+
+        *value = '\0';
+        ++value;
+        while (isspace(*value)) ++value;      /* Skip to start of value   */
+
+        table_merge(r->headers_in, field, value);
+    }
+}
+
+static void check_hostalias (request_rec *r) {
+  const char *hostname=r->hostname;
+  char *host = getword(r->pool, &hostname, ':');       /* Get rid of port */
+  unsigned port = (*hostname) ? atoi(hostname) : 80;
+  server_rec *s;
+  int l;
+
+  if (port && (port != r->server->port))
+    return;
+
+  l = strlen(host)-1;
+  if ((host[l]) == '.') {
+    host[l] = '\0';
+  }
+
+  r->hostname = host;
+
+  for (s = r->server->next; s; s = s->next) {
+    const char *names;
+    server_addr_rec *sar;
+
+    if (s->addrs == NULL) {
+       /* this server has been disabled because of DNS screwups during
+           configuration */
+       continue;
+    }
+
+    if ((!strcasecmp(host, s->server_hostname)) && (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);
+      }
+    }
+
+    /* search all the names from <VirtualHost> directive */
+    for( sar = s->addrs; sar; sar = sar->next ) {
+      if( !strcasecmp( sar->virthost, host ) &&
+       ( (sar->host_port == 0) || (port == sar->host_port) )) {
+       r->server = r->connection->server = s;
+       if( r->hostlen && !strncmp( r->uri, "http://", 7) ) {
+         r->uri += r->hostlen;
+         r->proxyreq = 0;
+       }
+      }
+    }
+
+    /* search all the aliases from ServerAlias directive */
+    names = s->names;
+    if( names ) {
+      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->addrs && s->path && !strncmp(r->uri, s->path, s->pathlen) &&
+       (s->path[s->pathlen - 1] == '/' ||
+        r->uri[s->pathlen] == '/' ||
+        r->uri[s->pathlen] == '\0'))
+      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;
+    conn->server = conn->base_server;
+    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->read_length  = 0;
+    r->read_body    = REQUEST_NO_BODY;
+    
+    r->status = HTTP_REQUEST_TIME_OUT; /* Until we get a request */
+
+    /* Get the request... */
+    
+    keepalive_timeout("read request line", r);
+    if (!read_request_line (r)) {
+        kill_timeout(r);
+        return NULL;
+    }
+    if (!r->assbackwards) {
+        hard_timeout("read request headers", r);
+        get_mime_headers (r);
+    }
+    kill_timeout(r);
+
+    r->status = HTTP_OK;                /* Until further notice. */
+
+    /* 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);
+    
+    /* we may have switched to another server */
+    r->per_dir_config = r->server->lookup_defaults;
+
+    conn->keptalive = 0;   /* We now have a request to play with */
+    
+    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 if(!strcmp(r->method,"OPTIONS"))
+        r->method_number = M_OPTIONS;
+    else if(!strcmp(r->method,"TRACE"))
+        r->method_number = M_TRACE;
+    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, const request_rec *r)
+{
+    rnew->the_request = r->the_request;  /* Keep original request-line */
+
+    rnew->assbackwards = 1;    /* Don't send headers from this. */
+    rnew->no_local_copy = 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 = HTTP_OK;
+
+    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->read_length = r->read_length;
+    rnew->read_body   = REQUEST_NO_BODY;
+    
+    rnew->main = (request_rec *)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[256];
+
+    ap_snprintf(nonce, sizeof(nonce), "%lu", r->request_time);
+    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)
+{
+    const 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_nc (r->pool, &t, ':');
+    r->connection->auth_type = "Basic";
+
+    *pw = t;
+
+    return OK;
+}
+
+/* New Apache routine to map status codes into array indicies 
+ *  e.g.  100 -> 0,  101 -> 1,  200 -> 2 ...                     
+ * The number of status lines must equal the value of RESPONSE_CODES (httpd.h)
+ * and must be listed in order.
+ */
+
+static char *status_lines[] = {
+   "100 Continue",
+   "101 Switching Protocols",
+#define LEVEL_200  2
+   "200 OK",
+   "201 Created",
+   "202 Accepted",
+   "203 Non-Authoritative Information",
+   "204 No Content",
+   "205 Reset Content",
+   "206 Partial Content",
+#define LEVEL_300  9
+   "300 Multiple Choices",
+   "301 Moved Permanently",
+   "302 Moved Temporarily",
+   "303 See Other",
+   "304 Not Modified",
+   "305 Use Proxy",
+#define LEVEL_400 15
+   "400 Bad Request",
+   "401 Authorization Required",
+   "402 Payment Required",
+   "403 Forbidden",
+   "404 File Not Found",
+   "405 Method Not Allowed",
+   "406 Not Acceptable",
+   "407 Proxy Authentication Required",
+   "408 Request Time-out",
+   "409 Conflict",
+   "410 Gone",
+   "411 Length Required",
+   "412 Precondition Failed",
+   "413 Request Entity Too Large",
+   "414 Request-URI Too Large",
+   "415 Unsupported Media Type",
+#define LEVEL_500 31
+   "500 Internal Server Error",
+   "501 Method Not Implemented",
+   "502 Bad Gateway",
+   "503 Service Temporarily Unavailable",
+   "504 Gateway Time-out",
+   "505 HTTP Version Not Supported",
+   "506 Variant Also Varies"
+}; 
+
+/* The index is found by its offset from the x00 code of each level.
+ * Although this is fast, it will need to be replaced if some nutcase
+ * decides to define a high-numbered code before the lower numbers.
+ * If that sad event occurs, replace the code below with a linear search
+ * from status_lines[shortcut[i]] to status_lines[shortcut[i+1]-1];
+ */
+
+int index_of_response(int status)
+{
+    static int shortcut[6] = { 0, LEVEL_200, LEVEL_300, LEVEL_400,
+                               LEVEL_500, RESPONSE_CODES };
+    int i, pos;
+
+    if (status < 100)          /* Below 100 is illegal for HTTP status */
+        return LEVEL_500;
+
+    for (i = 0; i < 5; i++) {
+        status -= 100;
+        if (status < 100) {
+            pos = (status + shortcut[i]);
+            if (pos < shortcut[i+1])
+                return pos;
+            else
+                return LEVEL_500;     /* status unknown (falls in gap) */
+        }
+    }
+   return LEVEL_500;                  /* 600 or above is also illegal */
+}
+
+/* Send a single HTTP header field to the client.  Note that this function
+ * is used in calls to table_do(), so their interfaces are co-dependent.
+ * In other words, don't change this one without checking table_do in alloc.c.
+ * It returns true unless there was a write error of some kind.
+ */
+int send_header_field (request_rec *r, const char *fieldname,
+                                       const char *fieldval)
+{
+    return (0 < bvputs(r->connection->client,
+                       fieldname, ": ", fieldval, "\015\012", NULL));
+}
+
+void basic_http_header (request_rec *r)
+{
+    char *protocol;
+    
+    if (r->assbackwards) return;
+    
+    if (!r->status_line)
+        r->status_line = status_lines[index_of_response(r->status)];
+    
+    if (table_get(r->subprocess_env,"force-response-1.0"))
+       protocol = "HTTP/1.0";
+    else
+       protocol = SERVER_PROTOCOL;
+
+    /* Output the HTTP/1.x Status-Line and the Date and Server fields */
+
+    bvputs(r->connection->client,
+           protocol, " ", r->status_line, "\015\012", NULL);
+
+    send_header_field(r, "Date", gm_timestr_822(r->pool, r->request_time));
+    send_header_field(r, "Server", SERVER_VERSION);
+
+    table_unset(r->headers_out, "Date");    /* Avoid bogosity */
+    table_unset(r->headers_out, "Server");
+}
+
+/* Navigator versions 2.x, 3.x and 4.0 betas up to and including 4.0b2
+ * have a header parsing bug.  If the terminating \r\n occur starting
+ * at the 256th or 257th byte of output then it will not properly parse
+ * the headers.  Curiously it doesn't exhibit this problem at 512, 513.
+ * We are guessing that this is because their initial read of a new request
+ * uses a 256 byte buffer, and subsequent reads use a larger buffer.
+ * So the problem might exist at different offsets as well.
+ *
+ * This should also work on keepalive connections assuming they use the
+ * same small buffer for the first read of each new request.
+ *
+ * At any rate, we check the bytes written so far and, if we are about to
+ * tickle the bug, we instead insert a bogus padding header.  Since the bug
+ * manifests as a broken image in Navigator, users blame the server.  :(
+ * It is more expensive to check the User-Agent than it is to just add the
+ * bytes, so we haven't used the BrowserMatch feature here.
+ */
+static void terminate_header (BUFF *client)
+{
+    long int bs;
+
+    bgetopt(client, BO_BYTECT, &bs);
+    if (bs == 256 || bs == 257)
+        bputs("X-Pad: avoid browser bug\015\012", client);
+
+    bputs("\015\012", client);    /* Send the terminating empty line */
+}
+
+static char *make_allow(request_rec *r)
+{
+    int allowed = r->allowed;
+
+    if( allowed == 0 ) {
+       /* RFC2068 #14.7, Allow must contain at least one method.  So rather
+        * than deal with the possibility of trying not to emit an Allow:
+        * header, i.e. #10.4.6 says 405 Method Not Allowed MUST include
+        * an Allow header, we'll just say TRACE is valid.
+        */
+       return( "TRACE" );
+    }
+
+    return 2 + pstrcat(r->pool, (allowed & (1 << M_GET)) ? ", GET, HEAD" : "",
+                      (allowed & (1 << M_POST)) ? ", POST" : "",
+                      (allowed & (1 << M_PUT)) ? ", PUT" : "",
+                      (allowed & (1 << M_DELETE)) ? ", DELETE" : "",
+                      (allowed & (1 << M_OPTIONS)) ? ", OPTIONS" : "",
+                      (allowed & (1 << M_TRACE)) ? ", TRACE" : "",
+                      NULL);
+    
+}
+
+int send_http_trace (request_rec *r)
+{
+    /* Get the original request */
+    while (r->prev) r = r->prev;
+
+    hard_timeout("send TRACE", r);
+
+    r->content_type = "message/http";
+    send_http_header(r);
+    
+    /* Now we recreate the request, and echo it back */
+
+    rvputs( r, r->the_request, "\015\012", NULL );
+
+    table_do((int (*)(void *, const char *, const char *))send_header_field,
+             (void *)r, r->headers_in, NULL);
+    bputs("\015\012", r->connection->client);
+
+    kill_timeout(r);
+    return OK;
+}
+
+int send_http_options(request_rec *r)
+{
+    const long int zero = 0L;
+
+    if (r->assbackwards) return DECLINED;
+
+    hard_timeout("send OPTIONS", r);
+
+    basic_http_header(r);
+
+    table_set(r->headers_out, "Content-Length", "0");
+    table_set(r->headers_out, "Allow", make_allow(r));
+    set_keepalive(r);
+
+    table_do((int (*)(void *, const char *, const char *))send_header_field,
+             (void *)r, r->headers_out, NULL);
+
+    terminate_header(r->connection->client);
+
+    kill_timeout(r);
+    bsetopt(r->connection->client, BO_BYTECT, &zero);
+
+    return OK;
+}
+
+/*
+ * Here we try to be compatible with clients that want multipart/x-byteranges
+ * instead of multipart/byteranges (also see above), as per HTTP/1.1. We
+ * look for the Request-Range header (e.g. Netscape 2 and 3) as an indication
+ * that the browser supports an older protocol. We also check User-Agent
+ * for Microsoft Internet Explorer 3, which needs this as well.
+ */
+
+static int use_range_x(request_rec *r) {
+    char *ua;
+    return (table_get(r->headers_in, "Request-Range") ||
+           ((ua = table_get(r->headers_in, "User-Agent"))
+            && strstr(ua, "MSIE 3")));
+}
+
+void send_http_header(request_rec *r)
+{
+    int i;
+    const long int zero = 0L;
+  
+    if (r->assbackwards) {
+        if(!r->main)
+           bsetopt(r->connection->client, BO_BYTECT, &zero);
+       r->sent_bodyct = 1;
+       return;
+    }
+
+    /* Now that we are ready to send a response, we need to combine the two
+     * header field tables into a single table.  If we don't do this, our
+     * later attempts to set or unset a given fieldname might be bypassed.
+     */
+    if (!is_empty_table(r->err_headers_out))
+        r->headers_out = overlay_tables(r->pool, r->err_headers_out,
+                                                 r->headers_out);
+    
+    hard_timeout("send headers", r);
+
+    basic_http_header(r);
+
+    set_keepalive(r);
+
+    if (r->chunked) {
+        table_merge(r->headers_out, "Transfer-Encoding", "chunked");
+        table_unset(r->headers_out, "Content-Length");
+    }
+
+    if (r->byterange > 1)
+        table_set(r->headers_out, "Content-Type",
+                  pstrcat(r->pool, "multipart", use_range_x(r) ? "/x-" : "/",
+                          "byteranges; boundary=", r->boundary, NULL));
+    else if (r->content_type)
+        table_set(r->headers_out, "Content-Type", r->content_type);
+    else 
+        table_set(r->headers_out, "Content-Type", default_type(r));
+    
+    if (r->content_encoding)
+        table_set(r->headers_out, "Content-Encoding", r->content_encoding);
+    
+    if (r->content_languages && r->content_languages->nelts) {
+        for (i = 0; i < r->content_languages->nelts; ++i) {
+            table_merge(r->headers_out, "Content-Language",
+                        ((char**)(r->content_languages->elts))[i]);
+        }
+    }
+    else if (r->content_language)
+        table_set(r->headers_out, "Content-Language", r->content_language);
+
+    /* Control cachability for non-cachable responses if not already set
+     * by some other part of the server configuration.
+     */
+    if (r->no_cache && !table_get(r->headers_out, "Expires"))
+        table_add(r->headers_out, "Expires",
+                  gm_timestr_822(r->pool, r->request_time));
+
+    /* Send the entire table of header fields, terminated by an empty line. */
+
+    table_do((int (*)(void *, const char *, const char *))send_header_field,
+             (void *)r, r->headers_out, NULL);
+
+    terminate_header(r->connection->client);
+
+    kill_timeout(r);
+
+    bsetopt(r->connection->client, BO_BYTECT, &zero);
+    r->sent_bodyct = 1;                /* Whatever follows is real body stuff... */
+
+    /* Set buffer flags for the body */
+    if (r->chunked) bsetflag(r->connection->client, B_CHUNK, 1);
+}
+
+void finalize_request_protocol (request_rec *r)
+{
+    /* Turn off chunked encoding */
+
+    if (r->chunked && !r->connection->aborted) {
+        soft_timeout("send ending chunk", r);
+        bsetflag(r->connection->client, B_CHUNK, 0);
+       bputs("0\015\012", r->connection->client);
+       /* If we had footer "headers", we'd send them now */
+       bputs("\015\012", r->connection->client);
+        kill_timeout(r);
+    }
+}
+
+/* Here we deal with getting the request message body from the client.
+ * Whether or not the request contains a body is signaled by the presence
+ * of a non-zero Content-Length or by a Transfer-Encoding: chunked.
+ *
+ * Note that this is more complicated than it was in Apache 1.1 and prior
+ * versions, because chunked support means that the module does less.
+ *
+ * The proper procedure is this:
+ *
+ * 1. Call setup_client_block() near the beginning of the request
+ *    handler. This will set up all the necessary properties, and will
+ *    return either OK, or an error code. If the latter, the module should
+ *    return that error code. The second parameter selects the policy to
+ *    apply if the request message indicates a body, and how a chunked
+ *    transfer-coding should be interpreted. Choose one of
+ *
+ *    REQUEST_NO_BODY          Send 413 error if message has any body
+ *    REQUEST_CHUNKED_ERROR    Send 411 error if body without Content-Length
+ *    REQUEST_CHUNKED_DECHUNK  If chunked, remove the chunks for me.
+ *    REQUEST_CHUNKED_PASS     Pass the chunks to me without removal.
+ *
+ *    In order to use the last two options, the caller MUST provide a buffer
+ *    large enough to hold a chunk-size line, including any extensions.
+ *
+ * 2. When you are ready to read a body (if any), call should_client_block().
+ *    This will tell the module whether or not to read input. If it is 0,
+ *    the module should assume that there is no message body to read.
+ *    This step also sends a 100 Continue response to HTTP/1.1 clients,
+ *    so should not be called until the module is *definitely* ready to
+ *    read content. (otherwise, the point of the 100 response is defeated).
+ *    Never call this function more than once.
+ *
+ * 3. Finally, call get_client_block in a loop. Pass it a buffer and its size.
+ *    It will put data into the buffer (not necessarily a full buffer), and
+ *    return the length of the input block. When it is done reading, it will
+ *    return 0 if EOF, or -1 if there was an error.
+ *    If an error occurs on input, we force an end to keepalive.
+ */
+
+int setup_client_block (request_rec *r, int read_policy)
+{
+    char *tenc = table_get(r->headers_in, "Transfer-Encoding");
+    char *lenp = table_get(r->headers_in, "Content-Length");
+
+    r->read_body    = read_policy;
+    r->read_chunked = 0;
+    r->remaining    = 0;
+
+    if (tenc) {
+        if (strcasecmp(tenc, "chunked")) {
+            log_printf(r->server, "Unknown Transfer-Encoding %s", tenc);
+            return HTTP_BAD_REQUEST;
+        }
+        if (r->read_body == REQUEST_CHUNKED_ERROR) {
+            log_reason("chunked Transfer-Encoding forbidden", r->uri, r);
+            return (lenp) ? HTTP_BAD_REQUEST : HTTP_LENGTH_REQUIRED;
+        }
+
+        r->read_chunked = 1;
+    }
+    else if (lenp) {
+        char *pos = lenp;
+
+        while (isdigit(*pos) || isspace(*pos)) ++pos;
+        if (*pos != '\0') {
+            log_printf(r->server, "Invalid Content-Length %s", lenp);
+            return HTTP_BAD_REQUEST;
+        }
+
+        r->remaining = atol(lenp);
+    }
+
+    if ((r->read_body == REQUEST_NO_BODY) &&
+        (r->read_chunked || (r->remaining > 0))) {
+        log_printf(r->server, "%s with body is not allowed for %s",
+                   r->method, r->uri);
+        return HTTP_REQUEST_ENTITY_TOO_LARGE;
+    }
+
+    return OK;
+}
+
+int should_client_block (request_rec *r)
+{
+    if (is_HTTP_ERROR(r->status))
+        return 0;
+
+    if (!r->read_chunked && (r->remaining <= 0))
+        return 0;
+
+    if (r->proto_num >= 1001) {    /* sending 100 Continue interim response */
+        bvputs(r->connection->client,
+            SERVER_PROTOCOL, " ", status_lines[0], "\015\012\015\012", NULL);
+        bflush(r->connection->client);
+    }
+
+    return 1;
+}
+
+static long get_chunk_size (char *b)
+{
+    long chunksize = 0;
+
+    while (isxdigit(*b)) {
+        int xvalue = 0;
+
+        if (*b >= '0' && *b <= '9')      xvalue = *b - '0';
+        else if (*b >= 'A' && *b <= 'F') xvalue = *b - 'A' + 0xa;
+        else if (*b >= 'a' && *b <= 'f') xvalue = *b - 'a' + 0xa;
+
+        chunksize = (chunksize << 4) | xvalue;
+        ++b;
+    }
+
+    return chunksize;
+}
+
+/* get_client_block is called in a loop to get the request message body.
+ * This is quite simple if the client includes a content-length
+ * (the normal case), but gets messy if the body is chunked. Note that
+ * r->remaining is used to maintain state across calls and that
+ * r->read_length is the total number of bytes given to the caller
+ * across all invocations.  It is messy because we have to be careful not
+ * to read past the data provided by the client, since these reads block.
+ * Returns 0 on End-of-body, -1 on error or premature chunk end.
+ *
+ * Reading the chunked encoding requires a buffer size large enough to
+ * hold a chunk-size line, including any extensions. For now, we'll leave
+ * that to the caller, at least until we can come up with a better solution.
+ */
+long get_client_block (request_rec *r, char *buffer, int bufsiz)
+{
+    int c;
+    long len_read, len_to_read;
+    long chunk_start = 0;
+
+    if (!r->read_chunked) {                 /* Content-length read */
+        len_to_read = (r->remaining > bufsiz) ? bufsiz : r->remaining;
+        len_read = bread(r->connection->client, buffer, len_to_read);
+        if (len_read <= 0) {
+            if (len_read < 0) r->connection->keepalive = -1;
+            return len_read;
+        }
+        r->read_length += len_read;
+        r->remaining   -= len_read;
+        return len_read;
+    }
+
+    /* Handle chunked reading
+     * Note: we are careful to shorten the input bufsiz so that there
+     * will always be enough space for us to add a CRLF (if necessary).
+     */
+    if (r->read_body == REQUEST_CHUNKED_PASS)
+        bufsiz -= 2;
+    if (bufsiz <= 0)
+        return -1;             /* Cannot read chunked with a small buffer */
+
+    if (r->remaining == 0) {         /* Start of new chunk */
+
+        chunk_start = getline(buffer, bufsiz, r->connection->client, 0);
+        if ((chunk_start <= 0) || (chunk_start >= (bufsiz - 1))
+                               || !isxdigit(*buffer)) {
+            r->connection->keepalive = -1;
+            return -1;
+        }
+
+        len_to_read = get_chunk_size(buffer);
+
+        if (len_to_read == 0) {      /* Last chunk indicated, get footers */
+            if (r->read_body == REQUEST_CHUNKED_DECHUNK) {
+                get_mime_headers(r);
+                ap_snprintf(buffer, bufsiz, "%ld", r->read_length);
+                table_unset(r->headers_in, "Transfer-Encoding");
+                table_set(r->headers_in, "Content-Length", buffer);
+                return 0;
+            }
+            r->remaining = -1;       /* Indicate footers in-progress */
+        }
+        else {
+            r->remaining = len_to_read;
+        }
+        if (r->read_body == REQUEST_CHUNKED_PASS) {
+            buffer[chunk_start++] = CR;  /* Restore chunk-size line end  */
+            buffer[chunk_start++] = LF;
+            buffer += chunk_start;       /* and pass line on to caller   */
+            bufsiz -= chunk_start;
+        }
+    }
+                                     /* When REQUEST_CHUNKED_PASS, we are */
+    if (r->remaining == -1) {        /* reading footers until empty line  */
+        len_read = chunk_start;
+
+        while ((bufsiz > 1) && ((len_read =
+                getline(buffer, bufsiz, r->connection->client, 1)) > 0)) {
+
+            if (len_read != (bufsiz - 1)) {
+                buffer[len_read++] = CR;  /* Restore footer line end  */
+                buffer[len_read++] = LF;
+            }
+            chunk_start += len_read;
+            buffer      += len_read;
+            bufsiz      -= len_read;
+        }
+        if (len_read < 0) {
+            r->connection->keepalive = -1;
+            return -1;
+        }
+
+        if (len_read == 0) {         /* Indicates an empty line */
+            buffer[0] = CR;
+            buffer[1] = LF;
+            chunk_start += 2;
+            r->remaining = -2;
+        }
+        r->read_length += chunk_start;
+        return chunk_start;
+    }
+                                     /* When REQUEST_CHUNKED_PASS, we     */
+    if (r->remaining == -2) {        /* finished footers when last called */
+        r->remaining = 0;            /*     so now we must signal EOF     */
+        return 0;
+    }
+
+    /* Otherwise, we are in the midst of reading a chunk of data */
+
+    len_to_read = (r->remaining > bufsiz) ? bufsiz : r->remaining;
+    
+    len_read = bread(r->connection->client, buffer, len_to_read);
+    if (len_read <= 0) {
+        r->connection->keepalive = -1;
+        return -1;
+    }
+
+    r->remaining -= len_read;
+
+    if (r->remaining == 0) {         /* End of chunk, get trailing CRLF */
+        if ((c = bgetc(r->connection->client)) == CR) {
+           c = bgetc(r->connection->client);
+        }
+        if (c != LF) {
+            r->connection->keepalive = -1;
+            return -1;
+        }
+        if (r->read_body == REQUEST_CHUNKED_PASS) {
+            buffer[len_read++] = CR;
+            buffer[len_read++] = LF;
+        }
+    }
+    r->read_length += (chunk_start + len_read);
+
+    return (chunk_start + len_read);
+}
+
+long send_fd(FILE *f, request_rec *r) { return send_fd_length(f, r, -1); }
+
+long send_fd_length(FILE *f, request_rec *r, long length)
+{
+    char buf[IOBUFSIZE];
+    long total_bytes_sent = 0;
+    register int n, w, o, len;
+    
+    if (length == 0) return 0;
+
+    soft_timeout("send body", r);
+
+    while (!r->connection->aborted) {
+       if ((length > 0) && (total_bytes_sent + IOBUFSIZE) > length)
+           len = length - total_bytes_sent;
+       else len = IOBUFSIZE;
+
+        while ((n= fread(buf, sizeof(char), len, f)) < 1
+              && ferror(f) && errno == EINTR && !r->connection->aborted)
+           continue;
+       
+       if (n < 1) {
+            break;
+        }
+        o=0;
+       total_bytes_sent += n;
+
+        while (n && !r->connection->aborted) {
+            w = bwrite(r->connection->client, &buf[o], n);
+            if (w > 0) {
+                reset_timeout(r); /* reset timeout after successful write */
+                n-=w;
+                o+=w;
+            }
+            else if (w < 0) {
+                if (r->connection->aborted)
+                    break;
+                else if (errno == EAGAIN)
+                    continue;
+                else {
+                    log_unixerr("send body lost connection to",
+                                get_remote_host(r->connection,
+                                    r->per_dir_config, REMOTE_NAME),
+                                NULL, r->server);
+                    bsetflag(r->connection->client, B_EOUT, 1);
+                    r->connection->aborted = 1;
+                    break;
+                }
+            }
+        }
+    }
+    
+    kill_timeout(r);
+    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 rwrite(const void *buf, int nbyte, request_rec *r)
+{
+    int n;
+    if (r->connection->aborted) return EOF;
+    n=bwrite(r->connection->client, buf, nbyte);
+    SET_BYTES_SENT(r);
+    return n;
+}
+
+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;
+}
+
+int rflush (request_rec *r) {
+    return bflush(r->connection->client);
+}
+
+/* We should have named this send_canned_response, since it is used for any
+ * response that can be generated by the server from the request record.
+ * This includes all 204 (no content), 3xx (redirect), 4xx (client error),
+ * and 5xx (server error) messages that have not been redirected to another
+ * handler via the ErrorDocument feature.
+ */
+void send_error_response (request_rec *r, int recursive_error)
+{
+    BUFF *fd = r->connection->client;
+    int status = r->status;
+    int idx = index_of_response (status);
+    char *custom_response;
+    char *location = pstrdup(r->pool, table_get(r->headers_out, "Location"));
+
+    /* We need to special-case the handling of 204 and 304 responses,
+     * since they have specific HTTP requirements and do not include a
+     * message body.  Note that being assbackwards here is not an option.
+     */
+    if (status == HTTP_NOT_MODIFIED) {
+        if (!is_empty_table(r->err_headers_out))
+            r->headers_out = overlay_tables(r->pool, r->err_headers_out,
+                                                     r->headers_out);
+        hard_timeout("send 304", r);
+
+        basic_http_header(r);
+        set_keepalive(r);
+
+        table_do((int (*)(void *, const char *, const char *))send_header_field,
+                 (void *)r, r->headers_out,
+                 "Connection",
+                 "Keep-Alive",
+                 "ETag",
+                 "Content-Location",
+                 "Expires",
+                 "Cache-Control",
+                 "Vary",
+                 "Warning",
+                 "WWW-Authenticate",
+                 NULL);
+
+        terminate_header(r->connection->client);
+
+        kill_timeout(r);
+        return;
+    }
+
+    if (status == HTTP_NO_CONTENT) {
+        send_http_header(r);
+        finalize_request_protocol(r);
+        return;
+    }
+
+    if (!r->assbackwards) {
+       table *tmp = r->headers_out;
+  
+       /* For all HTTP/1.x responses for which we generate the message,
+        * we need to avoid inheriting the "normal status" header fields
+        * that may have been set by the request handler before the
+        * error or redirect, except for Location on external redirects.
+        */
+       r->headers_out = r->err_headers_out;
+       r->err_headers_out = tmp;
+       clear_table(r->err_headers_out);
+
+       if (location && *location
+                    && (is_HTTP_REDIRECT(status) || status == HTTP_CREATED))
+           table_set(r->headers_out, "Location", location);
+
+       r->content_language = NULL;
+       r->content_languages = NULL;
+       r->content_encoding = NULL;
+       r->clength = 0;
+       r->content_type = "text/html";
+
+       if ((status == METHOD_NOT_ALLOWED) || (status == NOT_IMPLEMENTED))
+           table_set(r->headers_out, "Allow", make_allow(r));
+
+       send_http_header(r);
+
+       if (r->header_only) {
+           finalize_request_protocol(r);
+           return;
+       }
+    }
+    
+    hard_timeout("send error body", r);
+
+    if ((custom_response = response_code_string (r, idx))) {
+        /*
+        * We have a custom response output. This should only be
+        * a text-string to write back. But if the ErrorDocument
+        * was a local redirect and the requested resource failed
+        * for any reason, the custom_response will still hold the
+        * redirect URL. We don't really want to output this URL
+        * as a text message, so first check the custom response 
+        * string to ensure that it is a text-string (using the
+        * same test used in die(), i.e. does it start with a
+        * "). If it doesn't, we've got a recursive error, so find
+        * the original error and output that as well.
+        */
+       if (custom_response[0] == '\"') { 
+           bputs(custom_response+1, fd);
+           kill_timeout(r);
+           finalize_request_protocol(r);
+           return;
+       }
+       /* Redirect failed, so get back the original error
+        */
+       while (r->prev && (r->prev->status != HTTP_OK))
+           r = r->prev;
+    }
+    {
+       char *title = status_lines[idx];
+       /* folks decided they didn't want the error code in the H1 text */
+
+       char *h1 = 4 + status_lines[idx];
+       
+        bvputs
+           (
+               fd,
+               "<HTML><HEAD>\n<TITLE>",
+               title,
+               "</TITLE>\n</HEAD><BODY>\n<H1>",
+               h1,
+              "</H1>\n",
+              NULL
+           );
+       
+        switch (status) {
+       case REDIRECT:
+       case MOVED:
+           bvputs(fd, "The document has moved <A HREF=\"",
+                   escape_html(r->pool, location), "\">here</A>.<P>\n", NULL);
+           break;
+       case HTTP_SEE_OTHER:
+           bvputs(fd, "The answer to your request is located <A HREF=\"",
+                   escape_html(r->pool, location), "\">here</A>.<P>\n", NULL);
+           break;
+       case HTTP_USE_PROXY:
+           bvputs(fd, "This resource is only accessible through the proxy\n",
+                  escape_html(r->pool, location), "<BR>\nYou will need to ",
+                   "configure your client to use that proxy.<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 request 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 METHOD_NOT_ALLOWED:
+           bvputs(fd, "The requested method ", r->method, " is not allowed "
+                  "for the URL ", escape_html(r->pool, r->uri),
+                  ".<P>\n", NULL);
+           break;
+       case NOT_ACCEPTABLE:
+           bvputs(fd,
+                 "An appropriate representation of the requested resource ",
+                  escape_html(r->pool, r->uri),
+                  " could not be found on this server.<P>\n", NULL);
+           /* fall through */
+       case MULTIPLE_CHOICES: 
+           {
+               char *list;
+               if ((list = table_get (r->notes, "variant-list")))
+                   bputs(list, fd);
+           }
+           break;
+       case LENGTH_REQUIRED:
+           bvputs(fd, "A request of the requested method ", r->method,
+                  " requires a valid Content-length.<P>\n", NULL);
+           break;
+       case PRECONDITION_FAILED:
+           bvputs(fd, "The precondition on the request for the URL ",
+                  escape_html(r->pool, r->uri), " evaluated to false.<P>\n",
+                  NULL);
+           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;
+       case VARIANT_ALSO_VARIES:
+           bvputs(fd, "A variant for the requested entity  ",
+                  escape_html(r->pool, r->uri), " is itself a ",
+                  "transparently negotiable resource.<P>\n", NULL);
+           break;
+       case HTTP_REQUEST_TIME_OUT:
+           bputs("I'm tired of waiting for your request.\n", fd);
+           break;
+       case HTTP_GONE:
+           bvputs(fd, "The requested resource<BR>",
+                  escape_html(r->pool, r->uri),
+                   "<BR>\nis no longer available on this server ",
+                  "and there is no forwarding address.\n",
+                  "Please remove all references to this resource.\n", NULL);
+           break;
+       case HTTP_REQUEST_ENTITY_TOO_LARGE:
+           bvputs(fd, "The requested resource<BR>",
+                  escape_html(r->pool, r->uri), "<BR>\n",
+                  "does not allow request data with ", r->method,
+                  " requests, or the amount of data provided in\n",
+                  "the request exceeds the capacity limit.\n", NULL);
+           break;
+       case HTTP_REQUEST_URI_TOO_LARGE:
+           bputs("The requested URL's length exceeds the capacity\n", fd);
+           bputs("limit for this server.\n", fd);
+           break;
+       case HTTP_UNSUPPORTED_MEDIA_TYPE:
+           bputs("The supplied request data is not in a format\n", fd);
+           bputs("acceptable for processing by this resource.\n", fd);
+           break;
+       case HTTP_SERVICE_UNAVAILABLE:
+           bputs("The server is temporarily unable to service your\n", fd);
+           bputs("request due to maintenance downtime or capacity\n", fd);
+           bputs("problems. Please try again later.\n", fd);
+           break;
+       case HTTP_GATEWAY_TIME_OUT:
+           bputs("The proxy server did not receive a timely response\n", fd);
+           bputs("from the upstream server.<P>\n", fd);
+           break;
+       default:  /* HTTP_INTERNAL_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;
+       }
+
+       if (recursive_error) {
+           bvputs(fd, "<P>Additionally, a ",
+                  status_lines[index_of_response(recursive_error)],
+                  "\nerror was encountered while trying to use an "
+                  "ErrorDocument to handle the request.\n", NULL);
+       }
+       bputs("</BODY></HTML>\n", fd);
+    }
+    kill_timeout(r);
+    finalize_request_protocol(r);
+}
+
+/* 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/APACHE_1_2_X/src/main/http_request.c b/APACHE_1_2_X/src/main/http_request.c
new file mode 100644 (file)
index 0000000..72574be
--- /dev/null
@@ -0,0 +1,1084 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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 Apache.  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 HTTP_FORBIDDEN;
+       
+    if (stat (d, &fi) < 0) return HTTP_FORBIDDEN;
+    
+    return (fi.st_uid == lfi.st_uid) ? OK : HTTP_FORBIDDEN;
+
+#endif    
+}
+    
+/* Dealing with the file system to get PATH_INFO
+ */
+
+int 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';
+
+       errno = 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 OK;
+       }
+#if defined(ENOENT) && defined(ENOTDIR)
+       else if (errno == ENOENT || errno == ENOTDIR) {
+#else
+#error ENOENT || ENOTDIR not defined -- check the comment below this line in the source for details
+       /*
+        * If ENOENT || ENOTDIR is not defined in one of the your OS's
+        * include files, Apache does not know how to check to see why
+        * the stat() of the index file failed; there are cases where
+        * it can fail even though the file exists.  This means
+        * that it is possible for someone to get a directory
+        * listing of a directory even though there is an index
+        * (eg. index.html) file in it.  If you do not have a
+        * problem with this, delete the above #error line and
+        * start the compile again.  If you need to do this, please
+        * submit a bug report from http://www.apache.org/bug_report.html
+        * letting us know that you needed to do this.  Please be
+        * sure to include the operating system you are using.  
+        */
+
+       else {
+#endif
+           last_cp = cp;
+       
+           while (--cp > path && *cp != '/')
+               continue;
+
+           while (cp > path && cp[-1] == '/')
+               --cp;
+       } 
+#if defined(ENOENT) && defined(ENOTDIR)
+       else {
+#if defined(EACCES)
+           if (errno != EACCES) 
+#endif 
+           log_printf(r->server, 
+              "access to %s failed for %s, reason: stat: %s (errno = %d)",
+              r->uri, get_remote_host(r->connection, r->per_dir_config,
+              REMOTE_NAME), strerror(errno), errno);
+
+           return HTTP_FORBIDDEN;
+       }
+#endif /* ENOENT && ENOTDIR */
+    }
+    return OK;
+}
+
+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.
+     */
+
+#ifdef __EMX__
+    /* Add OS/2 drive name support */
+    if ((test_filename[0] != '/') && (test_filename[1] != ':'))
+#else
+    if (test_filename[0] != '/')
+#endif
+    {
+/* 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 (entry_core->r) {
+               if (!regexec(entry_core->r, test_filename, 0, NULL, 0))
+                   this_conf = entry_config;
+           }
+           else if (entry_core->d_is_matchexp) {
+               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);
+
+    res = get_path_info (r);
+    if (res != OK) {
+       return res;
+    }
+    
+    if (test_filename[strlen(test_filename)-1] == '/')
+       --num_dirs;
+
+    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 overrides_here;
+        void *this_conf = NULL, *htaccess_conf = NULL;
+       char *this_dir = make_dirstr (r->pool, test_filename, i);
+       int j;
+      
+       /* Do symlink checks first, because they are done with the
+        * permissions appropriate to the *parent* directory...
+        */
+       
+       if ((res = check_symlinks (this_dir, core_dir->opts)))
+       {
+           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 (entry_core->r) {
+               if (!regexec(entry_core->r, this_dir, 0, NULL,
+                            (j == num_sec) ? 0 : REG_NOTEOL)) {
+                   /* 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 (entry_core->d_is_matchexp &&
+                    !strcmp_match(this_dir, entry_dir)) {
+               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) {
+           char *config_name = make_full_path(r->pool, this_dir,
+                                          sconf->access_name);
+           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 len, num_url = url_array->nelts;
+    char *test_location = pstrdup (r->pool, r->uri);
+
+    /* Collapse multiple slashes, if it's a path URL (we don't want to
+     * do anything to <Location http://...> or such).
+     */
+    if (test_location[0] == '/')
+       no2slash (test_location);
+
+    /* 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;
+
+           len = strlen(entry_url);
+
+           this_conf = NULL;
+
+           if (entry_core->r) {
+               if (!regexec(entry_core->r, test_location, 0, NULL, 0))
+                   this_conf = entry_config;
+           }
+           else if( entry_core->d_is_matchexp ) {
+               if (!strcmp_match(test_location, entry_url))
+                   this_conf = entry_config;
+           }
+           else if (!strncmp (test_location, entry_url, len) &&
+                    (entry_url[len - 1] == '/' ||
+                     test_location[len] == '/' || test_location[len] == '\0'))
+               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;
+}
+
+int file_walk (request_rec *r)
+{
+    core_dir_config *conf = get_module_config(r->per_dir_config, &core_module);
+    array_header *file_array = copy_array (r->pool, conf->sec);
+    void *per_dir_defaults = r->per_dir_config;
+    
+    core_dir_config **file = (core_dir_config **)file_array->elts;
+    int len, num_files = file_array->nelts;
+    char *test_file = pstrdup (r->pool, r->filename);
+
+    /* Collapse multiple slashes */
+    no2slash (test_file);
+
+    /* Go through the file entries, and check for matches. */
+
+    if (num_files) {
+        void *this_conf, *entry_config;
+       core_dir_config *entry_core;
+       char *entry_file;
+       int j;
+
+/* 
+ * we apply the directive sections in some order; should really try them
+ * with the most general first.
+ */
+       for (j = 0; j < num_files; ++j) {
+
+           entry_config = file[j];
+           if (!entry_config) continue;
+           
+           entry_core =(core_dir_config *)
+               get_module_config(entry_config, &core_module);
+           entry_file = entry_core->d;
+
+           len = strlen(entry_file);
+
+           this_conf = NULL;
+
+           if (entry_core->r) {
+               if (!regexec(entry_core->r, test_file, 0, NULL, 0))
+                   this_conf = entry_config;
+           }
+           else if ( entry_core->d_is_matchexp ) {
+               if (!strcmp_match(test_file, entry_file))
+                   this_conf = entry_config;
+           }
+           else if (!strncmp (test_file, entry_file, len) &&
+                    (entry_file[len - 1] == '/' ||
+                     test_file[len] == '/' || test_file[len] == '\0'))
+               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 Apache 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 (const 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_uri (const char *new_file, const request_rec *r)
+{
+    request_rec *rnew;
+    int res;
+    char *udir;
+    
+    rnew = make_sub_request (r);
+    rnew->request_time = r->request_time;
+    rnew->connection = r->connection; 
+    rnew->server = r->server;
+    rnew->request_config = create_request_config (rnew->pool);
+    rnew->htaccess = r->htaccess; /* copy htaccess cache */
+    rnew->per_dir_config=r->server->lookup_defaults;
+    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);
+       
+    if ((res = location_walk (rnew))) {
+       rnew->status=res;
+       return rnew;
+    }
+
+    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.
+     */
+    /* NB: directory_walk() clears the per_dir_config, so we don't inherit from
+       location_walk() above */
+    
+    if ((res = directory_walk (rnew))
+       || (res = file_walk (rnew))
+       || (res = location_walk (rnew))
+        || ((satisfies(rnew)==SATISFY_ALL || satisfies(rnew)==SATISFY_NOSPEC)?
+           ((res = check_access (rnew))
+            || (some_auth_required (rnew) &&
+                ((res = check_user_id (rnew)) || (res = check_auth (rnew))))):
+           ((res = check_access (rnew))
+            && (!some_auth_required (rnew) ||
+                ((res = check_user_id (rnew)) || (res = check_auth (rnew)))))
+           )
+       || (res = find_types (rnew))
+       || (res = run_fixups (rnew))
+       )
+    {
+        rnew->status = res;
+    }
+
+    return rnew;
+}
+
+request_rec *sub_req_lookup_file (const char *new_file, const request_rec *r)
+{
+    request_rec *rnew;
+    int res;
+    char *fdir;
+
+    rnew = make_sub_request (r);
+    rnew->request_time = r->request_time;
+    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);
+    fdir = make_dirstr (rnew->pool, r->filename, count_dirs (r->filename));
+
+    /* 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 won't have to redo directory_walk, and we may not
+     * even have to redo access checks.
+     */
+
+    if (strchr (new_file, '/') == NULL) {
+       char *udir = make_dirstr(rnew->pool, r->uri, count_dirs(r->uri));
+
+       rnew->uri = make_full_path (rnew->pool, udir, new_file);
+       rnew->filename = make_full_path (rnew->pool, fdir, new_file);
+       if (stat (rnew->filename, &rnew->finfo) < 0) {
+           rnew->finfo.st_mode = 0;
+       }
+
+       rnew->per_dir_config = r->per_dir_config;
+
+       if ((res = check_symlinks (rnew->filename, allow_options (rnew)))) {
+           log_reason ("Symbolic link not allowed", rnew->filename, rnew);
+           rnew->status = res;
+           return rnew;
+       }
+       /* do a file_walk, if it doesn't change the per_dir_config then
+        * we know that we don't have to redo all the access checks */
+       if ((res = file_walk (rnew))) {
+           rnew->status = res;
+           return rnew;
+       }
+       if (rnew->per_dir_config == r->per_dir_config) {
+           if ((res = find_types (rnew)) || (res = run_fixups (rnew))) {
+               rnew->status = res;
+           }
+           return rnew;
+       }
+    } else {
+       /* XXX: this should be set properly like it is in the same-dir case
+        * but it's actually sometimes to impossible to do it... because the
+        * file may not have a uri associated with it -djg */
+       rnew->uri = "INTERNALLY GENERATED file-relative req";
+       rnew->filename = ((new_file[0] == '/') ?
+                       pstrdup(rnew->pool,new_file) :
+                       make_full_path (rnew->pool, fdir, new_file));
+       rnew->per_dir_config = r->server->lookup_defaults;
+       res = directory_walk (rnew);
+       if (!res) {
+           res = file_walk (rnew);
+       }
+    }
+
+    if (res
+        || ((satisfies(rnew)==SATISFY_ALL || satisfies(rnew)==SATISFY_NOSPEC)?
+           ((res = check_access (rnew))
+            || (some_auth_required (rnew) &&
+                ((res = check_user_id (rnew)) || (res = check_auth (rnew))))):
+           ((res = check_access (rnew))
+            && (!some_auth_required (rnew) ||
+                ((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 != HTTP_OK) {
+        recursive_error = type;
+
+       while (r->prev && (r->prev->status != HTTP_OK))
+         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_local_copy = 1; /* Do NOT send USE_LOCAL_COPY for
+                                  * error documents!
+                                  */
+           /* This redirect needs to be a GET no matter what the original
+            * method was.
+            */
+           table_set(r->subprocess_env, "REQUEST_METHOD", r->method);
+           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);
+}
+
+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)) ||
+       ((r->proto_num == 1001) && !table_get(r->headers_in, "Host"))) {
+        /* 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)
+    {
+        /* We don't want TRACE to run through the normal handler set,
+         * we handle it specially.
+         */
+        if (r->method_number == M_TRACE) {
+            send_http_trace(r);
+            finalize_request_protocol(r);
+            return;
+        }
+
+       access_status = unescape_url(r->uri);
+       if (access_status)
+       {
+           die(access_status, r);
+           return;
+       }
+
+       getparents(r->uri);     /* OK --- shrinking transformations... */
+    }
+
+    if ((access_status = location_walk (r))) {
+        die (access_status, r);
+       return;
+    }
+
+    if ((access_status = translate_name (r))) {
+        decl_die (access_status, "translate", r);
+       return;
+    }
+
+    /* NB: directory_walk() clears the per_dir_config, so we don't inherit from
+       location_walk() above */
+
+    if ((access_status = directory_walk (r))) {
+        die (access_status, r);
+       return;
+    }  
+
+    if ((access_status = file_walk (r))) {
+       die (access_status, r);
+       return;
+    }
+    
+    if ((access_status = location_walk (r))) {
+        die (access_status, r);
+       return;
+    }  
+
+    if ((access_status = header_parse (r))) {
+        die (access_status, r);
+       return;
+    }
+    
+    switch (satisfies(r)) {
+    case SATISFY_ALL: case SATISFY_NOSPEC:
+       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;
+           }
+       }
+       break;
+    case SATISFY_ANY:
+       if ((access_status = check_access (r)) != 0) {
+           if (!some_auth_required (r)) {
+               decl_die (access_status, "check access", r);
+               return;
+           }
+           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;
+           }
+       }
+       break;
+    }
+
+    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);
+       return;
+    }
+
+   /* Take care of little things that need to happen when we're done */
+   finalize_request_protocol (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 (const char *new_uri, request_rec *r)
+{
+    request_rec *new = (request_rec *)pcalloc(r->pool, sizeof(request_rec));
+    char t[256];               /* 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->the_request = r->the_request;
+
+    new->method = r->method;
+    new->method_number = r->method_number;
+    new->allowed = r->allowed;
+    
+    new->status = r->status;
+    new->assbackwards = r->assbackwards;
+    new->header_only = r->header_only;
+    new->protocol = r->protocol;
+    new->proto_num = r->proto_num;
+    new->hostname = r->hostname;
+    new->hostlen = r->hostlen;
+    new->request_time = r->request_time;
+    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!
+                                 */
+    new->no_local_copy = r->no_local_copy;
+
+    ap_snprintf (t, sizeof(t), "%d", r->status);
+    table_set (new->subprocess_env, "REDIRECT_STATUS", pstrdup (r->pool, t));
+
+    return new;
+}
+
+void internal_redirect (const 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 (const 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/APACHE_1_2_X/src/main/md5c.c b/APACHE_1_2_X/src/main/md5c.c
new file mode 100644 (file)
index 0000000..fd42bcb
--- /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,1997 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/APACHE_1_2_X/src/main/rfc1413.c b/APACHE_1_2_X/src/main/rfc1413.c
new file mode 100644 (file)
index 0000000..858a1b0
--- /dev/null
@@ -0,0 +1,226 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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 Apache --- 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, ap_longjmp, etc. */
+#include "http_log.h" /* for log_unixerr */
+#include "rfc1413.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
+
+#ifndef RFC1413_TIMEOUT
+#define RFC1413_TIMEOUT        30
+#endif
+#define        ANY_PORT        0               /* Any old port will do */
+#define FROM_UNKNOWN  "unknown"
+
+int rfc1413_timeout = RFC1413_TIMEOUT;  /* Global so it can be changed */
+
+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 */
+    ap_snprintf(buffer, sizeof(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;
+}
+
+/* ident_timeout - handle timeouts */
+static void
+ident_timeout(int sig)
+{
+    ap_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 (ap_setjmp(timebuf) == 0)
+    {
+       signal(SIGALRM, ident_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/APACHE_1_2_X/src/main/util.c b/APACHE_1_2_X/src/main/util.c
new file mode 100644 (file)
index 0000000..bd853d8
--- /dev/null
@@ -0,0 +1,1328 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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/>.
+ *
+ */
+
+/*
+ * util.c: string utility things
+ * 
+ * 3/21/93 Rob McCool
+ * 1995-96 Many changes by the Apache Group
+ * 
+ */
+
+#include "httpd.h"
+#include "http_conf_globals.h" /* for user_id & group_id */
+
+const char month_snames[12][4] = {
+    "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"
+};
+
+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, const 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' */
+    ap_snprintf(ts, sizeof(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. */
+#if defined(HAVE_GMTOFF)
+struct tm *get_gmtoff(int *tz) {
+    time_t tt = time(NULL);
+    struct tm *t;
+
+    t = localtime(&tt);
+    *tz = (int) (t->tm_gmtoff / 60);
+    return t;
+}
+#else
+struct tm *get_gmtoff(int *tz) {
+    time_t tt = time(NULL);
+    struct tm gmt;
+    struct tm *t;
+    int days, hours, minutes;
+
+    /* Assume we are never more than 24 hours away. */
+    gmt = *gmtime(&tt); /* remember gmtime/localtime return ptr to static */
+    t = localtime(&tt); /* buffer... so be careful */
+    days = t->tm_yday - gmt.tm_yday;
+    hours = ((days < -1 ? 24 : 1 < days ? -24 : days * 24)
+                + t->tm_hour - gmt.tm_hour);
+    minutes = hours * 60 + t->tm_min - gmt.tm_min;
+    *tz = minutes;
+    return t;
+}
+#endif
+
+
+/* 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(const char *str, const 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(const char *str, const 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(const char *str) {
+    register int x;
+
+    for(x=0;str[x];x++)
+        if((str[x] == '*') || (str[x] == '?'))
+            return 1;
+    return 0;
+}
+
+/* This function substitutes for $0-$9, filling in regular expression
+ * submatches. Pass it the same nmatch and pmatch arguments that you
+ * passed regexec(). pmatch should not be greater than the maximum number
+ * of subexpressions - i.e. one more than the re_nsub member of regex_t.
+ *
+ * input should be the string with the $-expressions, source should be the
+ * string that was matched against.
+ *
+ * It returns the substituted string, or NULL on error.
+ *
+ * Parts of this code are based on Henry Spencer's regsub(), from his
+ * AT&T V8 regexp package.
+ */
+
+char *pregsub(pool *p, const char *input, const char *source,
+             size_t nmatch, regmatch_t pmatch[]) {
+    const char *src = input;
+    char *dest, *dst;
+    char c;
+    int no, len;
+
+    if (!source) return NULL;
+    if (!nmatch) return pstrdup(p, src);
+
+    /* First pass, find the size */
+
+    len = 0;
+
+    while ((c = *src++) != '\0') {
+       if (c == '&')
+           no = 0;
+       else if (c == '$' && isdigit(*src))
+           no = *src++ - '0';
+       else
+           no = -1;
+       
+       if (no < 0) {   /* Ordinary character. */
+           if (c == '\\' && (*src == '$' || *src == '&'))
+               c = *src++;
+           len++;
+       } else if (no <= nmatch && pmatch[no].rm_so < pmatch[no].rm_eo) {
+           len += pmatch[no].rm_eo - pmatch[no].rm_so;
+       }
+
+    }
+
+    dest = dst = pcalloc(p, len + 1);
+
+    /* Now actually fill in the string */
+
+    src = input;
+
+    while ((c = *src++) != '\0') {
+       if (c == '&')
+           no = 0;
+       else if (c == '$' && isdigit(*src))
+           no = *src++ - '0';
+       else
+           no = -1;
+       
+       if (no < 0) {   /* Ordinary character. */
+           if (c == '\\' && (*src == '$' || *src == '&'))
+               c = *src++;
+           *dst++ = c;
+       } else if (no <= nmatch && pmatch[no].rm_so < pmatch[no].rm_eo) {
+           len = pmatch[no].rm_eo - pmatch[no].rm_so;
+           strncpy(dst, source + pmatch[no].rm_so, len);
+           dst += len;
+           if (*(dst-1) == '\0') /* strncpy hit NULL. */
+               return NULL;
+       }
+
+    }
+    *dst = '\0';
+    
+    return dest;
+}
+
+/*
+ * 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, const 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(const char *path) {
+    register int x,n;
+
+    for(x=0,n=0;path[x];x++)
+        if(path[x] == '/') n++;
+    return n;
+}
+
+
+void chdir_file(const char *file) {
+    int i;
+
+    if((i = rind(file,'/')) == -1)
+        return;
+    ((char *)file)[i] = '\0';
+    chdir(file);
+    ((char *)file)[i] = '/';
+}
+
+char *getword_nc(pool* atrans, char **line, char stop)
+    {
+    return getword(atrans,(const char **)line,stop);
+    }
+
+char *getword(pool* atrans, const 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_white_nc(pool* atrans, char **line)
+{
+    return getword_white(atrans,(const char **)line);
+}
+
+char *getword_white(pool* atrans, const char **line) {
+    int pos = -1, x;
+    char *res;
+
+    for(x=0;(*line)[x];x++) {
+        if (isspace((*line)[x])) {
+          pos=x;
+          break;
+      }
+   }
+
+    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 (isspace((*line)[pos])) ++pos;
+
+    *line += pos;
+
+    return res;
+}
+
+char *getword_nulls_nc(pool* atrans, char **line, char stop)
+{
+    return getword_nulls(atrans,(const char **)line,stop);
+}
+
+char *getword_nulls(pool* atrans, const 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
+ */
+
+static char *substring_conf (pool *p, const char *start, int len, char quote)
+{
+    char *result = palloc (p, len + 2);
+    char *resp = result;
+    int i;
+
+    for (i = 0; i < len; ++i) {
+        if (start[i] == '\\' && (start[i+1] == '/'
+                                || (quote && start[i+1] == quote)))
+           *resp++ = start[++i];
+       else
+           *resp++ = start[i];
+    }
+
+    *resp++ = '\0';
+    return result;
+}
+
+char *getword_conf_nc(pool* p, char **line) {
+    return getword_conf(p,(const char **)line);
+}
+
+char *getword_conf(pool* p, const char **line) {
+    const char *str = *line, *strend;
+    char *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[1] == quote)
+               strend += 2;
+           else ++strend;
+       }
+       res = substring_conf (p, str + 1, strend - str - 1, quote);
+
+       if (*strend == quote) ++strend;
+    } else {
+        strend = str;
+       while (*strend && !isspace (*strend))
+           ++strend;
+
+       res = substring_conf (p, str, strend - str, 0);
+    }
+
+    while (*strend && isspace(*strend)) ++ strend;
+    *line = strend;
+    return res;
+}
+
+#ifdef UNDEF
+/* this function is dangerous, and superceded by getword_white, so don't use it
+ */
+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);
+}
+#endif
+
+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 == ' ');
+
+    if(c == EOF)
+       return 1;
+
+    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 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;
+}
+
+static char* tspecials = " \t()<>@,;:\\/[]?={}";
+
+/* Next HTTP token from a header line.  Warning --- destructive!
+ * Use only with a copy!
+ */
+
+static char *next_token (char **toks) {
+    char *cp = *toks;
+    char *ret;
+
+    while (*cp && (iscntrl (*cp) || strchr (tspecials, *cp))) {
+        if (*cp == '"')
+         while (*cp && (*cp != '"')) ++cp;
+       else
+         ++cp;
+    }
+
+    if (!*cp) ret = NULL;
+    else {
+        ret = cp;
+
+        while (*cp && !iscntrl(*cp) && !strchr (tspecials, *cp))
+            ++cp;
+
+        if (*cp) {
+            *toks = cp + 1;
+            *cp = '\0';
+       }
+        else *toks = cp;
+    }
+
+    return ret;
+}
+
+int find_token (pool *p, const char *line, const char *tok) {
+    char *ltok;
+    char *lcopy;
+
+    if (!line) return 0;
+
+    lcopy = pstrdup (p, line);
+    while ((ltok = next_token (&lcopy)))
+        if (!strcasecmp (ltok, tok))
+            return 1;
+
+    return 0;
+}
+
+int find_last_token (pool *p, const char *line, const char *tok)
+{
+    int llen, tlen, lidx;
+
+    if (!line) return 0;
+
+    llen = strlen(line);
+    tlen = strlen(tok);
+    lidx = llen - tlen;
+
+    if ((lidx < 0) ||
+        ((lidx > 0) && !(isspace(line[lidx-1]) || line[lidx-1] == ',')))
+        return 0;
+
+    return (strncasecmp(&line[lidx], tok, tlen) == 0);
+}
+
+char *escape_shell_cmd(pool *p, const 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] = '+';
+}
+
+static char x2c(const 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_server(pool *p, const char *hostname, unsigned port) {
+    char portnum[22];          
+       /* Long enough, even if port > 16 bits for some reason */
+  
+    if (port == DEFAULT_PORT)
+       return (char *)hostname;
+    else {
+        ap_snprintf (portnum, sizeof(portnum), "%u", port);
+       return pstrcat (p, hostname, ":", portnum, NULL);
+    }
+}
+
+char *construct_url(pool *p, const char *uri, const server_rec *s) {
+    return pstrcat (p, "http://",
+                   construct_server(p, s->server_hostname, s->port),
+                   uri, NULL);
+}
+
+#define c2x(what,where) sprintf(where,"%%%02x",(unsigned char)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;
+}
+
+/* escape_uri is now a macro for os_escape_path */
+
+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;
+}
+
+int is_directory(const 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, const char *src1, const 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);
+}
+
+/*
+ * Check for an absoluteURI syntax (see section 3.2 in RFC2068).
+ */
+int is_url(const char *u) {
+    register int x;
+
+    for (x = 0; u[x] != ':'; x++) {
+        if ((! u[x]) ||
+           ((! isalpha(u[x])) && (! isdigit(u[x])) &&
+            (u[x] != '+') && (u[x] != '-') && (u[x] != '.'))) {
+            return 0;
+       }
+    }
+
+    return (x ? 1 : 0);  /* If the first character is ':', it's broken, too */
+}
+
+int can_exec(const struct stat *finfo) {
+#ifdef MULTIPLE_GROUPS
+  int cnt;
+#endif
+#ifdef __EMX__
+    /* OS/2 dosen't have Users and Groups */
+    return 1;
+#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;
+#ifdef MULTIPLE_GROUPS
+    for(cnt=0; cnt < NGROUPS_MAX; cnt++) {
+        if(group_id_list[cnt] == finfo->st_gid)
+            if(finfo->st_mode & S_IXGRP)
+                return 1;
+    }
+#endif
+    return (finfo->st_mode & S_IXOTH);
+#endif    
+}
+
+#ifdef NEED_STRDUP
+char *strdup (const 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)
+{
+#if defined(QNX) || defined(MPE)
+/* QNX and MPE do not appear to support supplementary groups. */
+       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(const 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);
+    }
+    return(ent->pw_uid);
+}
+
+gid_t gname2id(const 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);
+    }
+    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) {
+       perror ("getsockname");
+        fprintf (stderr, "Can't get local host address!\n");
+       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 (const char *w, unsigned short *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 != INADDR_NONE)
+    {
+       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;
+}
+
+
+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;
+    }
+    return pstrdup(a, (void *)p->h_name);
+}
+
+char *get_local_host(pool *a)
+{
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 256
+#endif
+    char str[MAXHOSTNAMELEN+1];
+    char *server_hostname;
+    struct hostent *p;
+
+    if( gethostname( str, sizeof( str ) - 1 ) != 0 ) {
+       perror( "Unable to gethostname" );
+       exit(1);
+    }
+    str[MAXHOSTNAMELEN] = '\0';
+    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, const 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 < sizeof(newpath)-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/APACHE_1_2_X/src/main/util_date.c b/APACHE_1_2_X/src/main/util_date.c
new file mode 100644 (file)
index 0000000..e544a0f
--- /dev/null
@@ -0,0 +1,296 @@
+/* ====================================================================
+ * Copyright (c) 1996,1997 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/>.
+ *
+ */
+
+/*
+ * util_date.c: date parsing utility routines
+ *     These routines are (hopefully) platform-independent.
+ * 
+ * 27 Oct 1996  Roy Fielding
+ *     Extracted (with many modifications) from mod_proxy.c and
+ *     tested with over 50,000 randomly chosen valid date strings
+ *     and several hundred variations of invalid date strings.
+ * 
+ */
+
+#include "util_date.h"
+#include <ctype.h>
+#include <string.h>
+
+/*
+ * Compare a string to a mask
+ * Mask characters (arbitrary maximum is 256 characters, just in case):
+ *   @ - uppercase letter
+ *   $ - lowercase letter
+ *   & - hex digit
+ *   # - digit
+ *   ~ - digit or space
+ *   * - swallow remaining characters 
+ *  <x> - exact match for any other character
+ */
+int checkmask(const char *data, const char *mask)
+{
+    int i;
+    char d;
+
+    for (i = 0; i < 256; i++) {
+        d  = data[i];
+        switch (mask[i]) {
+          case '\0': return (d == '\0');
+
+          case '*':  return 1;
+
+          case '@':  if (!isupper(d)) return 0;
+                     break;
+          case '$':  if (!islower(d)) return 0;
+                     break;
+          case '#':  if (!isdigit(d)) return 0;
+                     break;
+          case '&':  if (!isxdigit(d)) return 0;
+                     break;
+          case '~':  if ((d != ' ') && !isdigit(d)) return 0;
+                     break;
+          default:   if (mask[i] != d) return 0;
+                     break;
+        }
+    }
+    return 0;  /* We only get here if mask is corrupted (exceeds 256) */
+}
+
+/*
+ * tm2sec converts a GMT tm structure into the number of seconds since
+ * 1st January 1970 UT.  Note that we ignore tm_wday, tm_yday, and tm_dst.
+ * 
+ * The return value is always a valid time_t value -- (time_t)0 is returned
+ * if the input date is outside that capable of being represented by time(),
+ * i.e., before Thu, 01 Jan 1970 00:00:00 for all systems and 
+ * beyond 2038 for 32bit systems.
+ *
+ * This routine is intended to be very fast, much faster than mktime().
+ */
+time_t tm2sec(const struct tm *t)
+{
+    int  year;
+    time_t days;
+    const int dayoffset[12] =
+        {306, 337, 0, 31, 61, 92, 122, 153, 184, 214, 245, 275};
+
+    year = t->tm_year;
+
+    if (year < 70 || ((sizeof(time_t) <= 4) && (year >= 138)))
+        return BAD_DATE;
+
+    /* shift new year to 1st March in order to make leap year calc easy */
+
+    if (t->tm_mon < 2) year--;
+
+    /* Find number of days since 1st March 1900 (in the Gregorian calendar). */
+
+    days  = year * 365 + year/4 - year/100 + (year/100 + 3)/4;
+    days += dayoffset[t->tm_mon] + t->tm_mday - 1;
+    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 (days < 0)
+        return BAD_DATE;       /* must have overflowed */
+    else
+        return days;           /* must be a valid time */
+}
+
+/*
+ * Parses an HTTP date in one of three standard forms:
+ *
+ *     Sun, 06 Nov 1994 08:49:37 GMT  ; RFC 822, updated by RFC 1123
+ *     Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036
+ *     Sun Nov  6 08:49:37 1994       ; ANSI C's asctime() format
+ *
+ * and returns the time_t number of seconds since 1 Jan 1970 GMT, or
+ * 0 if this would be out of range or if the date is invalid.
+ *
+ * The restricted HTTP syntax is
+ * 
+ *     HTTP-date    = rfc1123-date | rfc850-date | asctime-date
+ *
+ *     rfc1123-date = wkday "," SP date1 SP time SP "GMT"
+ *     rfc850-date  = weekday "," SP date2 SP time SP "GMT"
+ *     asctime-date = wkday SP date3 SP time SP 4DIGIT
+ *
+ *     date1        = 2DIGIT SP month SP 4DIGIT
+ *                    ; day month year (e.g., 02 Jun 1982)
+ *     date2        = 2DIGIT "-" month "-" 2DIGIT
+ *                    ; day-month-year (e.g., 02-Jun-82)
+ *     date3        = month SP ( 2DIGIT | ( SP 1DIGIT ))
+ *                    ; month day (e.g., Jun  2)
+ *
+ *     time         = 2DIGIT ":" 2DIGIT ":" 2DIGIT
+ *                    ; 00:00:00 - 23:59:59
+ *
+ *     wkday        = "Mon" | "Tue" | "Wed"
+ *                  | "Thu" | "Fri" | "Sat" | "Sun"
+ *
+ *     weekday      = "Monday" | "Tuesday" | "Wednesday"
+ *                  | "Thursday" | "Friday" | "Saturday" | "Sunday"
+ *
+ *     month        = "Jan" | "Feb" | "Mar" | "Apr"
+ *                  | "May" | "Jun" | "Jul" | "Aug"
+ *                  | "Sep" | "Oct" | "Nov" | "Dec"
+ *
+ * However, for the sake of robustness (and Netscapeness), we ignore the
+ * weekday and anything after the time field (including the timezone).
+ *
+ * This routine is intended to be very fast; 10x faster than using sscanf.
+ *
+ * Originally from Andrew Daviel <andrew@vancouver-webpages.com>, 29 Jul 96
+ * but many changes since then.
+ *
+ */
+time_t parseHTTPdate(const char *date)
+{
+    struct tm ds;
+    int mint, mon;
+    const char *monstr, *timstr;
+    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 (!date)
+        return BAD_DATE;
+
+    while (*date && isspace(*date))      /* Find first non-whitespace char */
+        ++date;
+
+    if (*date == '\0')
+        return BAD_DATE;
+
+    if ((date = strchr(date,' ')) == NULL)   /* Find space after weekday */
+        return BAD_DATE;
+
+    ++date;    /* Now pointing to first char after space, which should be */
+               /* start of the actual date information for all 3 formats. */
+    
+    if (checkmask(date, "## @$$ #### ##:##:## *")) {     /* RFC 1123 format */
+        ds.tm_year = ((date[7] - '0') * 10 + (date[8] - '0') - 19) * 100;
+        if (ds.tm_year < 0)
+            return BAD_DATE;
+
+        ds.tm_year += ((date[9] - '0') * 10) + (date[10] - '0');
+
+        ds.tm_mday  = ((date[0] - '0') * 10) + (date[1] - '0');
+
+        monstr = date + 3;
+        timstr = date + 12;
+    }
+    else if (checkmask(date, "##-@$$-## ##:##:## *")) {  /* RFC 850 format  */
+        ds.tm_year = ((date[7] - '0') * 10) + (date[8] - '0');
+        if (ds.tm_year < 70)
+            ds.tm_year += 100;
+
+        ds.tm_mday = ((date[0] - '0') * 10) + (date[1] - '0');
+
+        monstr = date + 3;
+        timstr = date + 10;
+    }
+    else if (checkmask(date, "@$$ ~# ##:##:## ####*")) { /* asctime format  */
+        ds.tm_year = ((date[16] - '0') * 10 + (date[17] - '0') - 19) * 100;
+        if (ds.tm_year < 0)
+            return BAD_DATE;
+
+        ds.tm_year += ((date[18] - '0') * 10) + (date[19] - '0');
+
+        if (date[4] == ' ')
+            ds.tm_mday = 0;
+        else
+            ds.tm_mday = (date[4] - '0') * 10;
+
+        ds.tm_mday += (date[5] - '0');
+
+        monstr = date;
+        timstr = date + 7;
+    }
+    else return BAD_DATE;
+
+    if (ds.tm_mday <= 0 || ds.tm_mday > 31)
+        return BAD_DATE;
+
+    ds.tm_hour = ((timstr[0] - '0') * 10) + (timstr[1] - '0');
+    ds.tm_min  = ((timstr[3] - '0') * 10) + (timstr[4] - '0');
+    ds.tm_sec  = ((timstr[6] - '0') * 10) + (timstr[7] - '0');
+
+    if ((ds.tm_hour > 23) || (ds.tm_min > 59) || (ds.tm_sec > 61))
+        return BAD_DATE;
+
+    mint = (monstr[0] << 16) | (monstr[1] << 8) | monstr[2];
+    for (mon=0; mon < 12; mon++)
+        if (mint == months[mon])
+            break;
+    if (mon == 12)
+        return BAD_DATE;
+    
+    if ((ds.tm_mday == 31) && (mon == 3 || mon == 5 || mon == 8 || mon == 10))
+        return BAD_DATE;
+
+    /* February gets special check for leapyear */
+
+    if ((mon == 1) && ((ds.tm_mday > 29) ||
+         ((ds.tm_mday == 29) && ((ds.tm_year & 3) ||
+           (((ds.tm_year % 100) == 0) && (((ds.tm_year % 400) != 100)))))))
+        return BAD_DATE;
+
+    ds.tm_mon = mon;
+
+    return tm2sec(&ds);
+}
+
diff --git a/APACHE_1_2_X/src/main/util_md5.c b/APACHE_1_2_X/src/main/util_md5.c
new file mode 100644 (file)
index 0000000..bf5565e
--- /dev/null
@@ -0,0 +1,192 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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/APACHE_1_2_X/src/main/util_script.c b/APACHE_1_2_X/src/main/util_script.c
new file mode 100644 (file)
index 0000000..12e57b4
--- /dev/null
@@ -0,0 +1,638 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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_conf_globals.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"
+#include <assert.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
+
+/* If a request includes query info in the URL (stuff after "?"), and
+ * the query info does not contain "=" (indicative of a FORM submission),
+ * then this routine is called to create the argument list to be passed
+ * to the CGI script.  When suexec is enabled, the suexec path, user, and
+ * group are the first three arguments to be passed; if not, all three
+ * must be NULL.  The query info is split into separate arguments, where
+ * "+" is the separator between keyword arguments.
+ */
+static char **create_argv(pool *p, char *path, char *user, char *group,
+                          char *av0, const char *args)
+{
+    int x, numwords;
+    char **av;
+    char *w;
+    int idx = 0;
+
+    /* count the number of keywords */
+
+    for (x = 0, numwords = 1; args[x]; x++)
+        if (args[x] == '+') ++numwords;
+
+    if (numwords > APACHE_ARG_MAX - 5) {
+        numwords = APACHE_ARG_MAX - 5; /* Truncate args to prevent overrun */
+    }
+    av = (char **)palloc(p, (numwords + 5) * sizeof(char *));
+
+    if (path)
+        av[idx++] = path;
+    if (user)
+        av[idx++] = user;
+    if (group)
+        av[idx++] = group;
+
+    av[idx++] = av0;
+
+    for (x = 1; x <= numwords; x++) {
+        w = getword_nulls(p, &args, '+');
+        unescape_url(w);
+        av[idx++] = escape_shell_cmd(p, w);
+    }
+    av[idx] = 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);
+    }
+    
+    ap_snprintf(port, sizeof(port), "%u", 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); /* Apache */
+    
+    ap_snprintf(port, sizeof(port), "%d", ntohs(c->remote_addr.sin_port));
+    table_set (e, "REMOTE_PORT", port);            /* Apache */
+
+    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);
+    }
+}
+
+/* This "cute" little function comes about because the path info on
+ * filenames and URLs aren't always the same. So we take the two,
+ * and find as much of the two that match as possible.
+ */
+
+int find_path_info (char *uri, char *path_info)
+{
+    int lu = strlen(uri);
+    int lp = strlen(path_info);
+
+    while (lu-- && lp-- && uri[lu] == path_info[lp]);
+
+    if (lu == -1)
+       lu=0;
+
+    while (uri[lu] != '\0' && uri[lu] != '/')
+       lu++;
+
+    return lu;
+}
+
+/* Obtain the Request-URI from the original request-line, returning
+ * a new string from the request pool containing the URI or "".
+ */
+static char *original_uri(request_rec *r)
+{
+    char *first, *last;
+
+    if (r->the_request == NULL)
+        return (char *)pcalloc(r->pool, 1);
+
+    first = r->the_request;                      /* use the request-line */
+
+    while (*first && !isspace(*first)) ++first;  /* skip over the method */
+    while (isspace(*first)) ++first;             /*   and the space(s)   */
+
+    last = first;
+    while (*last && !isspace(*last)) ++last;     /* end at next whitespace */
+    
+    return pstrndup(r->pool, first, last - first);
+}
+
+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 : "");
+    table_set (e, "REQUEST_URI", original_uri(r));
+
+    /* 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 (!strcmp (r->protocol, "INCLUDED")) {
+        table_set (e, "SCRIPT_NAME", r->uri);
+       if (r->path_info && *r->path_info)
+           table_set (e, "PATH_INFO", r->path_info);
+    } else if (!r->path_info || !*r->path_info) {
+        table_set (e, "SCRIPT_NAME", r->uri);
+    } else {
+       int path_info_start = find_path_info (r->uri, r->path_info);
+
+       table_set (e, "SCRIPT_NAME", pstrndup(r->pool, r->uri,
+                                             path_info_start));
+
+       table_set (e, "PATH_INFO", r->path_info);
+    }
+       
+    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);
+      
+       /* 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_err(request_rec *r, FILE *f, char *buffer)
+{
+    char x[MAX_STRING_LEN];
+    char *w, *l;
+    int p;
+
+    if (buffer) *buffer = '\0';
+    w = buffer ? buffer : x;
+
+    hard_timeout ("read script header", r);
+    
+    while(1) {
+
+       if (fgets(w, MAX_STRING_LEN-1, f) == NULL) {
+           kill_timeout (r);
+           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);
+
+           if (!buffer)
+             /* 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);
+        }   
+        else if(!strcasecmp(w,"Content-Length")) {
+           table_set (r->headers_out, w, l);
+        }   
+        else if(!strcasecmp(w,"Transfer-Encoding")) {
+           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)
+        ap_snprintf(ss, sizeof(ss), "%4dk", (size + 512) / 1024);
+    else if(size < 103809024)
+       ap_snprintf(ss, sizeof(ss), "%4.1fM", size / 1048576.0);
+    else
+        ap_snprintf(ss, sizeof(ss), "%4dM", (size + 524288) / 1048576);
+    rputs(ss, r);
+}
+
+#ifdef __EMX__
+static char **create_argv_cmd(pool *p, char *av0, const 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
+
+
+void call_exec (request_rec *r, char *argv0, char **env, int shellcmd) 
+{
+#if defined(RLIMIT_CPU)  || defined(RLIMIT_NPROC) || \
+    defined(RLIMIT_DATA) || defined(RLIMIT_VMEM)
+
+    core_dir_config *conf =
+      (core_dir_config *)get_module_config(r->per_dir_config, &core_module);
+
+#endif
+
+    /* the fd on r->server->error_log is closed, but we need somewhere to
+     * put the error messages from the log_* functions. So, we use stderr,
+     * since that is better than allowing errors to go unnoticed.
+     */
+    r->server->error_log = stderr;
+
+#ifdef RLIMIT_CPU
+    if (conf->limit_cpu != NULL)
+       if ((setrlimit (RLIMIT_CPU, conf->limit_cpu)) != 0)
+           log_unixerr("setrlimit", NULL, "failed to set CPU usage limit",
+                       r->server);
+#endif
+#ifdef RLIMIT_NPROC
+    if (conf->limit_nproc != NULL)
+       if ((setrlimit (RLIMIT_NPROC, conf->limit_nproc)) != 0)
+           log_unixerr("setrlimit", NULL, "failed to set process limit",
+                       r->server);
+#endif
+#ifdef RLIMIT_DATA
+    if (conf->limit_mem != NULL)
+       if ((setrlimit (RLIMIT_DATA, conf->limit_mem)) != 0)
+           log_unixerr("setrlimit", NULL, "failed to set memory usage limit",
+                       r->server);
+#endif
+#ifdef RLIMIT_VMEM
+    if (conf->limit_mem != NULL)
+       if ((setrlimit (RLIMIT_VMEM, conf->limit_mem)) != 0)
+           log_unixerr("setrlimit", NULL, "failed to set memory usage limit",
+                       r->server);
+#endif
+    
+#ifdef __EMX__    
+    {
+        /* Additions by Alec Kloss, to allow exec'ing of scripts under OS/2 */
+        int is_script;
+        char interpreter[2048]; /* hope this is large enough for the interpreter path */
+        FILE * program;
+        program = fopen (r->filename, "r");
+        if (!program) {
+            char err_string[HUGE_STRING_LEN];
+            ap_snprintf(err_string, sizeof(err_string), "open of %s failed, errno is %d\n", r->filename, errno);
+            /* write(2, err_string, strlen(err_string)); */
+            /* exit(0); */
+            log_unixerr("fopen", NULL, err_string, r->server);
+            return;
+        }
+        fgets (interpreter, 2048, program);
+        fclose (program);
+        if (!strncmp (interpreter, "#!", 2)) {
+            is_script = 1;
+            interpreter[strlen(interpreter)-1] = '\0';
+        } else {
+            is_script = 0;
+        }
+
+    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);
+                
+    /* Additions by Alec Kloss, to allow exec'ing of scripts under OS/2 */
+    if (is_script) {
+        /* here's the stuff to run the interpreter */
+        execl (interpreter+2, interpreter+2, r->filename, NULL);
+    } else
+
+       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
+          environment so that they 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, NULL, NULL, NULL, argv0, r->args));
+    }
+    }
+#else
+    if ( suexec_enabled &&
+        ((r->server->server_uid != user_id) ||
+         (r->server->server_gid != group_id) ||
+         (!strncmp("/~",r->uri,2))) ) {
+
+       char *execuser, *grpname;
+       struct passwd *pw;
+       struct group *gr;
+
+       if (!strncmp("/~",r->uri,2)) {
+           gid_t user_gid;
+           char *username = pstrdup(r->pool, r->uri + 2);
+           int pos = ind(username, '/');
+
+           if (pos >= 0) username[pos] = '\0';
+
+           if ((pw = getpwnam(username)) == NULL) {
+               log_unixerr("getpwnam",username,"invalid username",r->server);
+               return;
+           }
+           execuser = pstrcat(r->pool, "~", pw->pw_name, NULL);
+           user_gid = pw->pw_gid;
+
+           if ((gr = getgrgid(user_gid)) == NULL) {
+               if ((grpname = palloc (r->pool, 16)) == NULL) 
+                   return;
+               else
+                   ap_snprintf(grpname, 16, "%d", user_gid);
+           }
+           else
+               grpname = gr->gr_name;
+       }
+       else {
+           if ((pw = getpwuid (r->server->server_uid)) == NULL) {
+               log_unixerr("getpwuid", NULL, "invalid userid", r->server);
+               return;
+           }
+           execuser = pstrdup(r->pool, pw->pw_name);
+
+           if ((gr = getgrgid (r->server->server_gid)) == NULL) {
+               log_unixerr("getgrgid", NULL, "invalid groupid", r->server);
+               return;
+           }
+           grpname = gr->gr_name;
+       }
+  
+       if (shellcmd)
+           execle(SUEXEC_BIN, SUEXEC_BIN, execuser, grpname, argv0, NULL, env);
+
+       else if((!r->args) || (!r->args[0]) || (ind(r->args,'=') >= 0))
+           execle(SUEXEC_BIN, SUEXEC_BIN, execuser, grpname, argv0, NULL, env);
+
+       else {
+           execve(SUEXEC_BIN, 
+                  create_argv(r->pool, SUEXEC_BIN, execuser, grpname,
+                              argv0, r->args),
+                  env);
+       }
+    }
+    else {
+       if (shellcmd) 
+           execle(SHELL_PATH, SHELL_PATH, "-c", argv0, NULL, env);
+       
+       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, NULL, NULL, NULL, argv0, r->args),
+                  env);
+    }
+#endif
+}
diff --git a/APACHE_1_2_X/src/main/util_snprintf.c b/APACHE_1_2_X/src/main/util_snprintf.c
new file mode 100644 (file)
index 0000000..d37c634
--- /dev/null
@@ -0,0 +1,949 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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 code is based on, and used with the permission of, the
+ * SIO stdio-replacement strx_* functions by Panos Tsirigotis
+ * <panos@alumni.cs.colorado.edu> for xinetd.
+ */
+
+#include "conf.h"
+
+#ifndef HAVE_SNPRINTF
+
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+
+#ifdef HAVE_CVT
+
+# define ap_ecvt ecvt
+# define ap_fcvt fcvt
+# define ap_gcvt gcvt
+
+#else
+
+/*
+ * cvt.c - IEEE floating point formatting routines for FreeBSD
+ * from GNU libc-4.6.27
+ */
+
+/*
+ *    ap_ecvt converts to decimal
+ *      the number of digits is specified by ndigit
+ *      decpt is set to the position of the decimal point
+ *      sign is set to 0 for positive, 1 for negative
+ */
+
+#define        NDIG    80
+
+static char *
+     ap_cvt(double arg, int ndigits, int *decpt, int *sign, int eflag)
+{
+    register int r2;
+    double fi, fj;
+    register char *p, *p1;
+    static char buf[NDIG];
+
+    if (ndigits >= NDIG - 1)
+       ndigits = NDIG - 2;
+    r2 = 0;
+    *sign = 0;
+    p = &buf[0];
+    if (arg < 0) {
+       *sign = 1;
+       arg = -arg;
+    }
+    arg = modf(arg, &fi);
+    p1 = &buf[NDIG];
+    /*
+     * Do integer part
+     */
+    if (fi != 0) {
+       p1 = &buf[NDIG];
+       while (fi != 0) {
+           fj = modf(fi / 10, &fi);
+           *--p1 = (int) ((fj + .03) * 10) + '0';
+           r2++;
+       }
+       while (p1 < &buf[NDIG])
+           *p++ = *p1++;
+    }
+    else if (arg > 0) {
+       while ((fj = arg * 10) < 1) {
+           arg = fj;
+           r2--;
+       }
+    }
+    p1 = &buf[ndigits];
+    if (eflag == 0)
+       p1 += r2;
+    *decpt = r2;
+    if (p1 < &buf[0]) {
+       buf[0] = '\0';
+       return (buf);
+    }
+    while (p <= p1 && p < &buf[NDIG]) {
+       arg *= 10;
+       arg = modf(arg, &fj);
+       *p++ = (int) fj + '0';
+    }
+    if (p1 >= &buf[NDIG]) {
+       buf[NDIG - 1] = '\0';
+       return (buf);
+    }
+    p = p1;
+    *p1 += 5;
+    while (*p1 > '9') {
+       *p1 = '0';
+       if (p1 > buf)
+           ++ * --p1;
+       else {
+           *p1 = '1';
+           (*decpt)++;
+           if (eflag == 0) {
+               if (p > buf)
+                   *p = '0';
+               p++;
+           }
+       }
+    }
+    *p = '\0';
+    return (buf);
+}
+
+static char *
+     ap_ecvt(double arg, int ndigits, int *decpt, int *sign)
+{
+    return (ap_cvt(arg, ndigits, decpt, sign, 1));
+}
+
+static char *
+     ap_fcvt(double arg, int ndigits, int *decpt, int *sign)
+{
+    return (ap_cvt(arg, ndigits, decpt, sign, 0));
+}
+
+/*
+ * ap_gcvt  - Floating output conversion to
+ * minimal length string
+ */
+
+static char *
+     ap_gcvt(double number, int ndigit, char *buf)
+{
+    int sign, decpt;
+    register char *p1, *p2;
+    register i;
+
+    p1 = ap_ecvt(number, ndigit, &decpt, &sign);
+    p2 = buf;
+    if (sign)
+       *p2++ = '-';
+    for (i = ndigit - 1; i > 0 && p1[i] == '0'; i--)
+       ndigit--;
+    if ((decpt >= 0 && decpt - ndigit > 4)
+       || (decpt < 0 && decpt < -3)) {         /* use E-style */
+       decpt--;
+       *p2++ = *p1++;
+       *p2++ = '.';
+       for (i = 1; i < ndigit; i++)
+           *p2++ = *p1++;
+       *p2++ = 'e';
+       if (decpt < 0) {
+           decpt = -decpt;
+           *p2++ = '-';
+       }
+       else
+           *p2++ = '+';
+       if (decpt / 100 > 0)
+           *p2++ = decpt / 100 + '0';
+       if (decpt / 10 > 0)
+           *p2++ = (decpt % 100) / 10 + '0';
+       *p2++ = decpt % 10 + '0';
+    }
+    else {
+       if (decpt <= 0) {
+           if (*p1 != '0')
+               *p2++ = '.';
+           while (decpt < 0) {
+               decpt++;
+               *p2++ = '0';
+           }
+       }
+       for (i = 1; i <= ndigit; i++) {
+           *p2++ = *p1++;
+           if (i == decpt)
+               *p2++ = '.';
+       }
+       if (ndigit < decpt) {
+           while (ndigit++ < decpt)
+               *p2++ = '0';
+           *p2++ = '.';
+       }
+    }
+    if (p2[-1] == '.')
+       p2--;
+    *p2 = '\0';
+    return (buf);
+}
+
+#endif /* HAVE_CVT */
+
+typedef enum {
+    NO = 0, YES = 1
+} boolean_e;
+
+#define FALSE                  0
+#define TRUE                   1
+#define NUL                    '\0'
+#define INT_NULL               ((int *)0)
+#define WIDE_INT               long
+
+typedef WIDE_INT               wide_int;
+typedef unsigned WIDE_INT      u_wide_int;
+typedef int                    bool_int;
+
+#define S_NULL                 "(null)"
+#define S_NULL_LEN             6
+
+#define FLOAT_DIGITS           6
+#define EXPONENT_LENGTH                10
+
+/*
+ * NUM_BUF_SIZE is the size of the buffer used for arithmetic conversions
+ *
+ * XXX: this is a magic number; do not decrease it
+ */
+#define NUM_BUF_SIZE           512
+
+
+/*
+ * Descriptor for buffer area
+ */
+struct buf_area {
+    char *buf_end;
+    char *nextb;               /* pointer to next byte to read/write   */
+};
+
+typedef struct buf_area buffy;
+
+/*
+ * The INS_CHAR macro inserts a character in the buffer and writes
+ * the buffer back to disk if necessary
+ * It uses the char pointers sp and bep:
+ *      sp points to the next available character in the buffer
+ *      bep points to the end-of-buffer+1
+ * While using this macro, note that the nextb pointer is NOT updated.
+ *
+ * NOTE: Evaluation of the c argument should not have any side-effects
+ */
+#define INS_CHAR( c, sp, bep, cc )     \
+           {                           \
+               if ( sp < bep )         \
+               {                       \
+                   *sp++ = c ;         \
+                   cc++ ;              \
+               }                       \
+           }
+
+#define NUM( c )                       ( c - '0' )
+
+#define STR_TO_DEC( str, num )         \
+    num = NUM( *str++ ) ;              \
+    while ( isdigit( *str ) )          \
+    {                                  \
+       num *= 10 ;                     \
+       num += NUM( *str++ ) ;          \
+    }
+
+/*
+ * This macro does zero padding so that the precision
+ * requirement is satisfied. The padding is done by
+ * adding '0's to the left of the string that is going
+ * to be printed.
+ */
+#define FIX_PRECISION( adjust, precision, s, s_len )   \
+    if ( adjust )                                      \
+       while ( s_len < precision )                     \
+       {                                               \
+           *--s = '0' ;                                \
+           s_len++ ;                                   \
+       }
+
+/*
+ * Macro that does padding. The padding is done by printing
+ * the character ch.
+ */
+#define PAD( width, len, ch )  do              \
+       {                                       \
+           INS_CHAR( ch, sp, bep, cc ) ;       \
+           width-- ;                           \
+       }                                       \
+       while ( width > len )
+
+/*
+ * Prefix the character ch to the string str
+ * Increase length
+ * Set the has_prefix flag
+ */
+#define PREFIX( str, length, ch )       *--str = ch ; length++ ; has_prefix = YES
+
+
+/*
+ * Convert num to its decimal format.
+ * Return value:
+ *   - a pointer to a string containing the number (no sign)
+ *   - len contains the length of the string
+ *   - is_negative is set to TRUE or FALSE depending on the sign
+ *     of the number (always set to FALSE if is_unsigned is TRUE)
+ *
+ * The caller provides a buffer for the string: that is the buf_end argument
+ * which is a pointer to the END of the buffer + 1 (i.e. if the buffer
+ * is declared as buf[ 100 ], buf_end should be &buf[ 100 ])
+ */
+static char *
+     conv_10(register wide_int num, register bool_int is_unsigned,
+         register bool_int * is_negative, char *buf_end, register int *len)
+{
+    register char *p = buf_end;
+    register u_wide_int magnitude;
+
+    if (is_unsigned) {
+       magnitude = (u_wide_int) num;
+       *is_negative = FALSE;
+    }
+    else {
+       *is_negative = (num < 0);
+
+       /*
+        * On a 2's complement machine, negating the most negative integer 
+        * results in a number that cannot be represented as a signed integer.
+        * Here is what we do to obtain the number's magnitude:
+        *      a. add 1 to the number
+        *      b. negate it (becomes positive)
+        *      c. convert it to unsigned
+        *      d. add 1
+        */
+       if (*is_negative) {
+           wide_int t = num + 1;
+
+           magnitude = ((u_wide_int) - t) + 1;
+       }
+       else
+           magnitude = (u_wide_int) num;
+    }
+
+    /*
+     * We use a do-while loop so that we write at least 1 digit 
+     */
+    do {
+       register u_wide_int new_magnitude = magnitude / 10;
+
+       *--p = magnitude - new_magnitude * 10 + '0';
+       magnitude = new_magnitude;
+    }
+    while (magnitude);
+
+    *len = buf_end - p;
+    return (p);
+}
+
+
+
+/*
+ * Convert a floating point number to a string formats 'f', 'e' or 'E'.
+ * The result is placed in buf, and len denotes the length of the string
+ * The sign is returned in the is_negative argument (and is not placed
+ * in buf).
+ */
+static char *
+     conv_fp(register char format, register double num,
+boolean_e add_dp, int precision, bool_int * is_negative, char *buf, int *len)
+{
+    register char *s = buf;
+    register char *p;
+    int decimal_point;
+
+    if (format == 'f')
+       p = ap_fcvt(num, precision, &decimal_point, is_negative);
+    else                       /* either e or E format */
+       p = ap_ecvt(num, precision + 1, &decimal_point, is_negative);
+
+    /*
+     * Check for Infinity and NaN
+     */
+    if (isalpha(*p)) {
+       *len = strlen(strcpy(buf, p));
+       *is_negative = FALSE;
+       return (buf);
+    }
+
+    if (format == 'f')
+       if (decimal_point <= 0) {
+           *s++ = '0';
+           if (precision > 0) {
+               *s++ = '.';
+               while (decimal_point++ < 0)
+                   *s++ = '0';
+           }
+           else if (add_dp)
+               *s++ = '.';
+       }
+       else {
+           while (decimal_point-- > 0)
+               *s++ = *p++;
+           if (precision > 0 || add_dp)
+               *s++ = '.';
+       }
+    else {
+       *s++ = *p++;
+       if (precision > 0 || add_dp)
+           *s++ = '.';
+    }
+
+    /*
+     * copy the rest of p, the NUL is NOT copied
+     */
+    while (*p)
+       *s++ = *p++;
+
+    if (format != 'f') {
+       char temp[EXPONENT_LENGTH];     /* for exponent conversion */
+       int t_len;
+       bool_int exponent_is_negative;
+
+       *s++ = format;          /* either e or E */
+       decimal_point--;
+       if (decimal_point != 0) {
+           p = conv_10((wide_int) decimal_point, FALSE, &exponent_is_negative,
+                       &temp[EXPONENT_LENGTH], &t_len);
+           *s++ = exponent_is_negative ? '-' : '+';
+
+           /*
+            * Make sure the exponent has at least 2 digits
+            */
+           if (t_len == 1)
+               *s++ = '0';
+           while (t_len--)
+               *s++ = *p++;
+       }
+       else {
+           *s++ = '+';
+           *s++ = '0';
+           *s++ = '0';
+       }
+    }
+
+    *len = s - buf;
+    return (buf);
+}
+
+
+/*
+ * Convert num to a base X number where X is a power of 2. nbits determines X.
+ * For example, if nbits is 3, we do base 8 conversion
+ * Return value:
+ *      a pointer to a string containing the number
+ *
+ * The caller provides a buffer for the string: that is the buf_end argument
+ * which is a pointer to the END of the buffer + 1 (i.e. if the buffer
+ * is declared as buf[ 100 ], buf_end should be &buf[ 100 ])
+ */
+static char *
+     conv_p2(register u_wide_int num, register int nbits,
+            char format, char *buf_end, register int *len)
+{
+    register int mask = (1 << nbits) - 1;
+    register char *p = buf_end;
+    static char low_digits[] = "0123456789abcdef";
+    static char upper_digits[] = "0123456789ABCDEF";
+    register char *digits = (format == 'X') ? upper_digits : low_digits;
+
+    do {
+       *--p = digits[num & mask];
+       num >>= nbits;
+    }
+    while (num);
+
+    *len = buf_end - p;
+    return (p);
+}
+
+
+/*
+ * Do format conversion placing the output in buffer
+ */
+static int format_converter(register buffy * odp, const char *fmt,
+                             va_list ap)
+{
+    register char *sp;
+    register char *bep;
+    register int cc = 0;
+    register int i;
+
+    register char *s = NULL;
+    char *q;
+    int s_len;
+
+    register int min_width = 0;
+    int precision = 0;
+    enum {
+       LEFT, RIGHT
+    } adjust;
+    char pad_char;
+    char prefix_char;
+
+    double fp_num;
+    wide_int i_num = (wide_int) 0;
+    u_wide_int ui_num;
+
+    char num_buf[NUM_BUF_SIZE];
+    char char_buf[2];          /* for printing %% and %<unknown> */
+
+    /*
+     * Flag variables
+     */
+    boolean_e is_long;
+    boolean_e alternate_form;
+    boolean_e print_sign;
+    boolean_e print_blank;
+    boolean_e adjust_precision;
+    boolean_e adjust_width;
+    bool_int is_negative;
+
+    sp = odp->nextb;
+    bep = odp->buf_end;
+
+    while (*fmt) {
+       if (*fmt != '%') {
+           INS_CHAR(*fmt, sp, bep, cc);
+       }
+       else {
+           /*
+            * Default variable settings
+            */
+           adjust = RIGHT;
+           alternate_form = print_sign = print_blank = NO;
+           pad_char = ' ';
+           prefix_char = NUL;
+
+           fmt++;
+
+           /*
+            * Try to avoid checking for flags, width or precision
+            */
+           if (isascii(*fmt) && !islower(*fmt)) {
+               /*
+                * Recognize flags: -, #, BLANK, +
+                */
+               for (;; fmt++) {
+                   if (*fmt == '-')
+                       adjust = LEFT;
+                   else if (*fmt == '+')
+                       print_sign = YES;
+                   else if (*fmt == '#')
+                       alternate_form = YES;
+                   else if (*fmt == ' ')
+                       print_blank = YES;
+                   else if (*fmt == '0')
+                       pad_char = '0';
+                   else
+                       break;
+               }
+
+               /*
+                * Check if a width was specified
+                */
+               if (isdigit(*fmt)) {
+                   STR_TO_DEC(fmt, min_width);
+                   adjust_width = YES;
+               }
+               else if (*fmt == '*') {
+                   min_width = va_arg(ap, int);
+                   fmt++;
+                   adjust_width = YES;
+                   if (min_width < 0) {
+                       adjust = LEFT;
+                       min_width = -min_width;
+                   }
+               }
+               else
+                   adjust_width = NO;
+
+               /*
+                * Check if a precision was specified
+                *
+                * XXX: an unreasonable amount of precision may be specified
+                * resulting in overflow of num_buf. Currently we
+                * ignore this possibility.
+                */
+               if (*fmt == '.') {
+                   adjust_precision = YES;
+                   fmt++;
+                   if (isdigit(*fmt)) {
+                       STR_TO_DEC(fmt, precision);
+                   }
+                   else if (*fmt == '*') {
+                       precision = va_arg(ap, int);
+                       fmt++;
+                       if (precision < 0)
+                           precision = 0;
+                   }
+                   else
+                       precision = 0;
+               }
+               else
+                   adjust_precision = NO;
+           }
+           else
+               adjust_precision = adjust_width = NO;
+
+           /*
+            * Modifier check
+            */
+           if (*fmt == 'l') {
+               is_long = YES;
+               fmt++;
+           }
+           else
+               is_long = NO;
+
+           /*
+            * Argument extraction and printing.
+            * First we determine the argument type.
+            * Then, we convert the argument to a string.
+            * On exit from the switch, s points to the string that
+            * must be printed, s_len has the length of the string
+            * The precision requirements, if any, are reflected in s_len.
+            *
+            * NOTE: pad_char may be set to '0' because of the 0 flag.
+            *   It is reset to ' ' by non-numeric formats
+            */
+           switch (*fmt) {
+           case 'u':
+               if (is_long)
+                   i_num = va_arg(ap, u_wide_int);
+               else
+                   i_num = (wide_int) va_arg(ap, unsigned int);
+               /*
+                * The rest also applies to other integer formats, so fall
+                * into that case.
+                */
+           case 'd':
+           case 'i':
+               /*
+                * Get the arg if we haven't already.
+                */
+               if ((*fmt) != 'u') {
+                   if (is_long)
+                       i_num = va_arg(ap, wide_int);
+                   else
+                       i_num = (wide_int) va_arg(ap, int);
+               };
+               s = conv_10(i_num, (*fmt) == 'u', &is_negative,
+                           &num_buf[NUM_BUF_SIZE], &s_len);
+               FIX_PRECISION(adjust_precision, precision, s, s_len);
+
+               if (*fmt != 'u') {
+                   if (is_negative)
+                       prefix_char = '-';
+                   else if (print_sign)
+                       prefix_char = '+';
+                   else if (print_blank)
+                       prefix_char = ' ';
+               }
+               break;
+
+
+           case 'o':
+               if (is_long)
+                   ui_num = va_arg(ap, u_wide_int);
+               else
+                   ui_num = (u_wide_int) va_arg(ap, unsigned int);
+               s = conv_p2(ui_num, 3, *fmt,
+                           &num_buf[NUM_BUF_SIZE], &s_len);
+               FIX_PRECISION(adjust_precision, precision, s, s_len);
+               if (alternate_form && *s != '0') {
+                   *--s = '0';
+                   s_len++;
+               }
+               break;
+
+
+           case 'x':
+           case 'X':
+               if (is_long)
+                   ui_num = (u_wide_int) va_arg(ap, u_wide_int);
+               else
+                   ui_num = (u_wide_int) va_arg(ap, unsigned int);
+               s = conv_p2(ui_num, 4, *fmt,
+                           &num_buf[NUM_BUF_SIZE], &s_len);
+               FIX_PRECISION(adjust_precision, precision, s, s_len);
+               if (alternate_form && i_num != 0) {
+                   *--s = *fmt;        /* 'x' or 'X' */
+                   *--s = '0';
+                   s_len += 2;
+               }
+               break;
+
+
+           case 's':
+               s = va_arg(ap, char *);
+               if (s != NULL) {
+                   s_len = strlen(s);
+                   if (adjust_precision && precision < s_len)
+                       s_len = precision;
+               }
+               else {
+                   s = S_NULL;
+                   s_len = S_NULL_LEN;
+               }
+               pad_char = ' ';
+               break;
+
+
+           case 'f':
+           case 'e':
+           case 'E':
+               fp_num = va_arg(ap, double);
+
+               s = conv_fp(*fmt, fp_num, alternate_form,
+                       (adjust_precision == NO) ? FLOAT_DIGITS : precision,
+                           &is_negative, &num_buf[1], &s_len);
+               if (is_negative)
+                   prefix_char = '-';
+               else if (print_sign)
+                   prefix_char = '+';
+               else if (print_blank)
+                   prefix_char = ' ';
+               break;
+
+
+           case 'g':
+           case 'G':
+               if (adjust_precision == NO)
+                   precision = FLOAT_DIGITS;
+               else if (precision == 0)
+                   precision = 1;
+               /*
+                * * We use &num_buf[ 1 ], so that we have room for the sign
+                */
+               s = ap_gcvt(va_arg(ap, double), precision, &num_buf[1]);
+               if (*s == '-')
+                   prefix_char = *s++;
+               else if (print_sign)
+                   prefix_char = '+';
+               else if (print_blank)
+                   prefix_char = ' ';
+
+               s_len = strlen(s);
+
+               if (alternate_form && (q = strchr(s, '.')) == NULL)
+                   s[s_len++] = '.';
+               if (*fmt == 'G' && (q = strchr(s, 'e')) != NULL)
+                   *q = 'E';
+               break;
+
+
+           case 'c':
+               char_buf[0] = (char) (va_arg(ap, int));
+               s = &char_buf[0];
+               s_len = 1;
+               pad_char = ' ';
+               break;
+
+
+           case '%':
+               char_buf[0] = '%';
+               s = &char_buf[0];
+               s_len = 1;
+               pad_char = ' ';
+               break;
+
+
+           case 'n':
+               *(va_arg(ap, int *)) = cc;
+               break;
+
+               /*
+                * Always extract the argument as a "char *" pointer. We 
+                * should be using "void *" but there are still machines 
+                * that don't understand it.
+                * If the pointer size is equal to the size of an unsigned
+                * integer we convert the pointer to a hex number, otherwise 
+                * we print "%p" to indicate that we don't handle "%p".
+                */
+           case 'p':
+               ui_num = (u_wide_int) va_arg(ap, char *);
+
+               if (sizeof(char *) <= sizeof(u_wide_int))
+                        s = conv_p2(ui_num, 4, 'x',
+                                    &num_buf[NUM_BUF_SIZE], &s_len);
+               else {
+                   s = "%p";
+                   s_len = 2;
+               }
+               pad_char = ' ';
+               break;
+
+
+           case NUL:
+               /*
+                * The last character of the format string was %.
+                * We ignore it.
+                */
+               continue;
+
+
+               /*
+                * The default case is for unrecognized %'s.
+                * We print %<char> to help the user identify what
+                * option is not understood.
+                * This is also useful in case the user wants to pass
+                * the output of format_converter to another function
+                * that understands some other %<char> (like syslog).
+                * Note that we can't point s inside fmt because the
+                * unknown <char> could be preceded by width etc.
+                */
+           default:
+               char_buf[0] = '%';
+               char_buf[1] = *fmt;
+               s = char_buf;
+               s_len = 2;
+               pad_char = ' ';
+               break;
+           }
+
+           if (prefix_char != NUL) {
+               *--s = prefix_char;
+               s_len++;
+           }
+
+           if (adjust_width && adjust == RIGHT && min_width > s_len) {
+               if (pad_char == '0' && prefix_char != NUL) {
+                   INS_CHAR(*s, sp, bep, cc)
+                       s++;
+                   s_len--;
+                   min_width--;
+               }
+               PAD(min_width, s_len, pad_char);
+           }
+
+           /*
+            * Print the string s. 
+            */
+           for (i = s_len; i != 0; i--) {
+               INS_CHAR(*s, sp, bep, cc);
+               s++;
+           }
+
+           if (adjust_width && adjust == LEFT && min_width > s_len)
+               PAD(min_width, s_len, pad_char);
+       }
+       fmt++;
+    }
+    odp->nextb = sp;
+    return (cc);
+}
+
+
+/*
+ * This is the general purpose conversion function.
+ */
+static void strx_printv(int *ccp, char *buf, size_t len, const char *format,
+                       va_list ap)
+{
+    buffy od;
+    int cc;
+
+    /*
+     * First initialize the descriptor
+     * Notice that if no length is given, we initialize buf_end to the
+     * highest possible address.
+     */
+    od.buf_end = len ? &buf[len] : (char *) ~0;
+    od.nextb = buf;
+
+    /*
+     * Do the conversion
+     */
+    cc = format_converter(&od, format, ap);
+    if (len == 0 || od.nextb <= od.buf_end)
+       *(od.nextb) = '\0';
+    if (ccp)
+       *ccp = cc;
+}
+
+
+int ap_snprintf(char *buf, size_t len, const char *format,...)
+{
+    int cc;
+    va_list ap;
+
+    va_start(ap, format);
+    strx_printv(&cc, buf, (len - 1), format, ap);
+    va_end(ap);
+    return (cc);
+}
+
+
+int ap_vsnprintf(char *buf, size_t len, const char *format, va_list ap)
+{
+    int cc;
+
+    strx_printv(&cc, buf, (len - 1), format, ap);
+    return (cc);
+}
+
+#endif /* HAVE_SNPRINTF */
diff --git a/APACHE_1_2_X/src/mod_browser.c b/APACHE_1_2_X/src/mod_browser.c
new file mode 100644 (file)
index 0000000..67cf99d
--- /dev/null
@@ -0,0 +1,189 @@
+/* ====================================================================
+ * Copyright (c) 1996,1997 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_browser.c
+ * Set environment variables based on browser support.
+ * 
+ * Alexei Kosut <akosut@organic.com>
+ */
+
+#include "httpd.h"
+#include "http_config.h"
+
+typedef struct {
+    char *name;
+    regex_t *preg;
+    table *features;
+} browser_entry;
+
+typedef struct {
+    array_header *browsers;
+} browser_server_config_rec;
+
+module browser_module;
+
+void *create_browser_config (pool *p, server_rec *dummy)
+{
+    browser_server_config_rec *new =
+   (browser_server_config_rec *) palloc (p, sizeof(browser_server_config_rec));
+
+    new->browsers = make_array (p, 20, sizeof(browser_entry));
+    return (void *)new;
+}
+
+void *merge_browser_config (pool *p, void *basev, void *overridesv)
+{
+    browser_server_config_rec *a =
+       pcalloc(p, sizeof(browser_server_config_rec));
+    browser_server_config_rec *base = basev, *overrides = overridesv;
+
+    a->browsers = append_arrays(p, base->browsers, overrides->browsers);
+    return a;
+}
+
+const char *add_browser(cmd_parms *cmd, void *dummy, char *name,
+                       const char *feature)
+{
+    browser_server_config_rec *sconf =
+      get_module_config (cmd->server->module_config, &browser_module);
+    browser_entry *new, *entries = (browser_entry *)sconf->browsers->elts;
+    char *var;
+    int i, cflags = (int)cmd->info;
+
+    /* First, try to merge into an existing entry */
+
+    for (i = 0; i < sconf->browsers->nelts; ++i) {
+       browser_entry *b = &entries[i];
+       if (!strcmp(b->name, name)) {
+           var = getword(cmd->pool, &feature, '=');
+           if (*feature) table_set(b->features, var, feature);
+           else if (*var == '!') table_set(b->features, var + 1, "!");
+           else table_set(b->features, var, "1");
+           return NULL;
+       }
+    }
+
+    /* If none was found, create a new entry */
+
+    new = push_array(sconf->browsers);
+    new->name = name;
+    new->preg = pregcomp (cmd->pool, name, REG_EXTENDED|REG_NOSUB|cflags);
+    if (new->preg == NULL) {
+       return "Browser regex could not be compiled.";
+    }
+    new->features = make_table(cmd->pool, 5);
+
+    var = getword(cmd->pool, &feature, '=');
+    if (*feature) table_set(new->features, var, feature);
+    else if (*var == '!') table_set(new->features, var + 1, "!");
+    else table_set(new->features, var, "1");
+
+    return NULL;
+}
+
+command_rec browser_module_cmds[] = {
+{ "BrowserMatch", add_browser, (void*)0,
+    RSRC_CONF, ITERATE2, "A browser regex and a list of variables." },
+{ "BrowserMatchNoCase", add_browser, (void*)REG_ICASE,
+    RSRC_CONF, ITERATE2, "a browser regex and a list of variables." },
+{ NULL },
+};
+
+int parse_headers_browser_module(request_rec *r)
+{
+    server_rec *s = r->server;
+    browser_server_config_rec *sconf = get_module_config (s->module_config,
+                                                         &browser_module);
+    browser_entry *entries = (browser_entry *)sconf->browsers->elts;
+    table_entry *elts;
+    char *ua = table_get(r->headers_in, "User-Agent");
+    int i, j;
+
+    if (!ua) return DECLINED;
+
+    for (i = 0; i < sconf->browsers->nelts; ++i) {
+       browser_entry *b = &entries[i];
+
+       if (!regexec(b->preg, ua, 0, NULL, 0)) {
+           elts = (table_entry *)b->features->elts;
+
+           for (j = 0; j < b->features->nelts; ++j) {
+               if (!strcmp(elts[j].val, "!"))
+                   table_unset(r->subprocess_env, elts[j].key);
+               else
+                   table_set(r->subprocess_env, elts[j].key, elts[j].val);
+           }
+       }
+    }
+
+    return OK;  
+}
+
+module browser_module = {
+   STANDARD_MODULE_STUFF,
+   NULL,                       /* initializer */
+   NULL,                       /* dir config creater */
+   NULL,                       /* dir merger --- default is to override */
+   create_browser_config,      /* server config */
+   merge_browser_config,       /* merge server configs */
+   browser_module_cmds,                /* command table */
+   NULL,                       /* handlers */
+   NULL,                       /* filename translation */
+   NULL,                       /* check_user_id */
+   NULL,                       /* check auth */
+   NULL,                       /* check access */
+   NULL,                       /* type_checker */
+   NULL,                       /* fixups */
+   NULL,                       /* logger */
+   parse_headers_browser_module        /* header parser */
+};
diff --git a/APACHE_1_2_X/src/modules/.cvsignore b/APACHE_1_2_X/src/modules/.cvsignore
new file mode 100644 (file)
index 0000000..f3c7a7c
--- /dev/null
@@ -0,0 +1 @@
+Makefile
diff --git a/APACHE_1_2_X/src/modules/example/Makefile b/APACHE_1_2_X/src/modules/example/Makefile
new file mode 100755 (executable)
index 0000000..9bec391
--- /dev/null
@@ -0,0 +1,107 @@
+# ====================================================================
+# Copyright (c) 1995-1997 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/>.
+# 
+# Makefile for the Apache example module
+# 
+
+#
+# This normally lives in modules/example under the Apache source
+# directory.  If the depth or relationship changes, the following line
+# may need to be changed.
+#
+INCDIR=../..
+
+#
+# Everything below this point should be invariant.
+#
+SHELL=/bin/sh
+
+#
+# We inherit the definitions of CC, AUX_CFLAGS, and RANLIB from an
+# upline make(1) call.
+#
+CFLAGS=-I$(INCDIR) $(AUX_CFLAGS)
+
+MODULES=mod_example.o
+OBJS= \
+    $(MODULES)
+
+#
+# Now the rules saying how things are built.
+#
+.c.o:
+       $(CC) -c $(CFLAGS) $<
+
+all:   $(OBJS)
+
+clean:
+       rm -f $(OBJS) 
+
+#
+# Finally, what depnds upon which, so make can figure out what it needs
+# to do.
+#
+
+#
+# Make sure that things get rebuilt if the Makefiles are changed.
+#
+$(OBJS): \
+    Makefile \
+    $(INCDIR)/Makefile
+
+mod_example.o: \
+    $(INCDIR)/httpd.h \
+    $(INCDIR)/http_config.h \
+    $(INCDIR)/http_core.h \
+    $(INCDIR)/http_log.h \
+    $(INCDIR)/http_main.h \
+    $(INCDIR)/http_protocol.h \
+    $(INCDIR)/util_script.h \
+    mod_example.c
diff --git a/APACHE_1_2_X/src/modules/example/README b/APACHE_1_2_X/src/modules/example/README
new file mode 100644 (file)
index 0000000..77abc09
--- /dev/null
@@ -0,0 +1,53 @@
+README for Apache 1.2 Example Module
+[April, 1997]
+
+The files in the src/modules/example directory under the Apache
+distribution directory tree are provided as an example to those that
+wish to write modules that use the Apache API.
+
+The main file is mod_example.c, which illustrates all the different
+callback mechanisms and call syntaces.  By no means does an add-on
+module need to include routines for all of the callbacks - quite the
+contrary!
+
+The example module is an actual working module.  If you link it into
+your server, enable the "example-handler" handler for a location, and then
+browse to that location, you will see a display of some of the tracing
+the example module did as the various callbacks were made.
+
+To include the example module in your server, follow the steps below:
+
+    1. Uncomment the "Module example_module" line near the bottom of
+       the src/Configuration file.  If there isn't one, add it; it
+       should look like this:
+
+       Module example_module        modules/example/mod_example.o
+
+    2. Run the src/Configure script ("cd src; ./Configure").  This will
+       build the Makefile for the server itself, and update the
+       src/modules/Makefile for any additional modules you have
+       requested from beneath that subdirectory.
+
+    3. Make the server (run "make" in the src directory).
+
+To add another module of your own:
+
+    A. mkdir src/modules/mymodule
+    B. cp src/modules/example/* src/modules/mymodule
+    C. Modify the files in the new directory
+    D. Follow steps [1] through [3] above, with appropriate changes.
+
+To activate the example module, include a block similar to the
+following in your srm.conf file:
+
+    <Location /example-info>
+       SetHandler example-handler
+    </Location>
+
+As an alternative, you can put the following into a .htaccess file and
+then request the file "test.example" from that location:
+
+    AddHandler example-handler .example
+
+After reloading/restarting your server, you should be able to browse
+to this location and see the brief display mentioned earlier.
diff --git a/APACHE_1_2_X/src/modules/example/mod_example.c b/APACHE_1_2_X/src/modules/example/mod_example.c
new file mode 100644 (file)
index 0000000..1aeda87
--- /dev/null
@@ -0,0 +1,1110 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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/>.
+ *
+ */
+
+/* 
+ * Apache example module.  Provide demonstrations of how modules do things.
+ *
+ */
+
+#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"
+
+#include <stdio.h>
+
+/*--------------------------------------------------------------------------*/
+/*                                                                         */
+/* Data declarations.                                                      */
+/*                                                                         */
+/* Here are the static cells and structure declarations private to our     */
+/* module.                                                                 */
+/*                                                                         */
+/*--------------------------------------------------------------------------*/
+
+/*
+ * Sample configuration record.  Used for both per-directory and per-server
+ * configuration data.
+ *
+ * It's perfectly reasonable to have two different structures for the two
+ * different environments.  The same command handlers will be called for
+ * both, though, so the handlers need to be able to tell them apart.  One
+ * possibility is for both structures to start with an int which is zero for
+ * one and 1 for the other.
+ *
+ * Note that while the per-directory and per-server configuration records are
+ * available to most of the module handlers, they should be treated as
+ * READ-ONLY by all except the command and merge handlers.  Sometimes handlers
+ * are handed a record that applies to the current location by implication or
+ * inheritance, and modifying it will change the rules for other locations.
+ */
+typedef struct example_config {
+    int            cmode;      /* Environment to which record applies (directory,  */
+                       /* server, or combination).                         */
+#define CONFIG_MODE_SERVER 1
+#define CONFIG_MODE_DIRECTORY 2
+#define CONFIG_MODE_COMBO 3  /* Shouldn't ever happen.                     */
+    int            local;      /* Boolean: was "Example" directive declared here?  */
+    int            congenital; /* Boolean: did we inherit an "Example"?            */
+    char    *trace;    /* Pointer to trace string.                         */
+    char    *loc;      /* Location to which this record applies.           */
+} example_config;
+
+/*
+ * Let's set up a module-local static cell to point to the accreting callback
+ * trace.  As each API callback is made to us, we'll tack on the particulars
+ * to whatever we've already recorded.  To avoid massive memory bloat as
+ * directories are walked again and again, we record the routine/environment
+ * the first time (non-request context only), and ignore subsequent calls for
+ * the same routine/environment.
+ */
+static char *trace = NULL;
+static table *static_calls_made = NULL;
+
+/*
+ * To avoid leaking memory from pools other than the per-request one, we
+ * allocate a module-private pool, and then use a sub-pool of that which gets
+ * freed each time we modify the trace.  That way previous layers of trace
+ * data don't get lost.
+ */
+static pool *example_pool = NULL;
+static pool *example_subpool = NULL;
+
+/*
+ * Declare ourselves so the configuration routines can find and know us.
+ * We'll fill it in at the end of the module.
+ */
+module example_module;
+
+/*--------------------------------------------------------------------------*/
+/*                                                                         */
+/* The following pseudo-prototype declarations illustrate the parameters    */
+/* passed to command handlers for the different types of directive         */
+/* syntax.  If an argument was specified in the directive definition       */
+/* (look for "command_rec" below), it's available to the command handler    */
+/* via the (void *) info field in the cmd_parms argument passed to the     */
+/* handler (cmd->info for the examples below).                             */
+/*                                                                         */
+/*--------------------------------------------------------------------------*/
+
+/*
+ * Command handler for a NO_ARGS directive.
+ *
+ * static const char *handle_NO_ARGS
+ *     (cmd_parms *cmd, void *mconfig);
+ */
+/*
+ * Command handler for a RAW_ARGS directive.  The "args" argument is the text
+ * of the commandline following the directive itself.
+ *
+ * static const char *handle_RAW_ARGS
+ *     (cmd_parms *cmd, void *mconfig, const char *args);
+ */
+
+/*
+ * Command handler for a TAKE1 directive.  The single parameter is passed in
+ * "word1".
+ *
+ * static const char *handle_TAKE1
+ *     (cmd_parms *cmd, void *mconfig, char *word1);
+ */
+
+/*
+ * Command handler for a TAKE2 directive.  TAKE2 commands must always have
+ * exactly two arguments.
+ *
+ * static const char *handle_TAKE2
+ *     (cmd_parms *cmd, void *mconfig, char *word1, char *word2);
+ */
+
+/*
+ * Command handler for a TAKE3 directive.  Like TAKE2, these must have exactly
+ * three arguments, or the parser complains and doesn't bother calling us.
+ *
+ * static const char *handle_TAKE3
+ *     (cmd_parms *cmd, void *mconfig, char *word1, char *word2, char *word3);
+ */
+
+/*
+ * Command handler for a TAKE12 directive.  These can take either one or two
+ * arguments.
+ * - word2 is a NULL pointer if no second argument was specified.
+ *
+ * static const char *handle_TAKE12
+ *     (cmd_parms *cmd, void *mconfig, char *word1, char *word2);
+ */
+
+/*
+ * Command handler for a TAKE123 directive.  A TAKE123 directive can be given,
+ * as might be expected, one, two, or three arguments.
+ * - word2 is a NULL pointer if no second argument was specified.
+ * - word3 is a NULL pointer if no third argument was specified.
+ *
+ * static const char *handle_TAKE123
+ *     (cmd_parms *cmd, void *mconfig, char *word1, char *word2, char *word3);
+ */
+
+/*
+ * Command handler for a TAKE13 directive.  Either one or three arguments are
+ * permitted - no two-parameters-only syntax is allowed.
+ * - word2 and word3 are NULL pointers if only one argument was specified.
+ *
+ * static const char *handle_TAKE13
+ *     (cmd_parms *cmd, void *mconfig, char *word1, char *word2, char *word3);
+ */
+
+/*
+ * Command handler for a TAKE23 directive.  At least two and as many as three
+ * arguments must be specified.
+ * - word3 is a NULL pointer if no third argument was specified.
+ *
+ * static const char *handle_TAKE23
+ *     (cmd_parms *cmd, void *mconfig, char *word1, char *word2, char *word3);
+ */
+
+/*
+ * Command handler for a ITERATE directive.
+ * - Handler is called once for each of n arguments given to the directive.
+ * - word1 points to each argument in turn.
+ *
+ * static const char *handle_ITERATE
+ *     (cmd_parms *cmd, void *mconfig, char *word1);
+ */
+
+/*
+ * Command handler for a ITERATE2 directive.
+ * - Handler is called once for each of the second and subsequent arguments
+ *   given to the directive.
+ * - word1 is the same for each call for a particular directive instance (the
+ *   first argument).
+ * - word2 points to each of the second and subsequent arguments in turn.
+ *
+ * static const char *handle_ITERATE2
+ *     (cmd_parms *cmd, void *mconfig, char *word1, char *word2);
+ */
+
+/*--------------------------------------------------------------------------*/
+/*                                                                         */
+/* These routines are strictly internal to this module, and support its            */
+/* operation.  They are not referenced by any external portion of the      */
+/* server.                                                                 */
+/*                                                                         */
+/*--------------------------------------------------------------------------*/
+
+/*
+ * Locate our directory configuration record for the current request.
+ */
+static example_config *our_dconfig
+       (request_rec *r) {
+
+    return (example_config *) get_module_config
+                               (
+                                   r->per_dir_config,
+                                   &example_module
+                               );
+}
+
+/*
+ * Locate our server configuration record for the specified server.
+ */
+static example_config *our_sconfig
+       (server_rec *s) {
+
+    return (example_config *) get_module_config
+                               (
+                                   s->module_config,
+                                   &example_module
+                               );
+}
+
+/*
+ * Likewise for our configuration record for the specified request.
+ */
+static example_config *our_rconfig
+       (request_rec *r) {
+
+    return (example_config *) get_module_config
+                               (
+                                   r->request_config,
+                                   &example_module
+                               );
+}
+
+/*
+ * This routine sets up some module-wide cells if they haven't been already.
+ */
+static void setup_module_cells () {
+    /*
+     * If we haven't already allocated our module-private pool, do so now.
+     */
+    if (example_pool == NULL) {
+       example_pool = make_sub_pool (NULL);
+    };
+    /*
+     * Likewise for the table of routine/environment pairs we visit outside of
+     * request context.
+     */
+    if (static_calls_made == NULL) {
+       static_calls_made = make_table (example_pool, 16);
+    };
+}
+
+/*
+ * This routine is used to add a trace of a callback to the list.  We're
+ * passed the server record (if available), the request record (if available),
+ * a pointer to our private configuration record (if available) for the
+ * environment to which the callback is supposed to apply, and some text.  We
+ * turn this into a textual representation and add it to the tail of the list.
+ * The list can be displayed by the example_handler() routine.
+ *
+ * If the call occurs within a request context (i.e., we're passed a request
+ * record), we put the trace into the request pool and attach it to the
+ * request via the notes mechanism.  Otherwise, the trace gets added
+ * to the static (non-request-specific) list.
+ *
+ * Note that the r->notes table is only for storing strings; if you need to
+ * maintain per-request data of any other type, you need to use another
+ * mechanism.
+ */
+
+#define TRACE_NOTE "example-trace"
+
+static void trace_add
+       (server_rec *s, request_rec *r, example_config *mconfig,
+        const char *note) {
+
+    char    *sofar;
+    char    *addon;
+    char    *where;
+    pool    *p;
+    char    *trace_copy;
+    example_config
+           *rconfig;
+
+    /*
+     * Make sure our pools and tables are set up - we need 'em.
+     */
+    setup_module_cells ();
+    /*
+     * Now, if we're in request-context, we use the request pool.
+     */
+    if (r != NULL) {
+       p = r->pool;
+       if ((trace_copy = table_get (r->notes, TRACE_NOTE)) == NULL) {
+           trace_copy = "";
+       }
+    } else {
+       /*
+        * We're not in request context, so the trace gets attached to our
+        * module-wide pool.  We do the create/destroy every time we're called
+        * in non-request context; this avoids leaking memory in some of
+        * the subsequent calls that allocate memory only once (such as the
+        * key formation below).
+        *
+        * Make a new sub-pool and copy any existing trace to it.  Point the
+        * trace cell at the copied value.
+        */
+       p = make_sub_pool (example_pool);
+       if (trace != NULL) {
+           trace = pstrdup (p, trace);
+       }
+       /*
+        * Now, if we have a sub-pool from before, nuke it and replace with
+        * the one we just allocated.
+        */
+       if (example_subpool != NULL) {
+           destroy_pool (example_subpool);
+       }
+       example_subpool = p;
+       trace_copy = trace;
+    }
+    /*
+     * If we weren't passed a configuration record, we can't figure out to
+     * what location this call applies.  This only happens for co-routines
+     * that don't operate in a particular directory or server context.  If we
+     * got a valid record, extract the location (directory or server) to which
+     * it applies.
+     */
+    where = (mconfig != NULL) ? mconfig->loc : "nowhere";
+    where = (where != NULL) ? where : "";
+    /*
+     * Now, if we're not in request context, see if we've been called with
+     * this particular combination before.  The table is allocated in the
+     * module's private pool, which doesn't get destroyed.
+     */
+    if (r == NULL) {
+       char    *key;
+
+       key = pstrcat (p, note, ":", where, NULL);
+       if (table_get (static_calls_made, key) != NULL) {
+           /*
+            * Been here, done this.
+            */
+           return;
+       } else {
+           /*
+            * First time for this combination of routine and environment -
+            * log it so we don't do it again.
+            */
+           table_set (static_calls_made, key, "been here");
+       }
+    }
+    addon = pstrcat 
+               (
+                   p,
+                   "   <LI>\n",
+                   "    <DL>\n",
+                   "     <DT><SAMP>",
+                   note,
+                   "</SAMP>\n",
+                   "     </DT>\n",
+                   "     <DD><SAMP>[",
+                   where,
+                   "]</SAMP>\n",
+                   "     </DD>\n",
+                   "    </DL>\n",
+                   "   </LI>\n",
+                   NULL
+               );
+    sofar = (trace_copy == NULL) ? "" : trace_copy;
+    trace_copy = pstrcat (p, sofar, addon, NULL);
+    if (r != NULL) {
+       table_set (r->notes, TRACE_NOTE, trace_copy);
+    } else {
+       trace = trace_copy;
+    }
+    /*
+     * You *could* uncomment the following if you wanted to see the calling
+     * sequence reported in the server's error_log, but beware - almost all of
+     * these co-routines are called for every single request, and the impact
+     * on the size (and readability) of the error_log is considerable.
+     */
+/*
+    if (s != NULL) {
+        log_printf (s, "mod_example: %s", note);
+    }
+ */
+}
+
+/*--------------------------------------------------------------------------*/
+/* We prototyped the various syntax for command handlers (routines that     */
+/* are called when the configuration parser detects a directive declared    */
+/* by our module) earlier.  Now we actually declare a "real" routine that   */
+/* will be invoked by the parser when our "real" directive is              */
+/* encountered.                                                                    */
+/*                                                                         */
+/* If a command handler encounters a problem processing the directive, it   */
+/* signals this fact by returning a non-NULL pointer to a string           */
+/* describing the problem.                                                 */
+/*                                                                         */
+/* The magic return value DECLINE_CMD is used to deal with directives      */
+/* that might be declared by multiple modules.  If the command handler     */
+/* returns NULL, the directive was processed; if it returns DECLINE_CMD,    */
+/* the next module (if any) that declares the directive is given a chance   */
+/* at it.  If it returns any other value, it's treated as the text of an    */
+/* error message.                                                          */
+/*--------------------------------------------------------------------------*/
+/* 
+ * Command handler for the NO_ARGS "Example" directive.  All we do is mark the
+ * call in the trace log, and flag the applicability of the directive to the
+ * current location in that location's configuration record.
+ */
+static const char *cmd_example
+       (cmd_parms *cmd, void *mconfig) {
+
+    example_config
+           *cfg = (example_config *) mconfig;
+
+    /*
+     * "Example Wuz Here"
+     */
+    cfg->local = 1;
+    trace_add (cmd->server, NULL, cfg, "cmd_example()");
+    return NULL;
+}
+
+/*--------------------------------------------------------------------------*/
+/*                                                                         */
+/* Now we declare our content handlers, which are invoked when the server   */
+/* encounters a document which our module is supposed to have a chance to   */
+/* see.  (See mod_mime's SetHandler and AddHandler directives, and the     */
+/* mod_info and mod_status examples, for more details.)                            */
+/*                                                                         */
+/* Since content handlers are dumping data directly into the connexion     */
+/* (using the r*() routines, such as rputs() and rprintf()) without        */
+/* intervention by other parts of the server, they need to make                    */
+/* sure any accumulated HTTP headers are sent first.  This is done by      */
+/* calling send_http_header().  Otherwise, no header will be sent at all,   */
+/* and the output sent to the client will actually be HTTP-uncompliant.            */
+/*--------------------------------------------------------------------------*/
+/* 
+ * Sample content handler.  All this does is display the call list that has
+ * been built up so far.
+ *
+ * The return value instructs the caller concerning what happened and what to
+ * do next:
+ *  OK ("we did our thing")
+ *  DECLINED ("this isn't something with which we want to get involved")
+ *  HTTP_mumble ("an error status should be reported")
+ */
+static int example_handler
+       (request_rec *r) {
+
+    example_config
+           *dcfg;
+    example_config
+           *rcfg;
+
+    dcfg = our_dconfig (r);
+    trace_add (r->server, r, dcfg, "example_handler()");
+    /*
+     * We're about to start sending content, so we need to force the HTTP
+     * headers to be sent at this point.  Otherwise, no headers will be sent
+     * at all.  We can set any we like first, of course.  **NOTE** Here's
+     * where you set the "Content-type" header, and you do so by putting it in
+     * r->content_type, *not* r->headers_out("Content-type").  If you don't
+     * set it, it will be filled in with the server's default type (typically
+     * "text/plain").
+     *
+     * We also need to start a timer so the server can know if the connexion
+     * is broken.
+     */
+    r->content_type = "text/html";
+    soft_timeout ("send example call trace", r);
+    send_http_header (r);
+    /*
+     * If we're only supposed to send header information (HEAD request), we're
+     * already there.
+     */
+    if (r->header_only) {
+       kill_timeout (r);
+       return OK;
+    }
+
+    /*
+     * Now send our actual output.  Since we tagged this as being
+     * "text/html", we need to embed any HTML.
+     */
+    rputs ("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2//EN\">\n", r);
+    rputs ("<HTML>\n", r);
+    rputs (" <HEAD>\n", r);
+    rputs ("  <TITLE>mod_example Module Content-Handler Output\n", r);
+    rputs ("  </TITLE>\n", r);
+    rputs (" </HEAD>\n", r);
+    rputs (" <BODY>\n", r);
+    rputs ("  <H1><SAMP>mod_example</SAMP> Module Content-Handler Output\n", r);
+    rputs ("  </H1>\n", r);
+    rputs ("  <P>\n", r);
+    rputs ("  The format for the callback trace is:\n", r);
+    rputs ("  </P>\n", r);
+    rputs ("  <DL>\n", r);
+    rputs ("   <DT><EM>n</EM>.<SAMP>&lt;routine-name&gt;", r);
+    rputs ("(&lt;routine-data&gt;)</SAMP>\n", r);
+    rputs ("   </DT>\n", r);
+    rputs ("   <DD><SAMP>[&lt;applies-to&gt;]</SAMP>\n", r);
+    rputs ("   </DD>\n", r);
+    rputs ("  </DL>\n", r);
+    rputs ("  <P>\n", r);
+    rputs ("  The <SAMP>&lt;routine-data&gt;</SAMP> is supplied by\n", r);
+    rputs ("  the routine when it requests the trace,\n", r);
+    rputs ("  and the <SAMP>&lt;applies-to&gt;</SAMP> is extracted\n", r);
+    rputs ("  from the configuration record at the time of the trace.\n", r); 
+    rputs ("  <STRONG>SVR()</STRONG> indicates a server environment\n", r);
+    rputs ("  (blank means the main or default server, otherwise it's\n", r);
+    rputs ("  the name of the VirtualHost); <STRONG>DIR()</STRONG>\n", r);
+    rputs ("  indicates a location in the URL or filesystem\n", r);
+    rputs ("  namespace.\n", r);
+    rputs ("  </P>\n", r);
+    rprintf
+       (
+           r,
+           "  <H2>Static callbacks so far:</H2>\n  <OL>\n%s  </OL>\n",
+           trace
+       );
+    rprintf
+       (
+           r,
+           "  <H2>Request-specific callbacks so far:</H2>\n  <OL>\n%s  </OL>\n",
+           table_get (r->notes, TRACE_NOTE)
+       );
+    rputs ("  <H2>Environment for <EM>this</EM> call:</H2>\n", r);
+    rputs ("  <UL>\n", r);
+    rprintf (r, "   <LI>Applies-to: <SAMP>%s</SAMP>\n   </LI>\n", dcfg->loc);
+    rprintf
+       (
+           r,
+           "   <LI>\"Example\" directive declared here: %s\n   </LI>\n",
+           (dcfg->local ? "YES" : "NO")
+       );
+    rprintf
+       (
+           r,
+           "   <LI>\"Example\" inherited: %s\n   </LI>\n",
+           (dcfg->congenital ? "YES" : "NO")
+       );
+    rputs ("  </UL>\n", r);
+    rputs (" </BODY>\n", r);
+    rputs ("</HTML>\n", r);
+    /*
+     * We're all done, so cancel the timeout we set.  Since this is probably
+     * the end of the request we *could* assume this would be done during
+     * post-processing - but it's possible that another handler might be
+     * called and inherit our outstanding timer.  Not good; to each its own.
+     */
+    kill_timeout (r);
+    /*
+     * We did what we wanted to do, so tell the rest of the server we
+     * succeeded.
+     */
+    return OK;
+}
+
+/*--------------------------------------------------------------------------*/
+/*                                                                         */
+/* Now let's declare routines for each of the callback phase in order.     */
+/* (That's the order in which they're listed in the callback list, *not            */
+/* the order in which the server calls them!  See the command_rec          */
+/* declaration near the bottom of this file.)  Note that these may be      */
+/* called for situations that don't relate primarily to our function - in   */
+/* other words, the fixup handler shouldn't assume that the request has            */
+/* to do with "example" stuff.                                             */
+/*                                                                         */
+/* With the exception of the content handler, all of our routines will be   */
+/* called for each request, unless an earlier handler from another module   */
+/* aborted the sequence.                                                   */
+/*                                                                         */
+/* Handlers that are declared as "int" can return the following:           */
+/*                                                                         */
+/*  OK         Handler accepted the request and did its thing with it.     */
+/*  DECLINED   Handler took no action.                                     */
+/*  HTTP_mumble        Handler looked at request and found it wanting.             */
+/*                                                                         */
+/* What the server does after calling a module handler depends upon the            */
+/* handler's return value.  In all cases, if the handler returns           */
+/* DECLINED, the server will continue to the next module with an handler    */
+/* for the current phase.  However, if the handler return a non-OK,        */
+/* non-DECLINED status, the server aborts the request right there.  If     */
+/* the handler returns OK, the server's next action is phase-specific;     */
+/* see the individual handler comments below for details.                  */
+/*                                                                         */
+/*--------------------------------------------------------------------------*/
+/* 
+ * This function is called during server initialisation.  Any information
+ * that needs to be recorded must be in static cells, since there's no
+ * configuration record.
+ *
+ * There is no return value.
+ */
+
+/*
+ * All our module-initialiser does is add its trace to the log.
+ */
+static void example_init
+       (server_rec *s, pool *p) {
+
+    char    *note;
+    char    *sname = s->server_hostname;
+
+    /*
+     * Set up any module cells that ought to be initialised.
+     */
+    setup_module_cells ();
+    /*
+     * The arbitrary text we add to our trace entry indicates for which server
+     * we're being called.
+     */
+    sname = (sname != NULL) ? sname : "";
+    note = pstrcat (p, "example_init(", sname, ")", NULL);
+    trace_add (s, NULL, NULL, note);
+}
+
+/*
+ * This function gets called to create up a per-directory configuration
+ * record.  This will be called for the "default" server environment, and for
+ * each directory for which the parser finds any of our directives applicable.
+ * If a directory doesn't have any of our directives involved (i.e., they
+ * aren't in the .htaccess file, or a <Location>, <Directory>, or related
+ * block), this routine will *not* be called - the configuration for the
+ * closest ancestor is used.
+ *
+ * The return value is a pointer to the created module-specific
+ * structure.
+ */
+static void *example_dir_create
+       (pool *p, char *dirspec) {
+
+    example_config
+           *cfg;
+    char    *dname = dirspec;
+
+    /*
+     * Allocate the space for our record from the pool supplied.
+     */
+    cfg = (example_config *) pcalloc (p, sizeof(example_config));
+    /*
+     * Now fill in the defaults.  If there are any `parent' configuration
+     * records, they'll get merged as part of a separate callback.
+     */
+    cfg->local = 0;
+    cfg->congenital = 0;
+    cfg->cmode = CONFIG_MODE_DIRECTORY;
+    /*
+     * Finally, add our trace to the callback list.
+     */
+    dname = (dname != NULL) ? dname : "";
+    cfg->loc = pstrcat (p, "DIR(", dname, ")", NULL);
+    trace_add (NULL, NULL, cfg, "example_dir_create()");
+    return (void *) cfg;
+}
+
+/*
+ * This function gets called to merge two per-directory configuration
+ * records.  This is typically done to cope with things like .htaccess files
+ * or <Location> directives for directories that are beneath one for which a
+ * configuration record was already created.  The routine has the
+ * responsibility of creating a new record and merging the contents of the
+ * other two into it appropriately.  If the module doesn't declare a merge
+ * routine, the record for the closest ancestor location (that has one) is
+ * used exclusively.
+ *
+ * The routine MUST NOT modify any of its arguments!
+ *
+ * The return value is a pointer to the created module-specific structure
+ * containing the merged values.
+ */
+static void *example_dir_merge
+       (pool *p, void *parent_conf, void *newloc_conf) {
+
+    example_config
+           *merged_config =
+               (example_config *) pcalloc (p, sizeof(example_config));
+    example_config
+           *pconf = (example_config *) parent_conf;
+    example_config
+           *nconf = (example_config *) newloc_conf;
+    char    *note;
+
+    /*
+     * Some things get copied directly from the more-specific record, rather
+     * than getting merged.
+     */
+    merged_config->local = nconf->local;
+    merged_config->loc = pstrdup (p, nconf->loc);
+    /*
+     * Others, like the setting of the `congenital' flag, get ORed in.  The
+     * setting of that particular flag, for instance, is TRUE if it was ever
+     * true anywhere in the upstream configuration.
+     */
+    merged_config->congenital = (pconf->congenital | pconf->local);
+    /*
+     * If we're merging records for two different types of environment (server
+     * and directory), mark the new record appropriately.  Otherwise, inherit
+     * the current value.
+     */
+    merged_config->cmode =
+       (pconf->cmode == nconf->cmode) ? pconf->cmode : CONFIG_MODE_COMBO;
+    /*
+     * Now just record our being called in the trace list.  Include the
+     * locations we were asked to merge.
+     */
+    note = pstrcat
+           (
+               p,
+               "example_dir_merge(\"",
+               pconf->loc,
+               "\",\"",
+               nconf->loc,
+               "\")",
+               NULL
+           );
+    trace_add (NULL, NULL, merged_config, note);
+    return (void *) merged_config;
+}
+
+/*
+ * This function gets called to create a per-server configuration
+ * record.  It will always be called for the "default" server.
+ *
+ * The return value is a pointer to the created module-specific
+ * structure.
+ */
+static void *example_server_create
+       (pool *p, server_rec *s) {
+
+    example_config
+           *cfg;
+    char    *sname = s->server_hostname;
+
+    /*
+     * As with the example_dir_create() reoutine, we allocate and fill in an
+     * empty record.
+     */
+    cfg = (example_config *) pcalloc (p, sizeof(example_config));
+    cfg->local = 0;
+    cfg->congenital = 0;
+    cfg->cmode = CONFIG_MODE_SERVER;
+    /*
+     * Note that we were called in the trace list.
+     */
+    sname = (sname != NULL) ? sname : "";
+    cfg->loc = pstrcat (p, "SVR(", sname, ")", NULL);
+    trace_add (s, NULL, cfg, "example_server_create()");
+    return (void *) cfg;
+}
+
+/*
+ * This function gets called to merge two per-server configuration
+ * records.  This is typically done to cope with things like virtual hosts and
+ * the default server configuration  The routine has the responsibility of
+ * creating a new record and merging the contents of the other two into it
+ * appropriately.  If the module doesn't declare a merge routine, the more
+ * specific existing record is used exclusively.
+ *
+ * The routine MUST NOT modify any of its arguments!
+ *
+ * The return value is a pointer to the created module-specific structure
+ * containing the merged values.
+ */
+static void *example_server_merge
+       (pool *p, void *server1_conf, void *server2_conf) {
+
+    example_config
+           *merged_config =
+               (example_config *) pcalloc (p, sizeof(example_config));
+    example_config
+           *s1conf = (example_config *) server1_conf;
+    example_config
+           *s2conf = (example_config *) server2_conf;
+    char    *note;
+
+    /*
+     * Our inheritance rules are our own, and part of our module's semantics.
+     * Basically, just note whence we came.
+     */
+    merged_config->cmode =
+       (s1conf->cmode == s2conf->cmode) ? s1conf->cmode : CONFIG_MODE_COMBO;
+    merged_config->local = s2conf->local;
+    merged_config->congenital = (s1conf->congenital | s1conf->local);
+    merged_config->loc = pstrdup (p, s2conf->loc);
+    /*
+     * Trace our call, including what we were asked to merge.
+     */
+    note = pstrcat
+           (
+               p,
+               "example_server_merge(\"",
+               s1conf->loc,
+               "\",\"",
+               s2conf->loc,
+               "\")",
+               NULL
+           );
+    trace_add (NULL, NULL, merged_config, note);
+    return (void *) merged_config;
+}
+
+/*
+ * This routine gives our module an opportunity to translate the URI into an
+ * actual filename.  If we don't do anything special, the server's default
+ * rules (Alias directives and the like) will continue to be followed.
+ *
+ * The return value is OK, DECLINED, or HTTP_mumble.  If we return OK, no
+ * further modules are called for this phase.
+ */
+static int example_xlate
+       (request_rec *r) {
+
+    example_config
+           *cfg;
+
+    cfg = our_dconfig (r);
+    /*
+     * We don't actually *do* anything here, except note the fact that we were
+     * called.
+     */
+    trace_add (r->server, r, cfg, "example_xlate()");
+    return DECLINED;
+}
+
+/*
+ * This routine is called to check the authentication information sent with
+ * the request (such as looking up the user in a database and verifying that
+ * the [encrypted] password sent matches the one in the database).
+ *
+ * The return value is OK, DECLINED, or some HTTP_mumble error (typically
+ * HTTP_UNAUTHORIZED).  If we return OK, no other modules are given a chance
+ * at the request during this phase.
+ */
+static int example_ckuser
+       (request_rec *r) {
+
+    example_config
+           *cfg;
+
+    cfg = our_dconfig (r);
+    /*
+     * Don't do anything except log the call.
+     */
+    trace_add (r->server, r, cfg, "example_ckuser()");
+    return DECLINED;
+}
+
+/*
+ * This routine is called to check to see if the resource being requested
+ * requires authorisation.
+ *
+ * The return value is OK, DECLINED, or HTTP_mumble.  If we return OK, no
+ * other modules are called during this phase.
+ *
+ * If *all* modules return DECLINED, the request is aborted with a server
+ * error.
+ */
+static int example_ckauth
+       (request_rec *r) {
+
+    example_config
+           *cfg;
+
+    cfg = our_dconfig (r);
+    /*
+     * Log the call and return OK, or access will be denied (even though we
+     * didn't actually do anything).
+     */
+    trace_add (r->server, r, cfg, "example_ckauth()");
+    return OK;
+}
+
+/*
+ * This routine is called to check for any module-specific restrictions placed
+ * upon the requested resource.  (See the mod_access module for an example.)
+ *
+ * The return value is OK, DECLINED, or HTTP_mumble.  All modules with an
+ * handler for this phase are called regardless of whether their predecessors
+ * return OK or DECLINED.  The first one to return any other status, however,
+ * will abort the sequence (and the request) as usual.
+ */
+static int example_ckaccess
+       (request_rec *r) {
+
+    example_config
+           *cfg;
+
+    cfg = our_dconfig (r);
+    trace_add (r->server, r, cfg, "example_ckaccess()");
+    return OK;
+}
+
+/*
+ * This routine is called to determine and/or set the various document type
+ * information bits, like Content-type (via r->content_type), language, et
+ * cetera.
+ *
+ * The return value is OK, DECLINED, or HTTP_mumble.  If we return OK, no
+ * further modules are given a chance at the request for this phase.
+ */
+static int example_typer
+       (request_rec *r) {
+
+    example_config
+           *cfg;
+
+    cfg = our_dconfig (r);
+    /*
+     * Log the call, but don't do anything else - and report truthfully that
+     * we didn't do anything.
+     */
+    trace_add (r->server, r, cfg, "example_typer()");
+    return DECLINED;
+}
+
+/*
+ * This routine is called to perform any module-specific fixing of header
+ * fields, et cetera.  It is invoked just before any content-handler.
+ *
+ * The return value is OK, DECLINED, or HTTP_mumble.  If we return OK, the
+ * server will still call any remaining modules with an handler for this
+ * phase.
+ */
+static int example_fixer
+       (request_rec *r) {
+
+    example_config
+           *cfg;
+
+    cfg = our_dconfig (r);
+    /*
+     * Log the call and exit.
+     */
+    trace_add (r->server, r, cfg, "example_fixer()");
+    return OK;
+}
+
+/*
+ * This routine is called to perform any module-specific logging activities
+ * over and above the normal server things.
+ *
+ * The return value is OK, DECLINED, or HTTP_mumble.  If we return OK, any
+ * remaining modules with an handler for this phase will still be called.
+ */
+static int example_logger
+       (request_rec *r) {
+
+    example_config
+           *cfg;
+
+    cfg = our_dconfig (r);
+    trace_add (r->server, r, cfg, "example_logger()");
+    return DECLINED;
+}
+
+/*
+ * This routine is called to give the module a chance to look at the request
+ * headers and take any appropriate specific actions early in the processing
+ * sequence.
+ *
+ * The return value is OK, DECLINED, or HTTP_mumble.  If we return OK, any
+ * remaining modules with handlers for this phase will still be called.
+ */
+static int example_hparser
+       (request_rec *r) {
+
+    example_config
+           *cfg;
+
+    cfg = our_dconfig (r);
+    trace_add (r->server, r, cfg, "example_hparser()");
+    return DECLINED;
+}
+
+/*--------------------------------------------------------------------------*/
+/*                                                                         */
+/* All of the routines have been declared now.  Here's the list of         */
+/* directives specific to our module, and information about where they     */
+/* may appear and how the command parser should pass them to us for        */
+/* processing.  Note that care must be taken to ensure that there are NO    */
+/* collisions of directive names between modules.                          */
+/*                                                                         */
+/*--------------------------------------------------------------------------*/
+/* 
+ * List of directives specific to our module.
+ */
+command_rec example_commands[] = {
+    {
+       "Example",                      /* directive name */
+       cmd_example,                    /* action routine for directive */
+       NULL,                           /* argument to include in call */
+       OR_OPTIONS,                     /* where available */
+       NO_ARGS,                        /* arguments */
+       "Example directive - no arguments"
+                                       /* directive description */
+    },
+    { NULL }
+};
+
+/*--------------------------------------------------------------------------*/
+/*                                                                         */
+/* Now the list of content handlers available from this module.                    */
+/*                                                                         */
+/*--------------------------------------------------------------------------*/
+/* 
+ * List of content handlers our module supplies.  Each handler is defined by
+ * two parts: a name by which it can be referenced (such as by
+ * {Add,Set}Handler), and the actual routine name.  The list is terminated by
+ * a NULL block, since it can be of variable length.
+ *
+ * Note that content-handlers are invoked on a most-specific to least-specific
+ * basis; that is, a handler that is declared for "text/plain" will be
+ * invoked before one that was declared for "text / *".  Note also that
+ * if a content-handler returns anything except DECLINED, no other
+ * content-handlers will be called.
+ */
+handler_rec example_handlers[] = {
+    { "example-handler", example_handler },
+    { NULL }
+};
+
+/*--------------------------------------------------------------------------*/
+/*                                                                         */
+/* Finally, the list of callback routines and data structures that         */
+/* provide the hooks into our module from the other parts of the server.    */
+/*                                                                         */
+/*--------------------------------------------------------------------------*/
+/* 
+ * Module definition for configuration.  If a particular callback is not
+ * needed, replace its routine name below with the word NULL.
+ *
+ * The number in brackets indicates the order in which the routine is called
+ * during request processing.  Note that not all routines are necessarily
+ * called (such as if a resource doesn't have access restrictions).
+ */
+module example_module = {
+    STANDARD_MODULE_STUFF,
+    example_init,              /* initializer */
+    example_dir_create,                /* per-directory config creater */
+    example_dir_merge,         /* dir config merger - default is to override */
+    example_server_create,     /* server config creator */
+    example_server_merge,      /* server config merger */
+    example_commands,          /* command table */
+    example_handlers,          /* [6] list of handlers */
+    example_xlate,             /* [1] filename-to-URI translation */
+    example_ckuser,            /* [4] check/validate HTTP user_id */
+    example_ckauth,            /* [5] check HTTP user_id is valid *here* */
+    example_ckaccess,          /* [3] check access by host address, etc. */
+    example_typer,             /* [6] MIME type checker/setter */
+    example_fixer,             /* [7] fixups */
+    example_logger,            /* [9] logger */
+    example_hparser            /* [2] header parser */
+};
diff --git a/APACHE_1_2_X/src/modules/proxy/Makefile b/APACHE_1_2_X/src/modules/proxy/Makefile
new file mode 100644 (file)
index 0000000..102dea2
--- /dev/null
@@ -0,0 +1,89 @@
+# ====================================================================
+# Copyright (c) 1995-1997 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/>.
+# 
+# Makefile for the Apache proxy library
+# 
+
+SHELL = /bin/sh
+
+INCDIR = ../..
+
+LIB=libproxy.a
+
+# AUX_CFLAGS comes from higher level Makefile
+CFLAGS=-I$(INCDIR) $(AUX_CFLAGS)
+
+# Internal stuff, should not need changing.
+PROXYSRC=mod_proxy.c proxy_cache.c proxy_connect.c proxy_ftp.c proxy_http.c \
+proxy_util.c
+
+OBJS=$(PROXYSRC:.c=.o)
+
+default:       force $(LIB)
+
+.c.a:
+       $(MAKE) $(CFLAGS) $<
+
+force:
+       rm -f $(LIB)
+
+$(LIB):        $(OBJS)
+       ar crv $@ $(OBJS)
+       $(RANLIB) $@
+
+clean:
+       rm -f *.o libproxy.a
+
+# dependencies
+$(OBJS): mod_proxy.h $(INCDIR)/httpd.h $(INCDIR)/http_config.h $(INCDIR)/http_protocol.h
+proxy_cache.o proxy_connect.o proxy_ftp.o proxy_http.o proxy_util.o: $(INCDIR)/http_main.h
+proxy_cache.o proxy_connect.o proxy_http.o: $(INCDIR)/http_log.h
+proxy_cache.o proxy_http.o: $(INCDIR)/util_date.h
+proxy_cache.o proxy_util.o: $(INCDIR)/md5.h
diff --git a/APACHE_1_2_X/src/modules/proxy/mod_proxy.c b/APACHE_1_2_X/src/modules/proxy/mod_proxy.c
new file mode 100644 (file)
index 0000000..c3dad86
--- /dev/null
@@ -0,0 +1,554 @@
+/* ====================================================================
+ * Copyright (c) 1996,1997 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 "mod_proxy.h"
+
+/* Some WWW schemes and their default ports; this is basically /etc/services */
+/* This will become global when the protocol abstraction comes */
+static struct proxy_services 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 */
+};
+
+/*
+ * 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
+ */
+
+/* -------------------------------------------------------------- */
+/* 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 proxy_http_canon(r, url+5, "http", DEFAULT_PORT);
+    else if (strncmp(url, "ftp:", 4) == 0)
+       return proxy_ftp_canon(r, url+4);
+    else return OK; /* otherwise; we've done the best we can */
+}
+
+/* -------------------------------------------------------------- */
+/* Invoke handler */
+static int
+proxy_handler(request_rec *r)
+{
+    char *url, *scheme, *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;
+
+    if ((rc = setup_client_block(r, REQUEST_CHUNKED_ERROR)))
+       return rc;
+
+    url = r->filename + 6;
+    p = strchr(url, ':');
+    if (p == NULL) return BAD_REQUEST;
+
+    rc = proxy_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 = proxy_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 proxy_connect_handler(r, cr, url);
+    if (strcmp(scheme, "http") == 0)
+       return proxy_http_handler(r, cr, url, NULL, 0);
+    if (strcmp(scheme, "ftp") == 0)
+       return proxy_ftp_handler(r, cr, url);
+    else return NOT_IMPLEMENTED;
+}
+
+/* -------------------------------------------------------------- */
+/* Setup configurable data */
+
+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->noproxies = make_array(p, 10, sizeof(struct noproxy_entry));
+  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 const 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 const 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 const char *
+set_proxy_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 noproxy_entry *new;
+    struct noproxy_entry *list=(struct noproxy_entry*)conf->noproxies->elts;
+    struct hostent hp;
+    int found = 0;
+    int i;
+
+    /* Don't duplicate entries */
+    for (i=0; i < conf->noproxies->nelts; i++)
+    {
+       if (strcmp(arg, list[i].name) == 0)
+           found = 1;
+    }
+
+    if (!found)
+    {
+       new = push_array (conf->noproxies);
+       new->name = arg;
+       /* Don't do name lookups on things that aren't dotted */
+       if (strchr(arg, '.') != NULL && proxy_host2addr(new->name, &hp) == NULL)
+           memcpy(&new->addr, hp.h_addr, sizeof(struct in_addr));
+       else
+           new->addr.s_addr = 0;
+    }
+    return NULL;
+}
+
+static const 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 const 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 const 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 const 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 const 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 const 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 const 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 const 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 const 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 const 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;
+    struct hostent hp;
+    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;
+       /* Don't do name lookups on things that aren't dotted */
+       if (strchr(arg, '.') != NULL && proxy_host2addr(new->name, &hp) == NULL)
+           memcpy(&new->addr, hp.h_addr, sizeof(struct in_addr));
+       else
+           new->addr.s_addr= 0;
+    }
+    return NULL;
+}
+
+static handler_rec proxy_handlers[] = {
+{ "proxy-server", proxy_handler },
+{ 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"},
+{ "ProxyBlock", set_proxy_exclude, NULL, RSRC_CONF, ITERATE,
+    "A list of names, hosts or domains to which the proxy will not connect" },
+{ "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 names, 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 */
+   NULL                         /* header parser */
+};
+
diff --git a/APACHE_1_2_X/src/modules/proxy/mod_proxy.h b/APACHE_1_2_X/src/modules/proxy/mod_proxy.h
new file mode 100644 (file)
index 0000000..939ebea
--- /dev/null
@@ -0,0 +1,273 @@
+/* ====================================================================
+ * Copyright (c) 1996,1997 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/>.
+ *
+ */
+
+/*
+ * Main include file for the Apache proxy
+ */
+
+/*
+
+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 things to do:
+
+0. Code cleanup (ongoing)
+
+1. add 230 response output for ftp now that it works
+
+2. Make the ftp proxy transparent, also same with (future) gopher & wais
+
+3. Use protocol handler struct a la Apache module handlers (Dirk van Gulik)
+4. Use a cache expiry database for more efficient GC (Jeremy Wohl)
+
+5. Bulletproof GC against SIGALRM
+
+Chuck Murcko <chuck@topsail.org> 15 April 1997
+
+*/
+
+#define TESTING        0
+#undef EXPLAIN
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_protocol.h"
+  
+#include "explain.h"
+
+DEF_Explain
+
+
+extern module proxy_module;
+
+
+/* for proxy_canonenc() */
+enum enctype { enc_path, enc_search, enc_user, enc_fpath, enc_parm }; 
+#define HDR_APP (0)    /* append header, for proxy_add_header() */
+#define HDR_REP (1)    /* replace header, for proxy_add_header() */
+
+/* number of characters in the hash */
+#define HASH_LEN (22*2)
+
+#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 */
+struct proxy_services
+{
+    const char *scheme;
+    int 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 noproxy_entry {
+    char *name;
+    struct in_addr addr;
+};
+
+struct nocache_entry {
+    char *name;
+    struct in_addr addr;
+};
+
+#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 *noproxies;
+    array_header *nocaches;
+    int req;                 /* true if proxy requests are enabled */
+} proxy_server_conf;
+
+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 */
+};
+      
+/* Function prototypes */
+
+/* proxy_cache.c */
+
+void proxy_cache_tidy(struct cache_req *c);
+int proxy_cache_check(request_rec *r, char *url, struct cache_conf *conf,
+    struct cache_req **cr);
+int proxy_cache_update(struct cache_req *c, array_header *resp_hdrs,
+    const char *protocol, int nocache);
+void proxy_garbage_coll(request_rec *r);
+
+/* proxy_connect.c */
+
+int proxy_connect_handler(request_rec *r, struct cache_req *c, char *url);
+
+/* proxy_ftp.c */
+
+int proxy_ftp_canon(request_rec *r, char *url);
+int proxy_ftp_handler(request_rec *r, struct cache_req *c, char *url);
+
+/* proxy_http.c */
+
+int proxy_http_canon(request_rec *r, char *url, const char *scheme,
+    int def_port);
+int proxy_http_handler(request_rec *r, struct cache_req *c, char *url,
+    const char *proxyhost, int proxyport);
+
+/* proxy_util.c */
+
+int proxy_hex2c(const char *x);
+void proxy_c2hex(int ch, char *x);
+char *proxy_canonenc(pool *p, const char *x, int len, enum enctype t,
+    int isenc);
+char *proxy_canon_netloc(pool *pool, char **const urlp, char **userp,
+    char **passwordp, char **hostp, int *port);
+char *proxy_date_canon(pool *p, char *x);
+array_header *proxy_read_headers(pool *pool, char *buffer, int size, BUFF *f);
+long int proxy_send_fb(BUFF *f, request_rec *r, BUFF *f2, struct cache_req *c);
+struct hdr_entry *proxy_get_header(array_header *hdrs_arr, const char *name);
+struct hdr_entry *proxy_add_header(array_header *hdrs_arr, char *field,
+    char *value, int rep);
+void proxy_del_header(array_header *hdrs_arr, const char *field);
+void proxy_send_headers(BUFF *fp, const char *respline, array_header *hdrs_arr);
+int proxy_liststr(const char *list, const char *val);
+void proxy_hash(const char *it, char *val,int ndepth,int nlength);
+int proxy_hex2sec(const char *x);
+void proxy_sec2hex(int t, char *y);
+void proxy_log_uerror(const char *routine, const char *file, const char *err,
+    server_rec *s);
+BUFF *proxy_cache_error(struct cache_req *r);
+int proxyerror(request_rec *r, const char *message);
+const char *proxy_host2addr(const char *host, struct hostent *reqhp);
+int proxy_doconnect(int sock, struct sockaddr_in *addr, request_rec *r);
+
diff --git a/APACHE_1_2_X/src/modules/proxy/proxy_cache.c b/APACHE_1_2_X/src/modules/proxy/proxy_cache.c
new file mode 100644 (file)
index 0000000..5c0eda2
--- /dev/null
@@ -0,0 +1,932 @@
+/* ====================================================================
+ * Copyright (c) 1996,1997 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/>.
+ *
+ */
+
+/* Cache and garbage collection routines for Apache proxy */
+
+#include "md5.h"
+
+#include "mod_proxy.h"
+#include "http_log.h"
+#include "http_main.h"
+#include "util_date.h"
+#include <utime.h>
+
+#define        abs(c)  ((c) >= 0 ? (c) : -(c))
+
+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);
+
+void proxy_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, timefd;
+    static time_t lastcheck=BAD_DATE;  /* static data!!! */
+
+    cachedir = conf->root;
+    cachesize = conf->space;
+    every = conf->gcinterval;
+
+    if (cachedir == NULL || every == -1) return;
+    now = time(NULL);
+    if (now != -1 && lastcheck != BAD_DATE && 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)
+       {
+           proxy_log_uerror("stat", filename, NULL, r->server);
+           unblock_alarms();
+           return;
+       }
+       if ((timefd = creat(filename, 0666)) == -1)
+       {
+           if (errno != EEXIST)
+               proxy_log_uerror("creat", filename, NULL, r->server);
+           else
+               lastcheck = abs(now);  /* someone else got in there */
+           unblock_alarms();
+           return;
+       }
+       close(timefd);
+    } else
+    {
+       lastcheck = buf.st_mtime;  /* save the time */
+       if (now < lastcheck + every)
+       {
+           unblock_alarms();
+           return;
+       }
+       if (utime(filename, NULL) == -1)
+           proxy_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)
+    {
+       unblock_alarms();
+       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)
+               proxy_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;
+
+    ap_snprintf(cachedir, sizeof(cachedir), "%s%s",cachebasedir,cachesubdir);
+    Explain1("GC Examining directory %s",cachedir);
+    dir = opendir(cachedir);
+    if (dir == NULL)
+    {
+       proxy_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", 3) == 0)
+       {
+/* then stat it to see how old it is; delete temporary files > 1 day old */
+           if (stat(filename, &buf) == -1)
+           {
+               if (errno != ENOENT)
+                   proxy_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) proxy_log_uerror("open", filename,NULL,
+               r->server);
+           continue;
+       }
+       if (fstat(fd, &buf) == -1)
+       {
+           proxy_log_uerror("fstat", filename, NULL, r->server);
+           close(fd);
+           continue;
+       }
+       if(S_ISDIR(buf.st_mode))
+           {
+           char newcachedir[HUGE_STRING_LEN];
+           close(fd);
+           ap_snprintf(newcachedir, sizeof(newcachedir),
+               "%s%s/",cachesubdir,ent->d_name);
+           if(!sub_garbage_coll(r,files,cachebasedir,newcachedir))
+               {
+               ap_snprintf(newcachedir, sizeof(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)
+       {
+           proxy_log_uerror("read", filename, NULL, r->server);
+           close(fd);
+           continue;
+       }
+       close(fd);
+       line[i] = '\0';
+       expire = proxy_hex2sec(line+18);
+       if (!checkmask(line, "&&&&&&&& &&&&&&&& &&&&&&&&") ||
+         expire == BAD_DATE)
+       {
+           /* 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 = proxy_hex2sec(urlbuff);
+    c->lmod = proxy_hex2sec(urlbuff+9);
+    c->expire = proxy_hex2sec(urlbuff+18);
+    c->version = proxy_hex2sec(urlbuff+27);
+    c->len = proxy_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 = proxy_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 = proxy_get_header(c->hdrs, "Content-Length");
+       if (q == NULL)
+       {
+           p = palloc(pool, 15);
+           ap_snprintf(p, 15, "%u", c->len);
+           proxy_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
+ */
+int
+proxy_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 = BAD_DATE;
+    imstr = table_get(r->headers_in, "If-Modified-Since");
+    if (imstr != NULL)
+    {
+/* this may modify the value in the original table */
+       imstr = proxy_date_canon(r->pool, imstr);
+       c->ims = parseHTTPdate(imstr);
+       if (c->ims == BAD_DATE)  /* bad or out of range date; remove it */
+           table_set(r->headers_in, "If-Modified-Since", NULL);
+    }
+
+/* find the filename for this cache entry */
+    proxy_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");
+    Explain5("Request for %s, pragma=%s, auth=%s, ims=%ld, imstr=%s",url,
+      pragma,auth,c->ims,imstr);
+    if (c->filename != NULL && r->method_number == M_GET &&
+       strlen(url) < 1024 && !proxy_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)
+           proxy_log_uerror("open", c->filename,
+               "proxy: error opening cache file", r->server);
+#ifdef EXPLAIN
+       else
+           Explain1("File %s not found",c->filename);
+#endif
+    }
+    
+    if (cachefp != NULL)
+    {
+       i = rdcache(r->pool, cachefp, c);
+       if (i == -1)
+           proxy_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 != BAD_DATE && now < c->expire)
+    {
+        Explain0("Unexpired data available");
+/* check IMS */
+       if (c->lmod != BAD_DATE && c->ims != BAD_DATE && c->ims >= c->lmod)
+       {
+/* has the cached file changed since this request? */
+           if (c->date == BAD_DATE || 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;
+       if (!r->assbackwards) {
+           soft_timeout("proxy send headers", r);
+           proxy_send_headers(r->connection->client, c->resp_line,  c->hdrs);
+           kill_timeout(r);
+       }
+       bsetopt(r->connection->client, BO_BYTECT, &zero);
+       r->sent_bodyct = 1;
+       if (!r->header_only) proxy_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 != BAD_DATE && !r->header_only)
+    {
+/*
+ * use the later of the one from the request and the last-modified date
+ * from the cache
+ */
+       if (c->ims == BAD_DATE || c->ims < c->lmod)
+       {
+           struct hdr_entry *q;
+
+           q = proxy_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
+ */
+int
+proxy_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 = proxy_get_header(resp_hdrs, "Expires");
+    if (expire != NULL) expc = parseHTTPdate(expire->value);
+    else expc = BAD_DATE;
+
+/*
+ * read the last-modified date; if the date is bad, then delete it
+ */
+    lmods = proxy_get_header(resp_hdrs, "Last-Modified");
+    if (lmods != NULL)
+    {
+       lmod = parseHTTPdate(lmods->value);
+       if (lmod == BAD_DATE)
+       {
+/* kill last modified date */
+           lmods->value = NULL;
+           lmods = NULL;
+       }
+    } else
+       lmod = BAD_DATE;
+
+/*
+ * 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 == BAD_DATE) ||
+       (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 = proxy_get_header(resp_hdrs, "Date");
+    if (dates != NULL) date = parseHTTPdate(dates->value);
+    else date = BAD_DATE;
+       
+    now = time(NULL);
+
+    if (date == BAD_DATE) /* No, or bad date */
+    {
+/* no date header! */
+/* add one; N.B. use the time _now_ rather than when we were checking the cache
+ */
+       date = abs(now);
+       p = gm_timestr_822(r->pool, now);
+       dates = proxy_add_header(resp_hdrs, "Date", p, HDR_REP);
+       Explain0("Added date header");
+    }
+
+/* check last-modified date */
+    if (lmod != BAD_DATE && 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 == BAD_DATE && 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 = proxy_get_header(c->hdrs, "Expires");
+       if (expire != NULL) expc = parseHTTPdate(expire->value);
+    }
+/* 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 == BAD_DATE)
+    {
+       if (lmod != BAD_DATE)
+       {
+           double x = (double)(date - lmod)*conf->cache.lmfactor;
+           double maxex=conf->cache.maxexpire;
+           if (x > maxex) x = maxex;
+           expc = abs(now) + (int)x;
+       } else
+           expc = abs(now) + conf->cache.defaultexpire;
+       Explain1("Expiry date calculated %ld",expc);
+    }
+
+/* get the content-length header */
+    clen = proxy_get_header(c->hdrs, "Content-Length");
+    if (clen == NULL) c->len = -1;
+    else c->len = atoi(clen->value);
+
+    proxy_sec2hex(date, buff);
+    buff[8] = ' ';
+    proxy_sec2hex(lmod, buff+9);
+    buff[17] = ' ';
+    proxy_sec2hex(expc, buff+18);
+    buff[26] = ' ';
+    proxy_sec2hex(c->version++, buff+27);
+    buff[35] = ' ';
+    proxy_sec2hex(c->len, buff+36);
+    buff[44] = '\n';
+    buff[45] = '\0';
+
+/* if file not modified */
+    if (r->status == 304)
+    {
+       if (c->ims != BAD_DATE && lmod != BAD_DATE && 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)
+                   proxy_log_uerror("lseek", c->filename,
+                              "proxy: error seeking on cache file",r->server);
+               else if (write(c->fp->fd, buff, 35) == -1)
+                   proxy_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;
+           if (!r->assbackwards) {
+               soft_timeout("proxy send headers", r);
+               proxy_send_headers(r->connection->client, c->resp_line,
+                   c->hdrs);
+               kill_timeout(r);
+           }
+           bsetopt(r->connection->client, BO_BYTECT, &zero);
+           r->sent_bodyct = 1;
+           if (!r->header_only) proxy_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)
+                   proxy_log_uerror("lseek", c->filename,
+                              "proxy: error seeking on cache file",r->server);
+               else if (write(c->fp->fd, buff, 35) == -1)
+                   proxy_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;
+    proxy_sec2hex(0, buff+27);
+    buff[35] = ' ';
+
+/* open temporary file */
+#define TMPFILESTR     "/tmpXXXXXX"
+    if (conf->cache.root == NULL)
+        return DECLINED;
+    c->tempfile=palloc(r->pool,strlen(conf->cache.root)+sizeof(TMPFILESTR));
+    strcpy(c->tempfile,conf->cache.root);
+    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)
+    {
+       proxy_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)
+    {
+       proxy_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;
+}
+
+void
+proxy_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
+    if (c->req->connection->aborted) {
+           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);
+       proxy_sec2hex(c->len, buff);
+       curpos = lseek(c->fp->fd, 36, SEEK_SET);
+       if (curpos == -1)
+           proxy_log_uerror("lseek", c->tempfile,
+               "proxy: error seeking on cache file", s);
+       else if (write(c->fp->fd, buff, 8) == -1)
+           proxy_log_uerror("write", c->tempfile,
+               "proxy: error updating cache file", s);
+    }
+
+    if (bflush(c->fp) == -1)
+    {
+       proxy_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)
+    {
+       proxy_log_uerror("close", c->tempfile,
+           "proxy: error closing cache file", s);
+       unlink(c->tempfile);
+       return;
+    }
+
+    if (unlink(c->filename) == -1 && errno != ENOENT)
+    {
+       proxy_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)
+               proxy_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)
+            proxy_log_uerror("rename", c->filename,
+               "proxy: error renaming cache file", s);
+}
+#else            
+
+       if (link(c->tempfile, c->filename) == -1)
+           proxy_log_uerror("link", c->filename,
+               "proxy: error linking cache file", s);
+       }
+
+    if (unlink(c->tempfile) == -1)
+       proxy_log_uerror("unlink", c->tempfile,
+           "proxy: error deleting temp file",s);
+#endif
+
+}
+
diff --git a/APACHE_1_2_X/src/modules/proxy/proxy_connect.c b/APACHE_1_2_X/src/modules/proxy/proxy_connect.c
new file mode 100644 (file)
index 0000000..ba12027
--- /dev/null
@@ -0,0 +1,228 @@
+/* ====================================================================
+ * Copyright (c) 1996,1997 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/>.
+ *
+ */
+
+/* CONNECT method SSL handling for Apache proxy */
+
+#include "mod_proxy.h"
+#include "http_log.h"
+#include "http_main.h"
+
+#ifdef HAVE_BSTRING_H
+#include <bstring.h>            /* for IRIX, FD_SET calls bzero() */
+#endif
+
+/*  
+ * 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.
+ */ 
+int
+proxy_connect_handler(request_rec *r, struct cache_req *c, char *url)
+{
+    struct sockaddr_in server;
+    struct in_addr destaddr;
+    struct hostent server_hp;
+    const char *host, *err;
+    char *p;
+    int   port, sock;
+    char buffer[HUGE_STRING_LEN];
+    int  nbytes, i, j;
+    fd_set fds;
+
+    void *sconf = r->server->module_config;
+    proxy_server_conf *conf =
+        (proxy_server_conf *)get_module_config(sconf, &proxy_module);
+    struct noproxy_entry *npent=(struct noproxy_entry *)conf->noproxies->elts;
+
+    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';
+    }
+/* check if ProxyBlock directive on this host */
+    destaddr.s_addr = inet_addr(host);
+    for (i=0; i < conf->noproxies->nelts; i++)
+    {
+        if ((npent[i].name != NULL && strstr(host, npent[i].name) != NULL)
+          || destaddr.s_addr == npent[i].addr.s_addr || npent[i].name[0] == '*')
+            return proxyerror(r, "Connect to remote machine blocked");
+    }
+
+    switch (port)
+    {
+       case DEFAULT_HTTPS_PORT:
+       case DEFAULT_SNEWS_PORT:
+           break;
+       default:
+           return HTTP_SERVICE_UNAVAILABLE;
+    }
+
+    Explain2("CONNECT to %s on port %d", host, port);
+    server.sin_port = htons(port);
+    err = proxy_host2addr(host, &server_hp);
+    if (err != NULL)
+       return proxyerror(r, err); /* give up */
+    sock = socket(PF_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);
+    j = 0;
+    while (server_hp.h_addr_list[j] != NULL) {
+        memcpy(&server.sin_addr, server_hp.h_addr_list[j],
+            sizeof(struct in_addr));
+        i = proxy_doconnect(sock, &server, r);
+        if (i == 0)
+            break; 
+        j++;
+    }   
+    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;
+}     
+
diff --git a/APACHE_1_2_X/src/modules/proxy/proxy_ftp.c b/APACHE_1_2_X/src/modules/proxy/proxy_ftp.c
new file mode 100644 (file)
index 0000000..a0f0d5e
--- /dev/null
@@ -0,0 +1,1014 @@
+/* ====================================================================
+ * Copyright (c) 1996,1997 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/>.
+ *
+ */
+
+/* FTP routines for Apache proxy */
+
+#include "mod_proxy.h"
+#include "http_main.h"
+
+extern int find_ct(request_rec *r);
+
+/*
+ * 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 = proxy_hex2c(&x[i+1]);
+           i += 2;
+       }
+       x[j] = ch;
+    }
+    x[j] = '\0';
+    return j;
+}
+
+/*
+ * 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 = proxy_hex2c(&x[i+1]);
+           i += 2;
+       }
+       if (ch == '\015' || ch == '\012' || (ch & 0x80)) return 0;
+    }
+    return 1;
+}
+
+/*
+ * Canonicalise ftp URLs.
+ */
+int
+proxy_ftp_canon(request_rec *r, char *url)
+{
+    char *user, *password, *host, *path, *parms, *p, sport[7];
+    pool *pool=r->pool;
+    const char *err;
+    int port;
+
+    port = DEFAULT_FTP_PORT;
+    err = proxy_canon_netloc(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 = proxy_canonenc(pool, p, strlen(p), enc_parm, r->proxyreq);
+       if (parms == NULL) return BAD_REQUEST;
+    } else
+       parms = "";
+
+    path = proxy_canonenc(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 = proxy_canonenc(pool, r->args, strlen(r->args), enc_parm, 1);
+           if (p == NULL) return BAD_REQUEST;
+           parms = pstrcat(pool, parms, "?", p, NULL);
+       }
+       else
+       {
+           p = proxy_canonenc(pool, r->args, strlen(r->args), enc_fpath, 1);
+           if (p == NULL) return BAD_REQUEST;
+           path = pstrcat(pool, path, "?", p, NULL);
+       }
+       r->args = NULL;
+    }
+
+/* now, rebuild URL */
+
+    if (port != DEFAULT_FTP_PORT) ap_snprintf(sport, sizeof(sport), ":%d", port);
+    else sport[0] = '\0';
+
+    r->filename = pstrcat(pool, "proxy:ftp://", (user != NULL) ? user : "",
+                         (password != NULL) ? ":" : "",
+                         (password != NULL) ? password : "",
+                         (user != NULL) ? "@" : "", host, sport, "/", path,
+                         (parms[0] != '\0') ? ";" : "", parms, NULL);
+
+    return OK;
+}
+
+/*
+ * Returns the ftp status code;
+ *  or -1 on I/O error, 0 on data error
+ */
+static 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] != '-'))
+       status = 0;
+    else
+       status = 100 * linebuff[0] + 10 * linebuff[1] + linebuff[2] - 111 * '0';
+
+    if (linebuff[len-1] != '\n')
+    {
+       i = bskiplf(f);
+    }
+
+/* skip continuation lines */    
+    if (linebuff[3] == '-')
+    {
+       memcpy(buff, linebuff, 3);
+       buff[3] = ' ';
+       do
+       {
+           len = bgets(linebuff, 100, f);
+           if (len == -1) return -1;
+           if (linebuff[len-1] != '\n')
+           {
+               i = bskiplf(f);
+           }
+       } while (memcmp(linebuff, buff, 4) != 0);
+    }
+
+    return status;
+}
+
+static char *
+encode_space(request_rec *r, char *path)
+{
+    pool *pool=r->pool;
+    char *newpath;
+    int i, j, len;
+
+    len = strlen(path);
+    newpath = palloc(pool, 3 * len + 1);
+    for (i=0, j=0; i < len; i++, j++) {
+       if (path[i] != ' ')
+           newpath[j] = path[i];
+       else {
+           proxy_c2hex(' ', &newpath[j]);
+           j += 2;
+       }
+    }
+    newpath[j] = '\0';
+    return newpath;
+}
+
+static long int
+send_dir(BUFF *f, request_rec *r, BUFF *f2, struct cache_req *c, char *url)
+{
+    char buf[IOBUFSIZE];
+    char buf2[IOBUFSIZE];
+    char *filename;
+    char *tempurl;
+    char *newurlptr;
+    int searchidx = 0;
+    char *searchptr = NULL;
+    int firstfile = 1;
+    char urlptr[HUGE_STRING_LEN];
+    long total_bytes_sent;
+    register int n, o, w;
+    conn_rec *con = r->connection;
+
+    tempurl = pstrdup(r->pool, url);
+    if ((n = strcspn(tempurl, "@")) != strlen(tempurl))        /* hide user/passwd */
+    {
+       memmove(tempurl + (n - 5), tempurl, 6);
+       tempurl += n - 5;       /* leave room for ftp:// */
+    }
+
+    n = decodeenc(tempurl);
+    ap_snprintf(buf, sizeof(buf), "<HTML><HEAD><TITLE>%s</TITLE></HEAD><BODY><H1>Directory %s</H1><HR><PRE>", tempurl, tempurl);
+    bwrite(con->client, buf, strlen(buf));
+    if (f2 != NULL) bwrite(f2, buf, strlen(buf));
+    total_bytes_sent=strlen(buf);
+    while(!con->aborted)
+    {
+        n = bgets(buf, IOBUFSIZE, f);
+        if (n == -1) /* input error */
+        {
+            if (f2 != NULL) f2 = proxy_cache_error(c);
+            break;
+        }
+        if (n == 0) break; /* EOF */
+        if(buf[0]=='l')
+        {
+            char *link;
+
+            link=strstr(buf, " -> ");
+            filename=link;
+            do filename--; while (filename[0]!=' ');
+            *(filename++)=0;
+            *(link++)=0;
+            ap_snprintf(urlptr, sizeof(urlptr), "%s%s%s",url,(url[strlen(url)-1]=='/' ? "" : "/"), filename);
+            ap_snprintf(buf2, sizeof(urlptr), "%s <A HREF=\"%s\">%s %s</A>\015\012", buf, urlptr, filename, link);
+            strncpy(buf, buf2, sizeof(buf)-1);
+           buf[sizeof(buf)-1] = '\0';
+            n=strlen(buf);
+        }
+        else if(buf[0]=='d' || buf[0]=='-' || buf[0]=='l' || isdigit(buf[0]))
+        {
+           if(isdigit(buf[0])) {               /* handle DOS dir */
+               searchptr = strchr(buf, '<');
+               if(searchptr != NULL)
+                   *searchptr = '[';
+               searchptr = strchr(buf, '>');
+               if(searchptr != NULL)
+                   *searchptr = ']';
+           }
+               
+            filename=strrchr(buf, ' ');
+            *(filename++)=0;
+            filename[strlen(filename)-1]=0;
+
+            /* handle filenames with spaces in 'em */
+            if(!strcmp(filename, ".") || !strcmp(filename, "..") || firstfile) {
+               firstfile = 0;
+                searchidx = filename - buf;
+            }
+            else if (searchidx != 0 && buf[searchidx] != 0) {
+                *(--filename) = ' ';
+                buf[searchidx - 1] = 0;
+                filename = &buf[searchidx];    
+            }   
+
+            /* Special handling for '.' and '..' */
+            if (!strcmp(filename, "."))
+            {
+                ap_snprintf(urlptr, sizeof(urlptr), "%s",url);
+                ap_snprintf(buf2, sizeof(buf2), "%s <A HREF=\"%s\">%s</A>\015\012", buf, urlptr, filename);
+            }
+            else if (!strcmp(filename, ".."))
+            {
+                char temp[200];
+                char newpath[200];
+                char *method, *host, *path, *newfile;
+   
+                strncpy(temp, url, sizeof(temp)-1);
+               temp[sizeof(temp)-1] = '\0';
+                method=temp;
+
+                host=strchr(method,':');
+                if (host == NULL) host="";
+                else *(host++)=0;
+                host++; host++;
+                
+                path=strchr(host,'/');
+                if (path == NULL) path="";
+                else *(path++)=0;
+                
+                strncpy(newpath, path, sizeof(newpath)-1);
+               newpath[sizeof(newpath)-1] = '\0';
+                newfile=strrchr(newpath,'/');
+                if (newfile) *(newfile)=0;
+                else newpath[0]=0;
+
+                ap_snprintf(urlptr, sizeof(urlptr), "%s://%s/%s",method,host,newpath);
+                ap_snprintf(buf2, sizeof(buf2), "%s <A HREF=\"%s\">%s</A>\015\012", buf, urlptr, filename);
+            }
+            else 
+            {
+                ap_snprintf(urlptr, sizeof(urlptr), "%s%s%s",url,(url[strlen(url)-1]=='/' ? "" : "/"), filename);
+               newurlptr = encode_space(r, urlptr);
+                ap_snprintf(buf2, sizeof(buf2), "%s <A HREF=\"%s\">%s</A>\015\012", buf, newurlptr, filename);
+            }
+            strncpy(buf, buf2, sizeof(buf));
+           buf[sizeof(buf)-1] = '\0';
+            n=strlen(buf);
+        }      
+
+        o=0;
+       total_bytes_sent += n;
+
+       if (f2 != NULL)
+           if (bwrite(f2, buf, n) != n) f2 = proxy_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;
+        }
+    }
+    ap_snprintf(buf, sizeof(buf), "</PRE><HR><I><A HREF=\"http://www.apache.org\">%s</A></I></BODY></HTML>", SERVER_VERSION);
+    bwrite(con->client, buf, strlen(buf));
+    if (f2 != NULL) bwrite(f2, buf, strlen(buf));
+    total_bytes_sent+=strlen(buf);
+    bflush(con->client);
+    
+    return total_bytes_sent;
+}
+
+/*
+ * Handles direct access of ftp:// URLs
+ * Original (Non-PASV) version from
+ * Troy Morrison <spiffnet@zoom.com>
+ * PASV added by Chuck
+ */
+int
+proxy_ftp_handler(request_rec *r, struct cache_req *c, char *url)
+{
+    char *host, *path, *p, *user, *password, *parms;
+    const char *err;
+    int port, userlen, i, j, len, sock, dsock, rc, nocache;
+    int passlen = 0;
+    int csd = 0;
+    struct sockaddr_in server;
+    struct hostent server_hp;
+    struct hdr_entry *hdr;
+    struct in_addr destaddr;
+    array_header *resp_hdrs;
+    BUFF *f, *cache;
+    BUFF *data = NULL;
+    pool *pool=r->pool;
+    const int one=1;
+    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 noproxy_entry *npent=(struct noproxy_entry *)conf->noproxies->elts;
+    struct nocache_entry *ncent=(struct nocache_entry *)conf->nocaches->elts;
+
+/* stuff for PASV mode */
+    unsigned int presult, h0, h1, h2, h3, p0, p1;
+    unsigned int paddr;
+    unsigned short pport;
+    struct sockaddr_in data_addr;
+    int pasvmode = 0;
+    char pasv[64];
+    char *pstr;
+/* we only support GET and HEAD */
+
+    if (r->method_number != M_GET) return NOT_IMPLEMENTED;
+
+/* We break the URL into host, port, path-search */
+
+    host = pstrdup(pool, url + 6);
+    port = DEFAULT_FTP_PORT;
+    path = strchr(host, '/');
+    if (path == NULL)
+       path = "";
+    else
+       *(path++) = '\0';
+
+    user = password = NULL;
+    nocache = 0;
+    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 = "apache_proxy@";
+       passlen = strlen(password);
+    }
+
+    p = strchr(host, ':');
+    if (p != NULL)
+    {
+       *(p++) = '\0';
+       if (isdigit(*p))
+           port = atoi(p);
+    }
+
+/* check if ProxyBlock directive on this host */
+    destaddr.s_addr = inet_addr(host);
+    for (i=0; i < conf->noproxies->nelts; i++)
+    {
+        if ((npent[i].name != NULL && strstr(host, npent[i].name) != NULL)
+          || destaddr.s_addr == npent[i].addr.s_addr || npent[i].name[0] == '*')
+            return proxyerror(r, "Connect to remote machine blocked");
+    }
+
+    Explain2("FTP: connect to %s:%d",host,port);
+
+    parms = strchr(path, ';');
+    if (parms != NULL) *(parms++) = '\0';
+
+    memset(&server, 0, sizeof(struct sockaddr_in));
+    server.sin_family = AF_INET;
+    server.sin_port = htons(port);
+    err = proxy_host2addr(host, &server_hp);
+    if (err != NULL) return proxyerror(r, err); /* give up */
+
+    sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+    if (sock == -1)
+    {
+       proxy_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)
+    {
+       proxy_log_uerror("setsockopt", NULL,
+           "proxy: error setting reuseaddr option", r->server);
+       pclosef(pool, sock);
+       return SERVER_ERROR;
+    }
+
+    j = 0;
+    while (server_hp.h_addr_list[j] != NULL) {
+        memcpy(&server.sin_addr, server_hp.h_addr_list[j],
+            sizeof(struct in_addr));
+        i = proxy_doconnect(sock, &server, r);
+        if (i == 0)
+            break; 
+        j++;
+    }   
+    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);
+    Explain1("FTP: returned status %d", i);
+    if (i == -1) {
+       kill_timeout(r);
+       return proxyerror(r, "Error reading from remote server");
+    }
+    if (i != 220) {
+       kill_timeout(r);
+       return BAD_GATEWAY;
+    }
+
+    Explain0("FTP: connected.");
+
+    bputs("USER ", f);
+    bwrite(f, user, userlen);
+    bputs("\015\012", f);
+    bflush(f); /* capture any errors */
+    Explain1("FTP: USER %s",user);
+    
+/* possible results; 230, 331, 332, 421, 500, 501, 530 */
+/* states: 1 - error, 2 - success; 3 - send password, 4,5 fail */
+    i = ftp_getrc(f);
+    Explain1("FTP: returned status %d",i);
+    if (i == -1) {
+       kill_timeout(r);
+       return proxyerror(r, "Error sending to remote server");
+    }
+    if (i == 530) {
+       kill_timeout(r);
+       return proxyerror(r, "Not logged in");
+    }
+    if (i != 230 && i != 331) {
+       kill_timeout(r);
+       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);
+        Explain1("FTP: PASS %s",password);
+/* possible results 202, 230, 332, 421, 500, 501, 503, 530 */
+       i = ftp_getrc(f);
+        Explain1("FTP: returned status %d",i);
+       if (i == -1) {
+           kill_timeout(r);
+           return proxyerror(r, "Error sending to remote server");
+       }
+       if (i == 332) {
+           kill_timeout(r);
+           return proxyerror(r, "Need account for login");
+       }
+       if (i == 530) {
+           kill_timeout(r);
+           return proxyerror(r, "Not logged in");
+       }
+       if (i != 230 && i != 202) {
+           kill_timeout(r);
+           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);
+        Explain1("FTP: CWD %s",path);
+/* responses: 250, 421, 500, 501, 502, 530, 550 */
+/* 1,3 error, 2 success, 4,5 failure */
+       i = ftp_getrc(f);
+        Explain1("FTP: returned status %d",i);
+       if (i == -1) {
+           kill_timeout(r);
+           return proxyerror(r, "Error sending to remote server");
+       }
+       if (i == 550) {
+           kill_timeout(r);
+           return NOT_FOUND;
+       }
+       if (i != 250) {
+           kill_timeout(r);
+           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 = "";
+
+    /* changed to make binary transfers the default */
+
+    if (parms[0] != 'a')
+    {
+       /* set type to image */
+        /* TM - Added \015\012 to the end of TYPE I, otherwise it hangs the
+           connection */
+       bputs("TYPE I\015\012", f);
+       bflush(f);
+        Explain0("FTP: TYPE I");
+/* responses: 200, 421, 500, 501, 504, 530 */
+       i = ftp_getrc(f);
+        Explain1("FTP: returned status %d",i);
+       if (i == -1) {
+           kill_timeout(r);
+           return proxyerror(r, "Error sending to remote server");
+       }
+       if (i != 200 && i != 504) {
+           kill_timeout(r);
+           return BAD_GATEWAY;
+       }
+/* Allow not implemented */
+       if (i == 504)
+           parms[0] = '\0';
+    }
+
+/* try to set up PASV data connection first */
+    dsock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+    if (dsock == -1)
+    { 
+       proxy_log_uerror("socket", NULL, "proxy: error creating PASV socket",
+           r->server);
+       pclosef(pool, sock);
+       kill_timeout(r);
+        return SERVER_ERROR;
+    }
+    note_cleanups_for_fd(pool, dsock);
+
+    bputs("PASV\015\012", f);
+    bflush(f);
+    Explain0("FTP: PASV command issued");
+/* possible results: 227, 421, 500, 501, 502, 530 */
+    i = bgets(pasv, sizeof(pasv), f); 
+
+    if (i == -1)
+    {
+       proxy_log_uerror("command", NULL, "PASV: control connection is toast",
+           r->server);
+       pclosef(pool, dsock);
+       pclosef(pool, sock);
+       kill_timeout(r);
+       return SERVER_ERROR;
+    } else
+    {
+       pasv[i-1] = '\0';
+       pstr = strtok(pasv, " ");       /* separate result code */
+       if (pstr != NULL)
+       {
+           presult = atoi(pstr);
+           pstr = strtok(NULL, "(");   /* separate address & port params */
+           if (pstr != NULL)
+               pstr = strtok(NULL, ")");
+       }
+       else
+           presult = atoi(pasv);
+
+       Explain1("FTP: returned status %d", presult);
+
+       if (presult == 227 && pstr != NULL && (sscanf(pstr,
+           "%d,%d,%d,%d,%d,%d", &h3, &h2, &h1, &h0, &p1, &p0) == 6))
+       {
+           /* pardon the parens, but it makes gcc happy */
+            paddr = (((((h3 << 8) + h2) << 8) + h1) << 8) + h0;
+            pport = (p1 << 8) + p0;
+           Explain5("FTP: contacting host %d.%d.%d.%d:%d",
+               h3, h2, h1, h0, pport);
+            data_addr.sin_family = AF_INET;
+            data_addr.sin_addr.s_addr = htonl(paddr);
+            data_addr.sin_port = htons(pport);
+           i = proxy_doconnect(dsock, &data_addr, r);
+
+           if (i == -1) {
+               kill_timeout(r);
+               return proxyerror(r, "Could not connect to remote machine");
+           }
+           else {
+               data = bcreate(pool, B_RDWR); 
+               bpushfd(data, dsock, dsock);
+               pasvmode = 1;
+           }
+       } else
+           pclosef(pool, dsock);       /* and try the regular way */
+    }
+
+    if (!pasvmode)     /* set up data connection */
+    {
+        len = sizeof(struct sockaddr_in);
+        if (getsockname(sock, (struct sockaddr *)&server, &len) < 0)
+        {
+           proxy_log_uerror("getsockname", NULL,
+               "proxy: error getting socket address", r->server);
+           pclosef(pool, sock);
+           kill_timeout(r);
+           return SERVER_ERROR;
+        }
+
+        dsock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+        if (dsock == -1)
+        {
+           proxy_log_uerror("socket", NULL, "proxy: error creating socket",
+               r->server);
+           pclosef(pool, sock);
+           kill_timeout(r);
+           return SERVER_ERROR;
+        }
+        note_cleanups_for_fd(pool, dsock);
+
+        if (setsockopt(dsock, SOL_SOCKET, SO_REUSEADDR, (const char *)&one,
+                  sizeof(int)) == -1)
+        {
+           proxy_log_uerror("setsockopt", NULL,
+               "proxy: error setting reuseaddr option", r->server);
+           pclosef(pool, dsock);
+           pclosef(pool, sock);
+           kill_timeout(r);
+           return SERVER_ERROR;
+        }
+
+        if (bind(dsock, (struct sockaddr *)&server,
+            sizeof(struct sockaddr_in)) == -1)
+        {
+           char buff[22];
+
+           ap_snprintf(buff, sizeof(buff), "%s:%d", inet_ntoa(server.sin_addr), server.sin_port);
+           proxy_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);
+
+    /* TM - if len == 0 then it must be a directory (you can't RETR nothing) */
+
+    if(len==0)
+    {
+       parms="d";
+    } else
+    {
+        bputs("SIZE ", f);
+        bwrite(f, path, len);
+        bputs("\015\012", f);
+        bflush(f);
+        Explain1("FTP: SIZE %s",path);
+        i = ftp_getrc(f);
+        Explain1("FTP: returned status %d", i);
+        if (i != 500) /* Size command not recognized */
+        {
+            if (i==550) /* Not a regular file */
+            {
+                Explain0("FTP: SIZE shows this is a directory");
+                parms="d";
+                bputs("CWD ", f);
+                bwrite(f, path, len);
+                bputs("\015\012", f);
+                bflush(f);
+                Explain1("FTP: CWD %s",path);
+                i = ftp_getrc(f);
+                Explain1("FTP: returned status %d", i);
+                if (i == -1) {
+                   kill_timeout(r);
+                   return proxyerror(r, "Error sending to remote server");
+                }
+                if (i == 550) {
+                   kill_timeout(r);
+                   return NOT_FOUND;
+                }
+                if (i != 250) {
+                   kill_timeout(r);
+                   return BAD_GATEWAY;
+                }
+                path=""; len=0;
+            }
+        }
+    }
+            
+    if (parms[0] == 'd')
+    {
+       if (len != 0) bputs("LIST ", f);
+       else bputs("LIST -lag", f);
+        Explain1("FTP: LIST %s",(len==0 ? "" : path));
+    }
+    else
+    {
+        bputs("RETR ", f);
+        Explain1("FTP: RETR %s",path);
+    }
+    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);
+    Explain1("FTP: returned status %d",rc);
+    if (rc == -1) {
+       kill_timeout(r);
+       return proxyerror(r, "Error sending to remote server");
+    }
+    if (rc == 550)
+    {
+       Explain0("FTP: RETR failed, trying LIST instead");
+       parms="d";
+       bputs("CWD ", f);
+       bwrite(f, path, len);
+       bputs("\015\012", f);
+       bflush(f);
+       Explain1("FTP: CWD %s", path);
+       rc = ftp_getrc(f);
+       Explain1("FTP: returned status %d", rc);
+       if (rc == -1) {
+          kill_timeout(r);
+          return proxyerror(r, "Error sending to remote server");
+       }
+       if (rc == 550) {
+          kill_timeout(r);
+          return NOT_FOUND;
+       }
+       if (rc != 250) {
+          kill_timeout(r);
+          return BAD_GATEWAY;
+       }
+
+       bputs("LIST -lag\015\012", f);
+       bflush(f);
+       Explain0("FTP: LIST -lag");
+       rc = ftp_getrc(f);
+       Explain1("FTP: returned status %d", rc);
+       if (rc == -1) return proxyerror(r, "Error sending to remote server");
+    }   
+    kill_timeout(r);
+    if (rc != 125 && rc != 150 && rc != 226 && rc != 250) return BAD_GATEWAY;
+
+    r->status = 200;
+    r->status_line = "200 OK";
+
+    resp_hdrs = make_array(pool, 2, sizeof(struct hdr_entry));
+    if (parms[0] == 'd')
+       proxy_add_header(resp_hdrs, "Content-Type", "text/html", HDR_REP);
+    else
+    {
+        find_ct(r);
+        if(r->content_type != NULL)
+        {
+            proxy_add_header(resp_hdrs, "Content-Type", r->content_type,
+               HDR_REP);
+            Explain1("FTP: Content-Type set to %s",r->content_type);
+        } else
+       {
+           proxy_add_header(resp_hdrs, "Content-Type", "text/plain", HDR_REP);
+       }
+    }
+
+/* check if NoCache directive on this host */ 
+    for (i=0; i < conf->nocaches->nelts; i++)
+    {
+        if ((ncent[i].name != NULL && strstr(host, ncent[i].name) != NULL)
+          || destaddr.s_addr == ncent[i].addr.s_addr || ncent[i].name[0] == '*')
+            nocache = 1;
+    }
+
+    i = proxy_cache_update(c, resp_hdrs, "FTP", nocache);
+
+    if (i != DECLINED)
+    {
+       pclosef(pool, dsock);
+       pclosef(pool, sock);
+       return i;
+    }
+    cache = c->fp;
+
+    if (!pasvmode)     /* 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);
+        if (csd == -1)
+        {
+           proxy_log_uerror("accept", NULL,
+               "proxy: failed to accept data connection", r->server);
+           pclosef(pool, dsock);
+           pclosef(pool, sock);
+           kill_timeout(r);
+           proxy_cache_error(c);
+           return BAD_GATEWAY;
+        }
+        note_cleanups_for_fd(pool, csd);
+        data = bcreate(pool, B_RDWR);
+        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 = proxy_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 = proxy_cache_error(c);
+    }
+
+    if (!r->assbackwards) rputs("\015\012", r);
+    if (cache != NULL)
+       if (bputs("\015\012", cache) == -1) cache = proxy_cache_error(c);
+
+    bsetopt(r->connection->client, BO_BYTECT, &zero);
+    r->sent_bodyct = 1;
+/* send body */
+    if (!r->header_only)
+    {
+       if (parms[0] != 'd') proxy_send_fb(data, r, cache, c);
+        else send_dir(data, r, cache, c, url);
+
+       if (rc == 125 || rc == 150) rc = ftp_getrc(f);
+       if (rc != 226 && rc != 250) proxy_cache_error(c);
+    }
+    else
+    {
+/* abort the transfer */
+       bputs("ABOR\015\012", f);
+       bflush(f);
+       if (!pasvmode)
+            pclosef(pool, csd);
+        Explain0("FTP: ABOR");
+/* responses: 225, 226, 421, 500, 501, 502 */
+       i = ftp_getrc(f);
+        Explain1("FTP: returned status %d",i);
+    }
+
+    kill_timeout(r);
+    proxy_cache_tidy(c);
+
+/* finish */
+    bputs("QUIT\015\012", f);
+    bflush(f);
+    Explain0("FTP: QUIT");
+/* responses: 221, 500 */    
+
+    if (!pasvmode)
+        pclosef(pool, csd);
+    pclosef(pool, dsock);
+    pclosef(pool, sock);
+
+    proxy_garbage_coll(r);
+
+    return OK;
+}
+
diff --git a/APACHE_1_2_X/src/modules/proxy/proxy_http.c b/APACHE_1_2_X/src/modules/proxy/proxy_http.c
new file mode 100644 (file)
index 0000000..4ca9cab
--- /dev/null
@@ -0,0 +1,414 @@
+/* ====================================================================
+ * Copyright (c) 1996,1997 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 routines for Apache proxy */
+
+#include "mod_proxy.h"
+#include "http_log.h"
+#include "http_main.h"
+#include "util_date.h"
+
+/*
+ * 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.
+ */
+int
+proxy_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 = proxy_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 = proxy_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 = NULL;
+
+    if (port != def_port) ap_snprintf(sport, sizeof(sport), ":%d", port);
+    else sport[0] = '\0';
+
+    r->filename = pstrcat(r->pool, "proxy:", scheme, "://", host, sport, "/",
+       path, (search) ? "?" : "", (search) ? search : "", NULL);
+    return OK;
+}
+
+/* Clear all connection-based headers from the incoming headers table */
+static void clear_connection (table *headers)
+{
+    char *name;
+    char *next = table_get(headers, "Connection");
+
+    if (!next) return;
+
+    while (*next) {
+        name = next;
+        while (*next && !isspace(*next) && (*next != ',')) ++next;
+        while (*next && (isspace(*next) || (*next == ','))) {
+            *next = '\0';
+            ++next;
+        }
+        table_unset(headers, name);
+    }
+    table_unset(headers, "Connection");
+}
+
+/*
+ * 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.)
+ */
+int
+proxy_http_handler(request_rec *r, struct cache_req *c, char *url,
+            const char *proxyhost, int proxyport)
+{
+    char *p;
+    const char *err, *desthost;
+    int i, j, sock, len;
+    array_header *reqhdrs_arr, *resp_hdrs;
+    table_entry *reqhdrs;
+    struct sockaddr_in server;
+    struct in_addr destaddr;
+    struct hostent server_hp;
+    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;
+    int destport = 0;
+    char *destportstr = NULL;
+
+    void *sconf = r->server->module_config;
+    proxy_server_conf *conf =
+        (proxy_server_conf *)get_module_config(sconf, &proxy_module);
+    struct noproxy_entry *npent=(struct noproxy_entry *)conf->noproxies->elts;
+    struct nocache_entry *ncent=(struct nocache_entry *)conf->nocaches->elts;
+    int nocache = 0;
+
+    memset(&server, '\0', sizeof(server));
+    server.sin_family = AF_INET;
+
+/* We break the URL into host, port, path-search */
+
+    url += 7;  /* skip http:// */
+    destport = DEFAULT_PORT;
+    p = strchr(url, '/');
+    if (p == NULL)
+    {
+        desthost = pstrdup(pool, url);
+        url = "/";
+    } else
+    {
+        char *q = palloc(pool, p-url+1);
+        memcpy(q, url, p-url);
+        q[p-url] = '\0';
+        url = p;
+        desthost = q;
+    }
+
+    p = strchr(desthost, ':');
+    if (p != NULL)
+    {
+        *(p++) = '\0';
+       if (isdigit(*p))
+       {
+            destport = atoi(p);
+            destportstr = p;
+       }
+    }
+
+/* check if ProxyBlock directive on this host */
+    destaddr.s_addr = inet_addr(desthost);
+    for (i=0; i < conf->noproxies->nelts; i++)
+    {
+        if ((npent[i].name != NULL && strstr(desthost, npent[i].name) != NULL)
+         || destaddr.s_addr == npent[i].addr.s_addr || npent[i].name[0] == '*')
+           return proxyerror(r, "Connect to remote machine blocked");
+    }
+
+    if (proxyhost != NULL)
+    {
+       url = r->uri;                   /* restore original URL */
+       server.sin_port = htons(proxyport);
+       err = proxy_host2addr(proxyhost, &server_hp);
+       if (err != NULL) return DECLINED;  /* try another */
+    } else
+    {
+       server.sin_port = htons(destport);
+       err = proxy_host2addr(desthost, &server_hp);
+       if (err != NULL) return proxyerror(r, err); /* give up */
+    }
+
+    sock = socket(PF_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);
+
+    
+    j = 0;
+    while (server_hp.h_addr_list[j] != NULL) {
+       memcpy(&server.sin_addr, server_hp.h_addr_list[j],
+           sizeof(struct in_addr));
+        i = proxy_doconnect(sock, &server, r);
+       if (i == 0)
+           break;
+       j++;
+    }
+    if (i == -1)
+    {
+       if (proxyhost != NULL) return DECLINED; /* try again another way */
+       else return proxyerror(r, "Could not connect to remote machine");
+    }
+
+    clear_connection(r->headers_in);   /* Strip connection-based headers */
+
+    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);
+    bvputs(f, "Host: ", desthost, NULL);
+    if (destportstr != NULL && destport != DEFAULT_PORT)
+       bvputs(f, ":", destportstr, "\015\012", NULL);
+    else
+       bputs("\015\012", f);
+
+    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
+         || !strcmp(reqhdrs[i].key, "Host"))   /* already sent if there */
+           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 (should_client_block(r))
+    {
+       while ((i = get_client_block(r, buffer, HUGE_STRING_LEN)) > 0)
+            bwrite(f, buffer, 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);
+       kill_timeout(r);
+       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);
+           kill_timeout(r);
+           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 = proxy_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 = proxy_date_canon(pool, hdr[i].value);
+    }
+
+/* check if NoCache directive on this host */
+    for (i=0; i < conf->nocaches->nelts; i++)
+    {
+        if ((ncent[i].name != NULL && strstr(desthost, ncent[i].name) != NULL)
+         || destaddr.s_addr == ncent[i].addr.s_addr || ncent[i].name[0] == '*')
+           nocache = 1; 
+    }
+
+    i = proxy_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 = proxy_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 = proxy_cache_error(c);
+    }
+
+    if (!r->assbackwards) rputs("\015\012", r);
+    if (cache != NULL)
+       if (bputs("\015\012", cache) == -1) cache = proxy_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 = proxy_cache_error(c);
+    }
+    kill_timeout(r);
+
+/* 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) proxy_send_fb(f, r, cache, c);
+
+    proxy_cache_tidy(c);
+
+    pclosef(pool, sock);
+
+    proxy_garbage_coll(r);
+    return OK;
+}
+
diff --git a/APACHE_1_2_X/src/modules/proxy/proxy_util.c b/APACHE_1_2_X/src/modules/proxy/proxy_util.c
new file mode 100644 (file)
index 0000000..6cd3bdb
--- /dev/null
@@ -0,0 +1,747 @@
+/* ====================================================================
+ * Copyright (c) 1996,1997 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/>.
+ *
+ */
+
+/* Utility routines for Apache proxy */
+
+#include "mod_proxy.h"
+#include "http_main.h"
+#include "md5.h"
+
+/* already called in the knowledge that the characters are hex digits */
+int
+proxy_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;
+}
+
+void
+proxy_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
+ */
+
+/*
+ * 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.
+ */
+char *
+proxy_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 = proxy_hex2c(&x[i+1]);
+           i += 2;
+           if (ch != 0 && ind(reserved, ch) != -1)
+           {  /* keep it encoded */
+               proxy_c2hex(ch, &y[j]);
+               j += 2;
+               continue;
+           }
+       }
+/* recode it, if necessary */
+       if (!isalnum(ch) && ind(allowed, ch) == -1)
+       {
+           proxy_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.
+ */
+char *
+proxy_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 = proxy_canonenc(pool, p+1, strlen(p+1), enc_user, 1);
+               if (password == NULL)
+                   return "Bad %-escape in URL (password)";
+           }
+
+           user = proxy_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;
+}
+
+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.
+ */
+char *
+proxy_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;
+
+    if (strlen(x) < 31) x = palloc(p, 31);
+    ap_snprintf(x, strlen(x)+1, "%s, %.2d %s %d %.2d:%.2d:%.2d GMT", wday[wk], mday,
+           months[mon], year, hour, min, sec);
+    return x;
+}
+
+/*
+ * Reads headers from a buffer and returns an array of headers.
+ * Returns NULL on file error
+ */
+array_header *
+proxy_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;
+}
+
+long int
+proxy_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;
+
+    /* Since we are reading from one buffer and writing to another,
+     * it is unsafe to do a soft_timeout here, at least until the proxy
+     * has its own timeout handler which can set both buffers to EOUT.
+     */
+    hard_timeout("proxy send body", r);
+
+    while (!con->aborted && f != NULL) {
+       n = bread(f, buf, IOBUFSIZE);
+       if (n == -1) /* input error */
+       {
+           if (f2 != NULL) f2 = proxy_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 = proxy_cache_error(c);
+       
+        while(n && !con->aborted) {
+            w = bwrite(con->client, &buf[o], n);
+            if (w <= 0) {
+                if (f2 != NULL) {
+                    pclosef(c->req->pool, c->fp->fd);
+                    c->fp = NULL; 
+                    unlink(c->tempfile);
+                }
+                break;
+            }
+           reset_timeout(r); /* reset timeout after successful write */
+            n-=w;
+            o+=w;
+        }
+    }
+    if (!con->aborted)
+        bflush(con->client);
+    
+    kill_timeout(r);
+    return total_bytes_sent;
+}
+
+/*
+ * Read a header from the array, returning the first entry
+ */
+struct hdr_entry *
+proxy_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;
+}
+
+/*
+ * 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
+ */
+struct hdr_entry *
+proxy_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;
+}
+
+void
+proxy_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;
+}
+
+/*
+ * Sends response line and headers
+ * A timeout should be set before calling this routine.
+ */
+void
+proxy_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.
+ */
+int
+proxy_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;
+}
+
+void
+proxy_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';
+}
+
+/*
+ * Converts 8 hex digits to a time integer
+ */
+int
+proxy_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
+ */
+void
+proxy_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';
+}
+
+void
+proxy_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);
+}
+
+BUFF *
+proxy_cache_error(struct cache_req *c)
+{
+    proxy_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;
+}
+
+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);
+    soft_timeout("proxy error", 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);
+
+    kill_timeout(r);
+    return OK;
+}
+
+/*
+ * This routine returns its own error message
+ */
+const char *
+proxy_host2addr(const char *host, struct hostent *reqhp)
+{
+    int i;
+    struct hostent *hp;
+    static struct hostent hpbuf;
+    static u_long ipaddr;
+    static char* charpbuf[2];
+
+    for (i=0; host[i] != '\0'; i++)
+       if (!isdigit(host[i]) && host[i] != '.')
+           break;
+
+    if (host[i] != '\0')
+    {
+       hp = gethostbyname(host);
+       if (hp == NULL)
+           return "Host not found";
+    } else
+    {
+       ipaddr = inet_addr(host);
+       hp = gethostbyaddr((char *)&ipaddr, sizeof(u_long), AF_INET);
+       if (hp == NULL) {
+           memset(&hpbuf, 0, sizeof(hpbuf));
+           hpbuf.h_name = 0;
+           hpbuf.h_addrtype = AF_INET;
+           hpbuf.h_length = sizeof(u_long);
+           hpbuf.h_addr_list = charpbuf;
+           hpbuf.h_addr_list[0] = (char*)&ipaddr;
+           hpbuf.h_addr_list[1] = 0;
+           hp = &hpbuf;
+       }
+    }
+    memcpy(reqhp, hp, sizeof(struct hostent));
+    return NULL;
+}
+
+int
+proxy_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) proxy_log_uerror("connect", NULL, NULL, r->server);
+    kill_timeout(r);
+
+    return i;
+}
+
diff --git a/APACHE_1_2_X/src/modules/standard/mod_access.c b/APACHE_1_2_X/src/modules/standard/mod_access.c
new file mode 100644 (file)
index 0000000..eb35238
--- /dev/null
@@ -0,0 +1,283 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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"
+#include "http_request.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;
+}
+
+const 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;
+}
+
+const 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 (strcasecmp(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] == '.');
+}
+
+static int is_ip(const char *host)
+{
+    while ((*host == '.') || isdigit(*host))
+        host++;
+    return (*host == '\0');
+}
+
+int find_allowdeny (request_rec *r, array_header *a, int method)
+{
+    allowdeny *ap = (allowdeny *)a->elts;
+    int mmask = (1 << method);
+    int i;
+    int gothost = 0;
+    const char *remotehost = NULL;
+
+    for (i = 0; i < a->nelts; ++i) {
+        if (!(mmask & ap[i].limited))
+           continue;
+
+       if (!strncmp(ap[i].from,"env=",4) && table_get(r->subprocess_env,ap[i].from+4))
+           return 1;
+           
+        if (ap[i].from && !strcmp(ap[i].from, "user-agents")) {
+           char * this_agent = table_get(r->headers_in, "User-Agent");
+           int j;
+  
+           if (!this_agent) return 0;
+  
+           for (j = i+1; j < a->nelts; ++j) {
+               if (strstr(this_agent, ap[j].from)) return 1;
+           }
+           return 0;
+       }
+       
+       if (!strcmp (ap[i].from, "all"))
+           return 1;
+
+       if (!gothost) {
+           remotehost = get_remote_host(r->connection, r->per_dir_config,
+                                        REMOTE_HOST);
+
+           if ((remotehost == NULL) || is_ip(remotehost))
+               gothost = 1;
+           else
+               gothost = 2;
+       }
+
+        if ((gothost == 2) && 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 && (
+        satisfies(r) != SATISFY_ANY || !some_auth_required(r)
+    )) {
+       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 */
+   NULL                                /* header parser */
+};
diff --git a/APACHE_1_2_X/src/modules/standard/mod_actions.c b/APACHE_1_2_X/src/modules/standard/mod_actions.c
new file mode 100644 (file)
index 0000000..5701470
--- /dev/null
@@ -0,0 +1,219 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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 is 
+ * requested. 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;
+}
+
+const char *add_action(cmd_parms *cmd, action_dir_config *m, char *type,
+                      char *script)
+{
+    table_set (m->action_types, type, script);
+    return NULL;
+}
+
+const 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;
+
+    /* Set allowed stuff */
+    if (conf->get) r->allowed |= (1 << M_GET);
+    if (conf->post) r->allowed |= (1 << M_POST);
+    if (conf->put) r->allowed |= (1 << M_PUT);
+    if (conf->delete) r->allowed |= (1 << M_DELETE);
+
+    /* 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 ((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 */
+   NULL                                /* header parser */
+};
diff --git a/APACHE_1_2_X/src/modules/standard/mod_alias.c b/APACHE_1_2_X/src/modules/standard/mod_alias.c
new file mode 100644 (file)
index 0000000..2d96fd7
--- /dev/null
@@ -0,0 +1,329 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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;
+    int redir_status;          /* 301, 302, 303, 410, etc */
+} alias_entry;
+
+typedef struct {
+    array_header *aliases;
+    array_header *redirects;
+} alias_server_conf;
+
+typedef struct {
+    array_header *redirects;
+} alias_dir_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 *create_alias_dir_config (pool *p, char *d)
+{
+    alias_dir_conf *a =
+      (alias_dir_conf *)pcalloc (p, sizeof(alias_dir_conf));
+    a->redirects = make_array (p, 2, 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;
+}
+
+void *merge_alias_dir_config (pool *p, void *basev, void *overridesv)
+{
+    alias_dir_conf *a =
+      (alias_dir_conf *)pcalloc (p, sizeof(alias_dir_conf));
+    alias_dir_conf *base = (alias_dir_conf *)basev,
+      *overrides = (alias_dir_conf *)overridesv;
+    a->redirects = append_arrays (p, overrides->redirects, base->redirects);
+    return a;
+}
+
+const 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;
+}
+
+const char *add_redirect(cmd_parms *cmd, alias_dir_conf *dirconf, char *arg1,
+                        char *arg2, char *arg3)
+{
+    alias_entry *new;
+    server_rec *s = cmd->server;
+    alias_server_conf *serverconf =
+        (alias_server_conf *)get_module_config(s->module_config,&alias_module);
+    int status = (int)cmd->info;
+    char *f = arg2;
+    char *url = arg3;
+
+    if (!strcasecmp(arg1, "gone"))
+       status = HTTP_GONE;
+    else if (!strcasecmp(arg1, "permanent"))
+       status = HTTP_MOVED_PERMANENTLY;
+    else if (!strcasecmp(arg1, "temp"))
+       status = HTTP_MOVED_TEMPORARILY;
+    else if (!strcasecmp(arg1, "seeother"))
+       status = HTTP_SEE_OTHER;
+    else if (isdigit(*arg1))
+       status = atoi(arg1);
+    else {
+       f = arg1;
+       url = arg2;
+    }
+
+    if (is_HTTP_REDIRECT(status)) {
+       if (!url) return "URL to redirect to is missing";
+       if (!is_url (url)) return "Redirect to non-URL";
+    }
+    else {
+       if (url) return "Redirect URL not valid for this status";
+    }
+
+    if ( cmd->path )
+        new = push_array (dirconf->redirects);
+    else
+        new = push_array (serverconf->redirects);
+
+    new->fake = f; new->real = url;
+    new->redir_status = status;
+    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, (void*)HTTP_MOVED_TEMPORARILY, 
+    OR_FILEINFO, TAKE23, 
+    "an optional status, then document to be redirected and destination URL" },
+{ "RedirectTemp", add_redirect, (void*)HTTP_MOVED_TEMPORARILY, 
+    OR_FILEINFO, TAKE2, 
+    "a document to be redirected, then the destination URL" },
+{ "RedirectPermanent", add_redirect, (void*)HTTP_MOVED_PERMANENTLY, 
+    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, int *status)
+{
+    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);
+           }
+
+           *status = p->redir_status;
+
+           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 *serverconf =
+        (alias_server_conf *)get_module_config(sconf, &alias_module);
+    char *ret;
+    int status;
+
+#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 DECLINED;
+
+    if ((ret = try_alias_list (r, serverconf->redirects, 1, &status)) != NULL) {
+       if (is_HTTP_REDIRECT(status)) {
+           /* include QUERY_STRING if any */
+           if (r->args) {
+               ret = pstrcat (r->pool, ret, "?", r->args, NULL);
+           }
+           table_set (r->headers_out, "Location", ret);
+       }
+        return status;
+    }
+    
+    if ((ret = try_alias_list (r, serverconf->aliases, 0, &status)) != NULL) {
+        r->filename = ret;
+        return OK;
+    }
+    
+    return DECLINED;
+}
+
+int fixup_redir(request_rec *r)
+{
+    void *dconf = r->per_dir_config;
+    alias_dir_conf *dirconf =
+        (alias_dir_conf *)get_module_config(dconf, &alias_module);
+    char *ret;
+    int status;
+
+    /* It may have changed since last time, so try again */
+
+    if ((ret = try_alias_list (r, dirconf->redirects, 1, &status)) != NULL) {
+       if (is_HTTP_REDIRECT(status))
+           table_set (r->headers_out, "Location", ret);
+        return status;
+    }
+
+    return DECLINED;
+}
+
+module alias_module = {
+   STANDARD_MODULE_STUFF,
+   NULL,                       /* initializer */
+   create_alias_dir_config,    /* dir config creater */
+   merge_alias_dir_config,     /* 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 */
+   NULL                                /* header parser */
+};
diff --git a/APACHE_1_2_X/src/modules/standard/mod_asis.c b/APACHE_1_2_X/src/modules/standard/mod_asis.c
new file mode 100644 (file)
index 0000000..93c590a
--- /dev/null
@@ -0,0 +1,130 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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 = pfopen (r->pool, 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 == HTTP_OK) || is_HTTP_REDIRECT(r->status))) {
+
+        pfclose(r->pool, f);
+
+        /* Internal redirect -- fake-up a pseudo-request */
+        r->status = HTTP_OK;
+
+       /* 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;
+    }
+    
+    send_http_header (r);
+    if (!r->header_only) send_fd (f, r);
+
+    pfclose(r->pool, 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 */
+   NULL                                /* header parser */
+};
diff --git a/APACHE_1_2_X/src/modules/standard/mod_auth.c b/APACHE_1_2_X/src/modules/standard/mod_auth.c
new file mode 100644 (file)
index 0000000..acacaf0
--- /dev/null
@@ -0,0 +1,298 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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 Apache by rst.
+ *
+ * dirkx - Added Authoritative control to allow passing on to lower
+ *        modules if and only if the user-id is not known to this
+ *        module. A known user with a faulty or absent password still
+ *        causes an AuthRequired. The default is 'Authoritative', i.e.
+ *        no control is passed along.
+ */
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_core.h"
+#include "http_log.h"
+#include "http_protocol.h"
+#if defined(HAVE_CRYPT_H)
+#include <crypt.h>
+#endif
+
+typedef struct auth_config_struct {
+    char *auth_pwfile;
+    char *auth_grpfile;
+    int auth_authoritative;
+} auth_config_rec;
+
+void *create_auth_dir_config (pool *p, char *d)
+{
+    auth_config_rec *sec =
+       (auth_config_rec *) pcalloc (p, sizeof(auth_config_rec));
+    sec->auth_pwfile = NULL; /* just to illustrate the default really */ 
+    sec->auth_grpfile = NULL; /* unless you have a broken HP cc */
+    sec->auth_authoritative = 1; /* keep the fortress secure by default */
+    return sec;
+}
+
+const char *set_auth_slot (cmd_parms *cmd, void *offset, char *f, char *t)
+{
+    if (t && strcmp(t, "standard"))
+        return pstrcat(cmd->pool, "Invalid auth file type: ",  t, NULL);
+
+    return set_string_slot(cmd, offset, f);
+}
+
+command_rec auth_cmds[] = {
+{ "AuthUserFile", set_auth_slot,
+  (void*)XtOffsetOf(auth_config_rec,auth_pwfile), OR_AUTHCFG, TAKE12, NULL },
+{ "AuthGroupFile", set_auth_slot,
+  (void*)XtOffsetOf(auth_config_rec,auth_grpfile), OR_AUTHCFG, TAKE12, NULL },
+{ "AuthAuthoritative", set_flag_slot,
+  (void*)XtOffsetOf(auth_config_rec,auth_authoritative), 
+    OR_AUTHCFG, FLAG, 
+   "Set to 'no' to allow access control to be passed along to lower modules if the UserID is not known to this module" },
+{ NULL }
+};
+
+module auth_module;
+
+char *get_pw(request_rec *r, char *user, char *auth_pwfile)
+{
+    FILE *f;
+    char l[MAX_STRING_LEN];
+    const 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];
+    const 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))) {
+       if (!(sec->auth_authoritative))
+           return DECLINED;
+        ap_snprintf(errstr, sizeof(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))) {
+        ap_snprintf(errstr, sizeof(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;
+    const 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;
+
+    if (!(sec -> auth_authoritative))
+      return DECLINED;
+
+    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 */
+   NULL                                /* header parser */
+};
diff --git a/APACHE_1_2_X/src/modules/standard/mod_auth_anon.c b/APACHE_1_2_X/src/modules/standard/mod_auth_anon.c
new file mode 100644 (file)
index 0000000..2a979e6
--- /dev/null
@@ -0,0 +1,299 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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 Apache by rst.
+ *
+ * Version 0.5 May 1996
+ *
+ * Modified 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_Authoritative      [ 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_authoritative;
+
+} 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_authoritative        =0;
+    return sec;
+}
+
+const char *anon_set_passwd_flag (cmd_parms *cmd, 
+       anon_auth_config_rec *sec, int arg) {
+    sec->auth_anon_mustemail=arg;
+    return NULL;
+}
+
+const char *anon_set_userid_flag (cmd_parms *cmd, 
+       anon_auth_config_rec *sec, int arg) {
+    sec->auth_anon_nouserid=arg;
+    return NULL;
+}
+const char *anon_set_logemail_flag (cmd_parms *cmd, 
+       anon_auth_config_rec *sec, int arg) {
+    sec->auth_anon_logemail=arg;
+    return NULL;
+}
+const char *anon_set_verifyemail_flag (cmd_parms *cmd, 
+       anon_auth_config_rec *sec, int arg) {
+    sec->auth_anon_verifyemail=arg;
+    return NULL;
+}
+const char *anon_set_authoritative_flag (cmd_parms *cmd, 
+       anon_auth_config_rec *sec, int arg) {
+    sec->auth_anon_authoritative=arg;
+    return NULL;
+}
+
+const 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_Authoritative", anon_set_authoritative_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) {
+       ap_snprintf(errstr, sizeof(errstr), "Anonymous: Passwd <%s> Accepted", 
+                       send_pw ? send_pw : "\'none\'");
+       log_error (errstr, r->server );
+      }
+      return OK;
+    } else {
+        if (sec->auth_anon_authoritative) {
+       ap_snprintf(errstr, sizeof(errstr),
+               "Anonymous: Authoritative, 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 */
+   NULL                                /* header parser */
+};
diff --git a/APACHE_1_2_X/src/modules/standard/mod_auth_db.c b/APACHE_1_2_X/src/modules/standard/mod_auth_db.c
new file mode 100644 (file)
index 0000000..76d21d7
--- /dev/null
@@ -0,0 +1,303 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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.
+ *
+ * dirkx - Added Authoritative control to allow passing on to lower  
+ *         modules if and only if the user-id is not known to this
+ *         module. A known user with a faulty or absent password still
+ *         causes an AuthRequired. The default is 'Authoritative', i.e.
+ *         no control is passed along.
+ */
+
+#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;
+    int   auth_dbauthoritative;
+} db_auth_config_rec;
+
+void *create_db_auth_dir_config (pool *p, char *d)
+{
+    db_auth_config_rec *sec
+       = (db_auth_config_rec *)pcalloc (p, sizeof(db_auth_config_rec));
+    sec->auth_dbpwfile = NULL;
+    sec->auth_dbgrpfile = NULL;
+    sec->auth_dbauthoritative=1; /* fortress is secure by default */
+    return sec;
+}
+
+const char *set_db_slot (cmd_parms *cmd, void *offset, char *f, char *t)
+{
+    if (!t || strcmp(t, "db"))
+        return DECLINE_CMD;
+
+    return set_string_slot(cmd, offset, f);
+}
+
+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 },
+{ "AuthUserFile", set_db_slot,
+    (void*)XtOffsetOf(db_auth_config_rec, auth_dbpwfile),
+    OR_AUTHCFG, TAKE12, NULL },
+{ "AuthGroupFile", set_db_slot,
+    (void*)XtOffsetOf(db_auth_config_rec, auth_dbgrpfile),
+    OR_AUTHCFG, TAKE12, NULL },
+{ "AuthDBAuthoritative", set_flag_slot,
+    (void*)XtOffsetOf(db_auth_config_rec, auth_dbauthoritative),
+    OR_AUTHCFG, FLAG, 
+    "Set to 'no' to allow access control to be passed along to lower modules if the userID is not known to this module" },
+{ 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))) {
+       if (!(sec -> auth_dbauthoritative))
+           return DECLINED; 
+        ap_snprintf(errstr, sizeof(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))) {
+        ap_snprintf(errstr, sizeof(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;
+    const char *t;
+    char *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) {
+          const char *orig_groups,*groups;
+           char *v;
+
+           if (!(groups = get_db_grp(r, user, sec->auth_dbgrpfile))) {
+              if (!(sec->auth_dbauthoritative))
+                return DECLINED;
+               ap_snprintf(errstr, sizeof(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;
+               }
+           }
+           ap_snprintf(errstr, sizeof(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 */
+   NULL                                /* header parser */
+};
diff --git a/APACHE_1_2_X/src/modules/standard/mod_auth_dbm.c b/APACHE_1_2_X/src/modules/standard/mod_auth_dbm.c
new file mode 100644 (file)
index 0000000..d383264
--- /dev/null
@@ -0,0 +1,291 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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 Apache by rst.
+ *
+ * dirkx - Added Authoritative control to allow passing on to lower  
+ *         modules if and only if the user-id is not known to this
+ *         module. A known user with a faulty or absent password still
+ *         causes an AuthRequired. The default is 'Authoritative', i.e.
+ *         no control is passed along.
+ */
+
+#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;
+    int   auth_dbmauthoritative;
+
+} dbm_auth_config_rec;
+
+void *create_dbm_auth_dir_config (pool *p, char *d)
+{
+    dbm_auth_config_rec *sec
+       = (dbm_auth_config_rec *)pcalloc (p, sizeof(dbm_auth_config_rec));
+
+    sec->auth_dbmpwfile = NULL;
+    sec->auth_dbmgrpfile = NULL;
+    sec->auth_dbmauthoritative = 1; /* fortress is secure by default */
+
+    return sec;
+}
+
+const char *set_dbm_slot (cmd_parms *cmd, void *offset, char *f, char *t)
+{
+    if (!t || strcmp(t, "dbm"))
+       return DECLINE_CMD;
+
+    return set_string_slot(cmd, offset, f);
+}
+
+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 },
+{ "AuthUserFile", set_dbm_slot,
+    (void*)XtOffsetOf(dbm_auth_config_rec, auth_dbmpwfile),
+    OR_AUTHCFG, TAKE12, NULL },
+{ "AuthGroupFile", set_dbm_slot,
+    (void*)XtOffsetOf(dbm_auth_config_rec, auth_dbmgrpfile),
+    OR_AUTHCFG, TAKE12, NULL },
+{ "AuthDBMAuthoritative", set_flag_slot,
+    (void*)XtOffsetOf(dbm_auth_config_rec, auth_dbmauthoritative),
+    OR_AUTHCFG, FLAG, "Set to 'no' to allow access control to be passed along to lower modules, if the UserID is not known in this module" },
+{ 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))) {
+       if (!(sec->auth_dbmauthoritative))
+           return DECLINED;
+        ap_snprintf(errstr, sizeof(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))) {
+        ap_snprintf(errstr, sizeof(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;
+    const char *t;
+    char *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) {
+           const char *orig_groups,*groups;
+          char *v;
+
+           if (!(groups = get_dbm_grp(r, user, sec->auth_dbmgrpfile))) {
+              if (!(sec->auth_dbmauthoritative))
+                  return DECLINED;
+               ap_snprintf(errstr, sizeof(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;
+               }
+           }
+           ap_snprintf(errstr, sizeof(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 */
+   NULL                                /* header parser */
+};
diff --git a/APACHE_1_2_X/src/modules/standard/mod_auth_msql.c b/APACHE_1_2_X/src/modules/standard/mod_auth_msql.c
new file mode 100644 (file)
index 0000000..dc80642
--- /dev/null
@@ -0,0 +1,996 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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 Apache 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_Authoritative        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 Authoritative 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_Authoritative <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  Authoritative 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_LEN claims. 
+ *        1.0  removed some error check as they where already done elsehwere
+ *             NumFields -> NumRows (Thanks Vitek). More stack memory.
+ *        1.1  no logging of empty password strings.
+ *        1.2  Problem with the Backward vitek which cause it to check
+ *             even if msql_auth was not configured; Also more carefull
+ *             with the authoritative stuff; caught by thomas@marvin.calvacom.fr.
+ *        1.3  Even more changes to get it right; that BACKWARD thing was a bad
+ *             idea. 
+ */
+
+
+#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_authoritative;
+    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_authoritative = 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;
+}
+
+const char *set_passwd_flag (cmd_parms *cmd, msql_auth_config_rec *sec, int arg) {
+    sec->auth_msql_nopasswd=arg;
+    return NULL;
+}
+
+const char *set_authoritative_flag (cmd_parms *cmd, msql_auth_config_rec *sec, int arg) {
+    sec->auth_msql_authoritative=arg;
+    return NULL;
+}
+
+const char *set_crypted_password_flag (cmd_parms *cmd, msql_auth_config_rec *sec , int arg) {
+    sec->auth_msql_encrypted = arg;
+    return NULL;
+}
+
+const 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_Authoritative", set_authoritative_flag, NULL, OR_AUTHCFG, FLAG,
+       "When 'on' the mSQL database is taken to be authoritative 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)) {
+       ap_snprintf(msql_errstr, MAX_STRING_LEN, 
+               "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) {
+               ap_snprintf (msql_errstr, MAX_STRING_LEN,
+                       "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 ) {
+               ap_snprintf (msql_errstr, MAX_STRING_LEN,
+                       "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 ) {
+               ap_snprintf (msql_errstr, MAX_STRING_LEN,
+                       "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())) {
+               ap_snprintf (msql_errstr, MAX_STRING_LEN,
+                       "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.
+           */
+          ap_snprintf (msql_errstr, MAX_STRING_LEN,
+               "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))) {
+                               ap_snprintf (msql_errstr, MAX_STRING_LEN,
+                                       "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)
+          ) {
+               ap_snprintf(msql_errstr, MAX_STRING_LEN,
+                       "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))) {
+               ap_snprintf(msql_errstr, MAX_STRING_LEN,
+                       "mSQL: Could not cope/escape the '%s' user_id value; ",user);
+               return NULL;
+       };
+       ap_snprintf(query, sizeof(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)
+          ) {
+               ap_snprintf(msql_errstr, MAX_STRING_LEN,
+                       "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))) {
+               ap_snprintf(msql_errstr, MAX_STRING_LEN,
+                       "mSQL: Could not cope/escape the '%s' user_id value",user);
+
+               return NULL;
+       };
+       if (!(msql_escape(esc_group, group,msql_errstr))) {
+               ap_snprintf(msql_errstr, MAX_STRING_LEN,
+                       "mSQL: Could not cope/escape the '%s' group_id value",group);
+
+               return NULL;
+       };
+
+       ap_snprintf(query, sizeof(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];
+        /* msql_errstr must be MAX_STRING_LEN in size unless you
+         * change size in ap_snprintf() calls
+         */
+    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.
+     * We no longer check on the user field name; to avoid problems
+     * with Backward VITEK.
+     */
+    if (!sec->auth_msql_pwd_table) 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_authoritative) {
+                  /* insist that the user is in the database
+                   */
+                  ap_snprintf(msql_errstr, MAX_STRING_LEN,
+                       "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 authoritative */
+               }; /* 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))) {
+/*
+        ap_snprintf(msql_errstr, MAX_STRING_LEN,
+               "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))) {
+        ap_snprintf(msql_errstr, MAX_STRING_LEN,
+               "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)) {
+        ap_snprintf(msql_errstr, MAX_STRING_LEN,
+               "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];
+       /* msql_errstr must be MAX_STRING_LEN in size unless you
+        * change size in ap_snprintf() calls
+        */
+    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;
+    const char *t, *w;
+    msql_errstr[0]='\0';
+
+    /* If we are not configured, ignore */
+    if (!sec->auth_msql_pwd_table) return DECLINED;
+
+    if (!reqs_arr) {
+       if (sec->auth_msql_authoritative) {
+               ap_snprintf(msql_errstr, MAX_STRING_LEN, "user %s denied, no access rules specified (MSQL-Authoritative) ",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_authoritative) && ( user_result != OK)) {
+               ap_snprintf(msql_errstr, MAX_STRING_LEN, "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_authoritative) && (group_result != OK) ) {
+               ap_snprintf(msql_errstr, MAX_STRING_LEN, "user %s not in right groups (MSQL-Authoritative) ",user);
+               log_reason (msql_errstr, r->uri, r);
+               note_basic_auth_failure(r);
+               return AUTH_REQUIRED;
+               };
+           };
+
+        if(!strcmp(w,"valid-user")) {
+            user_result= OK;
+           };
+        }
+
+    /* Get serious if we are authoritative, previous
+     * returns are only if msql yielded a correct result. 
+     * This really is not needed.
+     */
+    if (((group_result == AUTH_REQUIRED) || (user_result == AUTH_REQUIRED)) && (sec->auth_msql_authoritative) ) {
+        ap_snprintf(msql_errstr, MAX_STRING_LEN, "mSQL-Authoritative: Access denied on %s %s rule(s) ", 
+               (group_result == AUTH_REQUIRED) ? "USER" : "", 
+               (user_result == AUTH_REQUIRED) ? "GROUP" : ""
+               );
+       log_reason (msql_errstr, r->uri, r);
+       return AUTH_REQUIRED;
+       };
+
+    if ( (user_result == OK) || (group_result == OK))
+       return OK;
+
+    return DECLINED;
+}
+
+
+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 */
+   NULL                                /* header parser */
+};
diff --git a/APACHE_1_2_X/src/modules/standard/mod_cern_meta.c b/APACHE_1_2_X/src/modules/standard/mod_cern_meta.c
new file mode 100644 (file)
index 0000000..321175f
--- /dev/null
@@ -0,0 +1,331 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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;
+}   
+
+const 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;
+}
+
+const 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 */
+   NULL                                /* header parser */
+};
diff --git a/APACHE_1_2_X/src/modules/standard/mod_cgi.c b/APACHE_1_2_X/src/modules/standard/mod_cgi.c
new file mode 100644 (file)
index 0000000..ceed899
--- /dev/null
@@ -0,0 +1,574 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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"
+#include "http_conf_globals.h"
+
+module cgi_module;
+
+/* 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"));
+}
+
+/* Configuration stuff */
+
+#define DEFAULT_LOGBYTES 10385760
+#define DEFAULT_BUFBYTES 1024
+
+typedef struct {
+    char *logname;
+    long logbytes;
+    int bufbytes;
+} cgi_server_conf;
+
+void *create_cgi_config (pool *p, server_rec *s)
+{
+    cgi_server_conf *c = 
+      (cgi_server_conf *)pcalloc (p, sizeof(cgi_server_conf));
+
+    c->logname = NULL;
+    c->logbytes = DEFAULT_LOGBYTES;
+    c->bufbytes = DEFAULT_BUFBYTES;
+
+    return c;
+}
+
+void *merge_cgi_config (pool *p, void *basev, void *overridesv)
+{
+    cgi_server_conf *base = (cgi_server_conf *)basev,
+      *overrides = (cgi_server_conf *)overridesv;
+
+    return overrides->logname ? overrides : base;
+}
+
+const char *set_scriptlog (cmd_parms *cmd, void *dummy, char *arg) {
+    server_rec *s = cmd->server;
+    cgi_server_conf *conf = 
+      (cgi_server_conf *)get_module_config(s->module_config, &cgi_module);
+
+    conf->logname = arg;
+    return NULL;
+}
+
+const char *set_scriptlog_length (cmd_parms *cmd, void *dummy, char *arg) {
+    server_rec *s = cmd->server;
+    cgi_server_conf *conf = 
+      (cgi_server_conf *)get_module_config(s->module_config, &cgi_module);
+
+    conf->logbytes = atol (arg);
+    return NULL;
+}
+
+const char *set_scriptlog_buffer (cmd_parms *cmd, void *dummy, char *arg) {
+    server_rec *s = cmd->server;
+    cgi_server_conf *conf = 
+      (cgi_server_conf *)get_module_config(s->module_config, &cgi_module);
+
+    conf->bufbytes = atoi (arg);
+    return NULL;
+}
+
+command_rec cgi_cmds[] = {
+{ "ScriptLog", set_scriptlog, NULL, RSRC_CONF, TAKE1,
+  "the name of a log for script debugging info"},
+{ "ScriptLogLength", set_scriptlog_length, NULL, RSRC_CONF, TAKE1,
+  "the maximum length (in bytes) of the script debug log"},
+{ "ScriptLogBuffer", set_scriptlog_buffer, NULL, RSRC_CONF, TAKE1,
+  "the maximum size (in bytes) to record of a POST request"},
+{ NULL}
+};
+
+static int log_scripterror(request_rec *r, cgi_server_conf *conf, int ret,
+                   char *error)
+{
+    FILE *f;
+
+    log_reason(error, r->filename, r);
+
+    if (!conf->logname ||
+       ((stat(server_root_relative(r->pool, conf->logname), &r->finfo) == 0)
+       && (r->finfo.st_size > conf->logbytes)) ||
+       ((f = pfopen(r->pool, server_root_relative(r->pool, conf->logname),
+                    "a")) == NULL)) {
+      return ret;
+    }
+
+    /* "%% [Wed Jun 19 10:53:21 1996] GET /cgi-bin/printenv HTTP/1.0" */
+    fprintf(f, "%%%% [%s] %s %s%s%s %s\n", get_time(), r->method, r->uri,
+           r->args ? "?" : "", r->args ? r->args : "", r->protocol);
+    /* "%% 500 /usr/local/etc/httpd/cgi-bin */
+    fprintf(f, "%%%% %d %s\n", ret, r->filename);
+
+    fprintf(f, "%%error\n%s\n", error);
+
+    pfclose(r->pool, f);
+    return ret;
+}
+
+static int log_script(request_rec *r, cgi_server_conf *conf, int ret,
+              char *dbuf, char *sbuf, FILE *script_in, FILE *script_err)
+{
+    table *hdrs_arr = r->headers_in;
+    table_entry *hdrs = (table_entry *)hdrs_arr->elts;
+    char argsbuffer[HUGE_STRING_LEN];
+    FILE *f;
+    int i;
+
+    if (!conf->logname ||
+       ((stat(server_root_relative(r->pool, conf->logname), &r->finfo) == 0)
+       && (r->finfo.st_size > conf->logbytes)) ||
+       ((f = pfopen(r->pool, server_root_relative(r->pool, conf->logname),
+                    "a")) == NULL)) {
+      /* Soak up script output */
+      while (fgets(argsbuffer, MAX_STRING_LEN-1, script_in) != NULL)
+       continue;
+      while (fgets(argsbuffer, MAX_STRING_LEN-1, script_err) != NULL)
+       continue;
+      return ret;
+    }
+
+    /* "%% [Wed Jun 19 10:53:21 1996] GET /cgi-bin/printenv HTTP/1.0" */
+    fprintf(f, "%%%% [%s] %s %s%s%s %s\n", get_time(), r->method, r->uri,
+           r->args ? "?" : "", r->args ? r->args : "", r->protocol);
+    /* "%% 500 /usr/local/etc/httpd/cgi-bin */
+    fprintf(f, "%%%% %d %s\n", ret, r->filename);
+
+    fputs("%request\n", f);
+    for (i = 0; i < hdrs_arr->nelts; ++i) {
+      if (!hdrs[i].key) continue;
+      fprintf(f, "%s: %s\n", hdrs[i].key, hdrs[i].val);
+    }
+    if ((r->method_number == M_POST || r->method_number == M_PUT)
+       && dbuf && *dbuf) {
+      fprintf(f, "\n%s\n", dbuf);
+    }
+
+    fputs("%response\n", f);
+    hdrs_arr = r->err_headers_out;
+    hdrs = (table_entry *)hdrs_arr->elts;
+
+    for (i = 0; i < hdrs_arr->nelts; ++i) {
+      if (!hdrs[i].key) continue;
+      fprintf(f, "%s: %s\n", hdrs[i].key, hdrs[i].val);
+    }
+
+    if (sbuf && *sbuf)
+      fprintf(f, "%s\n", sbuf);
+
+    *argsbuffer = '\0';
+    fgets(argsbuffer, HUGE_STRING_LEN-1, script_in);
+    if (*argsbuffer) {
+      fputs("%stdout\n", f);
+      fputs(argsbuffer, f);
+      while (fgets(argsbuffer, HUGE_STRING_LEN-1, script_in) != NULL)
+       fputs(argsbuffer, f);
+      fputs("\n", f);
+    }
+
+    *argsbuffer = '\0';
+    fgets(argsbuffer, HUGE_STRING_LEN-1, script_err);
+    if (*argsbuffer) {
+      fputs("%stderr\n", f);
+      fputs(argsbuffer, f);
+      while (fgets(argsbuffer, HUGE_STRING_LEN-1, script_err) != NULL)
+       fputs(argsbuffer, f);
+      fputs("\n", f);
+    }
+
+    pfclose(r->main ? r->main->pool : r->pool, script_in);
+    pfclose(r->main ? r->main->pool : r->pool, script_err);
+
+    pfclose(r->pool, f);
+    return ret;
+}
+
+/****************************************************************
+ *
+ * Actual CGI handling...
+ */
+
+
+struct cgi_child_stuff {
+    request_rec *r;
+    int nph;
+    int debug;
+    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);
+    if (!cld->debug)
+      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();
+    
+    call_exec(r, argv0, env, 0);
+
+    /* 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).
+     */
+    
+    ap_snprintf(err_string, sizeof(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 retval, nph, dbpos = 0;
+    char *argv0, *dbuf = NULL;
+    FILE *script_out, *script_in, *script_err;
+    char argsbuffer[HUGE_STRING_LEN];
+    int is_included = !strcmp (r->protocol, "INCLUDED");
+    void *sconf = r->server->module_config;
+    cgi_server_conf *conf =
+       (cgi_server_conf *)get_module_config(sconf, &cgi_module);
+
+    struct cgi_child_stuff cld;
+    pid_t child_pid;
+
+    if (r->method_number == M_OPTIONS) {
+        /* 99 out of 100 CGI scripts, this is all they support */
+        r->allowed |= (1 << M_GET);
+        r->allowed |= (1 << M_POST);
+       return DECLINED;
+    }
+
+    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))
+       return log_scripterror(r, conf, FORBIDDEN,
+                              "Options ExecCGI is off in this directory");
+    if (nph && is_included)
+       return log_scripterror(r, conf, FORBIDDEN,
+                              "attempt to include NPH CGI script");
+    
+    if (S_ISDIR(r->finfo.st_mode))
+       return log_scripterror(r, conf, FORBIDDEN,
+                              "attempt to invoke directory as script");
+#ifdef __EMX__
+    /* Allow for cgi files without the .EXE extension on them under OS/2 */
+    if (r->finfo.st_mode == 0) {
+        struct stat statbuf;
+
+        r->filename = pstrcat (r->pool, r->filename, ".EXE", NULL);
+
+        if ((stat(r->filename, &statbuf) != 0) || (!S_ISREG(statbuf.st_mode))) {
+            return log_scripterror(r, conf, NOT_FOUND,
+                                   "script not found or unable to stat");
+        }
+    }
+#else
+    if (r->finfo.st_mode == 0)
+       return log_scripterror(r, conf, NOT_FOUND,
+                              "script not found or unable to stat");
+#endif
+    if (!suexec_enabled) {
+        if (!can_exec(&r->finfo))
+            return log_scripterror(r, conf, FORBIDDEN,
+                                   "file permissions deny server execution");
+    }
+
+    if ((retval = setup_client_block(r, REQUEST_CHUNKED_ERROR)))
+       return retval;
+
+    add_common_vars (r);
+    cld.argv0 = argv0; cld.r = r; cld.nph = nph;
+    cld.debug = conf->logname ? 1 : 0;
+    
+    if (!(child_pid =
+         /*
+          * we spawn out of r->main if it's there so that we can avoid
+          * waiting for free_proc_chain to cleanup in the middle of an
+          * SSI request -djg
+          */
+         spawn_child_err (r->main ? r->main->pool : r->pool, cgi_child,
+                           (void *)&cld,
+                          nph ? just_wait : kill_after_timeout,
+#ifdef __EMX__
+                          &script_out, &script_in, &script_err))) {
+#else
+                          &script_out, nph ? NULL : &script_in,
+                          &script_err))) {
+#endif
+        log_reason ("couldn't spawn child process", r->filename, r);
+        return SERVER_ERROR;
+    }
+
+    /* 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).
+     */
+    
+     if (should_client_block(r)) {
+        void (*handler)();
+       int dbsize, len_read;
+
+       if (conf->logname) {
+           dbuf = pcalloc(r->pool, conf->bufbytes+1);
+           dbpos = 0;
+       }
+
+        hard_timeout ("copy script args", r);
+        handler = signal (SIGPIPE, SIG_IGN);
+    
+       while ((len_read =
+                get_client_block(r, argsbuffer, HUGE_STRING_LEN)) > 0)
+       {
+           if (conf->logname) {
+               if ((dbpos + len_read) > conf->bufbytes) {
+                   dbsize = conf->bufbytes - dbpos;
+               }
+                else {
+                    dbsize = len_read;
+                }
+                memcpy(dbuf + dbpos, argsbuffer, dbsize);
+               dbpos += dbsize;
+           }
+           reset_timeout(r);
+           if (fwrite(argsbuffer, sizeof(char), len_read, script_out)
+                   < (size_t)len_read) {
+               /* silly script stopped reading, soak up remaining message */
+               while (get_client_block(r, argsbuffer, HUGE_STRING_LEN) > 0)
+                   ; /* dump it */
+               break;
+           }
+       }
+
+       fflush (script_out);
+       signal (SIGPIPE, handler);
+       
+       kill_timeout (r);
+    }
+    
+    pfclose (r->main ? r->main->pool : r->pool, script_out);
+    
+    /* Handle script return... */
+    if (script_in && !nph) {
+        char *location, sbuf[MAX_STRING_LEN];
+       int ret;
+      
+        if ((ret = scan_script_header_err(r, script_in, sbuf)))
+           return log_script(r, conf, ret, dbuf, sbuf, script_in, script_err);
+       
+       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 (fread(argsbuffer, sizeof(char), HUGE_STRING_LEN, script_in)
+                  > 0)
+               continue;
+           while (fread(argsbuffer, sizeof(char), HUGE_STRING_LEN, script_err)
+                  > 0)
+               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;
+
+           /* We already read the message body (if any), so don't allow
+            * the redirected request to think it has one.  We can ignore 
+            * Transfer-Encoding, since we used REQUEST_CHUNKED_ERROR.
+            */
+           table_unset(r->headers_in, "Content-Length");
+
+           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;
+       }
+       
+       send_http_header(r);
+       if (!r->header_only)
+           send_fd(script_in, r);
+       pfclose (r->main ? r->main->pool : r->pool, script_in);
+
+       /* Soak up stderr */
+       soft_timeout("soaking script stderr", r);
+       while (!r->connection->aborted &&
+         (fread(argsbuffer, sizeof(char), HUGE_STRING_LEN, script_err) > 0))
+           continue;
+       kill_timeout(r);
+       pfclose (r->main ? r->main->pool : r->pool, script_err);
+    }
+
+    if (nph) {
+#ifdef __EMX__
+        while (fgets(argsbuffer, HUGE_STRING_LEN-1, script_in) != NULL) {
+            bputs(argsbuffer, r->connection->client);
+        }
+#else
+       waitpid(child_pid, (int*)0, 0);
+#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 */
+   create_cgi_config,          /* server config */
+   merge_cgi_config,           /* merge server config */
+   cgi_cmds,                   /* 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 */
+   NULL                                /* header parser */
+};
diff --git a/APACHE_1_2_X/src/modules/standard/mod_digest.c b/APACHE_1_2_X/src/modules/standard/mod_digest.c
new file mode 100644 (file)
index 0000000..3564403
--- /dev/null
@@ -0,0 +1,363 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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));
+}
+
+const char *set_digest_slot (cmd_parms *cmd, void *offset, char *f, char *t)
+{
+    if (t && strcmp(t, "standard"))
+       return pstrcat(cmd->pool, "Invalid auth file type: ",  t, NULL);
+
+    return set_string_slot(cmd, offset, f);
+}
+
+command_rec digest_cmds[] = {
+{ "AuthDigestFile", set_digest_slot,
+  (void*)XtOffsetOf(digest_config_rec,pwfile), OR_AUTHCFG, TAKE12, NULL },
+{ NULL }
+};
+
+module digest_module;
+
+char *get_hash(request_rec *r, char *user, char *auth_pwfile)
+{
+    FILE *f;
+    char l[MAX_STRING_LEN];
+    const char *rpw;
+    char *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) {
+  const 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))) {
+        ap_snprintf(errstr, sizeof(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))) {
+        ap_snprintf(errstr, sizeof(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;
+    const char *t;
+    char *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 */
+   NULL                                /* header parser */
+};
diff --git a/APACHE_1_2_X/src/modules/standard/mod_dir.c b/APACHE_1_2_X/src/modules/standard/mod_dir.c
new file mode 100644 (file)
index 0000000..bb803ec
--- /dev/null
@@ -0,0 +1,891 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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 Apache 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;
+}
+
+const 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;
+}
+
+const char *add_icon(cmd_parms *cmd, void *d, char *icon, char *to)
+{
+    char *iconbak = pstrdup (cmd->pool, icon);
+
+    if(icon[0] == '(') {
+        char *alt = getword_nc (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;
+}
+
+const 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;
+}
+
+const 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;
+}
+
+const 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;
+}
+
+const 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;
+}
+
+
+const 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;
+}
+
+const char *fancy_indexing (cmd_parms *cmd, void *d, int arg)
+{
+    return add_opts_int (cmd, d, arg? FANCY_INDEXING : 0);
+}
+
+const char *add_opts(cmd_parms *cmd, void *d, const 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 = NULL;
+    char *tmp;
+    int dir_opts = find_opts(dir_conf, r);
+
+    if(!(d=opendir(name))) {
+        log_reason ("Can't open directory for index", r->filename, r);
+        return HTTP_FORBIDDEN;
+    }
+
+    r->content_type = "text/html";
+    
+    send_http_header(r);
+
+    if (r->header_only) {
+       closedir (d);
+       return 0;
+    }
+    hard_timeout("send directory", r);
+
+    /* Spew HTML preamble */
+    
+    title_endp = title_name + strlen(title_name) - 1;
+
+    while (title_endp > title_name && *title_endp == '/')
+       *title_endp-- = '\0';
+    
+    rvputs
+       (
+           r,
+           "<HTML><HEAD>\n<TITLE>Index of ",
+           title_name,
+           "</TITLE>\n</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++;
+        }
+    }
+    if (num_ent > 0) {
+        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></HTML>\n", r);
+
+    kill_timeout(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);
+    const char *names_ptr = d->index_names ? d->index_names : DEFAULT_INDEX;
+    int allow_opts = allow_options (r);
+    int error_notfound = 0;
+
+    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 HTTP_MOVED_PERMANENTLY;
+    }
+
+    /* 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 == HTTP_OK && 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;
+       }
+
+       /* If the request returned a redirect, propagate it to the client */
+
+       if (is_HTTP_REDIRECT(rr->status) ||
+           (rr->status == HTTP_NOT_ACCEPTABLE && *names_ptr == '\0')) {
+
+           error_notfound = rr->status;
+           r->notes = overlay_tables(r->pool, r->notes, rr->notes);
+           r->headers_out = overlay_tables(r->pool, r->headers_out,
+                                                   rr->headers_out);
+           r->err_headers_out = overlay_tables(r->pool, r->err_headers_out,
+                                                       rr->err_headers_out);
+           destroy_sub_req(rr);
+           return error_notfound;
+       }
+            
+       /* If the request returned something other than 404 (or 200),
+        * it means the module encountered some sort of problem. To be
+        * secure, we should return the error, rather than create
+        * along a (possibly unsafe) directory index.
+        *
+        * So we store the error, and if none of the listed files
+        * exist, we return the last error response we got, instead
+        * of a directory listing.
+        */
+       if (rr->status && rr->status != HTTP_NOT_FOUND && rr->status != HTTP_OK)
+           error_notfound = rr->status;
+
+        destroy_sub_req (rr);
+    }
+
+    if (error_notfound)
+       return error_notfound;
+
+    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 {
+        log_reason ("Directory index forbidden by rule", r->filename, r);
+        return HTTP_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 */
+   NULL                                /* header parser */
+};
diff --git a/APACHE_1_2_X/src/modules/standard/mod_dld.c b/APACHE_1_2_X/src/modules/standard/mod_dld.c
new file mode 100644 (file)
index 0000000..ac6ff33
--- /dev/null
@@ -0,0 +1,190 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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 */
+   NULL                                /* header parser */
+};
diff --git a/APACHE_1_2_X/src/modules/standard/mod_env.c b/APACHE_1_2_X/src/modules/standard/mod_env.c
new file mode 100644 (file)
index 0000000..8ae6970
--- /dev/null
@@ -0,0 +1,261 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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 FOO
+ *             SetEnv FOO override
+ *          Causes FOO to take the value 'override'.
+ * 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;
+    const char *uenv, *unset;
+
+      /* 
+       * 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 ); 
+    }
+
+    unset = add->unsetenv;
+    uenv = getword_conf( p, &unset );
+    while ( uenv[0] != '\0' ) {
+       table_unset( new_table, uenv );
+       uenv = getword_conf( p, &unset );
+    }
+
+    new->vars = new_table;
+
+    new->vars_present = base->vars_present || add->vars_present;
+
+    return new;
+}
+
+const char *add_env_module_vars_passed (cmd_parms *cmd, char *struct_ptr,
+                                 const 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;
+}
+
+const char *add_env_module_vars_set (cmd_parms *cmd, char *struct_ptr,
+                                    const 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;
+}
+
+const 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 */
+   NULL                                /* header parser */
+};
diff --git a/APACHE_1_2_X/src/modules/standard/mod_expires.c b/APACHE_1_2_X/src/modules/standard/mod_expires.c
new file mode 100644 (file)
index 0000000..226726a
--- /dev/null
@@ -0,0 +1,477 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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_expires.c
+ * version 0.0.11
+ * status beta
+ * 
+ * Andrew Wilson <Andrew.Wilson@cm.cf.ac.uk> 26.Jan.96
+ *
+ * This module allows you to control the form of the Expires: header
+ * that Apache issues for each access.  Directives can appear in
+ * configuration files or in .htaccess files so expiry semantics can
+ * be defined on a per-directory basis.  
+ *
+ * DIRECTIVE SYNTAX
+ *
+ * Valid directives are:
+ *
+ *     ExpiresActive on | off
+ *     ExpiresDefault <code><seconds>
+ *     ExpiresByType type/encoding <code><seconds>
+ *
+ * Valid values for <code> are:
+ *
+ *     'M'     expires header shows file modification date + <seconds>
+ *     'A'     expires header shows access time + <seconds>
+ *
+ *              [I'm not sure which of these is best under different
+ *              circumstances, I guess it's for other people to explore.
+ *             The effects may be indistinguishable for a number of cases]
+ *
+ * <seconds> should be an integer value [acceptable to atoi()]
+ *
+ * There is NO space between the <code> and <seconds>.
+ *
+ * For example, a directory which contains information which changes
+ * frequently might contain:
+ *
+ *     # reports generated by cron every hour.  don't let caches
+ *     # hold onto stale information
+ *     ExpiresDefault M3600
+ *
+ * Another example, our html pages can change all the time, the gifs
+ * tend not to change often:
+ * 
+ *     # pages are hot (1 week), images are cold (1 month)
+ *     ExpiresByType text/html A604800
+ *     ExpiresByType image/gif A2592000
+ *
+ * Expires can be turned on for all URLs on the server by placing the
+ * following directive in a conf file:
+ *
+ *     ExpiresActive on
+ *
+ * ExpiresActive can also appear in .htaccess files, enabling the
+ * behaviour to be turned on or off for each chosen directory.
+ *
+ *     # turn off Expires behaviour in this directory
+ *     # and subdirectories
+ *     ExpiresActive off
+ *
+ * Directives defined for a directory are valid in subdirectories
+ * unless explicitly overridden by new directives in the subdirectory
+ * .htaccess files.
+ *
+ * ALTERNATIVE DIRECTIVE SYNTAX
+ *
+ * Directives can also be defined in a more readable syntax of the form:
+ *
+ *     ExpiresDefault "<base> [plus] {<num> <type>}*"
+ *     ExpiresByType type/encoding "<base> [plus] {<num> <type>}*"
+ *
+ * where <base> is one of:
+ *     access  
+ *     now             equivalent to 'access'
+ *     modification
+ *
+ * where the 'plus' keyword is optional
+ *
+ * where <num> should be an integer value [acceptable to atoi()]
+ *
+ * where <type> is one of:
+ *     years
+ *     months
+ *     weeks
+ *     days
+ *     hours
+ *     minutes
+ *     seconds
+ *
+ * For example, any of the following directives can be used to make
+ * documents expire 1 month after being accessed, by default:
+ *
+ *     ExpiresDefault "access plus 1 month"
+ *     ExpiresDefault "access plus 4 weeks"
+ *     ExpiresDefault "access plus 30 days"
+ *
+ * The expiry time can be fine-tuned by adding several '<num> <type>'
+ * clauses:
+ *
+ *     ExpiresByType text/html "access plus 1 month 15 days 2 hours"
+ *     ExpiresByType image/gif "modification plus 5 hours 3 minutes"
+ *
+ * ---
+ *
+ * Change-log:
+ * 29.Jan.96   Hardened the add_* functions.  Server will now bail out
+ *             if bad directives are given in the conf files.
+ * 02.Feb.96   Returns DECLINED if not 'ExpiresActive on', giving other
+ *             expires-aware modules a chance to play with the same
+ *             directives. [Michael Rutman]
+ * 03.Feb.96   Call tzset() before localtime().  Trying to get the module
+ *             to work properly in non GMT timezones.
+ * 12.Feb.96   Modified directive syntax to allow more readable commands:
+ *               ExpiresDefault "now plus 10 days 20 seconds"
+ *               ExpiresDefault "access plus 30 days"
+ *               ExpiresDefault "modification plus 1 year 10 months 30 days"
+ * 13.Feb.96   Fix call to table_get() with NULL 2nd parameter [Rob Hartill]
+ * 19.Feb.96   Call gm_timestr_822() to get time formatted correctly, can't
+ *             rely on presence of HTTP_TIME_FORMAT in Apache 1.1+.
+ * 21.Feb.96   This version (0.0.9) reverses assumptions made in 0.0.8
+ *             about star/star handlers.  Reverting to 0.0.7 behaviour.
+ * 08.Jun.96    allows ExpiresDefault to be used with responses that use 
+ *              the DefaultType by not DECLINING, but instead skipping 
+ *              the table_get check and then looking for an ExpiresDefault.
+ *              [Rob Hartill]
+ * 04.Nov.96    'const' definitions added.
+ *
+ * TODO
+ * add support for Cache-Control: max-age=20 from the HTTP/1.1
+ * proposal (in this case, a ttl of 20 seconds) [ask roy]
+ * add per-file expiry and explicit expiry times - duplicates some
+ * of the mod_cern_meta.c functionality.  eg:
+ *             ExpiresExplicit index.html "modification plus 30 days"
+ *
+ * BUGS
+ * Hi, welcome to the internet.
+ */
+
+#include <ctype.h>
+#include "httpd.h"
+#include "http_config.h"
+#include "http_log.h"
+
+typedef struct {
+    int active;
+    char *expiresdefault;
+    table *expiresbytype;
+} expires_dir_config;
+
+/* from mod_dir, why is this alias used?
+ */
+#define DIR_CMD_PERMS OR_INDEXES
+
+#define ACTIVE_ON      1
+#define ACTIVE_OFF     0
+#define ACTIVE_DONTCARE 2
+
+module expires_module;
+
+void *create_dir_expires_config (pool *p, char *dummy)
+{     
+    expires_dir_config *new =
+        (expires_dir_config *) pcalloc (p, sizeof(expires_dir_config));
+    new->active = ACTIVE_DONTCARE;
+    new->expiresdefault = "";
+    new->expiresbytype = make_table(p, 4);
+    return (void *)new;
+}   
+
+const char *set_expiresactive (cmd_parms *cmd, expires_dir_config *dir_config, int arg)
+{
+    /* if we're here at all it's because someone explicitly
+     * set the active flag
+     */
+    dir_config->active = ACTIVE_ON;
+    if ( arg == 0 ) {
+        dir_config->active = ACTIVE_OFF;
+    };
+    return NULL;
+} 
+
+/* check_code() parse 'code' and return NULL or an error response
+ * string.  If we return NULL then real_code contains code converted
+ * to the cnnnn format.
+ */
+char *check_code( pool *pool, const char *code, char **real_code )
+{
+    char *word;
+    char base = 'X';
+    int modifier = 0;
+    int num = 0;
+    int factor = 0;
+    char foo[MAX_STRING_LEN];
+
+    /* 0.0.4 compatibility?
+     */
+    if ( (code[0] == 'A') || (code[0] == 'M') ) {
+       *real_code = pstrdup( pool, code );
+       return NULL;
+    };
+
+    /* <base> [plus] {<num> <type>}*
+     */
+
+    /* <base>
+     */
+    word = getword_conf( pool, &code );
+    if ( !strncasecmp( word, "now", 1 ) ||
+        !strncasecmp( word, "access", 1 ) ) {
+       base = 'A';
+    } else if ( !strncasecmp( word, "modification", 1 ) ) {
+       base = 'M';
+    } else {
+       return pstrcat( pool, "bad expires code, unrecognised <base> '",
+               word, "'", NULL);
+    };
+
+    /* [plus]
+     */
+    word = getword_conf( pool, &code );
+    if ( !strncasecmp( word, "plus", 1 ) ) {
+        word = getword_conf( pool, &code );
+    };
+
+    /* {<num> <type>}*
+     */
+    while ( word[0] ) {
+       /* <num>
+        */
+       if (isdigit(word[0])) {
+           num = atoi( word );
+       } else {
+            return pstrcat( pool, "bad expires code, numeric value expected <num> '",
+               word, "'", NULL);
+       };
+
+       /* <type>
+        */
+       word = getword_conf( pool, &code );
+       if ( word[0] ) {
+           /* do nothing */
+       } else {
+            return pstrcat( pool, "bad expires code, missing <type>", NULL);
+       };
+
+       factor = 0;
+       if ( !strncasecmp( word, "years", 1 ) ) {
+               factor = 60*60*24*365;
+       } else if ( !strncasecmp( word, "months", 2 ) ) {
+               factor = 60*60*24*30;
+       } else if ( !strncasecmp( word, "weeks", 1 ) ) {
+               factor = 60*60*24*7;
+       } else if ( !strncasecmp( word, "days", 1 ) ) {
+               factor = 60*60*24;
+       } else if ( !strncasecmp( word, "hours", 1 ) ) {
+               factor = 60*60;
+       } else if ( !strncasecmp( word, "minutes", 2 ) ) {
+               factor = 60;
+       } else if ( !strncasecmp( word, "seconds", 1 ) ) {
+               factor = 1;
+       } else {
+            return pstrcat( pool, "bad expires code, unrecognised <type>", 
+               "'", word, "'", NULL);
+       };
+
+       modifier = modifier + factor * num;
+
+       /* next <num>
+        */
+       word = getword_conf( pool, &code );
+    };
+
+    ap_snprintf(foo, sizeof(foo), "%c%d", base, modifier );
+    *real_code = pstrdup( pool, foo );
+
+    return NULL;
+}
+
+const char *set_expiresbytype(cmd_parms *cmd, expires_dir_config *dir_config, char *mime, char *code)
+{
+    char *response, *real_code;
+
+    if ( (response = check_code( cmd->pool, code, &real_code  )) == NULL ) {
+        table_set (dir_config->expiresbytype, mime, real_code);
+       return NULL;
+    };
+    return pstrcat( cmd->pool, 
+       "'ExpiresByType ", mime, " ", code, "': ", response, NULL );
+} 
+
+const char *set_expiresdefault (cmd_parms *cmd, expires_dir_config *dir_config, char *code)
+{
+    char *response, *real_code;
+
+    if ( (response = check_code( cmd->pool, code, &real_code )) == NULL ) {
+        dir_config->expiresdefault = pstrdup( cmd->pool, real_code );
+       return NULL;
+    };
+    return pstrcat( cmd->pool, 
+       "'ExpiresDefault ", code, "': ", response, NULL );
+} 
+
+command_rec expires_cmds[] = {
+{ "ExpiresActive", set_expiresactive, NULL, DIR_CMD_PERMS, FLAG, NULL},
+{ "ExpiresBytype", set_expiresbytype, NULL, DIR_CMD_PERMS, TAKE2,
+    "a mime type followed by an expiry date code"},
+{ "ExpiresDefault", set_expiresdefault, NULL, DIR_CMD_PERMS, TAKE1,
+    "an expiry date code"},
+{ NULL }
+};  
+
+void *merge_expires_dir_configs (pool *p, void *basev, void *addv)
+{
+    expires_dir_config *new= (expires_dir_config*)pcalloc (p, sizeof(expires_dir_config));
+    expires_dir_config *base = (expires_dir_config *)basev;
+    expires_dir_config *add = (expires_dir_config *)addv;
+
+    if ( add->active == ACTIVE_DONTCARE ) {
+       new->active = base->active;
+    } else {
+       new->active = add->active;
+    };
+
+    if ( add->expiresdefault != '\0' ) {
+        new->expiresdefault = add->expiresdefault;
+    };
+
+    new->expiresbytype = overlay_tables (p, add->expiresbytype,
+                                          base->expiresbytype);
+    return new;
+}  
+
+int add_expires(request_rec *r)
+{
+    expires_dir_config *conf =
+            (expires_dir_config *)get_module_config(r->per_dir_config, &expires_module);
+    char *code;
+    time_t base; 
+    time_t additional; 
+    time_t expires; 
+
+    if ( r->finfo.st_mode == 0 )
+       return DECLINED;
+
+    /* COMMA bites my ass...
+     */
+    if ( conf == NULL ) {
+        log_reason ("internal error in expires_module; add_expires(), conf == NULL", r->filename, r);
+       return SERVER_ERROR;
+    };
+
+    if ( conf->active != ACTIVE_ON )
+        return DECLINED;
+
+    /* we perhaps could use the default_type(r) in its place but that
+     * may be 2nd guesing the desired configuration...  calling table_get
+     * with a NULL key will SEGV us
+     *
+     * I still don't know *why* r->content_type would ever be NULL, this
+     * is possibly a result of fixups being called in many different
+     * places.  Fixups is probably the wrong place to be doing all this
+     * work...  Bah.
+     *
+     * Changed as of 08.Jun.96 don't DECLINE, look for an ExpiresDefault.
+     */
+    if ( r->content_type == NULL )
+       code = NULL;
+    else
+       code = (char *) table_get( conf->expiresbytype, r->content_type );
+
+    if ( code == NULL ) {
+       /* no expires defined for that type, is there a default? */
+       code = conf->expiresdefault;
+
+        if ( code[0] == '\0' )
+           return OK;
+    };
+
+    /* we have our code */
+
+    switch (code[0]) {
+       case 'M':
+            base = r->finfo.st_mtime;
+           additional = atoi( &code[1] );
+           break;
+       case 'A':
+           /* there's been some discussion and it's possible that 
+            * 'access time' will be stored in request structure
+            */
+           base = time( NULL );
+           additional = atoi( &code[1] );
+           break;
+       default:
+           /* expecting the add_* routines to be case-hardened this 
+            * is just a reminder that module is beta
+            */
+            log_reason ("internal error in expires_module; bad expires code", r->filename, r);
+            return SERVER_ERROR;
+    };
+
+    expires = base + additional;
+    tzset();   /* redundant? called implicitly by localtime, at least 
+                * under FreeBSD
+                */
+    table_set( r->headers_out, "Expires", gm_timestr_822( r->pool, expires ));
+    return OK;
+}
+
+module expires_module = {
+   STANDARD_MODULE_STUFF,
+   NULL,                       /* initializer */
+   create_dir_expires_config,  /* dir config creater */
+   merge_expires_dir_configs,  /* dir merger --- default is to override */
+   NULL,                       /* server config */
+   NULL,                       /* merge server configs */
+   expires_cmds,               /* command table */
+   NULL,                       /* handlers */
+   NULL,                       /* filename translation */
+   NULL,                       /* check_user_id */
+   NULL,                       /* check auth */
+   NULL,                       /* check access */
+   NULL,                       /* type_checker */
+   add_expires,                        /* fixups */
+   NULL,                       /* logger */
+   NULL                                /* header parser */
+};
diff --git a/APACHE_1_2_X/src/modules/standard/mod_headers.c b/APACHE_1_2_X/src/modules/standard/mod_headers.c
new file mode 100644 (file)
index 0000000..3976be7
--- /dev/null
@@ -0,0 +1,253 @@
+/* ====================================================================
+ * Copyright (c) 1996,1997 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_headers.c: Add/append/remove HTTP response headers
+ *     Written by Paul Sutton, paul@ukweb.com, 1 Oct 1996
+ *
+ * New directive, Header, can be used to add/replace/remove HTTP headers.
+ * Valid in both per-server and per-dir configurations.
+ *
+ * Syntax is:
+ *
+ *   Header action header value
+ *
+ * Where action is one of:
+ *     set    - set this header, replacing any old value
+ *     add    - add this header, possible resulting in two or more
+ *              headers with the same name
+ *     append - append this text onto any existing header of this same
+ *     unset  - remove this header
+ *
+ * Where action is unset, the third argument (value) should not be given.
+ * The header name can include the colon, or not.
+ *
+ * The Header directive can only be used where allowed by the FileInfo 
+ * override.
+ *
+ * When the request is processed, the header directives are processed in
+ * this order: firstly, the main server, then the virtual server handling
+ * this request (if any), then any <Directory> sections (working downwards 
+ * from the root dir), then an <Location> sections (working down from 
+ * shortest URL component), the any <File> sections. This order is
+ * important if any 'set' or 'unset' actions are used. For example,
+ * the following two directives have different effect if applied in
+ * the reverse order:
+ *
+ *   Header append Author "John P. Doe"
+ *   Header unset Author
+ *
+ * Examples:
+ *
+ *  To set the "Author" header, use
+ *     Header add Author "John P. Doe"
+ *
+ *  To remove a header:
+ *     Header unset Author
+ *
+ */
+
+#include "httpd.h"
+#include "http_config.h"
+
+typedef enum {
+    hdr_add = 'a',             /* add header (could mean multiple hdrs) */
+    hdr_set = 's',             /* set (replace old value) */
+    hdr_append = 'm',          /* append (merge into any old value) */
+    hdr_unset = 'u'            /* unset header */
+} hdr_actions;
+
+typedef struct {
+    hdr_actions action;
+    char *header;
+    char *value;
+} header_entry;
+
+/*
+ * headers_conf is our per-module configuration. This is used as both
+ * a per-dir and per-server config
+ */
+typedef struct {
+    array_header *headers;
+} headers_conf;
+
+module headers_module;
+
+void *create_headers_config (pool *p, server_rec *s)
+{
+    headers_conf *a =
+      (headers_conf *)pcalloc (p, sizeof(headers_conf));
+
+    a->headers = make_array (p, 2, sizeof(header_entry));
+    return a;
+}
+
+void *create_headers_dir_config (pool *p, char *d)
+{
+    return (headers_conf*)create_headers_config(p, NULL);
+}
+
+void *merge_headers_config (pool *p, void *basev, void *overridesv)
+{
+    headers_conf *a =
+       (headers_conf *)pcalloc (p, sizeof(headers_conf));
+    headers_conf *base = (headers_conf *)basev,
+       *overrides = (headers_conf *)overridesv;
+
+    a->headers = append_arrays(p, base->headers, overrides->headers);
+
+    return a;
+}
+
+
+const char *header_cmd(cmd_parms *cmd, headers_conf *dirconf, char *action, char *hdr, char *value)
+{
+    header_entry *new;
+    server_rec *s = cmd->server;
+    headers_conf *serverconf =
+        (headers_conf *)get_module_config(s->module_config,&headers_module);
+    char *colon;
+
+    if ( cmd->path )
+    {
+       new = (header_entry*)push_array(dirconf->headers);
+    }
+    else
+    {
+       new = (header_entry*)push_array(serverconf->headers);
+    }
+
+    if (!strcasecmp(action, "set")) new->action = hdr_set;
+    else if (!strcasecmp(action, "add")) new->action = hdr_add;
+    else if (!strcasecmp(action, "append")) new->action = hdr_append;
+    else if (!strcasecmp(action, "unset")) new->action = hdr_unset;
+    else 
+       return "first argument must be add, set, append or unset.";
+
+    if (new->action == hdr_unset) {
+       if (value) return "Header unset takes two arguments";
+    }
+    else if (!value)
+       return "Header requires three arguments";
+
+    if ((colon = strchr(hdr, ':')))
+        *colon = '\0';
+
+    new->header = pstrdup(cmd->pool, hdr);
+    new->value = value ? pstrdup(cmd->pool, value) : NULL;
+
+    return NULL;
+}
+
+command_rec headers_cmds[] = {
+{ "Header", header_cmd, NULL, OR_FILEINFO, TAKE23, 
+    "an action, header and value"},
+{ NULL }
+};
+
+void do_headers_fixup(request_rec *r, array_header *headers)
+{
+    int i;
+
+    for (i = 0; i < headers->nelts; ++i) {
+       header_entry *hdr = &((header_entry*)(headers->elts))[i];
+       switch (hdr->action) {
+       case hdr_add:
+           table_add(r->headers_out, hdr->header, hdr->value);
+           break;
+       case hdr_append:
+           table_merge(r->headers_out, hdr->header, hdr->value);
+           break;
+       case hdr_set:
+           table_set(r->headers_out, hdr->header, hdr->value);
+           break;
+       case hdr_unset:
+           table_unset(r->headers_out, hdr->header);
+           break;
+       }
+    }
+
+}
+
+int fixup_headers(request_rec *r)
+{
+    void *sconf = r->server->module_config;
+    headers_conf *serverconf =
+        (headers_conf *)get_module_config(sconf, &headers_module);
+    void *dconf = r->per_dir_config;
+    headers_conf *dirconf =
+        (headers_conf *)get_module_config(dconf, &headers_module);
+
+    do_headers_fixup(r, serverconf->headers);
+    do_headers_fixup(r, dirconf->headers);
+
+    return DECLINED;
+}
+
+module headers_module = {
+   STANDARD_MODULE_STUFF,
+   NULL,                       /* initializer */
+   create_headers_dir_config,  /* dir config creater */
+   merge_headers_config,       /* dir merger --- default is to override */
+   create_headers_config,      /* server config */
+   merge_headers_config,       /* merge server configs */
+   headers_cmds,               /* command table */
+   NULL,                       /* handlers */
+   NULL,                       /* filename translation */
+   NULL,                       /* check_user_id */
+   NULL,                       /* check auth */
+   NULL,                       /* check access */
+   NULL,                       /* type_checker */
+   fixup_headers,              /* fixups */
+   NULL,                       /* logger */
+   NULL                                /* header parser */
+};
diff --git a/APACHE_1_2_X/src/modules/standard/mod_imap.c b/APACHE_1_2_X/src/modules/standard/mod_imap.c
new file mode 100644 (file)
index 0000000..e65925b
--- /dev/null
@@ -0,0 +1,837 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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 256
+#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 */
+}
+
+/*
+ * url needs to point to a string with at least SMALLBUF memory allocated
+ */
+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 == DEFAULT_PORT ) { 
+      ap_snprintf(url, SMALLBUF,
+               "http://%s%s", r->server->server_hostname, r->uri);
+    }
+    else {
+      ap_snprintf(url, SMALLBUF, "http://%s:%d%s", r->server->server_hostname,
+             r->server->port, r->uri);      
+    }
+    return;  
+  }
+
+  if ( ! strcasecmp(value, "nocontent") || ! strcasecmp(value, "error") ) {
+    strncpy(url, value, SMALLBUF-1);
+    url[SMALLBUF-1] = '\0';
+    return;    /* these are handled elsewhere, so just copy them */
+  }
+
+  if ( ! strcasecmp(value, "referer" ) ) {
+    referer = table_get(r->headers_in, "Referer");
+    if ( referer && *referer ) {
+      strncpy(url, referer, SMALLBUF-1);
+      url[SMALLBUF-1] = '\0';
+      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 == ':' ) { 
+    strncpy(url, value, SMALLBUF-1);        /* if letters and then a colon (like http:) */
+    url[SMALLBUF-1] = '\0';
+    return;                    /* it's an absolute URL, so use it! */
+  }
+
+  if ( ! base || ! *base ) {
+    if ( value && *value ) {  
+      strncpy(url, value, SMALLBUF-1);   /* no base: use what is given */
+      url[SMALLBUF-1] = '\0';
+    }         
+    else {                  
+      if (r->server->port == DEFAULT_PORT ) {  
+       ap_snprintf(url, SMALLBUF, "http://%s/", r->server->server_hostname);
+      }            
+      if (r->server->port != DEFAULT_PORT ) {
+       ap_snprintf(url, SMALLBUF, "http://%s:%d/",
+               r->server->server_hostname, r->server->port);
+      }                     /* no base, no value: pick a simple default */
+    }
+    return;  
+  }
+
+  strncpy(my_base, base, sizeof(my_base)-1);  /* must be a relative URL to be combined with base */
+  my_base[sizeof(my_base)-1] = '\0';
+  if (strchr(my_base, '/') == NULL && (!strncmp(value, "../", 3) || !strcmp(value, "..")) ) {
+    url[0] = '\0';
+    log_reason("invalid base directive in map file", r->uri, r);
+    return;
+  }
+  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 ) {
+    ap_snprintf(url, SMALLBUF, "%s%s", my_base, value);   
+  }
+  else {
+    ap_snprintf(url, SMALLBUF, "%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") ) {
+    return HTTP_NO_CONTENT; /* 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)
+{
+  r->content_type = "text/html";
+  send_http_header(r);
+  hard_timeout("send menu", r);   /* killed in menu_footer */
+
+  rvputs(r, "<html><head>\n<title>Menu for ", r->uri,
+           "</title>\n</head><body>\n", NULL);
+
+  if (!strcasecmp(menu, "formatted")) {
+    rvputs(r, "<h1>Menu for ", r->uri, "</h1>\n<hr>\n\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 */
+  kill_timeout(r);
+}
+
+int imap_handler(request_rec *r)
+{
+  char input[LARGEBUF] = {'\0'};
+       /* size of input can not be lowered without changing hard-coded
+        * checks
+        */
+  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, "%255s %255s", 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" */
+         strncpy(href_text, mapdflt, sizeof(href_text)-1); /* use the href itself as text */
+         href_text[sizeof(href_text)-1] = '\0';
+       }
+       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(isspace(*string_pos))     /* past any more whitespace */
+           string_pos++;
+       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" */
+       strncpy(href_text, value, sizeof(href_text)-1);  /* use the href itself in the menu */
+       href_text[sizeof(href_text)-1] = '\0';
+      }
+      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) ) {
+       strncpy(closest, value, sizeof(closest)-1);  /* if the closest point yet save it */
+       closest[sizeof(closest)-1] = '\0';
+      }
+      
+      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 */
+   NULL                                /* header parser */
+};
diff --git a/APACHE_1_2_X/src/modules/standard/mod_include.c b/APACHE_1_2_X/src/modules/standard/mod_include.c
new file mode 100644 (file)
index 0000000..6640397
--- /dev/null
@@ -0,0 +1,1892 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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 Apache module framework by rst.
+ * 
+ */
+/* 
+ * sub key may be anything a Perl*Handler can be:
+ * subroutine name, package name (defaults to package::handler),
+ * Class->method call or anoymous sub {}
+ *
+ * Child <!--#perl sub="sub {print $$}" --> accessed
+ * <!--#perl sub="sub {print ++$Access::Cnt }" --> times. <br>
+ *
+ * <!--#perl arg="one" sub="mymod::includer" -->
+ *
+ * -Doug MacEachern
+ */
+
+#ifdef USE_PERL_SSI
+#include "config.h"
+#ifdef USE_SFIO
+#undef USE_SFIO
+#define USE_STDIO
+#endif
+#include "modules/perl/mod_perl.h"
+#else
+#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"
+#endif
+
+#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 = r->request_time;
+
+    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];
+      ap_snprintf(uid, sizeof(uid), "user#%lu", (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));
+    }
+}
+
+
+
+/* --------------------------- Parser functions --------------------------- */
+
+#define OUTBUFSIZE 4096
+/* PUT_CHAR and FLUSH_BUF currently only work within the scope of 
+ * find_string(); they are hacks to avoid calling rputc for each and
+ * every character output.  A common set of buffering calls for this 
+ * type of output SHOULD be implemented.
+ */
+#define PUT_CHAR(c,r) \
+ { \
+   outbuf[outind++] = c; \
+   if (outind == OUTBUFSIZE) { FLUSH_BUF(r) }; \
+ } 
+
+/* there SHOULD be some error checking on the return value of
+ * rwrite, however it is unclear what the API for rwrite returning
+ * errors is and little can really be done to help the error in 
+ * any case.
+ */
+#define FLUSH_BUF(r) \
+ { \
+   rwrite(outbuf, outind, r); \
+   outind = 0; \
+ }
+
+/*
+ * f: file handle being read from
+ * c: character to read into
+ * ret: return value to use if input fails
+ * r: current request_rec
+ *
+ * This macro is redefined after find_string() for historical reasons
+ * to avoid too many code changes.  This is one of the many things
+ * that should be fixed.
+ */
+#define GET_CHAR(f,c,ret,r) \
+ { \
+   int i = getc(f); \
+   if(i == EOF) { /* either EOF or error -- needs error handling if latter */ \
+       if (ferror(f)) \
+          fprintf(stderr, "encountered error in GET_CHAR macro, mod_include.\n"); \
+       FLUSH_BUF(r); \
+       pfclose(r->pool,f); \
+       return ret; \
+   } \
+   c = (char)i; \
+ }
+
+int find_string(FILE *in,char *str, request_rec *r, int printing) {
+    int x,l=strlen(str),p;
+    char outbuf[OUTBUFSIZE];
+    int outind = 0;
+    char c;
+
+    p=0;
+    while(1) {
+        GET_CHAR(in,c,1,r);
+        if(c == str[p]) {
+            if((++p) == l) {
+               FLUSH_BUF(r);
+                return 0;
+           }
+        }
+        else {
+            if (printing) {
+                for(x=0;x<p;x++) {
+                    PUT_CHAR(str[x],r);
+                }
+                PUT_CHAR(c,r);
+            }
+            p=0;
+        }
+    }
+}
+
+#undef FLUSH_BUF
+#undef PUT_CHAR
+#undef GET_CHAR
+#define GET_CHAR(f,c,r,p) \
+ { \
+   int i = getc(f); \
+   if(i == EOF) { /* either EOF or error -- needs error handling if latter */ \
+       if (ferror(f)) \
+          fprintf(stderr, "encountered error in GET_CHAR macro, mod_include.\n"); \
+       pfclose(p,f); \
+       return r; \
+   } \
+   c = (char)i; \
+ }
+
+/*
+ * 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 == '>') {
+                strncpy(tag,"done", tagbuf_len-1);
+               tag[tagbuf_len-1] = '\0';
+                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 != '=') {
+        ungetc(c, in);
+        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;
+       }
+/* Want to accept \" as a valid character within a string. */
+       if (c == '\\') {
+           *(t++) = c; /* Add backslash */
+           GET_CHAR(in,c,NULL,p);
+           if (c == term) /* Only if */
+               *(--t) = c; /* Replace backslash ONLY for terminator */
+       } else if (c == term) break;
+       *(t++) = c;
+    }
+    *t = '\0';
+    if (dodecode) decodehtml(tag_val);
+    return pstrdup (p, tag_val);
+}
+
+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;
+}
+
+/*
+ * Do variable substitution on strings
+ */
+void parse_string(request_rec *r, char *in, char *out, int length,
+                  int leave_name)
+{
+    char ch;
+    char *next = out;
+    int numchars = 0;
+
+    while ((ch = *in++) != '\0') {
+        switch(ch) {
+          case '\\':
+           if(*in == '$')
+               *next++=*in++;
+           else
+               *next++=ch;
+            break;
+          case '$':
+          {
+            char var[MAX_STRING_LEN];
+            char vtext[MAX_STRING_LEN];
+            char *val;
+            int braces=0;
+            int vlen, vtlen;
+            /* 
+             * Keep the $ and { around because we do no substitution
+             * if the variable isn't found
+             */
+            vlen = vtlen = 0;
+            vtext[vtlen++] = ch;
+            if (*in == '{') { braces = 1; vtext[vtlen++] = *in++; }
+            while (*in != '\0') {
+                if (vlen == (MAX_STRING_LEN - 1)) continue;
+                if (braces == 1) {
+                    if (*in == '}') break;
+                }
+                else if (! (isalpha((int)*in) || (*in == '_') || isdigit((int)*in)) ) break;
+                if (vtlen < (MAX_STRING_LEN - 1)) vtext[vtlen++] = *in;
+                var[vlen++] = *in++;
+            }
+            var[vlen] = vtext[vtlen] = '\0';
+            if (braces == 1) {
+                if (*in != '}') {
+                    log_printf(r->server, "Invalid variable %s%s", vtext,in);
+                    *next = '\0';
+                    return;
+                } else
+                    in++;
+            } 
+
+            val = (char *)NULL;
+            if (var[0] == '\0') {
+                val = &vtext[0];
+            } else {
+                val = table_get (r->subprocess_env, &var[0]);
+                if (!val && leave_name)
+                    val = &vtext[0];
+            }
+            while ((val != (char *)NULL) && (*val != '\0')) {
+                *next++ = *val++;
+                if (++numchars == (length -1)) break;
+            }
+            break;
+          }
+          default:
+            *next++ = ch;
+            break;
+        }
+        if (++numchars == (length -1)) break;
+    }
+    *next = '\0';
+    return;
+}
+
+/* --------------------------- 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 parsed_string[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;
+
+            parse_string(r, tag_val, parsed_string, MAX_STRING_LEN, 0);
+           if (tag[0] == 'f')
+           { /* be safe; only files in this directory or below allowed */
+               char tmp[MAX_STRING_LEN+2];
+               ap_snprintf(tmp, sizeof(tmp), "/%s/", parsed_string);
+               if (parsed_string[0] == '/' || strstr(tmp, "/../") != NULL)
+                   error_fmt = "unable to include file %s in parsed file %s";
+               else
+                   rr = sub_req_lookup_file (parsed_string, r);
+           } else
+               rr = sub_req_lookup_uri (parsed_string, 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    
+    FILE *dbg = fopen ("/dev/tty", "w");
+#endif    
+    char err_string [MAX_STRING_LEN];
+
+#ifdef DEBUG_INCLUDE_CMD    
+#ifdef __EMX__
+    /* under OS/2 /dev/tty is referenced as con */
+    FILE *dbg = fopen ("con", "w");
+#else
+    fprintf (dbg, "Attempting to include command '%s'\n", s);
+#endif    
+#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();
+    /* set shellcmd flag to pass arg to SHELL_PATH */
+    call_exec(r, s, create_environment (r->pool, env), 1);
+    
+    /* 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    
+    ap_snprintf(err_string, sizeof(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->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;
+    char parsed_string[MAX_STRING_LEN];
+
+    while(1) {
+        if(!(tag_val = get_tag (r->pool, in, tag, MAX_STRING_LEN, 1)))
+            return 1;
+        if(!strcmp(tag,"cmd")) {
+            parse_string(r, tag_val, parsed_string, MAX_STRING_LEN, 1);
+            if(include_cmd(parsed_string, r) == -1) {
+                log_printf(r->server, "unknown parameter %s to tag include in %s",
+                           tag, r->filename);
+                rputs(error, r);
+            }
+            /* just in case some stooge changed directories */
+            chdir_file(r->filename);
+        } 
+        else if(!strcmp(tag,"cgi")) {
+            parse_string(r, tag_val, parsed_string, MAX_STRING_LEN, 0);
+            if(include_cgi(parsed_string, 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);
+        }
+    }
+}
+#ifdef USE_PERL_SSI
+int handle_perl (FILE *in, request_rec *r, char *error) {
+    char tag[MAX_STRING_LEN];
+    char *tag_val;
+    SV *sub = Nullsv;
+    AV *av  = newAV();
+
+    if (!(allow_options (r) & OPT_INCLUDES)) {
+        log_printf(r->server,
+            "httpd: #perl SSI disallowed by IncludesNoExec in %s", r->filename);
+       return DECLINED;
+    }
+    while(1) {
+       if(!(tag_val = get_tag (r->pool, in, tag, MAX_STRING_LEN, 1))) 
+           break;
+       if(strnEQ(tag, "sub", 3)) 
+           sub = newSVpv(tag_val,0);
+       else if(strnEQ(tag, "arg", 3)) 
+           av_push(av, newSVpv(tag_val,0));    
+       else if(strnEQ(tag,"done", 4))
+           break;
+    }
+    perl_stdout2client(r);
+    perl_call_handler(sub, r, av);
+    return OK;
+}
+#endif
+
+/* error and tf must point to a string with room for at 
+ * least MAX_STRING_LEN characters 
+ */
+int handle_config(FILE *in, request_rec *r, char *error, char *tf,
+                  int *sizefmt) {
+    char tag[MAX_STRING_LEN];
+    char *tag_val;
+    char parsed_string[MAX_STRING_LEN];
+    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")) {
+            parse_string(r, tag_val, parsed_string, MAX_STRING_LEN, 0);
+            strncpy(error,parsed_string,MAX_STRING_LEN-1);
+           error[MAX_STRING_LEN-1] = '\0';
+        } else if(!strcmp(tag,"timefmt")) {
+           time_t date = r->request_time;
+            parse_string(r, tag_val, parsed_string, MAX_STRING_LEN, 0);
+            strncpy(tf,parsed_string,MAX_STRING_LEN-1);
+           tf[MAX_STRING_LEN-1] = '\0';
+            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")) {
+            parse_string(r, tag_val, parsed_string, MAX_STRING_LEN, 0);
+           decodehtml(parsed_string);
+            if(!strcmp(parsed_string,"bytes"))
+                *sizefmt = SIZEFMT_BYTES;
+            else if(!strcmp(parsed_string,"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 = "./";
+    char *to_send;
+
+    if(!strcmp(tag,"file")) {
+        getparents(tag_val); /* get rid of any nasties */
+        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;
+    char parsed_string[MAX_STRING_LEN];
+
+    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 {
+            parse_string(r, tag_val, parsed_string, MAX_STRING_LEN, 0);
+            if(!find_file(r,"fsize",tag,parsed_string,&finfo,error)) {
+                if(sizefmt == SIZEFMT_KMG) {
+                    send_size(finfo.st_size, r);
+                }
+                else {
+                    int l,x;
+#if defined(BSD) && BSD > 199305
+                   /* ap_snprintf can't handle %qd */
+                    sprintf(tag,"%qd", finfo.st_size);
+#else
+                    ap_snprintf(tag, sizeof(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;
+    char parsed_string[MAX_STRING_LEN];
+
+    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 {
+            parse_string(r, tag_val, parsed_string, MAX_STRING_LEN, 0);
+            if(!find_file(r,"flastmod",tag,parsed_string,&finfo,error))
+                rputs(ht_time(r->pool, finfo.st_mtime, tf, 0), r);
+        }
+    }
+}    
+
+int re_check(request_rec *r, char *string, char *rexp) 
+{
+    regex_t *compiled;
+    int regex_error;
+
+    compiled = pregcomp (r->pool, rexp, REG_EXTENDED|REG_NOSUB);
+    if (compiled == NULL) {
+        log_printf(r->server, "unable to compile pattern %s", rexp);
+        return -1;
+    }
+    regex_error = regexec(compiled, string, 0, (regmatch_t *)NULL, 0);
+    pregfree (r->pool, compiled);
+    return(!regex_error);
+}
+
+enum token_type { token_string,
+    token_and, token_or, token_not, token_eq, token_ne,
+    token_rbrace, token_lbrace, token_group
+};
+struct token {
+    enum token_type type;
+    char value[MAX_STRING_LEN];
+};
+
+char *get_ptoken(request_rec *r, char *string, struct token *token) {
+    char ch;
+    int next=0;
+    int qs=0;
+
+    /* Skip leading white space */
+    if (string == (char *)NULL) return (char *)NULL;
+    while ((ch = *string++))
+        if (!isspace(ch)) break;
+    if (ch == '\0') return (char *)NULL;
+
+    switch(ch) {
+      case '(':
+        token->type = token_lbrace;
+        return(string);
+      case ')':
+        token->type = token_rbrace;
+        return(string);
+      case '=':
+        token->type = token_eq;
+        return(string);
+      case '!':
+        if (*string == '=') {
+            token->type = token_ne;
+            return(string+1);
+        } else {
+            token->type = token_not;
+            return(string);
+        }
+      case '\'':
+        token->type = token_string;
+        qs = 1;
+        break;
+      case '|':
+        if (*string == '|') {
+            token->type = token_or;
+            return(string+1);
+        }
+      case '&':
+        if (*string == '&') {
+            token->type = token_and;
+            return(string+1);
+        }
+      default:
+        token->type = token_string;
+        break;
+    }
+    /* We should only be here if we are in a string */
+    if (!qs) token->value[next++] = ch;
+
+    /* 
+     * Yes I know that goto's are BAD.  But, c doesn't allow me to
+     * exit a loop from a switch statement.  Yes, I could use a flag,
+     * but that is (IMHO) even less readable/maintainable than the goto.
+     */ 
+    /* 
+     * I used the ++string throughout this section so that string
+     * ends up pointing to the next token and I can just return it
+     */ 
+    for (ch = *string; ch != '\0'; ch = *++string) {
+        if (ch == '\\') {
+            if ((ch = *++string) == '\0') goto TOKEN_DONE;
+            token->value[next++] = ch;
+            continue;
+        }
+        if (!qs) {
+            if (isspace(ch)) goto TOKEN_DONE;
+            switch(ch) {
+              case '(': goto TOKEN_DONE;
+              case ')': goto TOKEN_DONE;
+              case '=': goto TOKEN_DONE;
+              case '!': goto TOKEN_DONE;
+              case '|': if (*(string+1) == '|') goto TOKEN_DONE;
+              case '&': if (*(string+1) == '&') goto TOKEN_DONE;
+            }
+            token->value[next++] = ch;
+        } else {
+            if (ch == '\'') { qs=0; ++string; goto TOKEN_DONE; }
+            token->value[next++] = ch;
+        }
+    }
+TOKEN_DONE:
+    /* If qs is still set, I have an unmatched ' */
+    if (qs) { rputs("\nUnmatched '\n", r); next=0; }
+    token->value[next] = '\0';
+    return(string);
+}
+
+
+/*
+ * Hey I still know that goto's are BAD.  I don't think that I've ever
+ * used two in the same project, let alone the same file before.  But,
+ * I absolutely want to make sure that I clean up the memory in all
+ * cases.  And, without rewriting this completely, the easiest way
+ * is to just branch to the return code which cleans it up.
+ */
+int parse_expr(request_rec *r, char *expr, char *error)
+{
+    struct parse_node {
+        struct parse_node *left, *right, *parent;
+        struct token token;
+        int value, done;
+    } *root, *current, *new;
+    char *parse;
+    char buffer[MAX_STRING_LEN];
+    struct pool *expr_pool;
+    int retval = 0;
+
+    if ((parse = expr) == (char *)NULL) return(0);
+    root = current = (struct parse_node*)NULL;
+    if ((expr_pool = make_sub_pool(r->pool)) == (struct pool *)NULL) {
+        log_printf(r->server, "out of memory", r->filename);
+        rputs(error, r);
+        return(0);
+    }
+
+    /* Create Parse Tree */
+    while (1) {
+        new = (struct parse_node*)palloc(expr_pool, sizeof (struct parse_node));
+        if (new == (struct parse_node*)NULL) {
+            log_printf(r->server,"out of memory", r->filename);
+            rputs(error, r);
+            goto RETURN;
+        }
+        new->parent = new->left = new->right = (struct parse_node*)NULL;
+        new->done = 0;
+        if ((parse = get_ptoken(r, parse, &new->token)) == (char *)NULL)
+            break;
+        switch(new->token.type) {
+
+          case token_string:
+#ifdef DEBUG_INCLUDE
+            rvputs(r,"     Token: string (", new->token.value, ")\n", NULL);
+#endif
+            if (current == (struct parse_node*)NULL) {
+                root = current = new;
+                break;
+            }
+            switch(current->token.type) {
+              case token_string:
+                if (current->token.value[0] != '\0')
+                    strncat(current->token.value, " ", 
+                       MAX_STRING_LEN-strlen(current->token.value)-1);
+                strncat(current->token.value, new->token.value, 
+                       MAX_STRING_LEN-strlen(current->token.value)-1);
+                break;
+              case token_eq:
+              case token_ne:
+              case token_and:
+              case token_or:
+              case token_lbrace:
+              case token_not:
+                new->parent = current;
+                current = current->right = new;
+                break;
+              default:
+                log_printf(r->server,
+                    "Invalid expression %s", expr, r->filename);
+                rputs(error, r);
+                goto RETURN;
+            }
+            break;
+
+          case token_and:
+          case token_or:
+#ifdef DEBUG_INCLUDE
+rputs ("     Token: and/or\n", r);
+#endif
+            if (current == (struct parse_node*)NULL) {
+                log_printf(r->server,
+                    "Invalid expression %s", expr, r->filename);
+                rputs(error, r);
+                goto RETURN;
+            }
+            /* Percolate upwards */
+            while (current != (struct parse_node *)NULL) {
+                switch(current->token.type) {
+                  case token_string:
+                  case token_group:
+                  case token_not:
+                  case token_eq:
+                  case token_ne:
+                  case token_and:
+                  case token_or:
+                    current = current->parent;
+                    continue;
+                  case token_lbrace:
+                    break;
+                  default:
+                    log_printf(r->server,
+                        "Invalid expression %s", expr, r->filename);
+                    rputs(error, r);
+                    goto RETURN;
+                }
+                break;
+            }
+            if (current == (struct parse_node*)NULL) {
+                new->left = root;
+                new->left->parent = new;
+                new->parent = (struct parse_node*)NULL;
+                root = new;
+            } else {
+                new->left = current->right;
+                current->right = new;
+                new->parent = current;
+            }
+            current = new;
+            break;
+
+          case token_not:
+#ifdef DEBUG_INCLUDE
+rputs("     Token: not\n", r);
+#endif
+            if (current == (struct parse_node*)NULL) {
+                root = current = new;
+                break;
+            }
+            /* Percolate upwards */
+            while (current != (struct parse_node *)NULL) {
+                switch(current->token.type) {
+                  case token_not:
+                  case token_eq:
+                  case token_ne:
+                  case token_and:
+                  case token_or:
+                  case token_lbrace:
+                    break;
+                  default:
+                    log_printf(r->server,
+                        "Invalid expression %s", expr, r->filename);
+                    rputs(error, r);
+                    goto RETURN;
+                }
+                break;
+            }
+            if (current == (struct parse_node*)NULL) {
+                new->left = root;
+                new->left->parent = new;
+                new->parent = (struct parse_node*)NULL;
+                root = new;
+            } else {
+                new->left = current->right;
+                current->right = new;
+                new->parent = current;
+            }
+            current = new;
+            break;
+
+          case token_eq:
+          case token_ne:
+#ifdef DEBUG_INCLUDE
+rputs("     Token: eq/ne\n", r);
+#endif
+            if (current == (struct parse_node*)NULL) {
+                log_printf(r->server,
+                    "Invalid expression %s", expr, r->filename);
+                rputs(error, r);
+                goto RETURN;
+            }
+            /* Percolate upwards */
+            while (current != (struct parse_node *)NULL) {
+                switch(current->token.type) {
+                  case token_string:
+                  case token_group:
+                    current = current->parent;
+                    continue;
+                  case token_lbrace:
+                  case token_and:
+                  case token_or:
+                    break;
+                  case token_not:
+                  case token_eq:
+                  case token_ne:
+                  default:
+                    log_printf(r->server,
+                        "Invalid expression %s", expr, r->filename);
+                    rputs(error, r);
+                    goto RETURN;
+                }
+                break;
+            }
+            if (current == (struct parse_node*)NULL) {
+                new->left = root;
+                new->left->parent = new;
+                new->parent = (struct parse_node*)NULL;
+                root = new;
+            } else {
+                new->left = current->right;
+                current->right = new;
+                new->parent = current;
+            }
+            current = new;
+            break;
+
+          case token_rbrace:
+#ifdef DEBUG_INCLUDE
+rputs("     Token: rbrace\n", r);
+#endif
+            while (current != (struct parse_node*)NULL) {
+                if (current->token.type == token_lbrace) {
+                    current->token.type = token_group;
+                    break;
+                }
+                current = current->parent;
+            }
+            if (current == (struct parse_node*)NULL) {
+                log_printf(r->server,"Unmatched ')'in %s\n", expr, r->filename);
+                rputs(error, r);
+                goto RETURN;
+            }
+            break;
+
+          case token_lbrace:
+#ifdef DEBUG_INCLUDE
+rputs("     Token: lbrace\n", r);
+#endif
+            if (current == (struct parse_node*)NULL) {
+                root = current = new;
+                break;
+            }
+            /* Percolate upwards */
+            while (current != (struct parse_node *)NULL) {
+                switch(current->token.type) {
+                  case token_not:
+                  case token_eq:
+                  case token_ne:
+                  case token_and:
+                  case token_or:
+                  case token_lbrace:
+                    break;
+                  case token_string:
+                  case token_group:
+                  default:
+                    log_printf(r->server,
+                        "Invalid expression %s", expr, r->filename);
+                    rputs(error, r);
+                    goto RETURN;
+                }
+                break;
+            }
+            if (current == (struct parse_node*)NULL) {
+                new->left = root;
+                new->left->parent = new;
+                new->parent = (struct parse_node*)NULL;
+                root = new;
+            } else {
+                new->left = current->right;
+                current->right = new;
+                new->parent = current;
+            }
+            current = new;
+            break;
+         default:
+           break;
+        }
+    }
+
+    /* Evaluate Parse Tree */
+    current = root;
+    while (current != (struct parse_node *)NULL) {
+        switch(current->token.type) {
+          case token_string:
+#ifdef DEBUG_INCLUDE
+rputs("     Evaluate string\n", r);
+#endif
+            parse_string(r, current->token.value, buffer, MAX_STRING_LEN, 0);
+            strncpy(current->token.value, buffer, MAX_STRING_LEN-1);
+           current->token.value[MAX_STRING_LEN-1] = '\0';
+            current->value = (current->token.value[0] != '\0');
+            current->done = 1;
+            current = current->parent;
+            break;
+
+          case token_and:
+          case token_or:
+#ifdef DEBUG_INCLUDE
+rputs("     Evaluate and/or\n", r);
+#endif
+            if (current->left == (struct parse_node*)NULL ||
+                        current->right == (struct parse_node*)NULL) {
+                log_printf(r->server,
+                    "Invalid expression %s", expr, r->filename);
+                rputs(error, r);
+                goto RETURN;
+            }
+            if (!current->left->done) {
+                switch(current->left->token.type) {
+                  case token_string:
+                    parse_string(r, current->left->token.value,
+                            buffer, MAX_STRING_LEN, 0);
+                    strncpy(current->left->token.value, buffer,
+                            MAX_STRING_LEN-1);
+                   current->left->token.value[MAX_STRING_LEN-1] = '\0';
+                    current->left->done = 1;
+                    break;
+                  default:
+                    current = current->left;
+                    continue;
+                }
+            }
+            if (!current->right->done) {
+                switch(current->right->token.type) {
+                  case token_string:
+                    parse_string(r, current->right->token.value,
+                            buffer, MAX_STRING_LEN, 0);
+                    strncpy(current->right->token.value, buffer,
+                            MAX_STRING_LEN-1);
+                   current->right->token.value[MAX_STRING_LEN-1] = '\0';
+                    current->right->done = 1;
+                    break;
+                  default:
+                    current = current->right;
+                    continue;
+                }
+            }
+#ifdef DEBUG_INCLUDE
+rvputs(r,"     Left: ", current->left->value ? "1" : "0", "\n", NULL);
+rvputs(r,"     Right: ", current->right->value ? "1" : "0", "\n", NULL);
+#endif
+            if (current->token.type == token_and)
+                current->value =
+                    current->left->value && current->right->value;
+            else
+                current->value =
+                    current->left->value || current->right->value;
+#ifdef DEBUG_INCLUDE
+rvputs(r,"     Returning ", current->value ? "1" : "0", "\n", NULL);
+#endif
+            current->done = 1;
+            current = current->parent;
+            break;
+
+          case token_eq:
+          case token_ne:
+#ifdef DEBUG_INCLUDE
+rputs("     Evaluate eq/ne\n", r);
+#endif
+            if ((current->left == (struct parse_node*)NULL) ||
+                        (current->right == (struct parse_node*)NULL) ||
+                        (current->left->token.type != token_string) ||
+                        (current->right->token.type != token_string)) {
+                log_printf(r->server,
+                    "Invalid expression %s", expr, r->filename);
+                rputs(error, r);
+                goto RETURN;
+            }
+            parse_string(r, current->left->token.value,
+                         buffer, MAX_STRING_LEN, 0);
+            strncpy(current->left->token.value, buffer, MAX_STRING_LEN-1);
+           current->left->token.value[MAX_STRING_LEN-1] = '\0';
+            parse_string(r, current->right->token.value,
+                         buffer, MAX_STRING_LEN, 0);
+            strncpy(current->right->token.value, buffer, MAX_STRING_LEN-1);
+           current->right->token.value[MAX_STRING_LEN-1] = '\0';
+            if (current->right->token.value[0] == '/') {
+                int len;
+                len = strlen(current->right->token.value);
+                if (current->right->token.value[len-1] == '/') {
+                    current->right->token.value[len-1] = '\0';
+                } else {
+                    log_printf(r->server,"Invalid rexp %s",
+                            current->right->token.value, r->filename);
+                    rputs(error, r);
+                    goto RETURN;
+                }
+#ifdef DEBUG_INCLUDE
+rvputs(r,"     Re Compare (", current->left->token.value,
+         ") with /", &current->right->token.value[1], "/\n", NULL);
+#endif
+                current->value =
+                    re_check(r, current->left->token.value,
+                            &current->right->token.value[1]);
+            } else {
+#ifdef DEBUG_INCLUDE
+rvputs(r,"     Compare (", current->left->token.value,
+         ") with (", current->right->token.value, ")\n", NULL);
+#endif
+                current->value =
+                        (strcmp(current->left->token.value,
+                         current->right->token.value) == 0);
+            }
+            if (current->token.type == token_ne)
+                current->value = !current->value;
+#ifdef DEBUG_INCLUDE
+rvputs(r,"     Returning ", current->value ? "1" : "0", "\n", NULL);
+#endif
+            current->done = 1;
+            current = current->parent;
+            break;
+
+          case token_not:
+            if (current->right != (struct parse_node *)NULL) {
+                if (!current->right->done) {
+                    current = current->right;
+                    continue;
+                }
+                current->value = !current->right->value;
+            } else {
+                current->value = 0;
+            }
+#ifdef DEBUG_INCLUDE
+rvputs(r,"     Evaluate !: ", current->value ? "1" : "0", "\n", NULL);
+#endif
+            current->done = 1;
+            current = current->parent;
+            break;
+
+          case token_group:
+            if (current->right != (struct parse_node *)NULL) {
+                if (!current->right->done) {
+                    current = current->right;
+                    continue;
+                }
+                current->value = current->right->value;
+            } else {
+                current->value = 1;
+            }
+#ifdef DEBUG_INCLUDE
+rvputs(r,"     Evaluate (): ", current->value ? "1" : "0", "\n", NULL);
+#endif
+            current->done = 1;
+            current = current->parent;
+            break;
+
+          case token_lbrace:
+            log_printf(r->server,"Unmatched '(' in %s\n", expr, r->filename);
+            rputs(error, r);
+            goto RETURN;
+
+          case token_rbrace:
+            log_printf(r->server,"Unmatched ')' in %s\n", expr, r->filename);
+            rputs(error, r);
+            goto RETURN;
+
+          default:
+            log_printf(r->server,"bad token type");
+            rputs(error, r);
+            goto RETURN;
+        }
+    }
+
+    retval =  (root == (struct parse_node *)NULL) ? 0 : root->value;
+RETURN:
+    destroy_pool(expr_pool);
+    return (retval);
+}    
+
+int handle_if(FILE *in, request_rec *r, char *error,
+              int *conditional_status, int *printing) 
+{
+    char tag[MAX_STRING_LEN];
+    char *tag_val = '\0';
+    char *expr = '\0';
+
+    while(1) {
+        tag_val = get_tag(r->pool, in, tag, MAX_STRING_LEN, 0);
+        if(*tag == '\0')
+            return 1;
+        else if(!strcmp(tag,"done")) {
+            *printing = *conditional_status = parse_expr(r, expr, error);
+#ifdef DEBUG_INCLUDE
+rvputs(r,"**** if conditional_status=\"", *conditional_status ? "1" : "0", "\"\n", NULL);
+#endif
+            return 0;
+        } else if(!strcmp(tag,"expr")) {
+           expr = tag_val;
+#ifdef DEBUG_INCLUDE
+rvputs(r,"**** if expr=\"", expr, "\"\n", NULL);
+#endif
+        } else {
+            log_printf(r->server,"unknown parameter %s to tag if in %s",
+                    tag, r->filename);
+            rputs(error, r);
+        }
+    }
+}    
+
+int handle_elif(FILE *in, request_rec *r, char *error,
+              int *conditional_status, int *printing) 
+{
+    char tag[MAX_STRING_LEN];
+    char *tag_val = '\0';
+    char *expr = '\0';
+
+    while(1) {
+        tag_val = get_tag(r->pool, in, tag, MAX_STRING_LEN, 0);
+        if(*tag == '\0')
+            return 1;
+        else if(!strcmp(tag,"done")) {
+#ifdef DEBUG_INCLUDE
+rvputs(r,"**** elif conditional_status=\"", *conditional_status ? "1" : "0", "\"\n", NULL);
+#endif
+            if (*conditional_status) {
+                *printing = 0;
+                return(0);
+            }
+            *printing = *conditional_status = parse_expr(r, expr, error);
+#ifdef DEBUG_INCLUDE
+rvputs(r,"**** elif conditional_status=\"", *conditional_status ? "1" : "0", "\"\n", NULL);
+#endif
+            return 0;
+        } else if(!strcmp(tag,"expr")) {
+           expr = tag_val;
+#ifdef DEBUG_INCLUDE
+rvputs(r,"**** if expr=\"", expr, "\"\n", NULL);
+#endif
+        } else {
+            log_printf(r->server,"unknown parameter %s to tag if in %s",
+                    tag, r->filename);
+            rputs(error, r);
+        }
+    }
+}
+
+int handle_else(FILE *in, request_rec *r, char *error,
+              int *conditional_status, int *printing) 
+{
+    char tag[MAX_STRING_LEN];
+    char *tag_val;
+
+    if(!(tag_val = get_tag(r->pool, in, tag, MAX_STRING_LEN, 1)))
+        return 1;
+    else if(!strcmp(tag,"done")) {
+#ifdef DEBUG_INCLUDE
+rvputs(r,"**** else conditional_status=\"", *conditional_status ? "1" : "0", "\"\n", NULL);
+#endif
+        *printing = !(*conditional_status);
+        *conditional_status = 1;
+        return 0;
+    } else {
+        log_printf(r->server, "else directive does not take tags");
+        if (*printing) rputs(error, r);
+        return -1;
+    }
+}    
+
+int handle_endif(FILE *in, request_rec *r, char *error, 
+              int *conditional_status, int *printing) 
+{
+    char tag[MAX_STRING_LEN];
+    char *tag_val;
+
+    if(!(tag_val = get_tag(r->pool, in, tag, MAX_STRING_LEN, 1))) {
+        return 1;
+    } else if(!strcmp(tag,"done")) {
+#ifdef DEBUG_INCLUDE
+rvputs(r,"**** endif conditional_status=\"", *conditional_status ? "1" : "0", "\"\n", NULL);
+#endif
+        *conditional_status = 1;
+        return 0;
+    } else {
+        log_printf(r->server, "endif directive does not take tags");
+        rputs(error, r);
+        return -1;
+    }
+}    
+
+int handle_set(FILE *in, request_rec *r, char *error) 
+{
+    char tag[MAX_STRING_LEN];
+    char parsed_string[MAX_STRING_LEN];
+    char *tag_val;
+    char *var;
+
+    var = (char *)NULL;
+    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 (!strcmp(tag,"var")) {
+            var = tag_val;
+        } else if (!strcmp(tag,"value")) {
+            if (var == (char *)NULL) {
+                log_printf(r->server,
+                    "variable must precede value in set directive");
+                rputs(error, r);
+                return -1;
+            } 
+            parse_string(r, tag_val, parsed_string, MAX_STRING_LEN, 0);
+            table_set (r->subprocess_env, var, parsed_string);
+        }
+    }
+}    
+
+int handle_printenv(FILE *in, request_rec *r, char *error) 
+{
+    char tag[MAX_STRING_LEN];
+    char *tag_val;
+    table_entry *elts = (table_entry *) r->subprocess_env->elts;
+    int i;
+
+    if(!(tag_val = get_tag(r->pool, in, tag, MAX_STRING_LEN, 1)))
+        return 1;
+    else if(!strcmp(tag,"done")) {
+            for (i = 0; i < r->subprocess_env->nelts; ++i)
+                rvputs(r, elts[i].key, "=", elts[i].val, "\n", NULL);
+            return 0;
+    } else {
+        log_printf(r->server, "printenv directive does not take tags");
+        rputs(error, r);
+        return -1;
+    }
+}    
+
+
+
+/* -------------------------- 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;
+    int if_nesting;
+    int printing;
+    int conditional_status;
+
+    strncpy(error,DEFAULT_ERROR_MSG, sizeof(error)-1);
+    error[sizeof(error)-1] = '\0';
+    strncpy(timefmt,DEFAULT_TIME_FORMAT, sizeof(timefmt)-1);
+    timefmt[sizeof(timefmt)-1] = '\0';
+    sizefmt = SIZEFMT_KMG;
+
+/*  Turn printing on */
+    printing = conditional_status = 1;
+    if_nesting = 0;
+
+    chdir_file (r->filename);
+    if (r->args) { /* add QUERY stuff to env cause it ain't yet */
+        table_set (r->subprocess_env, "QUERY_STRING", r->args);
+        unescape_url (r->args);
+        table_set (r->subprocess_env, "QUERY_STRING_UNESCAPED",
+                escape_shell_cmd (r->pool, r->args));
+    }
+
+    while(1) {
+        if(!find_string(f,STARTING_SEQUENCE,r,printing)) {
+            if(get_directive(f,directive,r->pool))
+                return;
+            if(!strcmp(directive,"if")) {
+                if (!printing) {
+                    if_nesting++;
+                } else {
+                    ret=handle_if(f, r, error, &conditional_status, &printing);
+                    if_nesting = 0;
+                }
+                continue;
+            } else if(!strcmp(directive,"else")) {
+                if (!if_nesting)
+                    ret=handle_else(f, r, error, &conditional_status, &printing);
+                continue;
+            } else if(!strcmp(directive,"elif")) {
+                if (!if_nesting)
+                    ret = handle_elif(f, r, error, &conditional_status, &printing);
+                continue;
+            } else if(!strcmp(directive,"endif")) {
+                if (!if_nesting) {
+                    ret=handle_else(f, r, error, &conditional_status, &printing);
+                    printing = 1;
+                } else {
+                    if_nesting--;
+                }
+                continue;
+            } 
+            if (!printing) continue;
+            if(!strcmp(directive,"exec")) {
+                if(noexec) {
+                    log_printf(r->server,"httpd: exec used but not allowed in %s",
+                            r->filename);
+                    if (printing) rputs(error, r);
+                    ret = find_string(f,ENDING_SEQUENCE,r,0);
+                } else 
+                    ret=handle_exec(f, r, error);
+            } else if(!strcmp(directive,"config"))
+                ret=handle_config(f, r, error, timefmt, &sizefmt);
+            else if(!strcmp(directive,"set"))
+                ret=handle_set(f, r, error);
+            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 if(!strcmp(directive,"printenv"))
+                ret=handle_printenv(f, r, error);
+#ifdef USE_PERL_SSI
+            else if(!strcmp(directive,"perl")) 
+                ret=handle_perl(f, r, error);
+#endif
+            else {
+                log_printf(r->server,
+                        "httpd: unknown directive %s in parsed doc %s",
+                        directive,r->filename);
+                if (printing) rputs(error, r);
+                ret=find_string(f,ENDING_SEQUENCE,r,0);
+            }
+            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;
+}
+
+const 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) {
+        log_reason("File does not exist",
+            r->path_info ? pstrcat(r->pool, r->filename, r->path_info, NULL)
+                : r->filename, r);
+       return NOT_FOUND;
+    }
+
+    if(!(f=pfopen(r->pool, r->filename, "r"))) {
+        log_reason("file permissions deny server access", r->filename, r);
+       return FORBIDDEN;
+    }
+
+    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;
+
+    send_http_header(r);
+
+    if (r->header_only) {
+       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);
+    }
+    hard_timeout("send SSI", r);
+
+    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 */
+   NULL                                /* header parser */
+};
diff --git a/APACHE_1_2_X/src/modules/standard/mod_info.c b/APACHE_1_2_X/src/modules/standard/mod_info.c
new file mode 100644 (file)
index 0000000..1525dc7
--- /dev/null
@@ -0,0 +1,446 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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 /server-info>
+ * SetHandler server-info
+ * </Location>
+ *
+ * GET /server-info - Returns full configuration page for server and all modules
+ * GET /server-info?server - Returns server configuration only
+ * GET /server-info?module_name - Returns configuration for a single module
+ * GET /server-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[256];  /* What is the max size of a command? */
+       char *end_ret;
+
+       ret[0]='\0';
+       s = string;
+       t=ret;  
+       end_ret = t + sizeof(ret);
+       while((*s) && ((t-ret) < sizeof(ret))) {
+               if(*s=='<') { 
+                       strncpy(t,"&lt;", end_ret - t);
+                       t+=4;
+               } else if(*s=='>') {
+                       strncpy(t,"&gt;", end_ret - t);
+                       t+=4;
+               } else if(*s=='&') {
+                       strncpy(t,"&amp;", end_ret - t);
+                       t+=5;
+               } else {
+                   *t++=*s;
+               }
+               s++;
+       }
+       *t='\0';
+       return(ret);
+}
+
+mod_info_config_lines *mod_info_load_config(pool *p, char *filename, request_rec *r) {
+       char s[MAX_STRING_LEN];
+       FILE *fp;
+       mod_info_config_lines *new, *ret=NULL, *prev=NULL;
+       char *t,*tt,o, *msg;
+       
+       fp = pfopen(p,filename,"r");
+       if(!fp) {
+           msg = pstrcat
+                   (
+                       r->pool,
+                       "mod_info: couldn't open config file ",
+                       filename,
+                       NULL
+                   );
+           log_error (msg, r->server);
+           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[512], *cfname;
+       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];
+
+       r->content_type = "text/html";          
+       send_http_header(r);
+       if(r->header_only) {
+               return 0;
+    }
+       hard_timeout("send server info", r);
+       
+       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")) {
+               cfname = server_root_relative (r->pool, server_confname);
+               mod_info_cfg_httpd = mod_info_load_config (r->pool, cfname, r);
+               cfname = server_root_relative (r->pool, serv->srm_confname);
+               mod_info_cfg_srm = mod_info_load_config(r->pool, cfname, r);
+               cfname = server_root_relative (r->pool, serv->access_confname);
+               mod_info_cfg_access = mod_info_load_config (r->pool, cfname, r);
+               if(!r->args) {
+                       rputs("<tt><a href=\"#server\">Server Settings</a>, ",r);
+                       for(modp = top_module; modp; modp = modp->next) {
+                               ap_snprintf(buf, sizeof(buf), "<a href=\"#%s\">%s</a>",modp->name,modp->name);
+                               rputs(buf, r);
+                               if(modp->next) rputs(", ",r);
+                       }
+                       rputs("</tt><hr>",r);
+
+               }
+               if(!r->args || !strcasecmp(r->args,"server")) { 
+                       ap_snprintf(buf, sizeof(buf), "<a name=\"server\"><strong>Server Version:</strong> <font size=+1><tt>%s</tt></a></font><br>\n",SERVER_VERSION);
+                       rputs(buf,r);
+                       ap_snprintf(buf, sizeof(buf), "<strong>API Version:</strong> <tt>%d</tt><br>\n",MODULE_MAGIC_NUMBER);
+                       rputs(buf,r);
+                       ap_snprintf(buf, sizeof(buf), "<strong>Run Mode:</strong> <tt>%s</tt><br>\n",standalone?"standalone":"inetd");
+                       rputs(buf,r);
+                       ap_snprintf(buf, sizeof(buf), "<strong>User/Group:</strong> <tt>%s(%d)/%d</tt><br>\n",user_name,(int)user_id,(int)group_id);
+                       rputs(buf,r);
+                       ap_snprintf(buf, sizeof(buf), "<strong>Hostname/port:</strong> <tt>%s:%u</tt><br>\n",serv->server_hostname,serv->port);
+                       rputs(buf,r);
+                       ap_snprintf(buf, sizeof(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);
+                       ap_snprintf(buf, sizeof(buf), "<strong>Max Requests:</strong> <tt>per child: %d &nbsp;&nbsp; keep alive: %s &nbsp;&nbsp; max per connection: %d</tt><br>\n",max_requests_per_child,serv->keep_alive ? "on":"off", serv->keep_alive_max);
+                       rputs(buf,r);
+                       ap_snprintf(buf, sizeof(buf), "<strong>Timeouts:</strong> <tt>connection: %d &nbsp;&nbsp; keep-alive: %d</tt><br>",serv->timeout,serv->keep_alive_timeout);
+                       rputs(buf,r);
+                       ap_snprintf(buf, sizeof(buf), "<strong>Server Root:</strong> <tt>%s</tt><br>\n",server_root);
+                       rputs(buf,r);
+                       ap_snprintf(buf, sizeof(buf), "<strong>Config File:</strong> <tt>%s</tt><br>\n",server_confname);
+                       rputs(buf,r);
+                       ap_snprintf(buf, sizeof(buf), "<strong>PID File:</strong> <tt>%s</tt><br>\n",pid_fname);
+                       rputs(buf,r);
+                       ap_snprintf(buf, sizeof(buf), "<strong>Scoreboard File:</strong> <tt>%s</tt><br>\n",scoreboard_fname);
+                       rputs(buf,r);
+               }
+               rputs("<hr><dl>",r);
+               for(modp = top_module; modp; modp = modp->next) {
+                       if(!r->args || !strcasecmp(modp->name,r->args)) {       
+                               ap_snprintf(buf, sizeof(buf), "<dt><a name=\"%s\"><strong>Module Name:</strong> <font size=+1><tt>%s</tt></a></font>\n",modp->name,modp->name);
+                               rputs(buf,r);
+                               rputs("<dt><strong>Content-types affected:</strong>",r);        
+                               hand = modp->handlers;
+                               if(hand) {
+                                       while(hand) {
+                                               if(hand->content_type) {
+                                                       ap_snprintf(buf, sizeof(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) {
+                                                       ap_snprintf(buf, sizeof(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) {
+                       rputs(modp->name,r);
+                       if(modp->next) rputs("<br>",r);
+               }       
+       }       
+       rputs("</dl></body></html>\n",r);
+       /* Done, turn off timeout, close file and return */
+       kill_timeout(r);
+       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 */
+       NULL                            /* header parser */
+};
diff --git a/APACHE_1_2_X/src/modules/standard/mod_log_agent.c b/APACHE_1_2_X/src/modules/standard/mod_log_agent.c
new file mode 100644 (file)
index 0000000..234de33
--- /dev/null
@@ -0,0 +1,198 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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;
+}
+
+const 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);
+#ifdef __EMX__    
+    /* For OS/2 we need to use a '/' */
+    execl (SHELL_PATH, SHELL_PATH, "/c", (char *)cmd, NULL);
+#else    
+    execl (SHELL_PATH, SHELL_PATH, "-c", (char *)cmd, NULL);
+#endif    
+    perror ("exec");
+    fprintf (stderr, "Exec of shell for logging failed!!!\n");
+    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;
+       
+       if (!spawn_child (p, agent_log_child, (void *)(cls->fname+1),
+                   kill_after_timeout, &dummy, NULL)) {
+           perror ("spawn_child");
+           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) {
+        perror("open");
+        fprintf(stderr,"httpd: could not open agent log file %s.\n", fname);
+        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) 
+      {
+       ap_snprintf(str, sizeof(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 */
+   NULL                                /* header parser */
+};
diff --git a/APACHE_1_2_X/src/modules/standard/mod_log_config.c b/APACHE_1_2_X/src/modules/standard/mod_log_config.c
new file mode 100644 (file)
index 0000000..d383cd5
--- /dev/null
@@ -0,0 +1,787 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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 additional directives, LogFormat and CustomLog.
+ *
+ *
+ * Syntax:
+ *
+ *    TransferLog fn      Logs transfers to fn in standard log format, unless
+ *                        a custom format is set with LogFormat
+ *    LogFormat format    Set a log format from TransferLog files
+ *    CustomLog fn format
+ *                        Log to file fn with format given by the format
+ *                        argument
+ *
+ *    CookieLog fn        For backwards compatability with old Cookie
+ *                        logging module - now deprecated.
+ *
+ * There can be any number of TransferLog and CustomLog
+ * commands. Each request will be logged to _ALL_ the
+ * named files, in the appropriate format.
+ *
+ * If no TransferLog or CustomLog directive appears in a VirtualHost,
+ * the request will be logged to the log file(s) defined outside
+ * the virtual host section. If a TransferLog or CustomLog directive
+ * appears in the VirtualHost section, the log files defined outside
+ * the VirtualHost will _not_ be used. This makes this module compatable
+ * with the CLF and config log modules, where the use of TransferLog
+ * inside the VirtualHost section overrides its use outside.
+ * 
+ * Examples:
+ *
+ *    TransferLog    logs/access_log
+ *    <VirtualHost>
+ *    LogFormat      "... custom format ..."
+ *    TransferLog    log/virtual_only
+ *    CustomLog      log/virtual_useragents "%t %{user-agent}i"
+ *    </VirtualHost>
+ *
+ * This will log using CLF to access_log any requests handled by the
+ * main server, while any requests to the virtual host will be logged
+ * with the "... custom format..." to virtual_only _AND_ using
+ * the custom user-agent log to virtual_useragents.
+ *
+ * Note that the NCSA referer and user-agent logs are easily added with
+ * CustomLog:
+ *   CustomLog   logs/referer  "%{referer}i -> %U"
+ *   CustomLog   logs/agent    "%{user-agent}i"
+ *
+ * Except: no RefererIgnore functionality
+ *         logs '-' if no Referer or User-Agent instead of nothing
+ *
+ * But using this method allows much easier modification of the
+ * log format, e.g. to log hosts along with UA:
+ *   CustomLog   logs/referer "%{referer}i %U %h"
+ *
+ * The argument to LogFormat and CustomLog is a string, which can include
+ * literal characters copied into the log files, and '%' directives as
+ * follows:
+ *
+ * %...b:  bytes sent, excluding HTTP headers.
+ * %...{FOOBAR}e:  The contents of the environment variable FOOBAR
+ * %...f:  filename
+ * %...h:  remote host
+ * %...{Foobar}i:  The contents of Foobar: header line(s) in the request
+ *                 sent to the client.
+ * %...l:  remote logname (from identd, if supplied)
+ * %...{Foobar}n:  The contents of note "Foobar" from another module.
+ * %...{Foobar}o:  The contents of Foobar: header line(s) in the reply.
+ * %...p:  the port the request was served to
+ * %...P:  the process ID of the child that serviced the request.
+ * %...r:  first line of request
+ * %...s:  status.  For requests that got internally redirected, this
+ *         is status of the *original* request --- %...>s for the last.
+ * %...t:  time, in common log format time format
+ * %...{format}t:  The time, in the form given by format, which should
+ *                 be in strftime(3) format.
+ * %...T:  the time taken to serve the request, in seconds.
+ * %...u:  remote user (from auth; may be bogus if return status (%s) is 401)
+ * %...U:  the URL path requested.
+ * %...v:  the name of the server (i.e. which virtual host?)
+ *
+ * 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 "| ...").
+ *
+ * --- 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
+
+/*
+ * multi_log_state is our per-(virtual)-server configuration. We store
+ * an array of the logs we are going to use, each of type config_log_state.
+ * If a default log format is given by LogFormat, store in default_format
+ * (backward compat. with mod_log_config). We also store a pointer to
+ * the logs specified for the main server for virtual servers, so that
+ * if this vhost has now logs defined, we can use the main server's
+ * logs instead.
+ *
+ * So, for the main server, config_logs contains a list of the log files
+ * and server_config_logs in empty. For a vhost, server_config_logs
+ * points to the same array as config_logs in the main server, and
+ * config_logs points to the array of logs defined inside this vhost,
+ * which might be empty.
+ */
+
+typedef struct {
+  array_header *default_format;
+  array_header *config_logs;    
+  array_header *server_config_logs;
+} multi_log_state;
+
+/*
+ * config_log_state holds the status of a single log file. fname cannot
+ * be NULL. format might be NULL, in which case the default_format from
+ * the multi_log_state should be used, or if that is NULL as well, use
+ * the CLF. log_fd is -1 before the log file is opened and set to a valid
+ * fd after it is opened.
+ */
+
+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];
+    ap_snprintf (dummy, sizeof(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) {
+    char *rvalue = r->connection->user;
+
+    if (rvalue == NULL) {
+        rvalue = "-";
+    } else if (strlen (rvalue) == 0) {
+        rvalue = "\"\"";
+    }
+    return rvalue;
+}
+
+char *log_request_line (request_rec *r, char *a)
+{ return r->the_request; }
+
+char *log_request_file (request_rec *r, char *a)
+{ return r->filename; }
+char *log_request_uri (request_rec *r, char *a)
+{ return r->uri; }
+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);
+       ap_snprintf(dummy, sizeof(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 (!strcasecmp(a, "Content-type") && r->content_type)
+       cp = r->content_type;
+    if (cp) return cp;
+    return table_get (r->err_headers_out, a);
+}
+
+char *log_note (request_rec *r, char *a)
+{ return table_get (r->notes, 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)
+{
+    int timz;
+    struct tm *t;
+    char tstr[MAX_STRING_LEN];
+    
+    t = get_gmtoff(&timz);
+
+    if (a && *a) /* Custom format */
+       strftime(tstr, MAX_STRING_LEN, a, t);
+    else { /* CLF format */
+       char sign = (timz < 0 ? '-' : '+');
+
+       if(timz < 0) timz = -timz;
+
+       strftime(tstr,MAX_STRING_LEN,"[%d/%b/%Y:%H:%M:%S ",t);
+       ap_snprintf (tstr + strlen(tstr), sizeof(tstr)-strlen(tstr), 
+               "%c%.2d%.2d]", sign, timz/60, timz%60);
+    }
+
+    return pstrdup (r->pool, tstr);
+}
+
+char *log_request_duration (request_rec *r, char *a) {
+    char duration[22]; /* Long enough for 2^64 */
+
+    ap_snprintf(duration, sizeof(duration), "%ld", time(NULL) - r->request_time);
+    return pstrdup(r->pool, duration);
+}
+
+char *log_virtual_host (request_rec *r, char *a) {
+    return pstrdup(r->pool, r->server->server_hostname);
+}
+
+char *log_server_port (request_rec *r, char *a) {
+    char portnum[22];
+
+    ap_snprintf(portnum, sizeof(portnum), "%u", r->server->port);
+    return pstrdup(r->pool, portnum);
+}
+
+char *log_child_pid (request_rec *r, char *a) {
+    char pidnum[22];
+    ap_snprintf(pidnum, sizeof(pidnum), "%ld", (long)getpid());
+    return pstrdup(r->pool, pidnum);
+}
+/*****************************************************************
+ *
+ * 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 },
+    { 'T', log_request_duration, 1 },
+    { 'r', log_request_line, 1 },
+    { 'f', log_request_file, 0 },
+    { 'U', log_request_uri, 1 },
+    { 's', log_status, 1 },
+    { 'b', log_bytes_sent, 0 },
+    { 'i', log_header_in, 0 },
+    { 'o', log_header_out, 0 },
+    { 'n', log_note, 0 },
+    { 'e', log_env_var, 0 },
+    { 'v', log_virtual_host, 0 },
+    { 'p', log_server_port, 0 },
+    { 'P', log_child_pid, 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, const char *start, const 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, const char **sa)
+{
+    const 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, const char **sa)
+{
+    const 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, const char *s, const 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,
+                          array_header *default_format) {
+    array_header *strsa;
+    log_format_item *items;
+    char *str, **strs, *s;
+    request_rec *orig;
+    int i;
+    int len = 0;
+    array_header *format;
+
+    format = cls->format ? cls->format : default_format;
+
+    strsa= make_array(r->pool, format->nelts,sizeof(char*));
+    items = (log_format_item *)format->elts;
+
+    orig = r;
+    while (orig->prev) orig = orig->prev;
+    while (r->next) r = r->next;
+
+    for (i = 0; i < format->nelts; ++i)
+        *((char**)push_array (strsa)) = process_item (r, orig, &items[i]);
+
+    strs = (char **)strsa->elts;
+    
+    for (i = 0; i < format->nelts; ++i)
+        len += strlen (strs[i]);
+
+    str = palloc (r->pool, len + 1);
+
+    for (i = 0, s = str; i < format->nelts; ++i) {
+        strcpy (s, strs[i]);
+        s += strlen (strs[i]);
+    }
+    
+    write(cls->log_fd, str, strlen(str));
+
+    return OK;
+}
+
+int multi_log_transaction(request_rec *r)
+{
+    multi_log_state *mls = get_module_config (r->server->module_config,
+                                               &config_log_module);
+    config_log_state *clsarray;
+    int i;
+
+    if (mls->config_logs->nelts) {
+        clsarray = (config_log_state *)mls->config_logs->elts;
+        for (i = 0; i < mls->config_logs->nelts; ++i) {
+            config_log_state *cls = &clsarray[i];
+        
+            config_log_transaction(r, cls, mls->default_format);
+        }
+    }
+    else if (mls->server_config_logs) {
+        clsarray = (config_log_state *)mls->server_config_logs->elts;
+        for (i = 0; i < mls->server_config_logs->nelts; ++i) {
+            config_log_state *cls = &clsarray[i];
+        
+            config_log_transaction(r, cls, mls->default_format);
+        }
+    }
+
+    return OK;
+}
+
+/*****************************************************************
+ *
+ * Module glue...
+ */
+
+void *make_config_log_state (pool *p, server_rec *s)
+{
+    multi_log_state *mls =
+       (multi_log_state *)palloc(p, sizeof (multi_log_state));
+    
+    mls->config_logs = 
+       make_array(p, 5, sizeof (config_log_state));
+    mls->default_format = NULL;
+    mls->server_config_logs = NULL;
+    
+    return mls;
+}
+
+/*
+ * Use the merger to simply add a pointer from the vhost log state
+ * to the log of logs specified for the non-vhost configuration
+ */
+
+void *merge_config_log_state (pool *p, void *basev, void *addv)
+{
+    multi_log_state *base = (multi_log_state *)basev;
+    multi_log_state *add = (multi_log_state *)addv;
+    
+    add->server_config_logs = base->config_logs;
+    if (!add->default_format)
+        add->default_format = base->default_format;
+    
+    return add;
+}
+
+const char *log_format (cmd_parms *cmd, void *dummy, char *arg)
+{
+    const char *err_string = NULL;
+    multi_log_state *mls = get_module_config (cmd->server->module_config,
+                                              &config_log_module);
+  
+    mls->default_format = parse_log_string (cmd->pool, arg, &err_string);
+    return err_string;
+}
+
+const char *add_custom_log(cmd_parms *cmd, void *dummy, char *fn, char *fmt)
+{
+    const char *err_string = NULL;
+    multi_log_state *mls = get_module_config (cmd->server->module_config,
+                                             &config_log_module);
+    config_log_state *cls;
+
+    cls = (config_log_state*)push_array(mls->config_logs);
+    cls->fname = fn;
+    if (!fmt)
+       cls->format = NULL;
+    else
+       cls->format = parse_log_string (cmd->pool, fmt, &err_string);
+    cls->log_fd = -1;
+    
+    return err_string;
+}
+
+const char *set_transfer_log(cmd_parms *cmd, void *dummy, char *fn)
+{
+    return add_custom_log(cmd, dummy, fn, NULL);
+}
+
+const char *set_cookie_log(cmd_parms *cmd, void *dummy, char *fn)
+{
+    return add_custom_log(cmd, dummy, fn, "%{Cookie}n \"%r\" %t");
+}
+
+command_rec config_log_cmds[] = {
+{ "CustomLog", add_custom_log, NULL, RSRC_CONF, TAKE2,
+    "a file name and a custom log format string" },
+{ "TransferLog", set_transfer_log, NULL, RSRC_CONF, TAKE1,
+    "the filename of the access log" },
+{ "LogFormat", log_format, NULL, RSRC_CONF, TAKE1,
+    "a log format string (see docs)" },
+{ "CookieLog", set_cookie_log, NULL, RSRC_CONF, TAKE1,
+    "the filename of the cookie log" },
+{ 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);
+#ifdef __EMX__
+    /* For OS/2 we need to use a '/' */
+    execl (SHELL_PATH, SHELL_PATH, "/c", (char *)cmd, NULL);
+#else
+    execl (SHELL_PATH, SHELL_PATH, "-c", (char *)cmd, NULL);
+#endif
+    perror ("exec");
+    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 *cls,
+                                  array_header *default_format) {
+    if (cls->log_fd > 0) return cls; /* virtual config shared w/main server */
+
+    if (*cls->fname == '|') {
+        FILE *dummy;
+        
+        if (!spawn_child (p, config_log_child, (void *)(cls->fname+1),
+                    kill_after_timeout, &dummy, NULL)) {
+           perror ("spawn_child");
+            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) {
+            perror("open");
+            fprintf (stderr,
+                     "httpd: could not open transfer log file %s.\n", fname);
+            exit(1);
+        }
+    }
+
+    return cls;
+}
+
+config_log_state *open_multi_logs (server_rec *s, pool *p)
+{
+    int i;
+    multi_log_state *mls = get_module_config(s->module_config,
+                                             &config_log_module);
+    config_log_state *clsarray;
+    const char *dummy;
+
+    if (!mls->default_format)
+      mls->default_format = parse_log_string (p, DEFAULT_LOG_FORMAT, &dummy);
+
+    if (mls->config_logs->nelts) {
+        clsarray = (config_log_state *)mls->config_logs->elts;
+        for (i = 0; i < mls->config_logs->nelts; ++i) {
+            config_log_state *cls = &clsarray[i];
+
+            cls = open_config_log(s, p, cls, mls->default_format);
+                }
+    }
+    else if (mls->server_config_logs) {
+        clsarray = (config_log_state *)mls->server_config_logs->elts;
+        for (i = 0; i < mls->server_config_logs->nelts; ++i) {
+            config_log_state *cls = &clsarray[i];
+
+            cls = open_config_log(s, p, cls, mls->default_format);
+        }
+    }
+
+    return NULL;
+}
+
+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...
+     */
+    
+    open_multi_logs (s, p);
+    
+    /* Then, virtual servers */
+    
+    for (s = s->next; s; s = s->next) open_multi_logs (s, p);
+}
+
+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 */
+   merge_config_log_state,             /* 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 */
+   multi_log_transaction,      /* logger */
+   NULL                                /* header parser */
+};
diff --git a/APACHE_1_2_X/src/modules/standard/mod_log_referer.c b/APACHE_1_2_X/src/modules/standard/mod_log_referer.c
new file mode 100644 (file)
index 0000000..e494298
--- /dev/null
@@ -0,0 +1,235 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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;
+}
+
+const 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;
+}
+
+const 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);
+#ifdef __EMX__
+    /* For OS/2 we need to use a '/' */
+    execl (SHELL_PATH, SHELL_PATH, "/c", (char *)cmd, NULL);
+#else
+    execl (SHELL_PATH, SHELL_PATH, "-c", (char *)cmd, NULL);
+#endif
+    perror ("execl");
+    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;
+       
+       if (!spawn_child (p, referer_log_child, (void *)(cls->fname+1),
+                   kill_after_timeout, &dummy, NULL)) {
+           perror ("spawn_child");
+           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) {
+        perror("open");
+        fprintf(stderr,"httpd: could not open referer log file %s.\n", fname);
+        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 */
+   NULL                                /* header parser */
+};
diff --git a/APACHE_1_2_X/src/modules/standard/mod_mime.c b/APACHE_1_2_X/src/modules/standard/mod_mime.c
new file mode 100644 (file)
index 0000000..dc84975
--- /dev/null
@@ -0,0 +1,324 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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;
+}
+
+const 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;
+}
+
+const 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;
+}
+
+const 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;
+}
+
+const 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...
+ */
+
+const 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"))) {
+        perror("fopen");
+        fprintf(stderr,"httpd: could not open mime types file %s\n",
+                types_confname);
+        exit(1);
+    }
+
+    for(x=0;x<27;x++) 
+        hash_buckets[x] = make_table (p, 10);
+
+    while(!(cfg_getline(l,MAX_STRING_LEN,f))) {
+        const 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)
+{
+    const 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))) {
+         char **new;
+
+         r->content_language = type; /* back compat. only */
+         if (!r->content_languages)
+             r->content_languages = make_array (r->pool, 2, sizeof(char*));
+         new = (char **)push_array (r->content_languages);
+         *new = 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_languages = 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 */
+   NULL                                /* header parser */
+};
diff --git a/APACHE_1_2_X/src/modules/standard/mod_negotiation.c b/APACHE_1_2_X/src/modules/standard/mod_negotiation.c
new file mode 100644 (file)
index 0000000..02be3f1
--- /dev/null
@@ -0,0 +1,2041 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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"
+#include "util_script.h"
+
+/* define TCN_02 to allow for Holtman I-D transparent negotiation.
+ * This file currently implements the draft-02, except for
+ * anything to do with features and cache-control (max-age etc)
+ *
+ * Since the draft is just that, and we don't yet implement
+ * everything, regard the transparent negotiation stuff as experimental.
+ */
+/*#define TCN_02*/
+
+/* Commands --- configuring document caching on a per (virtual?)
+ * server basis...
+ */
+
+typedef struct {
+    array_header *language_priority;
+} neg_dir_config;
+
+module negotiation_module;
+
+char *merge_string_array (pool *p, array_header *arr, char *sep)
+{
+    int i;
+    char *t = "";
+
+    for (i = 0; i < arr->nelts; i++) {
+       t = pstrcat(p, t, i ? sep : "", ((char**)arr->elts)[i], NULL);
+    }
+    return t;
+}
+
+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;
+}
+
+const 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;
+}
+
+const 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 }
+};
+
+/* 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;
+    char *charset;              /* for content-type only */
+} 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:
+ *
+ * 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;
+    array_header *content_languages; /* list of languages for this variant */
+    char *content_charset;
+    char *description;
+
+    /* The next five items give the quality values for the dimensions
+     * of negotiation for this variant. They are obtained from the
+     * appropriate header lines, except for accept_type_quality, which
+     * is obtained from the variant itself (the 'qs' parameter value
+     * from the variant's mime-type). Apart from type_quality,
+     * these values are set when we find the quality for each variant
+     * (see best_match()). type_quality is set from the 'qs' parameter
+     * of the variant description or mime type: see set_mime_fields().
+     */
+    float lang_quality;         /* quality of this variant's language */
+    int   encoding_quality;     /* ditto encoding (1 or 0 only) */
+    float charset_quality;      /* ditto charset */
+    float accept_type_quality;  /* ditto media type */
+    float type_quality;         /* quality of source for this type */
+
+    /* Now some special values */
+    float level;                /* Auxiliary to content-type... */
+    float bytes;               /* content length, if known */
+    int lang_index;             /* pre HTTP/1.1 language priority stuff */
+    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 level_matched;
+    int mime_stars;
+    int definite;
+} 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;
+    int accept_q;              /* 1 if an Accept item has a q= param */
+    float default_lang_quality;        /* fiddle lang q for variants with no lang */
+
+   
+    array_header *accepts;      /* accept_recs */
+    int have_accept_header;    /* 1 if Accept-Header present */
+    array_header *accept_encodings; /* accept_recs */
+    array_header *accept_charsets; /* accept_recs */
+    array_header *accept_langs; /* accept_recs */
+    array_header *avail_vars;   /* available variants */
+
+    int ua_can_negotiate;       /* 1 if ua can do transparent negotiate */
+    int use_transparent_neg;    /* 1 if we are using transparent neg */
+    int short_accept_headers;   /* 1 if ua does trans neg & sent short accpt */
+} 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_languages = NULL;
+    mime_info->content_charset = "";
+    mime_info->description = "";
+
+    mime_info->is_pseudo_html = 0;
+    mime_info->level = 0.0;
+    mime_info->level_matched = 0.0;
+    mime_info->bytes = 0;
+    mime_info->lang_index = -1;
+    mime_info->mime_stars = 0;
+    mime_info->definite = 1;
+
+    mime_info->charset_quality = 1.0;
+    mime_info->type_quality = 0.0;
+    mime_info->encoding_quality = 1;
+    mime_info->lang_quality = 1.0;
+    mime_info->accept_type_quality = 1.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->type_quality = mime_info->quality;
+    var->level = mime_info->level;
+    var->content_charset = mime_info->charset;
+
+    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;
+    result->charset = "";
+    
+    /* 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;
+       char *end;
+           
+       ++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;
+           for (end = cp; *end && 
+                    *end != '\n' && *end != '\r' && *end != '\"';
+                end++)
+               ;
+       }
+       else {
+           for (end = cp; *end && !isspace(*end); end++)
+               ;
+       }
+       if (*end)
+           *end = '\0';        /* strip ending quote or return */
+       str_tolower(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);
+       else if (!strcmp(parm, "charset"))
+           result->charset = cp;
+    }
+
+    if (*accept_line == ',') ++accept_line;
+
+    return accept_line;
+}
+                 
+/*****************************************************************
+ *
+ * Dealing with header lines ...
+ *
+ * Accept, Accept-Charset, Accept-Language and Accept-Encoding
+ * are handled by do_header_line() - they all have the same
+ * basic structure of a list of items of the format
+ *    name; q=N; charset=TEXT
+ *
+ * where q is only valid in Accept, Accept-Charset and Accept-Languages,
+ * and charset is only valid in Accept.
+ */
+
+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;
+}
+
+/* Given the text of the Content-Languages: line from the var map file,
+ * return an array containing the languages of this variant
+ */
+
+array_header *do_languages_line (pool *p, char **lang_line)
+{
+    array_header *lang_recs = make_array (p, 2, sizeof (char *));
+  
+    if (!lang_line) return lang_recs;
+    
+    while (**lang_line) {
+        char **new = (char **)push_array (lang_recs);
+       *new = get_token (p, lang_line, 0);
+       str_tolower (*new);
+       if (**lang_line == ',' || **lang_line == ';')
+           ++(*lang_line);
+    }
+
+    return lang_recs;
+}
+
+/*****************************************************************
+ *
+ * Handling header lines from clients...
+ */
+
+negotiation_state *parse_accept_headers (request_rec *r)
+{
+    negotiation_state *new =
+        (negotiation_state *)pcalloc (r->pool, sizeof (negotiation_state));
+    accept_rec *elts;
+    table *hdrs = r->headers_in;
+    int i;   
+    char *hdr;
+
+    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"));
+
+    hdr = table_get (hdrs, "Accept-encoding");
+    if (hdr)
+      new->have_accept_header = 1;
+    new->accept_encodings = do_header_line (r->pool, hdr);
+
+    new->accept_langs =
+      do_header_line (r->pool, table_get (hdrs, "Accept-language"));
+    new->accept_charsets =
+      do_header_line (r->pool, table_get (hdrs, "Accept-charset"));
+    new->avail_vars = make_array (r->pool, 40, sizeof (var_rec));
+
+#ifdef TCN_02
+    if (table_get(r->headers_in, "Negotiate")) {
+        /* Negotiate: header tells us UA does transparent negotiation
+         * We have to decide whether we want to ... for now, yes,
+         * we do */
+
+        new->ua_can_negotiate = 1;
+        if (r->method_number == M_GET)
+            new->use_transparent_neg = 1; /* should be configurable */
+
+        /* Check for 'Short Accept', ie either no Accept: header,
+         * or just "Accept: * / *" */
+        if (new->accepts->nelts == 0 || 
+            (new->accepts->nelts == 1 &&
+            (!strcmp(((accept_rec *)new->accepts->elts)[0].type_name, 
+                                               "*/*")))) {
+            /* Using short accept header */
+            new->short_accept_headers = 1;
+        }
+    }
+#endif
+
+    if (!new->use_transparent_neg) {
+        /* Now we check for q-values. If they're all 1.0, we assume the
+         * client is "broken", and we are allowed to fiddle with the
+         * values later. Otherwise, we leave them alone.
+         */
+    
+        elts = (accept_rec *)new->accepts->elts;
+    
+        for (i = 0; i < new->accepts->nelts; ++i)
+            if (elts[i].quality < 1.0) new->accept_q = 1;
+    }
+    else new->accept_q = 1;
+    
+    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_languages = 
+                   do_languages_line(neg->pool, &body);
+           }
+           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 (!strncmp (buffer, "description:", 12)) {
+               mime_info.description = get_token (neg->pool, &body, 0);
+           }
+       } else {
+           if (mime_info.type_quality > 0 && *mime_info.file_name)
+               {
+                   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... */
+
+    if (strncmp(r->filename, "proxy:", 6) == 0)
+        return DECLINED;
+
+    ++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 != HTTP_OK || !sub_req->content_type) {
+           destroy_sub_req(sub_req);
+           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);
+       if (sub_req->content_encoding) {
+           mime_info.content_encoding = sub_req->content_encoding;
+           str_tolower(mime_info.content_encoding);
+       }
+       if (sub_req->content_languages) {
+           int i;
+           mime_info.content_languages = sub_req->content_languages;
+           if (mime_info.content_languages)
+               for (i = 0; i < mime_info.content_languages->nelts; ++i)
+                   str_tolower(((char**)
+                                (mime_info.content_languages->elts))[i]);
+       }
+
+       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.  The main entry point is set_language_quality()
+ * which is called for each variant. It sets two elements in the
+ * variant record:
+ *    language_quality  - the 'q' value of the 'best' matching language
+ *                        from Accept-Language: header (HTTP/1.1)
+ *    lang_index    -     Pre HTTP/1.1 language priority, using
+ *                        position of language on the Accept-Language:
+ *                        header, if present, else LanguagePriority
+ *                        directive order.
+ *
+ * When we do the variant checking for best variant, we use language
+ * quality first, and if a tie, language_index next (this only
+ * applies when _not_ using the network algorithm). If using
+ * network algorithm, lang_index is never used.
+ *
+ * set_language_quality() calls find_lang_index() and find_default_index()
+ * to set lang_index.
+ */
+
+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;
+}
+
+/* set_default_lang_quality() sets the quality we apply to variants
+ * which have no language assigned to them. If none of the variants
+ * have a language, we are not negotiating on language, so all are
+ * acceptable, and we set the default q value to 1.0. However if
+ * some of the variants have languages, we set this default to 0.001.
+ * The value of this default will be applied to all variants with
+ * no explicit language -- which will have the effect of making them
+ * acceptable, but only if no variants with an explicit language
+ * are acceptable. The default q value set here is assigned to variants
+ * with no language type in set_language_quality().
+ *
+ * Note that if using the transparent negotiation network algorythm,
+ * we don't use this fiddle.
+ */
+
+void set_default_lang_quality(negotiation_state *neg)
+{
+    var_rec *avail_recs = (var_rec *)neg->avail_vars->elts;
+    int j;
+
+    if (!neg->use_transparent_neg)
+       for (j = 0; j < neg->avail_vars->nelts; ++j) {
+           var_rec *variant = &avail_recs[j];
+           if (variant->content_languages && 
+               variant->content_languages->nelts) {
+               neg->default_lang_quality = 0.001;
+               return;
+           }
+       }
+         
+    neg->default_lang_quality = 1.0;
+}
+
+/* Set the language_quality value in the variant record. Also
+ * assigns lang_index for back-compat. 
+ *
+ * To find the language_quality value, we look for the 'q' value
+ * of the 'best' matching language on the Accept-Language:
+ * header. The'best' match is the language on Accept-Language:
+ * header which matches the language of this variant either fully,
+ * or as far as the prefix marker (-). If two or more languages
+ * match, use the longest string from the Accept-Language: header
+ * (see HTTP/1.1 [14.4])
+ *
+ * When a variant has multiple languages, we find the 'best'
+ * match for each variant language tag as above, then select the
+ * one with the highest q value. Because both the accept-header
+ * and variant can have multiple languages, we now have a hairy
+ * loop-within-a-loop here.
+ *
+ * If the variant has no language and we have no Accept-Language
+ * items, leave the quality at 1.0 and return.
+ *
+ * If the variant has no language, we use the default as set by
+ * set_default_lang_quality() (1.0 if we are not negotiating on
+ * language, 0.001 if we are).
+ *
+ * Following the setting of the language quality, we drop through to
+ * set the old 'lang_index'. This is set based on either the order
+ * of the languages on the Accept-Language header, or the
+ * order on the LanguagePriority directive. This is only used
+ * in the negotiation if the language qualities tie.
+ */
+
+void set_language_quality(negotiation_state *neg, var_rec *variant)
+{
+    int i;
+    int naccept = neg->accept_langs->nelts;
+    int index;
+    neg_dir_config *conf = NULL;
+    char *firstlang;
+
+    if (naccept == 0)
+        conf = (neg_dir_config *) get_module_config (neg->r->per_dir_config,
+                                                     &negotiation_module);
+
+    if (naccept == 0 && (!variant->content_languages || 
+                        !variant->content_languages->nelts))
+       return;                 /* no accept-language and no variant lang */
+
+    if (!variant->content_languages || !variant->content_languages->nelts) {
+        /* This variant has no content-language, so use the default
+        * quality factor for variants with no content-language
+        * (previously set by set_default_lang_quality()). */
+        variant->lang_quality = neg->default_lang_quality;
+
+       if (naccept == 0)
+           return;             /* no accept-language items */
+
+    }
+    else if (naccept) {
+       /* Variant has one (or more) languages, and we have one (or more)
+        * language ranges on the Accept-Language header. Look for
+        * the best match. We do this by going through each language
+        * on the variant description looking for a match on the
+        * Accept-Language header. The best match is the longest matching
+        * language on the header. The final result is the best q value
+        * from all the languages on the variant description.
+        */
+       int j;
+       float fiddle_q = 0.0;
+       accept_rec *accs = (accept_rec *)neg->accept_langs->elts;
+       accept_rec *best = NULL, *star = NULL;
+       char *p;
+       
+       for (j = 0; j < variant->content_languages->nelts; ++j) {
+           char *lang;         /* language from variant description */
+           accept_rec *bestthistag = NULL;
+           int prefixlen = 0;
+           int longest_lang_range_len = 0;
+           int len;
+           /* lang is the variant's language-tag, which is the one
+            * we are allowed to use the prefix of in HTTP/1.1
+            */
+           lang = ((char **)(variant->content_languages->elts))[j];
+           p = strchr(lang, '-');      /* find prefix part (if any) */
+           if (p)
+               prefixlen = p - lang; 
+           
+           /* now find the best (i.e. longest) matching Accept-Language
+            * header language. We put the best match for this tag in 
+            * bestthistag. We cannot update the overall best (based on
+            * q value) because the best match for this tag is the longest
+            * language item on the accept header, not necessarily the
+            * highest q.
+            */
+           for (i = 0; i < neg->accept_langs->nelts; ++i) {
+               if (!strcmp(accs[i].type_name, "*")) {
+                   if (!star)
+                       star = &accs[i];
+                   continue;
+               }
+              
+               /* Find language. We match if either the variant language
+                * tag exactly matches, or the prefix of the tag up to the
+                * '-' character matches the whole of the language in the
+                * Accept-Language header. We only use this accept-language
+                * item as the best match for the current tag if it
+                * is longer than the previous best match */
+               if ((!strcmp (lang, accs[i].type_name) ||
+                    (prefixlen &&
+                     !strncmp(lang, accs[i].type_name, prefixlen) &&
+                     (accs[i].type_name[prefixlen] == '\0'))) &&
+                   ((len = strlen(accs[i].type_name)) > 
+                                     longest_lang_range_len)) {
+                   longest_lang_range_len = len;
+                   bestthistag = &accs[i];
+               }
+  
+               if (! bestthistag) {
+                   /* The next bit is a fiddle. Some browsers might be
+                    * configured to send more specific language ranges
+                    * than desirable. For example, an Accept-Language of
+                    * en-US should never match variants with languages en
+                    * or en-GB. But US English speakers might pick en-US
+                    * as their language choice.  So this fiddle checks if
+                    * the language range has a prefix, and if so, it
+                    * matches variants which match that prefix with a
+                    * priority of 0.001. So a request for en-US would
+                    * match variants of types en and en-GB, but at much
+                    * lower priority than matches of en-US directly, or
+                    * of any other language listed on the Accept-Language
+                    * header
+                    */
+                   if ((p = strchr(accs[i].type_name, '-'))) {
+                       int plen = p - accs[i].type_name;
+                       if (!strncmp(lang, accs[i].type_name, plen))
+                           fiddle_q = 0.001;
+                   }
+               }
+           }
+           /* Finished looking at Accept-Language headers, the best
+            * (longest) match is in bestthistag, or NULL if no match
+            */
+           if (!best ||
+               (bestthistag && bestthistag->quality > best->quality))
+               best = bestthistag;
+          }
+       
+          variant->lang_quality = best ? best->quality : 
+                            (star ? star->quality : fiddle_q);
+    }
+
+    /* Now set the old lang_index field. Since this is old 
+     * stuff anyway, don't both with handling multiple languages
+     * per variant, just use the first one assigned to it
+     */
+    index = 0;
+    if (variant->content_languages && variant->content_languages->nelts)
+       firstlang = ((char**)variant->content_languages->elts)[0];
+    else
+       firstlang = "";
+    if (naccept == 0)           /* Client doesn't care */
+        index = find_default_index (conf, firstlang);
+    else                        /* Client has Accept-Language */
+        index = find_lang_index (neg->accept_langs, firstlang);
+    variant->lang_index = index;
+
+    return;             
+}
+
+/* Determining the content length --- if the map didn't tell us,
+ * we have to do a stat() and remember for next time.
+ *
+ * Grump.  For Apache, 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;
+}
+
+/* For a given variant, find the best matching Accept: header
+ * and assign the Accept: header's quality value to the
+ * accept_type_quality field of the variant, for later use in
+ * determining the best matching variant.
+ */
+
+void set_accept_quality(negotiation_state *neg, var_rec *variant)
+{
+    int i;
+    accept_rec *accept_recs = (accept_rec *)neg->accepts->elts;
+    float q = 0.0;
+    int q_definite = 1;
+
+    /* if no Accept: header, leave quality alone (will
+     * remain at the default value of 1) */
+    if (!neg->accepts || neg->accepts->nelts == 0) 
+        return;
+
+    /*
+     * Go through each of the ranges on the Accept: header,
+     * looking for the 'best' match with this variant's
+     * content-type. We use the best match's quality
+     * value (from the Accept: header) for this variant's
+     * accept_type_quality field.
+     *
+     * The best match is determined like this:
+     *    type/type is better than type/ * is better than * / *
+     *    if match is type/type, use the level mime param if available
+     */
+    for (i = 0; i < neg->accepts->nelts; ++i) {
+
+        accept_rec *type = &accept_recs[i];
+        int prev_mime_stars;
+            
+        prev_mime_stars = variant->mime_stars;
+
+        if (!mime_match(type, variant)) 
+            continue;           /* didn't match the content type at all */
+        else 
+            /* did match - see if there were less or more stars than
+             * in previous match
+             */
+            if (prev_mime_stars == variant->mime_stars)
+                continue;       /* more stars => not as good a match */
+
+        /* Check maxbytes -- not in HTTP/1.1 or Holtman */
+                
+        if (type->max_bytes > 0
+            && (find_content_length(neg, variant)
+                > type->max_bytes))
+            continue;
+        
+        /* If we are allowed to mess with the q-values,
+         * make wildcards very low, so we have a low chance
+         * of ending up with them if there's something better.
+         */
+
+        if (!neg->accept_q && variant->mime_stars == 1) q = 0.01;
+        else if (!neg->accept_q && variant->mime_stars == 2) q = 0.02;
+        else q = type->quality;
+
+        q_definite = (variant->mime_stars == 3);
+    }
+    variant->accept_type_quality = q;
+    variant->definite=variant->definite && q_definite;
+
+    /* if the _best_ quality we got for this variant was 0.0,
+     * eliminate it now */
+}
+
+/* For a given variant, find the 'q' value of the charset given
+ * on the Accept-Charset line. If not charsets are listed,
+ * assume value of '1'.
+ */
+
+void set_charset_quality(negotiation_state *neg, var_rec *variant)
+{
+    int i;
+    accept_rec *accept_recs = (accept_rec *)neg->accept_charsets->elts;
+    char *charset = variant->content_charset;
+    accept_rec *star = NULL;
+
+    /* if no Accept-Charset: header, leave quality alone (will
+     * remain at the default value of 1) */
+    if (!neg->accept_charsets || neg->accept_charsets->nelts == 0) 
+        return;
+
+    if (charset == NULL || !*charset) charset = "iso-8859-1";
+
+    /*
+     * Go through each of the items on the Accept-Charset: header,
+     * looking for a match with this variant's charset. If none
+     * match, charset is unacceptable, so set quality to 0.
+     */
+    for (i = 0; i < neg->accept_charsets->nelts; ++i) {
+
+        accept_rec *type = &accept_recs[i];
+            
+        if (!strcmp(type->type_name, charset)) {
+            variant->charset_quality = type->quality;
+            return;
+        } else
+        if (strcmp(type->type_name, "*") == 0) {
+            star = type;    
+        }
+    }
+    /* No explicit match */
+    if (star) {
+        variant->charset_quality = star->quality;
+        return;
+    }
+    /* If this variant is in charset iso-8859-1, the default is 1.0 */
+    if (strcmp(charset, "iso-8859-1") == 0) {
+        variant->charset_quality = 1.0;
+    } else {
+        variant->charset_quality = 0.0;
+    }
+}
+
+/* For a given variant, find the best matching Accept: header
+ * and assign the Accept: header's quality value to the
+ * accept_type_quality field of the variant, for later use in
+ * determining the best matching variant.
+ */
+
+/* is_identity_encoding is included for back-compat, but does anyone
+ * use 7bit, 8bin or binary in their var files??
+ */
+
+int is_identity_encoding (char *enc)
+{
+    return (!enc || !enc[0] || !strcmp (enc, "7bit") || !strcmp (enc, "8bit")
+            || !strcmp (enc, "binary"));
+}
+
+void set_encoding_quality(negotiation_state *neg, var_rec *variant)
+{
+    int i;
+    accept_rec *accept_recs = (accept_rec *)neg->accept_encodings->elts;
+    char *enc = variant->content_encoding;
+
+    if (!enc || is_identity_encoding(enc))
+        return;
+    
+
+    /* if no Accept: header, leave quality alone (will
+     * remain at the default value of 1) */
+    if (neg->accept_encodings->nelts == 0) {
+        /* If we had an empty Accept-Encoding header, assume that
+        * no encodings are acceptable, else all encodings are ok */
+        variant->encoding_quality = neg->have_accept_header ? 0 : 1;
+        return;
+    }
+
+    /* Go through each of the encodings on the Accept-Encoding: header,
+     * looking for a match with our encoding
+     */
+    for (i = 0; i < neg->accept_encodings->nelts; ++i) {
+        char *name = accept_recs[i].type_name;
+
+        if (!strcmp(name, enc)) {
+            variant->encoding_quality = 1;
+            return;
+        }
+    }
+
+    /* Encoding not found on Accept-Encoding: header, so it is
+     * _not_ acceptable */
+    variant->encoding_quality = 0;
+}
+
+/* Possible results of the network algorithm */
+enum algorithm_results {
+    na_not_applied = -1,        /* net algorithm not used */
+    na_choice = 1,              /* choose variant */
+    na_list                     /* list variants */
+};
+
+/*
+ * This is a heavily-rewritten 'best_match' function. For a start, it
+ * now returns an int, which has one of the three values: na_not_applied,
+ * na_choice or na_list, which give the result of the network algorithm
+ * (if it was not applied, the return value is na_not_applied).
+ * The best variable is returned in *pbest. It also has two possible
+ * algorithms for determining the best match: the network algorithm,
+ * and the standard Apache algorithm. These are split out into
+ * separate functions (is_variant_better_na() and is_variant_better()).
+ *
+ * Previously, best_match iterated first through the content_types
+ * in the Accept: header, then checked each variant, and eliminated
+ * those that didn't match the variant's type. We cannot do this because
+ * we need full information, including language, charset, etc
+ * quality for _every_ variant, for the Alternates: header,
+ * and (possibly) the human-readable choice responses or 406 errors.
+ *
+ * After the 'best' (if any) is determined, the overall result of
+ * the negotiation is obtained. If the network algorithm was not
+ * in use, the result is na_not_applied. Else the result is
+ * na_list if 'short accept header' is in use, else na_list
+ * if _no_ best match was found, or na_choice if a best match
+ * was found.
+ */
+
+/* Firstly, the negotiation 'network algorithm' from Holtman.
+ */
+
+int is_variant_better_na(negotiation_state *neg, var_rec *variant, var_rec *best, float *p_bestq)
+{
+    float bestq = *p_bestq, q;
+
+    /* Note: Encoding is not negotiated in the Holtman
+     * transparent neg draft, so we ignored it here. But
+     * it does mean we could return encodings the UA
+     * or proxy cannot handle. Eek. */
+    
+    q = variant->accept_type_quality *
+        variant->type_quality *
+        variant->charset_quality *
+        variant->lang_quality;
+    
+#ifdef NEG_DEBUG
+    fprintf(stderr, "Variant: file=%s type=%s lang=%s acceptq=%1.3f langq=%1.3f typeq=%1.3f q=%1.3f definite=%d\n",
+            variant->file_name ? variant->file_name : "",
+            variant->type_name ? variant->type_name : "",
+            variant->content_languages ? merge_string_array(neg->pool, variant->content_languages, ",") : "",
+            variant->accept_type_quality,
+            variant->lang_quality,
+            variant->type_quality,
+            q,
+            variant->definite
+            );
+#endif
+    
+    if (q > bestq) {
+        *p_bestq = q;
+        return 1;
+    }
+    if (q == bestq) {  
+        /* If the best variant's charset is ISO-8859-1 and this variant has
+           the same charset quality, then we prefer this variant */
+        if (variant->charset_quality == best->charset_quality &&
+            (best->content_charset == NULL || *best->content_charset == 0 ||
+            strcmp(best->content_charset, "iso-8859-1") == 0)) {
+            *p_bestq = q;
+            return 1;
+       }
+    }
+    return 0;
+}    
+
+/* Negotiation algorithm as used by previous versions of Apache
+ * (just about). 
+ */
+
+float is_variant_better(negotiation_state *neg, var_rec *variant, var_rec *best, float *p_bestq)
+{
+    float bestq = *p_bestq, q;
+    int levcmp;
+
+    /*
+     * For non-transparent negotiation, server can choose how
+     * to handle the negotiation. We'll use the following in
+     * order: content-type, language, content-type level, charset,
+     * content length.
+     *
+     * For each check, we have three possible outcomes:
+     *   This variant is worse than current best: return 0
+     *   This variant is better than the current best:
+     *          assign this variant's q to *p_bestq, and return 1
+     *   This variant is just as desirable as the current best:
+     *          drop through to the next test.
+     *
+     * This code is written in this long-winded way to allow future
+     * customisation, either by the addition of additional
+     * checks, or to allow the order of the checks to be determined
+     * by configuration options (e.g. we might prefer to check
+     * language quality _before_ content type).
+     */
+
+    /* First though, eliminate this variant if it is not
+     * acceptable by type, charset, encoding or language.
+     */
+
+    if (variant->encoding_quality == 0 ||
+        variant->lang_quality == 0 ||
+        variant->type_quality == 0 ||
+        variant->charset_quality == 0 ||
+        variant->accept_type_quality == 0)
+        return 0;               /* don't consider unacceptables */
+    
+    q = variant->accept_type_quality * variant->type_quality;
+    if (q == 0.0 || q < bestq) return 0;
+    if (q > bestq || !best) {
+        *p_bestq = q;
+        return 1;
+    }
+    
+    /* language */
+    if (variant->lang_quality < best->lang_quality)
+        return 0;
+    if (variant->lang_quality > best->lang_quality) {
+        *p_bestq = q;
+        return 1;
+    }
+    
+    /* if language qualities were equal, try the LanguagePriority
+     * stuff */
+    if (best->lang_index != -1 && variant->lang_index > best->lang_index)
+        return 0;
+    if (variant->lang_index != -1 &&
+        (variant->lang_index < best->lang_index || best->lang_index == -1)) {
+        *p_bestq = q;
+        return 1;
+    }
+    
+    /* content-type level (text/html only?) */
+    levcmp = level_cmp (variant, best);
+    if (levcmp == -1) return 0;
+    if (levcmp == 1) {
+        *p_bestq = q;
+        return 1;
+    }
+    
+    /* encoding -- can only be 1 or 0, and if 0 we eliminated this
+     * variant at the start of this function. However we 
+     * prefer variants with no encoding over those with encoding */
+    if (!*best->content_encoding && *variant->content_encoding)
+       return 0;
+    if (*best->content_encoding && !*variant->content_encoding) {
+       *p_bestq = q;
+       return 1;
+    }
+    
+
+    /* charset */
+    if (variant->charset_quality < best->charset_quality)
+        return 0;
+    /* If the best variant's charset is ISO-8859-1 and this variant has
+       the same charset quality, then we prefer this variant */
+    if (variant->charset_quality > best->charset_quality ||
+        (variant->charset_quality == best->charset_quality &&
+        (best->content_charset == NULL || *best->content_charset == 0 ||
+        strcmp(best->content_charset, "iso-8859-1") == 0))) {
+        *p_bestq = q;
+        return 1;
+    }
+    
+    
+    /* content length if all else equal */
+    if (find_content_length(neg, variant)
+         >=
+         find_content_length(neg, best))
+        return 0;
+    
+    /* ok, to get here means every thing turned out equal, except
+     * we have a shorter content length, so use this variant */
+    *p_bestq = q;
+    return 1;
+}
+
+int best_match(negotiation_state *neg, var_rec **pbest)
+{
+    int j;
+    var_rec *best = NULL;
+    float bestq = 0.0;
+    enum algorithm_results algorithm_result = na_not_applied;
+    
+    var_rec *avail_recs = (var_rec *)neg->avail_vars->elts;
+
+    set_default_lang_quality(neg);
+
+    /*
+     * Find the 'best' variant
+     */
+
+    for (j = 0; j < neg->avail_vars->nelts; ++j) {
+            
+        var_rec *variant = &avail_recs[j];
+
+        /* Find all the relevant 'quality' values from the
+         * Accept... headers, and store in the variant
+         */
+        set_accept_quality(neg, variant);
+        set_language_quality(neg, variant);
+        set_encoding_quality(neg, variant);
+        set_charset_quality(neg, variant);
+
+        /* Now find out if this variant is better than the current
+         * best, either using the network algorithm, or Apache's
+         * internal server-driven algorithm. Presumably other
+         * server-driven algorithms are possible, and could be
+         * implemented here.
+         */
+
+        if (neg->use_transparent_neg) {
+            if (is_variant_better_na(neg, variant, best, &bestq))
+                best = variant;
+        } 
+        else {
+            if (is_variant_better(neg, variant, best, &bestq))
+                best = variant;
+        }
+    }
+
+    /* We now either have a best variant, or no best variant 
+     */
+    if (neg->use_transparent_neg) {
+        if (neg->short_accept_headers)
+            algorithm_result = na_list;
+        else {
+            /* From Holtman, result is:
+             *   If variant & URI are not neigbors, list_ua or list_os
+             *   Else
+             *     If UA can do trans neg
+             *        IF best is definite && best q > 0, choice_ua 
+             *        ELSE                               list_ua
+             *     ELSE
+             *        IF best q > 0, choose_os
+             *        ELSE           list_os (or forward_os on proxy)
+             */
+
+            /* assume variant and URI are neigbors (since URI in
+             * var map must be in same directory) */
+            
+            if(neg->use_transparent_neg)
+               algorithm_result = (best && best->definite) && (bestq>0)
+                                       ? na_choice : na_list;
+            else
+               algorithm_result = bestq>0 ? na_choice : na_list;
+        }
+    }   
+
+    *pbest = best;
+    return algorithm_result;
+}
+
+/*
+ * Sets the Alternates and Vary headers, used if we are going to
+ * return 406 Not Acceptable status, a 300 Multiple Choice status,
+ * or a Choice response.
+ *
+ * 'type' is the result of the network algorithm, if applied.
+ * We do different things if the network algorithm was not applied
+ * (type == na_not_applied): no Alternates header, and Vary:
+ * does not include 'negotiate'.
+ *
+ * We should also add a max-age lifetime for the Alternates header,
+ * but how long we we give it? Presumably this should be
+ * configurable in the map file.
+ */
+
+void set_neg_headers(request_rec *r, negotiation_state *neg, int na_result)
+{
+    int j;
+    var_rec *avail_recs = (var_rec *)neg->avail_vars->elts;
+    char *sample_type = NULL;
+    char *sample_language = NULL;
+    char *sample_encoding = NULL;
+    char *sample_charset = NULL;
+    int vary_by_type = 0;
+    int vary_by_language = 0;
+    int vary_by_charset = 0;
+    int vary_by_encoding = 0;
+    array_header *hdrs;
+
+    /* Put headers into err_headers_out, new send_http_header()
+     * outputs both headers_out and err_headers_out */
+    hdrs = r->err_headers_out;
+
+    for (j = 0; j < neg->avail_vars->nelts; ++j) {
+            
+        var_rec *variant = &avail_recs[j];
+        char *rec;
+        char qstr[6];
+        long len;
+        char lenstr[22];                /* enough for 2^64 */
+
+        ap_snprintf(qstr, sizeof(qstr), "%1.3f", variant->type_quality);
+
+        /* Strip trailing zeros (saves those valuable network bytes) */
+        if (qstr[4] == '0') {
+            qstr[4] = '\0';
+            if (qstr[3] == '0') {
+                qstr[3] = '\0';
+                if (qstr[2] == '0') {
+                    qstr[1] = '\0';
+                }
+            }
+        }
+                              
+        rec = pstrcat(r->pool, "{\"", variant->file_name, "\" ", qstr, NULL);
+        if (variant->type_name) {
+           if (*variant->type_name)
+               rec = pstrcat(r->pool, rec, " {type ", 
+                             variant->type_name, "}", NULL);
+           if (!sample_type) sample_type = variant->type_name;
+           else if (strcmp(sample_type, variant->type_name))
+             vary_by_type = 1;
+        }
+        if (variant->content_languages && variant->content_languages->nelts) {
+           char *langs = 
+               merge_string_array (r->pool, variant->content_languages, ",");
+           rec = pstrcat(r->pool, rec, " {language ", langs, "}", NULL);
+            if (!sample_language) sample_language = langs;
+            else if (strcmp(sample_language, langs))
+                vary_by_language = 1;
+        }
+        if (variant->content_encoding) {
+            if (!sample_encoding) sample_encoding = variant->content_encoding;
+            else if (strcmp(sample_encoding, variant->content_encoding))
+                vary_by_encoding = 1;
+        }
+        if (variant->content_charset) {
+            if (*variant->content_charset)
+                rec = pstrcat(r->pool, rec, " {charset ", 
+                              variant->content_charset, "}", NULL);
+            if (!sample_charset) sample_charset = variant->content_charset;
+            else if (strcmp(sample_charset, variant->content_charset))
+                vary_by_charset = 1;
+        }
+        if ((len = find_content_length(neg, variant)) != 0) {
+            ap_snprintf(lenstr, sizeof(lenstr), "%ld", len);
+            rec = pstrcat(r->pool, rec, " {length ", lenstr, "}", NULL);
+        }
+        
+        rec = pstrcat(r->pool, rec, "}", NULL);
+        
+        if (na_result != na_not_applied)
+            table_merge(hdrs, "Alternates", rec);
+    }
+
+    if (na_result != na_not_applied)
+        table_merge(hdrs, "Vary", "negotiate");
+    if (vary_by_type) 
+        table_merge(hdrs, "Vary", "accept");
+    if (vary_by_language) 
+        table_merge(hdrs, "Vary", "accept-language");
+    if (vary_by_charset) 
+        table_merge(hdrs, "Vary", "accept-charset");
+    if (vary_by_encoding && na_result == na_not_applied) 
+        table_merge(hdrs, "Vary", "accept-encoding");
+}
+
+/**********************************************************************
+ *
+ * Return an HTML list of variants. This is output as part of the
+ * 300 or 406 status body.
+ */
+
+char *make_variant_list (request_rec *r, negotiation_state *neg)
+{
+    int i;
+    char *t;
+
+    t = pstrdup(r->pool, "Available variants:\n<ul>\n");
+    for (i = 0; i < neg->avail_vars->nelts; ++i) {
+        var_rec *variant = &((var_rec *)neg->avail_vars->elts)[i];
+        char *filename = variant->file_name ? variant->file_name : "";
+        array_header *languages = variant->content_languages;
+        char *description = variant->description ? variant->description : "";
+
+       /* The format isn't very neat, and it would be nice to make
+        * the tags human readable (eg replace 'language en' with
+        * 'English'). */
+        t = pstrcat(r->pool, t, "<li><a href=\"", filename, "\">", 
+                    filename, "</a> ", description, NULL);
+       if (variant->type_name && *variant->type_name)
+           t = pstrcat(r->pool, t, ", type ", variant->type_name, NULL);
+       if (languages && languages->nelts)
+           t = pstrcat(r->pool, t, ", language ",
+                       merge_string_array(r->pool, languages, ", "),
+                       NULL);
+       if (variant->content_charset && *variant->content_charset)
+           t = pstrcat(r->pool, t, ", charset ", variant->content_charset, NULL);
+       t = pstrcat(r->pool, t, "\n", NULL);
+    }
+    t = pstrcat(r->pool, t, "</ul>\n", NULL);
+
+    return t;
+}
+
+void store_variant_list (request_rec *r, negotiation_state *neg)
+{
+  if (r->main == NULL) {
+     table_set (r->notes, "variant-list", make_variant_list (r, neg));
+  } else {
+     table_set (r->main->notes, "variant-list", make_variant_list (r->main, neg));
+  }
+}
+
+/* Called if we got a "Choice" response from the network algorithm.
+ * It checks the result of the chosen variant to see if it
+ * is itself negotiated (if so, return error VARIANT_ALSO_VARIES).
+ * Otherwise, add the appropriate headers to the current response.
+ */
+
+int setup_choice_response(request_rec *r, negotiation_state *neg, var_rec *variant)
+{
+    request_rec *sub_req;
+    char *sub_vary;
+
+    if (!variant->sub_req) {
+        int status;
+
+        sub_req = sub_req_lookup_file(variant->file_name, r);
+        status = sub_req->status;
+        if (status != HTTP_OK && status != HTTP_MULTIPLE_CHOICES) {
+            destroy_sub_req(sub_req);
+            return status;
+        }
+        variant->sub_req = sub_req;
+    }
+    else 
+        sub_req = variant->sub_req;
+    
+
+    /* The network algorithm told us to return a "Choice"
+     * response. This is the normal variant response, with
+     * some extra headers. First, ensure that the chosen
+     * variant did not itself return a "List" or "Choice" response.
+     * If not, set the appropriate headers, and fall through to
+     * the normal variant handling 
+     */
+
+    if ((sub_req->status == HTTP_MULTIPLE_CHOICES) ||
+        (table_get(sub_req->err_headers_out, "Alternates")) ||
+        (table_get(sub_req->err_headers_out, "Content-Location")))
+        return VARIANT_ALSO_VARIES;
+    
+    if ((sub_vary = table_get(sub_req->err_headers_out, "Vary")) != NULL)
+        table_set(r->err_headers_out, "Variant-Vary", sub_vary);
+    table_set(r->err_headers_out, "Content-Location", variant->file_name);
+    set_neg_headers(r, neg, na_choice); /* add Alternates and Vary */
+    /* to do: add Expires */
+
+    return 0;
+}
+
+/****************************************************************
+ *
+ * Executive...
+ */
+
+int handle_map_file (request_rec *r)
+{
+    negotiation_state *neg = parse_accept_headers (r);
+    var_rec *best;
+    int res;
+    int na_result;
+    
+    char *udir;
+    
+    if ((res = read_type_map (neg, r->filename))) return res;
+    
+    maybe_add_default_encodings(neg, 0);
+    
+    na_result = best_match(neg, &best);
+
+    /* na_result is one of
+     *   na_not_applied: we didn't use the network algorithm
+     *   na_choice: return a "Choice" response
+     *   na_list: return a "List" response (no variant chosen)
+     */
+
+    if (na_result == na_list) {
+        set_neg_headers(r, neg, na_list);
+        store_variant_list (r, neg);
+        return MULTIPLE_CHOICES;
+    }
+
+    if (!best) {
+      log_reason ("no acceptable variant", r->filename, r);
+
+      set_neg_headers(r, neg, na_result);
+      store_variant_list (r, neg);
+      return NOT_ACCEPTABLE;
+    }
+
+    if (na_result == na_choice)
+        if ((res = setup_choice_response(r, neg, best)) != 0)
+            return res;
+
+    /* Make sure caching works - Vary should handle HTTP/1.1, but for
+     * HTTP/1.0, we can't allow caching at all. NB that we merge the
+     * header in case some other module negotiates on something else.
+     */
+    if (!do_cache_negotiated_docs(r->server) && (r->proto_num < 1001))
+        r->no_cache = 1;
+
+    if (na_result == na_not_applied)
+        set_neg_headers(r, neg, na_not_applied);
+
+    if (r->path_info && *r->path_info) {
+        r->uri[find_path_info(r->uri, r->path_info)] = '\0';
+    }
+    udir = make_dirstr (r->pool, r->uri, count_dirs (r->uri));
+    udir = escape_uri(r->pool, udir);
+    internal_redirect(pstrcat(r->pool, udir, best->file_name, r->path_info,
+                              NULL), r);
+    return OK;
+}
+
+int handle_multi (request_rec *r)
+{
+    negotiation_state *neg;
+    var_rec *best, *avail_recs;
+    request_rec *sub_req;
+    int res;
+    int j;
+    int na_result;              /* result of network algorithm */
+    
+    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_from_multi:
+       /* free all allocated memory from subrequests */
+        avail_recs = (var_rec *)neg->avail_vars->elts;
+        for (j = 0; j < neg->avail_vars->nelts; ++j) {
+            var_rec *variant = &avail_recs[j];
+            if (variant->sub_req) {
+                destroy_sub_req(variant->sub_req);
+            }
+        }
+        return res;
+    }
+    if (neg->avail_vars->nelts == 0) return DECLINED;
+
+    maybe_add_default_encodings(neg,
+                                r->method_number != M_GET
+                                  || r->args || r->path_info);
+    
+    na_result = best_match(neg, &best);
+    if (na_result == na_list) {
+        /*
+         * Network algorithm tols us to output a "List" response.
+        * This is output at a 300 status code, which we will
+        * return. The list of variants will be stored in r->notes
+        * under the name "variants-list".
+         */
+        set_neg_headers(r, neg, na_list); /* set Alternates: and Vary: */
+
+        store_variant_list (r, neg);
+        res = MULTIPLE_CHOICES;
+        goto return_from_multi;
+    }
+
+    if (!best) {
+      log_reason ("no acceptable variant", r->filename, r);
+
+      set_neg_headers (r, neg, na_result);
+      store_variant_list (r, neg);
+      res = NOT_ACCEPTABLE;
+      goto return_from_multi;
+    }
+
+    if (na_result == na_choice)
+        if ((res = setup_choice_response(r, neg, best)) != 0) {
+            goto return_from_multi;
+        }
+
+    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 != HTTP_OK) {
+           res = sub_req->status;
+           destroy_sub_req(sub_req);
+           goto return_from_multi;
+        }
+    }
+      
+    /* BLETCH --- don't multi-resolve non-ordinary files */
+
+    if (!S_ISREG(sub_req->finfo.st_mode)) {
+       res = NOT_FOUND;
+       goto return_from_multi;
+    }
+    
+    /* Otherwise, use it. */
+    
+    if (!do_cache_negotiated_docs(r->server) && (r->proto_num < 1001))
+        r->no_cache = 1;
+
+    if (na_result == na_not_applied)
+        set_neg_headers(r, neg, na_not_applied);
+
+    r->filename = sub_req->filename;
+    r->handler = sub_req->handler;
+    r->content_type = sub_req->content_type;
+    r->content_encoding = sub_req->content_encoding;
+    r->content_languages = sub_req->content_languages;
+    r->content_language = sub_req->content_language;
+    r->finfo = sub_req->finfo;
+    r->per_dir_config = sub_req->per_dir_config;
+    /* copy output headers from subrequest, but leave negotiation headers */
+    r->notes = overlay_tables(r->pool, sub_req->notes, r->notes);
+    r->headers_out = overlay_tables(r->pool, sub_req->headers_out,
+                                             r->headers_out);
+    r->err_headers_out = overlay_tables(r->pool, sub_req->err_headers_out,
+                                                 r->err_headers_out);
+    r->subprocess_env = overlay_tables(r->pool, sub_req->subprocess_env,
+                                               r->subprocess_env);
+    avail_recs = (var_rec *)neg->avail_vars->elts;
+    for (j = 0; j < neg->avail_vars->nelts; ++j) {
+        var_rec *variant = &avail_recs[j];
+        if (variant != best && variant->sub_req) {
+           destroy_sub_req(variant->sub_req);
+        }
+    }
+    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 */
+   NULL                                /* header parser */
+};
diff --git a/APACHE_1_2_X/src/modules/standard/mod_rewrite.c b/APACHE_1_2_X/src/modules/standard/mod_rewrite.c
new file mode 100644 (file)
index 0000000..cb14372
--- /dev/null
@@ -0,0 +1,3294 @@
+/* ====================================================================
+ * Copyright (c) 1996,1997 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_rewrite.c -- The Main Module Code
+**                       _                            _ _ 
+**   _ __ ___   ___   __| |    _ __ _____      ___ __(_) |_ ___ 
+**  | '_ ` _ \ / _ \ / _` |   | '__/ _ \ \ /\ / / '__| | __/ _ \
+**  | | | | | | (_) | (_| |   | | |  __/\ V  V /| |  | | ||  __/
+**  |_| |_| |_|\___/ \__,_|___|_|  \___| \_/\_/ |_|  |_|\__\___|
+**                       |_____|
+**
+**  URL Rewriting Module, Version 3.0.5 (16-Apr-1997)
+**
+**  This module uses a rule-based rewriting engine (based on a
+**  regular-expression parser) to rewrite requested URLs on the fly. 
+**  
+**  It supports an unlimited number of additional rule conditions (which can
+**  operate on a lot of variables, even on HTTP headers) for granular
+**  matching and even external database lookups (either via plain text
+**  tables, DBM hash files or even external processes) for advanced URL
+**  substitution.
+**  
+**  It operates on the full URLs (including the PATH_INFO part) both in
+**  per-server context (httpd.conf) and per-dir context (.htaccess) and even
+**  can generate QUERY_STRING parts on result.   The rewriting result finally
+**  can lead to internal subprocessing, external request redirection or even
+**  to internal proxy throughput.
+**
+**  The documentation and latest release can be found on
+**  http://www.engelschall.com/sw/mod_rewrite/
+**
+**  Copyright (c) 1996-1997 Ralf S. Engelschall, All rights reserved.
+**
+**  Written for The Apache Group by
+**      Ralf S. Engelschall
+**      rse@engelschall.com
+**      www.engelschall.com
+*/
+
+
+
+
+    /* from the underlaying Unix system ... */
+#include <string.h>
+#include <stdarg.h>
+#include <time.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+
+    /* from the Apache server ... */
+#include "httpd.h"
+#include "http_config.h"
+#include "http_request.h"
+#include "http_core.h"
+#include "http_log.h"
+
+    /* now our own stuff ... */
+#include "mod_rewrite.h"
+
+
+
+/*
+** +-------------------------------------------------------+
+** |                                                       |
+** |             static module configuration
+** |                                                       |
+** +-------------------------------------------------------+
+*/
+
+
+/*
+**
+**  our interface to the Apache server kernel
+**
+**  keep in mind: 
+**
+**  o  Runtime logic of a request is as following:
+**
+**       while(request or subrequest) {
+**           foreach(stage #1...#9) {
+**               foreach(module) { (**)
+**                   try to run hook
+**               }
+**           }
+**       }
+**
+**  o  the order of modules at (**) is the inverted order as
+**     given in the "Configuration" file, i.e. the last module
+**     specified is the first one called for each hook!
+**     The core module is always the last!
+**
+**  o  there are two different types of result checking and 
+**     continue processing:
+**     for hook #1,#4,#5,#6,#8:
+**         hook run loop stops on first modules which gives
+**         back a result != DECLINED, i.e. it usually returns OK
+**         which says "OK, module has handled this _stage_" and for #1
+**         this have not to mean "Ok, the filename is now valid".
+**     for hook #2,#3,#7,#9:
+**         all hooks are run, independend of result
+**
+**  o  at the last stage, the core module always 
+**       - says "BAD_REQUEST" if r->filename does not begin with "/"
+**       - prefix URL with document_root or replaced server_root
+**         with document_root and sets r->filename
+**       - always return a "OK" independed if the file really exists
+**         or not!
+**
+*/
+
+    /* the table of commands we provide */
+static command_rec command_table[] = {
+    { "RewriteEngine",   cmd_rewriteengine,   NULL, OR_FILEINFO, FLAG, 
+      "On or Off to enable or disable (default) the whole rewriting engine" },
+    { "RewriteOptions",  cmd_rewriteoptions,  NULL, OR_FILEINFO, ITERATE, 
+      "List of option strings to set" },
+    { "RewriteBase",     cmd_rewritebase,     NULL, OR_FILEINFO, TAKE1, 
+      "the base URL of the per-directory context" },
+    { "RewriteCond",     cmd_rewritecond,     NULL, OR_FILEINFO, RAW_ARGS, 
+      "a input string and a to be applied regexp-pattern" },
+    { "RewriteRule",     cmd_rewriterule,     NULL, OR_FILEINFO, RAW_ARGS, 
+      "a URL-applied regexp-pattern and a substitution URL" },
+    { "RewriteMap",      cmd_rewritemap,      NULL, RSRC_CONF,   TAKE2, 
+      "a mapname and a filename" },
+    { "RewriteLog",      cmd_rewritelog,      NULL, RSRC_CONF,   TAKE1, 
+      "the filename of the rewriting logfile" },
+    { "RewriteLogLevel", cmd_rewriteloglevel, NULL, RSRC_CONF,   TAKE1, 
+      "the level of the rewriting logfile verbosity (0=none, 1=std, .., 9=max)" },
+    { NULL }
+};
+
+    /* the table of content handlers we provide */
+static handler_rec handler_table[] = {
+    { "redirect-handler", handler_redirect },
+    { NULL }
+};
+
+    /* the main config structure */
+module rewrite_module = {
+   STANDARD_MODULE_STUFF, 
+
+   init_module,                 /* module initializer */
+
+   config_perdir_create,        /* create per-dir    config structures */
+   config_perdir_merge,         /* merge  per-dir    config structures */
+   config_server_create,        /* create per-server config structures */
+   config_server_merge,         /* merge  per-server config structures */
+   command_table,               /* table of config file commands */
+
+   handler_table,               /* [#8] table of MIME-typed-dispatched request action handlers */
+
+   hook_uri2file,               /* [#1] URI to filename translation */
+
+   NULL,                        /* [#4] check_user_id: get and validate user id from the HTTP request */
+   NULL,                        /* [#5] check_auth:    check if the user is ok _here_ */
+   NULL,                        /* [#2] check_access:  check access by host address, etc. */
+
+   hook_mimetype,               /* [#6] determine MIME type */
+
+   hook_fixup,                  /* [#7] pre-run fixups */
+   NULL,                        /* [#9] log a transaction */
+   NULL                         /* [#3] header parser */
+};
+
+    /* the cache */
+cache *cachep;
+
+    /* whether proxy module is available or not */
+static int proxy_available;
+
+    /* the txt mapfile parsing stuff */
+#define MAPFILE_PATTERN "^([^ \t]+)[ \t]+([^ \t]+).*$"
+#define MAPFILE_OUTPUT "$1,$2"
+static regex_t   *lookup_map_txtfile_regexp = NULL;
+static regmatch_t lookup_map_txtfile_regmatch[10];
+
+
+
+
+/*
+** +-------------------------------------------------------+
+** |                                                       |
+** |           configuration directive handling
+** |                                                       |
+** +-------------------------------------------------------+
+*/
+
+
+/*
+**
+**  per-server configuration structure handling
+**
+*/
+
+static void *config_server_create(pool *p, server_rec *s)
+{
+    rewrite_server_conf *a;
+
+    a = (rewrite_server_conf *)pcalloc(p, sizeof(rewrite_server_conf));
+
+    a->state           = ENGINE_DISABLED;
+    a->options         = OPTION_NONE;
+    a->rewritelogfile  = NULL;
+    a->rewritelogfp    = -1;
+    a->rewriteloglevel = 1;
+    a->rewritemaps     = make_array(p, 2, sizeof(rewritemap_entry));
+    a->rewriteconds    = make_array(p, 2, sizeof(rewritecond_entry));
+    a->rewriterules    = make_array(p, 2, sizeof(rewriterule_entry));
+
+    return (void *)a;
+}
+
+static void *config_server_merge(pool *p, void *basev, void *overridesv)
+{
+    rewrite_server_conf *a, *base, *overrides;
+
+    a         = (rewrite_server_conf *)pcalloc(p, sizeof(rewrite_server_conf));
+    base      = (rewrite_server_conf *)basev;
+    overrides = (rewrite_server_conf *)overridesv;
+
+    a->state           = overrides->state;
+    a->options         = overrides->options;
+    a->rewritelogfile  = base->rewritelogfile  != NULL ? base->rewritelogfile  : overrides->rewritelogfile;
+    a->rewritelogfp    = base->rewritelogfp    != -1   ? base->rewritelogfp    : overrides->rewritelogfp;
+    a->rewriteloglevel = overrides->rewriteloglevel;
+
+    if (a->options & OPTION_INHERIT) {
+        a->rewritemaps  = append_arrays(p, overrides->rewritemaps,  base->rewritemaps);
+        a->rewriteconds = append_arrays(p, overrides->rewriteconds, base->rewriteconds);
+        a->rewriterules = append_arrays(p, overrides->rewriterules, base->rewriterules);
+    }
+    else {
+        a->rewritemaps  = overrides->rewritemaps;
+        a->rewriteconds = overrides->rewriteconds;
+        a->rewriterules = overrides->rewriterules;
+    }
+
+    return (void *)a;
+}
+
+
+/*
+**
+**  per-directory configuration structure handling
+**
+*/
+
+static void *config_perdir_create(pool *p, char *path)
+{
+    rewrite_perdir_conf *a;
+
+    a = (rewrite_perdir_conf *)pcalloc(p, sizeof(rewrite_perdir_conf));
+
+    a->state           = ENGINE_DISABLED;
+    a->options         = OPTION_NONE;
+    a->baseurl         = NULL;
+    a->rewriteconds    = make_array(p, 2, sizeof(rewritecond_entry));
+    a->rewriterules    = make_array(p, 2, sizeof(rewriterule_entry));
+
+    if (path == NULL)
+        a->directory = NULL;
+    else {
+        /* make sure it has a trailing slash */
+        if (path[strlen(path)-1] == '/')
+            a->directory = pstrdup(p, path);
+        else
+            a->directory = pstrcat(p, path, "/", NULL);
+    }
+
+    return (void *)a;
+}
+
+static void *config_perdir_merge(pool *p, void *basev, void *overridesv)
+{
+    rewrite_perdir_conf *a, *base, *overrides;
+
+    a         = (rewrite_perdir_conf *)pcalloc(p, sizeof(rewrite_perdir_conf));
+    base      = (rewrite_perdir_conf *)basev;
+    overrides = (rewrite_perdir_conf *)overridesv;
+
+    a->state           = overrides->state;
+    a->options         = overrides->options;
+    a->directory       = overrides->directory;
+    a->baseurl         = overrides->baseurl;
+
+    if (a->options & OPTION_INHERIT) {
+        a->rewriteconds = append_arrays(p, overrides->rewriteconds, base->rewriteconds);
+        a->rewriterules = append_arrays(p, overrides->rewriterules, base->rewriterules);
+    }
+    else {
+        a->rewriteconds = overrides->rewriteconds;
+        a->rewriterules = overrides->rewriterules;
+    }
+
+    return (void *)a;
+}
+
+
+/*
+**
+**  the configuration commands
+**
+*/
+
+static const char *cmd_rewriteengine(cmd_parms *cmd, rewrite_perdir_conf *dconf, int flag)
+{
+    rewrite_server_conf *sconf;
+
+    sconf = (rewrite_server_conf *)get_module_config(cmd->server->module_config, &rewrite_module);
+    if (cmd->path == NULL) /* is server command */
+        sconf->state = (flag ? ENGINE_ENABLED : ENGINE_DISABLED);
+    else                   /* is per-directory command */
+        dconf->state = (flag ? ENGINE_ENABLED : ENGINE_DISABLED);
+
+    return NULL;
+}
+
+static const char *cmd_rewriteoptions(cmd_parms *cmd, rewrite_perdir_conf *dconf, char *option)
+{
+    rewrite_server_conf *sconf;
+    const char *err;
+
+    sconf = (rewrite_server_conf *)get_module_config(cmd->server->module_config, &rewrite_module);
+    if (cmd->path == NULL) /* is server command */
+        err = cmd_rewriteoptions_setoption(cmd->pool, &(sconf->options), option);
+    else                   /* is per-directory command */
+        err = cmd_rewriteoptions_setoption(cmd->pool, &(dconf->options), option);
+
+    return err;
+}
+
+static const char *cmd_rewriteoptions_setoption(pool *p, int *options, char *name)
+{
+    if (strcasecmp(name, "inherit") == 0)
+        *options |= OPTION_INHERIT;
+    else
+        return pstrcat(p, "RewriteOptions: unknown option '", name, "'\n", NULL);
+    return NULL;
+}
+
+static const char *cmd_rewritelog(cmd_parms *cmd, void *dconf, char *a1)
+{
+    rewrite_server_conf *sconf;
+
+    sconf = (rewrite_server_conf *)get_module_config(cmd->server->module_config, &rewrite_module);
+    sconf->rewritelogfile = a1;
+
+    return NULL;
+}
+
+static const char *cmd_rewriteloglevel(cmd_parms *cmd, void *dconf, char *a1)
+{
+    rewrite_server_conf *sconf;
+
+    sconf = (rewrite_server_conf *)get_module_config(cmd->server->module_config, &rewrite_module);
+    sconf->rewriteloglevel = atoi(a1);
+
+    return NULL;
+}
+
+static const char *cmd_rewritemap(cmd_parms *cmd, void *dconf, char *a1, char *a2)
+{
+    rewrite_server_conf *sconf;
+    rewritemap_entry *new;
+    struct stat st;
+
+    sconf = (rewrite_server_conf *)get_module_config(cmd->server->module_config, &rewrite_module);
+    new = push_array(sconf->rewritemaps);
+
+    new->name = a1;
+    if (strncmp(a2, "txt:", 4) == 0) {
+        new->type      = MAPTYPE_TXT;
+        new->datafile  = a2+4;
+        new->checkfile = a2+4;
+    }
+    else if (strncmp(a2, "dbm:", 4) == 0) {
+#ifdef HAS_NDBM_LIB
+        new->type      = MAPTYPE_DBM;
+        new->datafile  = a2+4;
+        new->checkfile = pstrcat(cmd->pool, a2+4, NDBM_FILE_SUFFIX, NULL);
+#else
+        return pstrdup(cmd->pool, "RewriteMap: cannot use NDBM mapfile, because no NDBM support compiled in");
+#endif
+    }
+    else if (strncmp(a2, "prg:", 4) == 0) {
+        new->type = MAPTYPE_PRG;
+        new->datafile = a2+4;
+        new->checkfile = a2+4;
+    }
+    else {
+        new->type      = MAPTYPE_TXT;
+        new->datafile  = a2;
+        new->checkfile = a2;
+    }
+    new->fpin  = 0;
+    new->fpout = 0;
+
+    if (new->checkfile)
+        if (stat(new->checkfile, &st) == -1)
+            return pstrcat(cmd->pool, "RewriteMap: map file or program not found:", new->checkfile, NULL);
+
+    return NULL;
+}
+
+static const char *cmd_rewritebase(cmd_parms *cmd, rewrite_perdir_conf *dconf, char *a1)
+{
+    if (cmd->path == NULL || dconf == NULL)
+        return "RewriteBase: only valid in per-directory config files";
+    if (a1[0] != '/') 
+        return "RewriteBase: argument is not a valid URL";
+    if (a1[0] == '\0')
+        return "RewriteBase: empty URL not allowed";
+
+    dconf->baseurl = pstrdup(cmd->pool, a1);
+
+    return NULL;
+}
+
+static const char *cmd_rewritecond(cmd_parms *cmd, rewrite_perdir_conf *dconf, char *str)
+{
+    rewrite_server_conf *sconf;
+    rewritecond_entry *new;
+    regex_t *regexp;
+    char *a1;
+    char *a2;
+    char *a3;
+    char *cp;
+    const char *err;
+    int rc;
+
+    sconf = (rewrite_server_conf *)get_module_config(cmd->server->module_config, &rewrite_module);
+
+    /*  make a new entry in the internal temporary rewrite rule list */
+    if (cmd->path == NULL)   /* is server command */
+        new = push_array(sconf->rewriteconds);
+    else                     /* is per-directory command */
+        new = push_array(dconf->rewriteconds);
+
+    /*  parse the argument line ourself */
+    if (parseargline(str, &a1, &a2, &a3)) 
+        return pstrcat(cmd->pool, "RewriteCond: bad argument line '", str, "'\n", NULL);
+
+    /*  arg1: the input string */
+    new->input = pstrdup(cmd->pool, a1);
+
+    /* arg3: optional flags field 
+       (this have to be first parsed, because we need to
+        know if the regex should be compiled with ICASE!) */
+    new->flags = CONDFLAG_NONE;
+    if (a3 != NULL) {
+        if ((err = cmd_rewritecond_parseflagfield(cmd->pool, new, a3)) != NULL)
+            return err;
+    }
+
+    /*  arg2: the pattern
+        try to compile the regexp to test if is ok */
+    cp = a2;
+    if (cp[0] == '!') {
+        new->flags |= CONDFLAG_NOTMATCH;
+        cp++;
+    }
+
+    /* now be careful: Under the POSIX regex library
+       we can compile the pattern for case-insensitive matching,
+       under the old V8 library we have to do it self via a hack */
+    if (new->flags & CONDFLAG_NOCASE)
+        rc = ((regexp = pregcomp(cmd->pool, cp, REG_EXTENDED|REG_ICASE)) == NULL);
+    else
+        rc = ((regexp = pregcomp(cmd->pool, cp, REG_EXTENDED)) == NULL);
+    if (rc)
+        return pstrcat(cmd->pool, "RewriteCond: cannot compile regular expression '", a2, "'\n", NULL);
+    new->pattern = pstrdup(cmd->pool, cp);
+    new->regexp  = regexp;
+
+    return NULL;
+}
+
+static const char *cmd_rewritecond_parseflagfield(pool *p, rewritecond_entry *cfg, char *str)
+{
+    char *cp;
+    char *cp1;
+    char *cp2;
+    char *cp3;
+    char *key;
+    char *val;
+    const char *err;
+
+    if (str[0] != '[' || str[strlen(str)-1] != ']')
+        return pstrdup(p, "RewriteCond: bad flag delimiters");
+
+    cp = str+1;
+    str[strlen(str)-1] = ','; /* for simpler parsing */
+    for ( ; *cp != '\0'; ) {
+        /* skip whitespaces */
+        for ( ; (*cp == ' ' || *cp == '\t') && *cp != '\0'; cp++)
+            ;
+        if (*cp == '\0')
+            break;
+        cp1 = cp;
+        if ((cp2 = strchr(cp, ',')) != NULL) {
+            cp = cp2+1;
+            for ( ; (*(cp2-1) == ' ' || *(cp2-1) == '\t'); cp2--)
+                ;
+            *cp2 = '\0';
+            if ((cp3 = strchr(cp1, '=')) != NULL) {
+                *cp3 = '\0';
+                key = cp1;
+                val = cp3+1;
+            }
+            else {
+                key = cp1;
+                val = "";
+            }
+            if ((err = cmd_rewritecond_setflag(p, cfg, key, val)) != NULL)
+                return err;
+        }
+        else
+            break;
+    }
+    
+    return NULL;
+}
+
+static const char *cmd_rewritecond_setflag(pool *p, rewritecond_entry *cfg, char *key, char *val)
+{
+    if (   strcasecmp(key, "nocase") == 0
+        || strcasecmp(key, "NC") == 0    ) {
+        cfg->flags |= CONDFLAG_NOCASE;
+    }
+    else if (   strcasecmp(key, "ornext") == 0
+             || strcasecmp(key, "OR") == 0    ) {
+        cfg->flags |= CONDFLAG_ORNEXT;
+    }
+    else {
+        return pstrcat(p, "RewriteCond: unknown flag '", key, "'\n", NULL);
+    }
+    return NULL;
+}
+
+/* NON static */
+const char *cmd_rewriterule(cmd_parms *cmd, rewrite_perdir_conf *dconf, char *str)
+{
+    rewrite_server_conf *sconf;
+    rewriterule_entry *new;
+    regex_t *regexp;
+    char *a1;
+    char *a2;
+    char *a3;
+    char *cp;
+    const char *err;
+
+    sconf = (rewrite_server_conf *)get_module_config(cmd->server->module_config, &rewrite_module);
+
+    /*  make a new entry in the internal rewrite rule list */
+    if (cmd->path == NULL)   /* is server command */
+        new = push_array(sconf->rewriterules);
+    else                     /* is per-directory command */
+        new = push_array(dconf->rewriterules);
+
+    /*  parse the argument line ourself */
+    if (parseargline(str, &a1, &a2, &a3)) 
+        return pstrcat(cmd->pool, "RewriteRule: bad argument line '", str, "'\n", NULL);
+
+    /*  arg1: the pattern
+        try to compile the regexp to test if is ok */
+    new->flags = RULEFLAG_NONE;
+    cp = a1;
+    if (cp[0] == '!') {
+        new->flags |= RULEFLAG_NOTMATCH;
+        cp++;
+    }
+    if ((regexp = pregcomp(cmd->pool, cp, REG_EXTENDED)) == NULL)
+        return pstrcat(cmd->pool, "RewriteRule: cannot compile regular expression '", a1, "'\n", NULL);
+    new->pattern = pstrdup(cmd->pool, cp);
+    new->regexp  = regexp;
+
+    /*  arg2: the output string
+        replace the $<N> by \<n> which is needed by the currently
+        used Regular Expression library */
+    new->output = pstrdup(cmd->pool, a2);
+
+    /* arg3: optional flags field */
+    new->forced_mimetype = NULL;
+    new->forced_responsecode = HTTP_MOVED_TEMPORARILY;
+    new->env[0] = NULL;
+    new->skip = 0;
+    if (a3 != NULL) {
+        if ((err = cmd_rewriterule_parseflagfield(cmd->pool, new, a3)) != NULL)
+            return err;
+    }
+
+    /* now, if the server or per-dir config holds an
+       array of RewriteCond entries, we take it for us 
+       and clear the array */
+    if (cmd->path == NULL) {  /* is server command */
+        new->rewriteconds   = sconf->rewriteconds;
+        sconf->rewriteconds = make_array(cmd->pool, 2, sizeof(rewritecond_entry));
+    }
+    else {                    /* is per-directory command */
+        new->rewriteconds   = dconf->rewriteconds;
+        dconf->rewriteconds = make_array(cmd->pool, 2, sizeof(rewritecond_entry));
+    }
+
+    return NULL;
+}
+
+static const char *cmd_rewriterule_parseflagfield(pool *p, rewriterule_entry *cfg, char *str)
+{
+    char *cp;
+    char *cp1;
+    char *cp2;
+    char *cp3;
+    char *key;
+    char *val;
+    const char *err;
+
+    if (str[0] != '[' || str[strlen(str)-1] != ']')
+        return pstrdup(p, "RewriteRule: bad flag delimiters");
+
+    cp = str+1;
+    str[strlen(str)-1] = ','; /* for simpler parsing */
+    for ( ; *cp != '\0'; ) {
+        /* skip whitespaces */
+        for ( ; (*cp == ' ' || *cp == '\t') && *cp != '\0'; cp++)
+            ;
+        if (*cp == '\0')
+            break;
+        cp1 = cp;
+        if ((cp2 = strchr(cp, ',')) != NULL) {
+            cp = cp2+1;
+            for ( ; (*(cp2-1) == ' ' || *(cp2-1) == '\t'); cp2--)
+                ;
+            *cp2 = '\0';
+            if ((cp3 = strchr(cp1, '=')) != NULL) {
+                *cp3 = '\0';
+                key = cp1;
+                val = cp3+1;
+            }
+            else {
+                key = cp1;
+                val = "";
+            }
+            if ((err = cmd_rewriterule_setflag(p, cfg, key, val)) != NULL)
+                return err;
+        }
+        else
+            break;
+    }
+    
+    return NULL;
+}
+
+static const char *cmd_rewriterule_setflag(pool *p, rewriterule_entry *cfg, char *key, char *val)
+{
+    int status = 0;
+    int i;
+
+    if (   strcasecmp(key, "redirect") == 0
+        || strcasecmp(key, "R") == 0       ) {
+        cfg->flags |= RULEFLAG_FORCEREDIRECT;
+        if (strlen(val) > 0) {
+            if (strcasecmp(val, "permanent") == 0)
+                status = HTTP_MOVED_PERMANENTLY;
+            else if (strcasecmp(val, "temp") == 0)
+                status = HTTP_MOVED_TEMPORARILY;
+            else if (strcasecmp(val, "seeother") == 0)
+                status = HTTP_SEE_OTHER;
+            else if (isdigit(*val))
+                status = atoi(val);
+            if (!is_HTTP_REDIRECT(status))
+                return pstrdup(p, "RewriteRule: invalid HTTP response code for flag 'R'");
+            cfg->forced_responsecode = status;
+        }
+    }
+    else if (   strcasecmp(key, "last") == 0
+             || strcasecmp(key, "L") == 0   ) {
+        cfg->flags |= RULEFLAG_LASTRULE;
+    }
+    else if (   strcasecmp(key, "next") == 0
+             || strcasecmp(key, "N") == 0   ) {
+        cfg->flags |= RULEFLAG_NEWROUND;
+    }
+    else if (   strcasecmp(key, "chain") == 0
+             || strcasecmp(key, "C") == 0    ) {
+        cfg->flags |= RULEFLAG_CHAIN;
+    }
+    else if (   strcasecmp(key, "type") == 0
+             || strcasecmp(key, "T") == 0   ) {
+        cfg->forced_mimetype = pstrdup(p, val);
+    }
+    else if (   strcasecmp(key, "env") == 0
+             || strcasecmp(key, "E") == 0   ) {
+        for (i = 0; (cfg->env[i] != NULL) && (i < MAX_ENV_FLAGS); i++)
+            ;
+        if (i < MAX_ENV_FLAGS) {
+            cfg->env[i] = pstrdup(p, val);
+            cfg->env[i+1] = NULL;
+        }
+        else 
+            return pstrdup(p, "RewriteRule: to much environment flags 'E'");
+    }
+    else if (   strcasecmp(key, "nosubreq") == 0
+             || strcasecmp(key, "NS") == 0      ) {
+        cfg->flags |= RULEFLAG_IGNOREONSUBREQ;
+    }
+    else if (   strcasecmp(key, "proxy") == 0
+             || strcasecmp(key, "P") == 0      ) {
+        cfg->flags |= RULEFLAG_PROXY;
+    }
+    else if (   strcasecmp(key, "passthrough") == 0
+             || strcasecmp(key, "PT") == 0      ) {
+        cfg->flags |= RULEFLAG_PASSTHROUGH;
+    }
+    else if (   strcasecmp(key, "skip") == 0
+             || strcasecmp(key, "S") == 0   ) {
+        cfg->skip = atoi(val);
+    }
+    else if (   strcasecmp(key, "forbidden") == 0
+             || strcasecmp(key, "F") == 0   ) {
+        cfg->flags |= RULEFLAG_FORBIDDEN;
+    }
+    else if (   strcasecmp(key, "gone") == 0
+             || strcasecmp(key, "G") == 0   ) {
+        cfg->flags |= RULEFLAG_GONE;
+    }
+    else {
+        return pstrcat(p, "RewriteRule: unknown flag '", key, "'\n", NULL);
+    }
+    return NULL;
+}
+
+
+/*
+**
+**  module initialisation 
+**  [called from read_config() after all 
+**  config commands were already called]
+**
+*/
+
+static void init_module(server_rec *s, pool *p)
+{
+    /* step through the servers and
+       - open eachs rewriting logfile 
+       - open the RewriteMap prg:xxx programs */
+    for (; s; s = s->next) {
+        open_rewritelog(s, p);
+        run_rewritemap_programs(s, p);
+    }
+
+    /* create the lookup cache */
+    cachep = init_cache(p);
+
+    /* check if proxy module is available */
+    proxy_available = is_proxy_available(s);
+
+    /* precompile a static pattern 
+       for the txt mapfile parsing */
+    lookup_map_txtfile_regexp = pregcomp(p, MAPFILE_PATTERN, REG_EXTENDED);
+}
+
+
+
+
+/*
+** +-------------------------------------------------------+
+** |                                                       |
+** |                     runtime hooks
+** |                                                       |
+** +-------------------------------------------------------+
+*/
+
+
+/*
+**
+**  URI-to-filename hook
+**
+**  [used for the rewriting engine triggered by
+**  the per-server 'RewriteRule' directives]
+**
+*/
+
+static int hook_uri2file(request_rec *r)
+{
+    void *sconf;
+    rewrite_server_conf *conf;
+    char *var;
+    char *thisserver, *thisport, *thisurl;
+    char buf[512];
+    char docroot[512];
+    char *cp, *cp2;
+    struct stat finfo;
+    int n;
+    int l;
+
+    /*
+     *  retrieve the config structures
+     */
+    sconf = r->server->module_config;
+    conf  = (rewrite_server_conf *)get_module_config(sconf, &rewrite_module);
+
+    /*
+     *  only do something under runtime if the engine is really enabled,
+     *  else return immediately!
+     */
+    if (conf->state == ENGINE_DISABLED)
+        return DECLINED;
+
+    /*
+     *  add the SCRIPT_URL variable to the env. this is a bit complicated
+     *  due to the fact that apache uses subrequests and internal redirects
+     */
+
+    if (r->main == NULL) {
+         var = pstrcat(r->pool, "REDIRECT_", ENVVAR_SCRIPT_URL, NULL);
+         var = table_get(r->subprocess_env, var);
+         if (var == NULL) 
+             table_set(r->subprocess_env, ENVVAR_SCRIPT_URL, pstrdup(r->pool, r->uri));
+         else 
+             table_set(r->subprocess_env, ENVVAR_SCRIPT_URL, pstrdup(r->pool, var));
+    } 
+    else {
+         var = table_get(r->main->subprocess_env, ENVVAR_SCRIPT_URL);
+         table_set(r->subprocess_env, ENVVAR_SCRIPT_URL, pstrdup(r->pool, var));
+    }
+
+    /*
+     *  create the SCRIPT_URI variable for the env
+     */
+
+    /* add the canonical URI of this URL */
+    thisserver = r->server->server_hostname;
+#ifdef APACHE_SSL
+    if (((!r->connection->client->ssl) && (r->server->port == DEFAULT_PORT)) ||
+         ((r->connection->client->ssl) && (r->server->port == 443)))
+#else
+    if (r->server->port == DEFAULT_PORT)
+#endif 
+        thisport = "";
+    else {
+        ap_snprintf(buf, sizeof(buf), ":%u", r->server->port);
+        thisport = pstrdup(r->pool, buf);
+    }
+    thisurl = table_get(r->subprocess_env, ENVVAR_SCRIPT_URL);
+
+    /* set the variable */
+#ifdef APACHE_SSL
+    var = pstrcat(r->pool, http_method(r), "://", thisserver, thisport, thisurl, NULL);
+#else
+    var = pstrcat(r->pool, "http://", thisserver, thisport, thisurl, NULL);
+#endif
+    table_set(r->subprocess_env, ENVVAR_SCRIPT_URI, pstrdup(r->pool, var));
+
+
+    /* if filename was not initially set,
+       we start with the requested URI */
+    if (r->filename == NULL) {
+        r->filename = pstrdup(r->pool, r->uri);
+        rewritelog(r, 2, "init rewrite engine with requested uri %s", r->filename);
+    }
+
+    /*
+     *  now apply the rules ... 
+     */
+    if (apply_rewrite_list(r, conf->rewriterules, NULL)) {
+
+        if (strlen(r->filename) > 6 &&
+            strncmp(r->filename, "proxy:", 6) == 0) {
+            /* it should be go on as an internal proxy request */
+
+            /* check if the proxy module is enabled, so
+               we can actually use it! */
+            if (!proxy_available)
+                return FORBIDDEN; 
+
+            /* make sure the QUERY_STRING and
+               PATH_INFO parts get incorporated */
+            r->filename = pstrcat(r->pool, r->filename, 
+                                           r->path_info ? r->path_info : "", 
+                                           r->args ? "?" : NULL, r->args, 
+                                           NULL);
+
+            /* now make sure the request gets handled by the
+               proxy handler */
+            r->proxyreq = 1;
+            r->handler  = "proxy-server";
+
+            rewritelog(r, 1, "go-ahead with proxy request %s [OK]", r->filename);
+            return OK; 
+        }
+        else if (  (strlen(r->filename) > 7 &&
+                    strncmp(r->filename, "http://", 7) == 0)
+                || (strlen(r->filename) > 8 &&
+                    strncmp(r->filename, "https://", 8) == 0)
+                || (strlen(r->filename) > 9 &&
+                    strncmp(r->filename, "gopher://", 9) == 0)
+                || (strlen(r->filename) > 6 &&
+                    strncmp(r->filename, "ftp://", 6) == 0)    ) {
+            /* it was finally rewritten to a remote URL */
+
+            /* skip 'scheme:' */
+            for (cp = r->filename; *cp != ':' && *cp != '\0'; cp++)
+                ;
+            /* skip '://' */
+            cp += 3;
+            /* skip host part */
+            for ( ; *cp != '/' && *cp != '\0'; cp++)
+                ;
+            if (*cp != '\0') {
+                rewritelog(r, 1, "escaping %s for redirect", r->filename);
+                cp2 = escape_uri(r->pool, cp);
+                *cp = '\0';
+                r->filename = pstrcat(r->pool, r->filename, cp2, NULL);
+            }
+
+            /* append the QUERY_STRING part */
+            if (r->args != NULL)
+               r->filename = pstrcat(r->pool, r->filename, "?", r->args, NULL);
+
+            /* determine HTTP redirect response code */
+            if (is_HTTP_REDIRECT(r->status)) {
+                n = r->status; 
+                r->status = HTTP_OK; /* make Apache kernel happy */
+            }
+            else
+                n = REDIRECT;
+
+            /* now do the redirection */
+            table_set(r->headers_out, "Location", r->filename);
+            rewritelog(r, 1, "redirect to %s [REDIRECT/%d]", r->filename, n);
+            return n;
+        }
+        else if (strlen(r->filename) > 10 &&
+                 strncmp(r->filename, "forbidden:", 10) == 0) {
+            /* This URLs is forced to be forbidden for the requester */
+            return FORBIDDEN; 
+        }
+        else if (strlen(r->filename) > 5 &&
+                 strncmp(r->filename, "gone:", 5) == 0) {
+            /* This URLs is forced to be gone */
+            return HTTP_GONE; 
+        }
+        else if (strlen(r->filename) > 12 &&
+                 strncmp(r->filename, "passthrough:", 12) == 0) {
+            /* Hack because of underpowered API: passing the current
+               rewritten filename through to other URL-to-filename handlers
+               just as it were the requested URL. This is to enable
+               post-processing by mod_alias, etc.  which always act on
+               r->uri! The difference here is: We do not try to
+               add the document root */
+            r->uri = pstrdup(r->pool, r->filename+12);
+            return DECLINED; 
+        }
+        else {
+            /* it was finally rewritten to a local path */
+
+            /* expand "/~user" prefix */
+            r->filename = expand_tildepaths(r, r->filename);  
+
+            rewritelog(r, 2, "local path result: %s", r->filename);
+
+            /* the filename has to start with a slash! */
+            if (r->filename[0] != '/')
+                return BAD_REQUEST;
+
+            /* if there is no valid prefix, we have 
+               to emulate the translator from the core and
+               prefix the filename with document_root
+
+               NOTICE:
+               We cannot leave out the prefix_stat because
+               - when we always prefix with document_root
+                 then no absolute path can be created, e.g. via 
+                 emulating a ScriptAlias directive, etc.
+               - when we always NOT prefix with document_root
+                 then the files under document_root have to
+                 be references directly and document_root
+                 gets never used and will be a dummy parameter -
+                 this is also bad
+
+               BUT:
+               Under real Unix systems this is no problem,
+               because we only do stat() on the first directory
+               and this gets cached by the kernel for along time!
+             */
+            n = prefix_stat(r->filename, &finfo);
+            if (n == 0) {
+                if ((cp = document_root(r)) != NULL) {
+                    strncpy(docroot, cp, sizeof(docroot)-1);
+                    EOS_PARANOIA(docroot);
+
+                    /* always NOT have a trailing slash */
+                    l = strlen(docroot);
+                    if (docroot[l-1] == '/') {
+                        docroot[l-1] = '\0';
+                    }
+                    if (r->server->path && !strncmp(r->filename, r->server->path, r->server->pathlen))
+                        r->filename = pstrcat(r->pool, docroot, (r->filename + r->server->pathlen), NULL);
+                    else
+                        r->filename = pstrcat(r->pool, docroot, r->filename, NULL);
+                    rewritelog(r, 2, "prefixed with document_root to %s", r->filename);
+                }
+            }
+
+            rewritelog(r, 1, "go-ahead with %s [OK]", r->filename);
+            return OK;
+        }
+    }
+    else {
+        rewritelog(r, 1, "pass through %s", r->filename);
+        return DECLINED;
+    }
+}
+
+
+/*
+**
+**  MIME-type hook
+**
+**  [used to support the forced-MIME-type feature]
+**
+*/
+
+static int hook_mimetype(request_rec *r)
+{
+    char *t;
+    
+    /* now check if we have to force a MIME-type */
+    t = table_get(r->notes, REWRITE_FORCED_MIMETYPE_NOTEVAR);
+    if (t == NULL) 
+        return DECLINED;
+    else {
+        rewritelog(r, 1, "force filename %s to have MIME-type '%s'", r->filename, t);
+        r->content_type = t;
+        return OK;
+    }
+}
+
+
+/*
+**
+**  Fixup hook
+**
+**  [used for the rewriting engine triggered by
+**  the per-directory 'RewriteRule' directives]
+**
+*/
+
+static int hook_fixup(request_rec *r)
+{
+    rewrite_perdir_conf *dconf;
+    char *cp;
+    char *cp2;
+    char *prefix;
+    int l;
+    int n;
+
+    dconf = (rewrite_perdir_conf *)get_module_config(r->per_dir_config, &rewrite_module);
+
+    /* if there is no per-dir config we return immediately */
+    if (dconf == NULL)
+        return DECLINED;
+
+    /* we shouldn't do anything in subrequests */
+    if (r->main != NULL) 
+        return DECLINED;
+
+    /* if there are no real (i.e. no RewriteRule directives!)
+       per-dir config of us, we return also immediately */
+    if (dconf->directory == NULL) 
+        return DECLINED;
+
+    /*
+     *  only do something under runtime if the engine is really enabled,
+     *  for this directory, else return immediately!
+     */
+    if (!(allow_options(r) & (OPT_SYM_LINKS | OPT_SYM_OWNER))) {
+        /* FollowSymLinks is mandatory! */
+        log_reason("Options FollowSymLinks or SymLinksIfOwnerMatch is off which implies that RewriteRule directive is forbidden", r->filename, r);
+        return FORBIDDEN;
+    }
+    else {
+        /* FollowSymLinks is given, but the user can
+           still turn off the rewriting engine */
+        if (dconf->state == ENGINE_DISABLED)
+            return DECLINED;
+    }
+
+    /*
+     *  now apply the rules ... 
+     */
+    if (apply_rewrite_list(r, dconf->rewriterules, dconf->directory)) {
+
+        if (strlen(r->filename) > 6 &&
+            strncmp(r->filename, "proxy:", 6) == 0) {
+            /* it should go on as an internal proxy request */
+
+            /* make sure the QUERY_STRING and
+               PATH_INFO parts get incorporated */
+            r->filename = pstrcat(r->pool, r->filename, 
+                                           /* r->path_info was already
+                                              appended by the rewriting engine
+                                              because of the per-dir context! */
+                                           r->args ? "?" : NULL, r->args, 
+                                           NULL);
+
+            /* now make sure the request gets handled by the
+               proxy handler */
+            r->proxyreq = 1;
+            r->handler  = "proxy-server";
+
+            rewritelog(r, 1, "[per-dir %s] go-ahead with proxy request %s [OK]", dconf->directory, r->filename);
+            return OK; 
+        }
+        else if (  (strlen(r->filename) > 7 &&
+                    strncmp(r->filename, "http://", 7) == 0)
+                || (strlen(r->filename) > 8 &&
+                    strncmp(r->filename, "https://", 8) == 0)
+                || (strlen(r->filename) > 9 &&
+                    strncmp(r->filename, "gopher://", 9) == 0)
+                || (strlen(r->filename) > 6 &&
+                    strncmp(r->filename, "ftp://", 6) == 0)    ) {
+            /* it was finally rewritten to a remote URL */
+
+            /* because we are in a per-dir context
+               first try to replace the directory with its base-URL
+               if there is a base-URL available */
+            if (dconf->baseurl != NULL) {
+                /* skip 'scheme:' */
+                for (cp = r->filename; *cp != ':' && *cp != '\0'; cp++)
+                    ;
+                /* skip '://' */
+                cp += 3;
+                if ((cp = strchr(cp, '/')) != NULL) {
+                    rewritelog(r, 2, "[per-dir %s] trying to replace prefix %s with %s", dconf->directory, dconf->directory, dconf->baseurl);
+                    cp2 = subst_prefix_path(r, cp, dconf->directory, dconf->baseurl);
+                    if (strcmp(cp2, cp) != 0) {
+                        *cp = '\0';
+                        r->filename = pstrcat(r->pool, r->filename, cp2, NULL);
+                    }
+                }
+            }
+
+            /* now prepare the redirect... */
+
+            /* skip 'scheme:' */
+            for (cp = r->filename; *cp != ':' && *cp != '\0'; cp++)
+                ;
+            /* skip '://' */
+            cp += 3;
+            /* skip host part */
+            for ( ; *cp != '/' && *cp != '\0'; cp++)
+                ;
+            if (*cp != '\0') {
+                rewritelog(r, 1, "[per-dir %s] escaping %s for redirect", dconf->directory, r->filename);
+                cp2 = escape_uri(r->pool, cp);
+                *cp = '\0';
+                r->filename = pstrcat(r->pool, r->filename, cp2, NULL);
+            }
+
+            /* append the QUERY_STRING part */
+            if (r->args != NULL)
+               r->filename = pstrcat(r->pool, r->filename, "?", r->args, NULL);
+
+            /* determine HTTP redirect response code */
+            if (is_HTTP_REDIRECT(r->status)) {
+                n = r->status; 
+                r->status = HTTP_OK; /* make Apache kernel happy */
+            }
+            else
+                n = REDIRECT;
+
+            /* now do the redirection */
+            table_set(r->headers_out, "Location", r->filename);
+            rewritelog(r, 1, "[per-dir %s] redirect to %s [REDIRECT/%d]", dconf->directory, r->filename, n);
+            return n;
+        }
+        else if (strlen(r->filename) > 10 &&
+                 strncmp(r->filename, "forbidden:", 10) == 0) {
+            /* This URLs is forced to be forbidden for the requester */
+            return FORBIDDEN; 
+        }
+        else if (strlen(r->filename) > 5 &&
+                 strncmp(r->filename, "gone:", 5) == 0) {
+            /* This URLs is forced to be gone */
+            return HTTP_GONE; 
+        }
+        else {
+            /* it was finally rewritten to a local path */
+
+            /* if someone used the PASSTHROUGH flag in per-dir
+               context we just ignore it. It is only useful
+               in per-server context */
+            if (strlen(r->filename) > 12 &&
+                strncmp(r->filename, "passthrough:", 12) == 0) {
+                r->filename = pstrdup(r->pool, r->filename+12);
+            }
+
+            /* the filename has to start with a slash! */
+            if (r->filename[0] != '/')
+                return BAD_REQUEST;
+
+            /* if there is a valid base-URL then substitute
+               the per-dir prefix with this base-URL if the
+               current filename still is inside this per-dir 
+               context. If not then treat the result as a 
+               plain URL */
+            if (dconf->baseurl != NULL) {
+                rewritelog(r, 2, "[per-dir %s] trying to replace prefix %s with %s", dconf->directory, dconf->directory, dconf->baseurl);
+                r->filename = subst_prefix_path(r, r->filename, dconf->directory, dconf->baseurl);
+            }
+            else {
+                /* if no explicit base-URL exists we assume
+                   that the directory prefix is also a valid URL
+                   for this webserver and only try to remove the
+                   document_root if it is prefix */
+
+                if ((cp = document_root(r)) != NULL) {
+                    prefix = pstrdup(r->pool, cp);
+                    /* always NOT have a trailing slash */
+                    l = strlen(prefix);
+                    if (prefix[l-1] == '/') {
+                        prefix[l-1] = '\0';
+                        l--;
+                    }
+                    if (strncmp(r->filename, prefix, l) == 0) {
+                        rewritelog(r, 2, "[per-dir %s] strip document_root prefix: %s -> %s", dconf->directory, r->filename, r->filename+l);
+                        r->filename = pstrdup(r->pool, r->filename+l); 
+                    }
+                }
+            }
+
+            /* now initiate the internal redirect */
+            rewritelog(r, 1, "[per-dir %s] internal redirect with %s [INTERNAL REDIRECT]", dconf->directory, r->filename);
+            r->filename = pstrcat(r->pool, "redirect:", r->filename, NULL);
+            r->handler = "redirect-handler";
+            return OK; 
+        }
+    }
+    else {
+        rewritelog(r, 1, "[per-dir %s] pass through %s", dconf->directory, r->filename);
+        return DECLINED;
+    }
+}
+
+
+/*
+**
+**  Content-Handlers
+**
+**  [used for redirect support]
+**
+*/
+
+static int handler_redirect(request_rec *r)
+{
+    /* just make sure that we are really meant! */
+    if (strncmp(r->filename, "redirect:", 9) != 0) 
+        return DECLINED;
+
+    /* now do the internal redirect */
+    internal_redirect(pstrcat(r->pool, r->filename+9, 
+                                       r->args ? "?" : NULL, r->args, NULL), r);
+
+    /* and return gracefully */
+    return OK;
+}
+
+
+
+
+/*
+** +-------------------------------------------------------+
+** |                                                       |
+** |                  rewriting engine
+** |                                                       |
+** +-------------------------------------------------------+
+*/
+
+
+static int apply_rewrite_list(request_rec *r, array_header *rewriterules, char *perdir)
+{
+    rewriterule_entry *entries;
+    rewriterule_entry *p;
+    int i;
+    int changed;
+    int rc;
+    int s;
+    
+    entries = (rewriterule_entry *)rewriterules->elts;
+    changed = 0;
+    loop:
+    for (i = 0; i < rewriterules->nelts; i++) {
+        p = &entries[i];
+
+        /* ignore this rule on subrequests if we are explicitly asked to do so
+           or this is a proxy throughput or a forced redirect rule */
+        if (r->main != NULL &&
+            (p->flags & RULEFLAG_IGNOREONSUBREQ ||
+             p->flags & RULEFLAG_PROXY          ||
+             p->flags & RULEFLAG_FORCEREDIRECT    ))
+            continue;
+
+        /* apply the current rule */
+        rc = apply_rewrite_rule(r, p, perdir);
+        if (rc) {
+            if (rc != 2) /* not a match-only rule */
+                changed = 1;
+            if (p->flags & RULEFLAG_PASSTHROUGH) {
+                rewritelog(r, 2, "forcing '%s' to get passed through to next URI-to-filename handler", r->filename);
+                r->filename = pstrcat(r->pool, "passthrough:", r->filename, NULL);
+                changed = 1;
+                break;
+            }
+            if (p->flags & RULEFLAG_FORBIDDEN) {
+                rewritelog(r, 2, "forcing '%s' to be forbidden", r->filename);
+                r->filename = pstrcat(r->pool, "forbidden:", r->filename, NULL);
+                changed = 1;
+                break;
+            }
+            if (p->flags & RULEFLAG_GONE) {
+                rewritelog(r, 2, "forcing '%s' to be gone", r->filename);
+                r->filename = pstrcat(r->pool, "gone:", r->filename, NULL);
+                changed = 1;
+                break;
+            }
+            if (p->flags & RULEFLAG_PROXY) 
+                break;
+            if (p->flags & RULEFLAG_LASTRULE) 
+                break;
+            if (p->flags & RULEFLAG_NEWROUND) 
+                goto loop;
+
+            /* if we are forced to skip N next rules, do it now */
+            if (p->skip > 0) {
+                s = p->skip;
+                while (   i < rewriterules->nelts
+                       && s > 0) {
+                    i++;
+                    p = &entries[i];
+                    s--;
+                }
+            }
+        }
+        else {
+            /* if current rule is chained with next rule(s),
+               skip all this next rule(s) */
+            while (   i < rewriterules->nelts
+                   && p->flags & RULEFLAG_CHAIN) {
+                i++;
+                p = &entries[i];
+            }
+        }
+    }
+    return changed;
+}
+
+static int apply_rewrite_rule(request_rec *r, rewriterule_entry *p, char *perdir)
+{
+    char *uri;
+    char *output;
+    int flags;
+    char newuri[MAX_STRING_LEN];
+    char env[MAX_STRING_LEN];
+    char port[32];
+    char env2[MAX_STRING_LEN];
+    regex_t *regexp;
+    regmatch_t regmatch[10];
+    int rc;
+    int prefixstrip;
+    int i;
+    int failed;
+    array_header *rewriteconds;
+    rewritecond_entry *conds;
+    rewritecond_entry *c;
+
+    uri     = r->filename;
+    regexp  = p->regexp;
+    output  = p->output;
+    flags   = p->flags;
+
+    if (perdir != NULL && r->path_info != NULL && r->path_info[0] != '\0') {
+        rewritelog(r, 3, "[per-dir %s] add path-info postfix: %s -> %s%s", perdir, uri, uri, r->path_info);
+        uri = pstrcat(r->pool, uri, r->path_info, NULL);
+    }
+
+    prefixstrip = 0;
+    if (perdir != NULL) {
+        /* this is a per-directory match */
+        if (   strlen(uri) >= strlen(perdir)
+            && strncmp(uri, perdir, strlen(perdir)) == 0) {
+            rewritelog(r, 3, "[per-dir %s] strip per-dir prefix: %s -> %s", perdir, uri, uri+strlen(perdir));
+            uri = uri+strlen(perdir);
+            prefixstrip = 1;
+        }
+    }
+
+    if (perdir != NULL) 
+        rewritelog(r, 3, "[per-dir %s] applying pattern '%s' to uri '%s'", perdir, p->pattern, uri);
+
+    rc = (regexec(regexp, uri, regexp->re_nsub+1, regmatch, 0) == 0);   /* try to match the pattern */
+    if (( rc && !(p->flags & RULEFLAG_NOTMATCH)) ||
+        (!rc &&  (p->flags & RULEFLAG_NOTMATCH))   ) {     
+
+        /* ok, the pattern matched, but we now additionally have to check 
+           for any preconditions which have to be also true. We do this
+           at this very late stage to avoid unnessesary checks which
+           slow down the rewriting engine!! */
+        rewriteconds = p->rewriteconds;
+        conds = (rewritecond_entry *)rewriteconds->elts;
+        failed = 0;
+        for (i = 0; i < rewriteconds->nelts; i++) {
+            c = &conds[i];
+            rc = apply_rewrite_cond(r, c, perdir);
+            if (c->flags & CONDFLAG_ORNEXT) {
+                /* there is a "or" flag */
+                if (rc == 0) {
+                    /* one cond is false, but another can be true... */
+                    continue;
+                }
+                else {
+                    /* one true cond is enough, so skip the other conds
+                       of the "ornext" chained conds */
+                    while (   i < rewriteconds->nelts
+                           && c->flags & CONDFLAG_ORNEXT) {
+                        i++;
+                        c = &conds[i];
+                    }
+                    continue;
+                }
+            }
+            else {
+                /* no "or" flag, so a single fail means total fail */
+                if (rc == 0) { /* failed */
+                    failed = 1;
+                    break;
+                }
+            }
+        }
+        if (failed) 
+            return 0; /* if any condition fails this complete rule fails */
+
+        /* if this is a pure matching rule we return immediately */
+        if (strcmp(output, "-") == 0) 
+            return 2;
+
+        /* if this is a forced proxy request ... */
+        if (p->flags & RULEFLAG_PROXY) {
+            if (p->flags & RULEFLAG_NOTMATCH) {
+                output = pstrcat(r->pool, "proxy:", output, NULL);
+                strncpy(newuri, output, sizeof(newuri)-1);
+                EOS_PARANOIA(newuri);
+                expand_variables_inbuffer(r, newuri, sizeof(newuri));/* expand %{...} */
+                expand_map_lookups(r, newuri, sizeof(newuri));       /* expand ${...} */
+            }
+            else {
+                output = pstrcat(r->pool, "proxy:", output, NULL);
+                strncpy(newuri, pregsub(r->pool, output, uri, regexp->re_nsub+1, regmatch), sizeof(newuri)-1);    /* substitute in output */
+                EOS_PARANOIA(newuri);
+                for (i = 0; p->env[i] != NULL; i++) {
+                    strncpy(env2, p->env[i], sizeof(env2)-1);
+                    EOS_PARANOIA(env2);
+                    strncpy(env, pregsub(r->pool, env2, uri, regexp->re_nsub+1, regmatch), sizeof(env)-1);    /* substitute in output */
+                    EOS_PARANOIA(env);
+                    add_env_variable(r, env);
+                }
+                expand_variables_inbuffer(r, newuri, sizeof(newuri));   /* expand %{...} */
+                expand_map_lookups(r, newuri, sizeof(newuri));          /* expand ${...} */
+            }
+            if (perdir == NULL)
+                rewritelog(r, 2, "rewrite %s -> %s", r->filename, newuri);
+            else
+                rewritelog(r, 2, "[per-dir %s] rewrite %s -> %s", perdir, r->filename, newuri);
+            r->filename = pstrdup(r->pool, newuri);
+            return 1;
+        }
+
+        /* if this is a implicit redirect in a per-dir rule */
+        i = strlen(output);
+        if (perdir != NULL
+            && (   (i > 7 && strncmp(output, "http://", 7) == 0)
+                || (i > 8 && strncmp(output, "https://", 8) == 0)
+                || (i > 9 && strncmp(output, "gopher://", 9) == 0)
+                || (i > 6 && strncmp(output, "ftp://", 6) == 0)   ) ) {
+            if (p->flags & RULEFLAG_NOTMATCH) {
+                strncpy(newuri, output, sizeof(newuri)-1);
+                EOS_PARANOIA(newuri);
+                expand_variables_inbuffer(r, newuri, sizeof(newuri));/* expand %{...} */
+                expand_map_lookups(r, newuri, sizeof(newuri));       /* expand ${...} */
+            }
+            else {
+                strncpy(newuri, pregsub(r->pool, output, uri, regexp->re_nsub+1, regmatch), sizeof(newuri)-1);    /* substitute in output */
+                EOS_PARANOIA(newuri);
+                for (i = 0; p->env[i] != NULL; i++) {
+                    strncpy(env2, p->env[i], sizeof(env2)-1);
+                    EOS_PARANOIA(env2);
+                    strncpy(env, pregsub(r->pool, env2, uri, regexp->re_nsub+1, regmatch), sizeof(env)-1);    /* substitute in output */
+                    EOS_PARANOIA(env);
+                    add_env_variable(r, env);
+                }
+                expand_variables_inbuffer(r, newuri, sizeof(newuri));/* expand %{...} */
+                expand_map_lookups(r, newuri, sizeof(newuri));       /* expand ${...} */
+            }
+            rewritelog(r, 2, "[per-dir %s] redirect %s -> %s", perdir, r->filename, newuri);
+            r->filename = pstrdup(r->pool, newuri);
+            return 1;
+        }
+
+        /* add the previously stripped perdir prefix 
+           if the new URI is not a new one (i.e.
+           prefixed by a slash which means that is 
+           no for this per-dir context) */
+        if (prefixstrip && output[0] != '/') {
+            rewritelog(r, 3, "[per-dir %s] add per-dir prefix: %s -> %s%s", perdir, output, perdir, output);
+            output = pstrcat(r->pool, perdir, output, NULL);
+        }
+
+        if (p->flags & RULEFLAG_NOTMATCH) {
+            /* just overtake the URI */
+            strncpy(newuri, output, sizeof(newuri)-1);
+            EOS_PARANOIA(newuri);
+        }
+        else {
+            /* substitute in output */
+            strncpy(newuri, pregsub(r->pool, output, uri, regexp->re_nsub+1, regmatch), sizeof(newuri)-1);    /* substitute in output */
+            EOS_PARANOIA(newuri);
+            for (i = 0; p->env[i] != NULL; i++) {
+                strncpy(env2, p->env[i], sizeof(env2)-1);
+                EOS_PARANOIA(env2);
+                strncpy(env, pregsub(r->pool, env2, uri, regexp->re_nsub+1, regmatch), sizeof(env)-1);    /* substitute in output */
+                EOS_PARANOIA(env);
+                add_env_variable(r, env);
+            }
+        }
+        expand_variables_inbuffer(r, newuri, sizeof(newuri));  /* expand %{...} */
+        expand_map_lookups(r, newuri, sizeof(newuri));         /* expand ${...} */
+
+        if (perdir == NULL)
+            rewritelog(r, 2, "rewrite %s -> %s", uri, newuri);
+        else
+            rewritelog(r, 2, "[per-dir %s] rewrite %s -> %s", perdir, uri, newuri);
+
+        r->filename = pstrdup(r->pool, newuri);
+
+        /* reduce http[s]://<ourhost>[:<port>] */
+        reduce_uri(r);
+
+        /* split out on-the-fly generated QUERY_STRING '....?xxxxx&xxxx...' */
+        splitout_queryargs(r);
+
+        /* if a MIME-type should be later forced for this URL, then remember this */
+        if (p->forced_mimetype != NULL) {
+            table_set(r->notes, REWRITE_FORCED_MIMETYPE_NOTEVAR, p->forced_mimetype);
+            if (perdir == NULL)
+                rewritelog(r, 2, "remember %s to have MIME-type '%s'", r->filename, p->forced_mimetype);
+            else
+                rewritelog(r, 2, "[per-dir %s] remember %s to have MIME-type '%s'", perdir, r->filename, p->forced_mimetype);
+        }
+
+        /* if we are forced to do a explicit redirect by [R] flag
+           and the current URL still is not a fully qualified one we
+           finally prefix it with http[s]://<ourname> explicitly */
+        if (flags & RULEFLAG_FORCEREDIRECT) {
+            if (  !(strlen(r->filename) > 7 &&
+                    strncmp(r->filename, "http://", 7) == 0)
+               && !(strlen(r->filename) > 8 &&
+                    strncmp(r->filename, "https://", 8) == 0)
+               && !(strlen(r->filename) > 9 &&
+                    strncmp(r->filename, "gopher://", 9) == 0)
+               && !(strlen(r->filename) > 6 &&
+                    strncmp(r->filename, "ftp://", 6) == 0)    ) {
+
+#ifdef APACHE_SSL
+                if ((!r->connection->client->ssl && r->server->port == DEFAULT_PORT) ||
+                    ( r->connection->client->ssl && r->server->port == 443)  )
+#else
+                if (r->server->port == DEFAULT_PORT)
+#endif
+                    port[0] = '\0';
+                else 
+                    ap_snprintf(port, sizeof(port), ":%u", r->server->port);
+                if (r->filename[0] == '/')
+#ifdef APACHE_SSL
+                    ap_snprintf(newuri, sizeof(newuri), "%s://%s%s%s", http_method(r), r->server->server_hostname, port, r->filename);
+#else
+                    ap_snprintf(newuri, sizeof(newuri), "http://%s%s%s", r->server->server_hostname, port, r->filename);
+#endif
+                else
+#ifdef APACHE_SSL
+                    ap_snprintf(newuri, sizeof(newuri), "%s://%s%s/%s", http_method(r), r->server->server_hostname, port, r->filename);
+#else
+                    ap_snprintf(newuri, sizeof(newuri), "http://%s%s/%s", r->server->server_hostname, port, r->filename);
+#endif
+                if (perdir == NULL) 
+                    rewritelog(r, 2, "prepare forced redirect %s -> %s", r->filename, newuri);
+                else
+                    rewritelog(r, 2, "[per-dir %s] prepare forced redirect %s -> %s", perdir, r->filename, newuri);
+                r->filename = pstrdup(r->pool, newuri);
+                r->status = p->forced_responsecode;
+                return 1;
+            }
+        }
+
+        return 1;
+    }
+    return 0;
+}
+
+static int apply_rewrite_cond(request_rec *r, rewritecond_entry *p, char *perdir)
+{
+    char *input;
+    int rc;
+    struct stat sb;
+    request_rec *rsub;
+
+    /* first, we have to expand the input string to match */
+    input = expand_variables(r, p->input);
+
+    rc = 0;
+    if (strcmp(p->pattern, "-f") == 0) {
+        if (stat(input, &sb) == 0)
+            if (S_ISREG(sb.st_mode))
+                rc = 1;
+    }
+    else if (strcmp(p->pattern, "-s") == 0) {
+        if (stat(input, &sb) == 0)
+            if (S_ISREG(sb.st_mode) && sb.st_size > 0) 
+                rc = 1;
+    }
+    else if (strcmp(p->pattern, "-l") == 0) {
+#ifndef __EMX__
+/* OS/2 dosen't support links. */
+        if (stat(input, &sb) == 0)
+            if (S_ISLNK(sb.st_mode))
+                rc = 1;
+#endif
+    }
+    else if (strcmp(p->pattern, "-d") == 0) {
+        if (stat(input, &sb) == 0)
+            if (S_ISDIR(sb.st_mode))
+                rc = 1;
+    }
+    else if (strcmp(p->pattern, "-U") == 0) {
+        /* avoid infinite subrequest recursion */
+        if (strlen(input) > 0               /* nonempty path, and */
+            && (   r->main == NULL          /* - either not in a subrequest */
+                || (   r->main->uri != NULL /* - or in a subrequest...*/
+                    && r->uri != NULL       /*   ...and then URIs aren't NULL... */
+                                            /*   ...and sub and main URIs differ */
+                    && strcmp(r->main->uri, r->uri) != 0) ) ) {
+
+            /* run a URI-based subrequest */
+            rsub = sub_req_lookup_uri(input, r);
+
+            /* URI exists for any result up to 3xx, redirects allowed */
+            if (rsub->status < 400)
+                rc = 1;
+
+            /* log it */
+            rewritelog(r, 5, "RewriteCond URI (-U) check: path=%s -> status=%d", input, rsub->status);
+
+            /* cleanup by destroying the subrequest */
+            destroy_sub_req(rsub);
+        }
+    }
+    else if (strcmp(p->pattern, "-F") == 0) {
+        /* avoid infinite subrequest recursion */
+        if (strlen(input) > 0               /* nonempty path, and */
+            && (   r->main == NULL          /* - either not in a subrequest */
+                || (   r->main->uri != NULL /* - or in a subrequest...*/
+                    && r->uri != NULL       /*   ...and then URIs aren't NULL... */
+                                            /*   ...and sub and main URIs differ */
+                    && strcmp(r->main->uri, r->uri) != 0) ) ) {
+
+            /* process a file-based subrequest: 
+               this differs from -U in that no path translation is done. */
+            rsub = sub_req_lookup_file(input, r);
+            /* file exists for any result up to 2xx, no redirects */
+            if (rsub->status < 300 &&
+                /* double-check that file exists since default result is 200 */
+                stat(rsub->filename, &sb) == 0)
+                rc = 1;
+
+            /* log it */
+            rewritelog(r, 5, "RewriteCond file (-F) check: path=%s -> file=%s status=%d", input, rsub->filename, rsub->status);
+
+            /* cleanup by destroying the subrequest */
+            destroy_sub_req(rsub);
+        }
+    }
+    else if (strlen(p->pattern) > 1 && *(p->pattern) == '>') {
+        rc = (compare_lexicography(input, p->pattern+1) == 1 ? 1 : 0);
+    }
+    else if (strlen(p->pattern) > 1 && *(p->pattern) == '<') {
+        rc = (compare_lexicography(input, p->pattern+1) == -1 ? 1 : 0);
+    }
+    else if (strlen(p->pattern) > 1 && *(p->pattern) == '=') {
+        rc = (strcmp(input, p->pattern+1) == 0 ? 1 : 0);
+    }
+    else {
+        /* it is really a regexp pattern, so apply it */
+        rc = (regexec(p->regexp, input, 0, NULL, 0) == 0);
+    }
+
+    /* if this is a non-matching regexp, just negate the result */ 
+    if (p->flags & CONDFLAG_NOTMATCH) 
+        rc = !rc;
+
+    rewritelog(r, 4, "RewriteCond: input='%s' pattern='%s' => %s", input, p->pattern, rc ? "matched" : "not-matched");
+
+    /* end just return the result */
+    return rc;
+}
+
+
+
+
+/*
+** +-------------------------------------------------------+
+** |                                                       |
+** |              URL transformation functions
+** |                                                       |
+** +-------------------------------------------------------+
+*/
+
+
+/*
+**
+**  split out a QUERY_STRING part from
+**  the current URI string
+**
+*/
+
+static void splitout_queryargs(request_rec *r)
+{
+    char *q;
+    char *olduri;
+
+    q = strchr(r->filename, '?');
+    if (q != NULL) {
+        olduri = pstrdup(r->pool, r->filename);
+        *q++ = '\0';
+        r->args = pstrcat(r->pool, q, "&", r->args, NULL);
+        if (r->args[strlen(r->args)-1] == '&')
+            r->args[strlen(r->args)-1] = '\0';
+        rewritelog(r, 3, "split uri=%s -> uri=%s, args=%s", olduri, r->filename, r->args);
+    }
+    return;            
+}
+
+
+/*
+**
+**  strip 'http[s]://ourhost/' from URI
+**
+*/
+
+static void reduce_uri(request_rec *r)
+{
+    char *cp;
+    unsigned short port;
+    char *portp;
+    char *hostp;
+    char *url;
+    char c;
+    char host[LONG_STRING_LEN];
+    char buf[MAX_STRING_LEN];
+    char *olduri;
+
+#ifdef APACHE_SSL
+    if (   (!r->connection->client->ssl &&
+            strncmp(r->filename, "http://", 7) == 0)
+        || (r->connection->client->ssl &&
+            strncmp(r->filename, "https://", 8) == 0)) {
+#else
+    if (strncmp(r->filename, "http://", 7) == 0) {
+#endif
+        /* there was really a rewrite to a remote path */
+
+        olduri = pstrdup(r->pool, r->filename); /* save for logging */
+
+        /* cut the hostname and port out of the URI */
+#ifdef APACHE_SSL
+        strncpy(buf, r->filename+strlen(http_method(r))+3, sizeof(buf)-1);
+#else
+        strncpy(buf, r->filename+7, sizeof(buf)-1);
+#endif
+        EOS_PARANOIA(buf);
+        hostp = buf;
+        for (cp = hostp; *cp != '\0' && *cp != '/' && *cp != ':'; cp++)
+            ;
+        if (*cp == ':') {
+            /* set host */
+            *cp++ = '\0';
+            strncpy(host, hostp, sizeof(host)-1);
+            EOS_PARANOIA(host);
+            /* set port */
+            portp = cp;
+            for (; *cp != '\0' && *cp != '/'; cp++)
+                ;
+            c = *cp;
+            *cp = '\0';
+            port = atoi(portp);
+            *cp = c;
+            /* set remaining url */
+            url = cp;
+        }
+        else if (*cp == '/') {
+            /* set host */
+            *cp = '\0';
+            strncpy(host, hostp, sizeof(host)-1);
+            EOS_PARANOIA(host);
+            *cp = '/';
+            /* set port */
+            port = DEFAULT_PORT;
+            /* set remaining url */
+            url = cp;
+        }
+        else {
+            /* set host */
+            strncpy(host, hostp, sizeof(host)-1);
+            EOS_PARANOIA(host);
+            /* set port */
+            port = DEFAULT_PORT;
+            /* set remaining url */
+            url = "/";
+        }
+
+        /* now check whether we could reduce it to a local path... */
+        if (is_this_our_host(r, host) && port == r->server->port) {
+            /* this is our host, so only the URL remains */
+            r->filename = pstrdup(r->pool, url);
+            rewritelog(r, 3, "reduce %s -> %s", olduri, r->filename);
+        }
+    }
+    return;            
+}
+
+
+/*
+**
+**  Expand tilde-paths (~user) through
+**  Unix /etc/passwd database information
+**
+*/
+
+static char *expand_tildepaths(request_rec *r, char *uri)
+{
+    char user[LONG_STRING_LEN];
+    struct passwd *pw;
+    char *newuri;
+    int i, j;
+
+    newuri = uri;
+    if (uri != NULL && strlen(uri) > 2 && uri[0] == '/' && uri[1] == '~') {
+        /* cut out the username */
+        for (j = 0, i = 2; j < sizeof(user)-1 && uri[i] != '\0' && 
+                       (   (uri[i] >= '0' && uri[i] <= '9')
+                        || (uri[i] >= 'a' && uri[i] <= 'z')
+                        || (uri[i] >= 'A' && uri[i] <= 'Z')); )
+            user[j++] = uri[i++];
+        user[j] = '\0';
+
+        /* lookup username in systems passwd file */
+        if ((pw = getpwnam(user)) != NULL) {
+            /* ok, user was found, so expand the ~user string */
+            if (uri[i] != '\0') {
+                /* ~user/anything...  has to be expanded */
+                if (pw->pw_dir[strlen(pw->pw_dir)-1] == '/') 
+                    pw->pw_dir[strlen(pw->pw_dir)-1] = '\0';
+                newuri = pstrcat(r->pool, pw->pw_dir, uri+i, NULL);
+            }
+            else {
+                /* only ~user has to be expanded */
+                newuri = pstrdup(r->pool, pw->pw_dir);
+            }
+        }
+    }
+    return newuri;
+}
+
+
+/*
+**
+**  mapfile expansion support
+**  i.e. expansion of MAP lookup directives
+**  ${<mapname>:<key>} in RewriteRule rhs
+**
+*/
+
+#define limit_length(n) (n > LONG_STRING_LEN-1 ? LONG_STRING_LEN-1 : n)
+
+static void expand_map_lookups(request_rec *r, char *uri, int uri_len)
+{
+    char newuri[MAX_STRING_LEN];
+    char *cpI;
+    char *cpIE;
+    char *cpO;
+    char *cpT;
+    char *cpT2;
+    char mapname[LONG_STRING_LEN];
+    char mapkey[LONG_STRING_LEN];
+    char defaultvalue[LONG_STRING_LEN];
+    int n;
+
+    cpI = uri;
+    cpIE = cpI+strlen(cpI);
+    cpO = newuri;
+    while (cpI < cpIE) {
+        if (cpI+6 < cpIE && strncmp(cpI, "${", 2) == 0) {
+            /* missing delimiter -> take it as plain text */
+            if (   strchr(cpI+2, ':') == NULL
+                || strchr(cpI+2, '}') == NULL) {
+                memcpy(cpO, cpI, 2);
+                cpO += 2;
+                cpI += 2;
+                continue;
+            }
+            cpI += 2;
+
+            cpT = strchr(cpI, ':');
+            n = cpT-cpI;
+            memcpy(mapname, cpI, limit_length(n));
+            mapname[limit_length(n)] = '\0';
+            cpI += n+1;
+
+            cpT2 = strchr(cpI, '|');
+            cpT = strchr(cpI, '}');
+            if (cpT2 != NULL && cpT2 < cpT) {
+                n = cpT2-cpI;
+                memcpy(mapkey, cpI, limit_length(n));
+                mapkey[limit_length(n)] = '\0';
+                cpI += n+1;
+
+                n = cpT-cpI;
+                memcpy(defaultvalue, cpI, limit_length(n));
+                defaultvalue[limit_length(n)] = '\0';
+                cpI += n+1;
+            }
+            else {
+                n = cpT-cpI;
+                memcpy(mapkey, cpI, limit_length(n));
+                mapkey[limit_length(n)] = '\0';
+                cpI += n+1;
+
+                defaultvalue[0] = '\0';
+            }
+
+            cpT = lookup_map(r, mapname, mapkey);
+            if (cpT != NULL) {
+                n = strlen(cpT);
+                if (cpO + n >= newuri + sizeof(newuri)) {
+                    log_printf(r->server, "insufficient space in expand_map_lookups, aborting");
+                    return;
+                }
+                memcpy(cpO, cpT, n);
+                cpO += n;
+            }
+            else {
+                n = strlen(defaultvalue);
+                if (cpO + n >= newuri + sizeof(newuri)) {
+                    log_printf(r->server, "insufficient space in expand_map_lookups, aborting");
+                    return;
+                }
+                memcpy(cpO, defaultvalue, n);
+                cpO += n;
+            }
+        }
+        else {
+            cpT = strstr(cpI, "${");
+            if (cpT == NULL)
+                cpT = cpI+strlen(cpI);
+            n = cpT-cpI;
+            if (cpO + n >= newuri + sizeof(newuri)) {
+                log_printf(r->server, "insufficient space in expand_map_lookups, aborting");
+                return;
+            }
+            memcpy(cpO, cpI, n);
+            cpO += n;
+            cpI += n;
+        }
+    }
+    *cpO = '\0';
+    strncpy(uri, newuri, uri_len-1);
+    uri[uri_len-1] = '\0';
+    return;
+}
+
+#undef limit_length
+
+
+
+/*
+** +-------------------------------------------------------+
+** |                                                       |
+** |              DBM hashfile support
+** |                                                       |
+** +-------------------------------------------------------+
+*/
+
+
+static char *lookup_map(request_rec *r, char *name, char *key)
+{
+    void *sconf;
+    rewrite_server_conf *conf;
+    array_header *rewritemaps;
+    rewritemap_entry *entries;
+    rewritemap_entry *s;
+    char *value;
+    struct stat st;
+    int i;
+
+    /* get map configuration */
+    sconf = r->server->module_config;
+    conf  = (rewrite_server_conf *)get_module_config(sconf, &rewrite_module);
+    rewritemaps = conf->rewritemaps;
+
+    entries = (rewritemap_entry *)rewritemaps->elts;
+    for (i = 0; i < rewritemaps->nelts; i++) {
+        s = &entries[i];
+        if (strcmp(s->name, name) == 0) {
+            if (s->type == MAPTYPE_TXT) {
+                stat(s->checkfile, &st); /* existence was checked at startup! */
+                value = get_cache_string(cachep, s->name, CACHEMODE_TS, st.st_mtime, key);
+                if (value == NULL) {
+                    rewritelog(r, 6, "cache lookup FAILED, forcing new map lookup");
+                    if ((value = lookup_map_txtfile(r, s->datafile, key)) != NULL) {
+                        rewritelog(r, 5, "map lookup OK: map=%s key=%s[txt] -> val=%s", s->name, key, value);
+                        set_cache_string(cachep, s->name, CACHEMODE_TS, st.st_mtime, key, value);
+                        return value;
+                    }
+                    else {
+                        rewritelog(r, 5, "map lookup FAILED: map=%s[txt] key=%s", s->name, key);
+                        return NULL;
+                    }
+                }
+                else {
+                    rewritelog(r, 5, "cache lookup OK: map=%s[txt] key=%s -> val=%s", s->name, key, value);
+                    return value;
+                }
+            }
+            else if (s->type == MAPTYPE_DBM) {
+#if HAS_NDBM_LIB
+                stat(s->checkfile, &st); /* existence was checked at startup! */
+                value = get_cache_string(cachep, s->name, CACHEMODE_TS, st.st_mtime, key);
+                if (value == NULL) {
+                    rewritelog(r, 6, "cache lookup FAILED, forcing new map lookup");
+                    if ((value = lookup_map_dbmfile(r, s->datafile, key)) != NULL) {
+                        rewritelog(r, 5, "map lookup OK: map=%s[dbm] key=%s -> val=%s", s->name, key, value);
+                        set_cache_string(cachep, s->name, CACHEMODE_TS, st.st_mtime, key, value);
+                        return value;
+                    }
+                    else {
+                        rewritelog(r, 5, "map lookup FAILED: map=%s[dbm] key=%s", s->name, key);
+                        return NULL;
+                    }
+                }
+                else {
+                    rewritelog(r, 5, "cache lookup OK: map=%s[dbm] key=%s -> val=%s", s->name, key, value);
+                    return value;
+                }
+#else
+                return NULL;
+#endif
+            }
+            else if (s->type == MAPTYPE_PRG) {
+                if ((value = lookup_map_program(r, s->fpin, s->fpout, key)) != NULL) {
+                    rewritelog(r, 5, "map lookup OK: map=%s key=%s -> val=%s", s->name, key, value);
+                    return value;
+                }
+                else {
+                    rewritelog(r, 5, "map lookup FAILED: map=%s key=%s", s->name, key);
+                }
+            }
+        }
+    }
+    return NULL;
+}
+
+
+static char *lookup_map_txtfile(request_rec *r, char *file, char *key)
+{
+    FILE *fp = NULL;
+    char line[1024];
+    char output[1024];
+    char result[1024];
+    char *value = NULL;
+    char *cpT;
+    char *curkey;
+    char *curval;
+
+    if ((fp = pfopen(r->pool, file, "r")) == NULL)
+        return NULL;
+
+    strncpy(output, MAPFILE_OUTPUT, sizeof(output)-1);
+    EOS_PARANOIA(output);
+    while (fgets(line, sizeof(line), fp) != NULL) {
+        if (line[strlen(line)-1] == '\n')
+            line[strlen(line)-1] = '\0';
+        if (regexec(lookup_map_txtfile_regexp, line, lookup_map_txtfile_regexp->re_nsub+1, lookup_map_txtfile_regmatch, 0) == 0) {
+            strncpy(result, pregsub(r->pool, output, line, lookup_map_txtfile_regexp->re_nsub+1, lookup_map_txtfile_regmatch), sizeof(result)-1); /* substitute in output */
+            EOS_PARANOIA(result);
+            cpT = strchr(result, ',');
+            *cpT = '\0';
+            curkey = result;
+            curval = cpT+1;
+
+            if (strcmp(curkey, key) == 0) {
+                value = pstrdup(r->pool, curval);
+                break;
+            }
+        }
+    }
+    pfclose(r->pool, fp);
+    return value;
+}
+
+#if HAS_NDBM_LIB
+static char *lookup_map_dbmfile(request_rec *r, char *file, char *key)
+{
+    DBM *dbmfp = NULL;
+    datum dbmkey;
+    datum dbmval;
+    char *value = NULL;
+    char buf[MAX_STRING_LEN];
+
+    dbmkey.dptr  = key;
+    dbmkey.dsize = (strlen(key) < sizeof(buf) - 1 ? strlen(key) : sizeof(buf)-1);
+    if ((dbmfp = dbm_open(file, O_RDONLY, 0666)) != NULL) {
+        dbmval = dbm_fetch(dbmfp, dbmkey);
+        if (dbmval.dptr != NULL) {
+            memcpy(buf, dbmval.dptr, dbmval.dsize);
+            buf[dbmval.dsize] = '\0';
+            value = pstrdup(r->pool, buf);
+        }
+        dbm_close(dbmfp);
+    }
+    return value;
+}
+#endif
+
+static char *lookup_map_program(request_rec *r, int fpin, int fpout, char *key)
+{
+    char buf[LONG_STRING_LEN];
+    char c;
+    int i;
+
+    /* lock the channel */
+    fd_lock(fpin);
+
+    /* write out the request key */
+    write(fpin, key, strlen(key));
+    write(fpin, "\n", 1);
+
+    /* read in the response value */
+    i = 0;
+    while (read(fpout, &c, 1) == 1 && (i < LONG_STRING_LEN-1)) {
+        if (c == '\n')
+            break;
+        buf[i++] = c;
+    }
+    buf[i] = '\0';
+
+    /* unlock the channel */
+    fd_unlock(fpin);
+
+    if (strcasecmp(buf, "NULL") == 0)
+        return NULL;
+    else
+        return pstrdup(r->pool, buf);
+}
+
+
+
+
+/*
+** +-------------------------------------------------------+
+** |                                                       |
+** |              rewriting logfile support
+** |                                                       |
+** +-------------------------------------------------------+
+*/
+
+
+static void open_rewritelog(server_rec *s, pool *p)
+{
+    rewrite_server_conf *conf;
+    char *fname;
+    FILE *fp;
+    static int    rewritelog_flags = ( O_WRONLY|O_APPEND|O_CREAT );
+    static mode_t rewritelog_mode  = ( S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH );
+  
+    conf = get_module_config(s->module_config, &rewrite_module);
+    
+    if (conf->rewritelogfile == NULL)
+        return; 
+    if (*(conf->rewritelogfile) == '\0')
+        return;
+    if (conf->rewritelogfp > 0)
+        return; /* virtual log shared w/main server */
+
+    fname = server_root_relative(p, conf->rewritelogfile);
+    
+    if (*conf->rewritelogfile == '|') {
+        if (!spawn_child(p, rewritelog_child, (void *)(conf->rewritelogfile+1),
+                    kill_after_timeout, &fp, NULL)) {
+            perror("spawn_child");
+            fprintf (stderr, "mod_rewrite: could not fork child for RewriteLog process\n");
+            exit (1);
+        }
+        conf->rewritelogfp = fileno(fp);
+    }
+    else if (*conf->rewritelogfile != '\0') {
+        if ((conf->rewritelogfp = popenf(p, fname, rewritelog_flags, rewritelog_mode)) < 0) {
+            perror("open");
+            fprintf(stderr, "mod_rewrite: could not open RewriteLog file %s.\n", fname);
+            exit(1);
+        }
+    }
+    return;
+}
+
+/* Child process code for 'RewriteLog "|..."' */
+static void rewritelog_child(void *cmd)
+{
+    cleanup_for_exec();
+    signal(SIGHUP, SIG_IGN);
+#ifdef __EMX__
+    /* OS/2 needs a '/' */
+    execl(SHELL_PATH, SHELL_PATH, "/c", (char *)cmd, NULL);
+#else
+    execl(SHELL_PATH, SHELL_PATH, "-c", (char *)cmd, NULL);
+#endif
+    exit(1);
+}
+
+static void rewritelog(request_rec *r, int level, const char *text, ...)
+{
+    rewrite_server_conf *conf;
+    conn_rec *connect;
+    char *str1;
+    static char str2[HUGE_STRING_LEN];
+    static char str3[HUGE_STRING_LEN];
+    static char type[20];
+    static char redir[20];
+    va_list ap;
+    int i;
+    request_rec *req;
+    char *ruser;
+    
+    va_start(ap, text);
+    conf = get_module_config(r->server->module_config, &rewrite_module);
+    connect = r->connection;
+
+    if (conf->rewritelogfp <0)
+        return;
+    if (conf->rewritelogfile == NULL)
+        return;
+    if (*(conf->rewritelogfile) == '\0')
+        return;
+
+    if (level > conf->rewriteloglevel)
+        return;
+
+    if (connect->user == NULL) {
+        ruser = "-";
+    }
+    else if (strlen (connect->user) != 0) {
+        ruser = connect->user;
+    }
+    else {
+        ruser = "\"\"";
+    }
+
+    str1 = pstrcat(r->pool, get_remote_host(connect, r->server->module_config, REMOTE_NAME), " ",
+                            (connect->remote_logname != NULL ? connect->remote_logname : "-"), " ",
+                            ruser, NULL);
+    ap_vsnprintf(str2, sizeof(str2), text, ap);
+
+    if (r->main == NULL)
+        strcpy(type, "initial");
+    else
+        strcpy(type, "subreq");
+
+    for (i = 0, req = r->prev; req != NULL; req = req->prev) 
+        ;
+    if (i == 0)
+        redir[0] = '\0';
+    else
+        ap_snprintf(redir, sizeof(redir), "/redir#%d", i);
+
+    ap_snprintf(str3, sizeof(str3), "%s %s [%s/sid#%x][rid#%x/%s%s] (%d) %s\n", str1, current_logtime(r), r->server->server_hostname, (unsigned int)(r->server), (unsigned int)r, type, redir, level, str2);
+
+    fd_lock(conf->rewritelogfp);
+    write(conf->rewritelogfp, str3, strlen(str3));
+    fd_unlock(conf->rewritelogfp);
+
+    va_end(ap);
+    return;
+}
+
+static char *current_logtime(request_rec *r)
+{
+    int timz;
+    struct tm *t;
+    char tstr[80];
+    char sign;
+    
+    t = get_gmtoff(&timz);
+    sign = (timz < 0 ? '-' : '+');
+    if(timz < 0) 
+        timz = -timz;
+
+    strftime(tstr, 80, "[%d/%b/%Y:%H:%M:%S ", t);
+    ap_snprintf(tstr + strlen(tstr), 80-strlen(tstr), "%c%.2d%.2d]", sign, timz/60, timz%60);
+    return pstrdup(r->pool, tstr);
+}
+
+
+
+
+/*
+** +-------------------------------------------------------+
+** |                                                       |
+** |                  program map support
+** |                                                       |
+** +-------------------------------------------------------+
+*/
+
+static void run_rewritemap_programs(server_rec *s, pool *p)
+{
+    rewrite_server_conf *conf;
+    char *fname;
+    FILE *fpin;
+    FILE *fpout;
+    array_header *rewritemaps;
+    rewritemap_entry *entries;
+    rewritemap_entry *map;
+    int i;
+    int rc;
+  
+    conf = get_module_config(s->module_config, &rewrite_module);
+
+    rewritemaps = conf->rewritemaps;
+    entries = (rewritemap_entry *)rewritemaps->elts;
+    for (i = 0; i < rewritemaps->nelts; i++) {
+        map = &entries[i];
+        if (map->type != MAPTYPE_PRG)
+            continue;
+        if (map->datafile == NULL    ||
+            *(map->datafile) == '\0' ||
+            map->fpin > 0        ||
+            map->fpout > 0         )
+            continue;
+        fname = server_root_relative(p, map->datafile);
+        fpin = NULL;
+        fpout = NULL;
+        rc = spawn_child(p, rewritemap_program_child, (void *)map->datafile, kill_after_timeout, &fpin, &fpout);
+        if (rc == 0 || fpin == NULL || fpout == NULL) {
+            perror("spawn_child");
+            fprintf(stderr, "mod_rewrite: could not fork child for RewriteMap process\n");
+            exit(1);
+        }
+        map->fpin  = fileno(fpin);
+        map->fpout = fileno(fpout);
+    }
+    return;
+}
+
+/* child process code */
+static void rewritemap_program_child(void *cmd)
+{
+    cleanup_for_exec();
+    signal(SIGHUP, SIG_IGN);
+#ifdef __EMX__
+    /* OS/2 needs a '/' */
+    execl(SHELL_PATH, SHELL_PATH, "/c", (char *)cmd, NULL);
+#else
+    execl(SHELL_PATH, SHELL_PATH, "-c", (char *)cmd, NULL);
+#endif
+    exit(1);
+}
+
+
+
+
+/*
+** +-------------------------------------------------------+
+** |                                                       |
+** |             environment variable support
+** |                                                       |
+** +-------------------------------------------------------+
+*/
+
+
+static void expand_variables_inbuffer(request_rec *r, char *buf, int buf_len)
+{
+    char *newbuf;
+    newbuf = expand_variables(r, buf);
+    if (strcmp(newbuf, buf) != 0) {
+        strncpy(buf, newbuf, buf_len-1);
+        buf[buf_len-1] = '\0';
+    }
+    return;
+}
+
+static char *expand_variables(request_rec *r, char *str)
+{
+    char output[MAX_STRING_LEN];
+    char input[MAX_STRING_LEN];
+    char *cp;
+    char *cp2;
+    char *cp3;
+    int expanded;
+
+    strncpy(input, str, sizeof(input)-1);
+    EOS_PARANOIA(input);
+    output[0] = '\0';
+    expanded = 0;
+    for (cp = input; cp < input+MAX_STRING_LEN; ) {
+        if ((cp2 = strstr(cp, "%{")) != NULL) {
+            if ((cp3 = strstr(cp2, "}")) != NULL) {
+                *cp2 = '\0';
+                strncpy(&output[strlen(output)], cp, sizeof(output)-strlen(output)-1);
+
+                cp2 += 2;
+                *cp3 = '\0';
+                strncpy(&output[strlen(output)], lookup_variable(r, cp2), sizeof(output)-strlen(output)-1);
+
+                cp = cp3+1;
+                expanded = 1;
+                continue;
+            }
+        }
+        strncpy(&output[strlen(output)], cp, sizeof(output)-strlen(output)-1);
+        EOS_PARANOIA(output);
+        break;
+    }
+    return expanded ? pstrdup(r->pool, output) : str;
+}
+
+static char *lookup_variable(request_rec *r, char *var)
+{
+    char *result;
+    char resultbuf[LONG_STRING_LEN];
+    time_t tc;
+    struct tm *tm;
+    request_rec *rsub;
+    struct passwd *pw;
+    struct group *gr;
+    struct stat finfo;
+
+    result = NULL;
+
+    /* HTTP headers */
+    if (strcasecmp(var, "HTTP_USER_AGENT") == 0) {
+        result = lookup_header(r, "User-Agent");
+    }
+    else if (strcasecmp(var, "HTTP_REFERER") == 0) {
+        result = lookup_header(r, "Referer");
+    }
+    else if (strcasecmp(var, "HTTP_COOKIE") == 0) {
+        result = lookup_header(r, "Cookie");
+    }
+    else if (strcasecmp(var, "HTTP_FORWARDED") == 0) {
+        result = lookup_header(r, "Forwarded");
+    }
+    else if (strcasecmp(var, "HTTP_HOST") == 0) {
+        result = lookup_header(r, "Host");
+    }
+    else if (strcasecmp(var, "HTTP_PROXY_CONNECTION") == 0) {
+        result = lookup_header(r, "Proxy-Connection");
+    }
+    else if (strcasecmp(var, "HTTP_ACCEPT") == 0) {
+        result = lookup_header(r, "Accept");
+    }
+    /* all other headers from which we are still not know about */
+    else if (strlen(var) > 5 && strncasecmp(var, "HTTP:", 5) == 0) {
+        result = lookup_header(r, var+5);
+    }
+
+    /* connection stuff */
+    else if (strcasecmp(var, "REMOTE_ADDR") == 0) {
+        result = r->connection->remote_ip;
+    }
+    else if (strcasecmp(var, "REMOTE_HOST") == 0) {
+        result = (char *)get_remote_host(r->connection, r->per_dir_config, REMOTE_NAME);
+    }
+    else if (strcasecmp(var, "REMOTE_USER") == 0) {
+        result = r->connection->user;
+    }
+    else if (strcasecmp(var, "REMOTE_IDENT") == 0) {
+        result = (char *)get_remote_logname(r);
+    }
+
+    /* request stuff */
+    else if (strcasecmp(var, "THE_REQUEST") == 0) { /* non-standard */
+        result = r->the_request;
+    }
+    else if (strcasecmp(var, "REQUEST_METHOD") == 0) {
+        result = r->method;
+    }
+    else if (strcasecmp(var, "REQUEST_URI") == 0) { /* non-standard */
+        result = r->uri;
+    }
+    else if (strcasecmp(var, "SCRIPT_FILENAME") == 0 ||
+             strcasecmp(var, "REQUEST_FILENAME") == 0  ) {
+        result = r->filename;
+    }
+    else if (strcasecmp(var, "PATH_INFO") == 0) {
+        result = r->path_info;
+    }
+    else if (strcasecmp(var, "QUERY_STRING") == 0) {
+        result = r->args;
+    }
+    else if (strcasecmp(var, "AUTH_TYPE") == 0) {
+        result = r->connection->auth_type;
+    }
+    else if (strcasecmp(var, "IS_SUBREQ") == 0) { /* non-standard */
+        result = (r->main != NULL ? "true" : "false");
+    }
+
+    /* internal server stuff */
+    else if (strcasecmp(var, "DOCUMENT_ROOT") == 0) {
+        result = document_root(r);
+    }
+    else if (strcasecmp(var, "SERVER_ADMIN") == 0) {
+        result = r->server->server_admin;
+    }
+    else if (strcasecmp(var, "SERVER_NAME") == 0) {
+        result = r->server->server_hostname;
+    }
+    else if (strcasecmp(var, "SERVER_PORT") == 0) {
+        ap_snprintf(resultbuf, sizeof(resultbuf), "%u", r->server->port);
+        result = resultbuf;
+    }
+    else if (strcasecmp(var, "SERVER_PROTOCOL") == 0) {
+        result = r->protocol;
+    }
+    else if (strcasecmp(var, "SERVER_SOFTWARE") == 0) {
+        result = pstrdup(r->pool, SERVER_VERSION);
+    }
+    else if (strcasecmp(var, "API_VERSION") == 0) { /* non-standard */
+        ap_snprintf(resultbuf, sizeof(resultbuf), "%d", MODULE_MAGIC_NUMBER);
+        result = resultbuf;
+    }
+
+    /* underlaying Unix system stuff */
+    else if (strcasecmp(var, "TIME_YEAR") == 0) {
+        tc = time(NULL); 
+        tm = localtime(&tc); 
+        ap_snprintf(resultbuf, sizeof(resultbuf), "%02d%02d", (tm->tm_year / 100) + 19, tm->tm_year % 100);
+        result = resultbuf;
+    }
+#define MKTIMESTR(format, tmfield) \
+    tc = time(NULL); \
+    tm = localtime(&tc); \
+    ap_snprintf(resultbuf, sizeof(resultbuf), format, tm->tmfield); \
+    result = resultbuf;
+    else if (strcasecmp(var, "TIME_MON") == 0) {
+        MKTIMESTR("%02d", tm_mon+1)
+    }
+    else if (strcasecmp(var, "TIME_DAY") == 0) {
+        MKTIMESTR("%02d", tm_mday)
+    }
+    else if (strcasecmp(var, "TIME_HOUR") == 0) {
+        MKTIMESTR("%02d", tm_hour)
+    }
+    else if (strcasecmp(var, "TIME_MIN") == 0) {
+        MKTIMESTR("%02d", tm_min)
+    }
+    else if (strcasecmp(var, "TIME_SEC") == 0) {
+        MKTIMESTR("%02d", tm_sec)
+    }
+    else if (strcasecmp(var, "TIME_WDAY") == 0) {
+        MKTIMESTR("%d", tm_wday)
+    }
+    else if (strcasecmp(var, "TIME") == 0) {
+        tc = time(NULL);
+        tm = localtime(&tc);
+        ap_snprintf(resultbuf, sizeof(resultbuf), "%02d%02d%02d%02d%02d%02d%02d",
+            (tm->tm_year / 100) + 19, (tm->tm_year % 100),
+            tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
+        result = resultbuf;
+        rewritelog(r, 1, "RESULT='%s'", result);
+    }
+
+    /* all other env-variables from the parent Apache process */
+    else if (strlen(var) > 4 && strncasecmp(var, "ENV:", 4) == 0) {
+        /* first try the internal Apache notes structure */
+        result = table_get(r->notes, var+4);
+        /* second try the internal Apache env structure  */
+        if (result == NULL) 
+            result = table_get(r->subprocess_env, var+4);
+        /* third try the external OS env */
+        if (result == NULL) 
+            result = getenv(var+4);
+    }
+
+#define LOOKAHEAD(subrecfunc) \
+        if ( \
+          /* filename is safe to use */ \
+          r->filename != NULL \
+              /* - and we're either not in a subrequest */ \
+              && ( r->main == NULL \
+                  /* - or in a subrequest where paths are non-NULL... */ \
+                    || ( r->main->uri != NULL && r->uri != NULL \
+                        /*   ...and sub and main paths differ */ \
+                        && strcmp(r->main->uri, r->uri) != 0))) { \
+            /* process a file-based subrequest */ \
+            rsub = subrecfunc(r->filename, r); \
+            /* now recursively lookup the variable in the sub_req */ \
+            result = lookup_variable(rsub, var+5); \
+            /* copy it up to our scope before we destroy the sub_req's pool */ \
+            result = pstrdup(r->pool, result); \
+            /* cleanup by destroying the subrequest */ \
+            destroy_sub_req(rsub); \
+            /* log it */ \
+            rewritelog(r, 5, "lookahead: path=%s var=%s -> val=%s", r->filename, var+5, result); \
+            /* return ourself to prevent re-pstrdup */ \
+            return result; \
+        }
+
+    /* look-ahead for parameter through URI-based sub-request */
+    else if (strlen(var) > 5 && strncasecmp(var, "LA-U:", 5) == 0) {
+        LOOKAHEAD(sub_req_lookup_uri)
+    }
+    /* look-ahead for parameter through file-based sub-request */
+    else if (strlen(var) > 5 && strncasecmp(var, "LA-F:", 5) == 0) {
+        LOOKAHEAD(sub_req_lookup_file)
+    }
+
+    /* file stuff */
+    else if (strcasecmp(var, "SCRIPT_USER") == 0) {
+        result = pstrdup(r->pool, "<unknown>");
+        if (r->finfo.st_mode != 0) {
+            if ((pw = getpwuid(r->finfo.st_uid)) != NULL) { 
+                result = pstrdup(r->pool, pw->pw_name);
+            }
+        }
+        else {
+            if (stat(r->filename, &finfo) == 0) {
+                if ((pw = getpwuid(finfo.st_uid)) != NULL) { 
+                    result = pstrdup(r->pool, pw->pw_name);
+                }
+            }
+        }
+    }
+    else if (strcasecmp(var, "SCRIPT_GROUP") == 0) {
+        result = pstrdup(r->pool, "<unknown>");
+        if (r->finfo.st_mode != 0) {
+            if ((gr = getgrgid(r->finfo.st_gid)) != NULL) { 
+                result = pstrdup(r->pool, gr->gr_name);
+            }
+        }
+        else {
+            if (stat(r->filename, &finfo) == 0) {
+                if ((gr = getgrgid(finfo.st_gid)) != NULL) { 
+                    result = pstrdup(r->pool, gr->gr_name);
+                }
+            }
+        }
+    }
+
+    if (result == NULL)
+        return pstrdup(r->pool, "");
+    else
+        return pstrdup(r->pool, result);
+}
+static char *lookup_header(request_rec *r, const char *name)
+{
+    array_header *hdrs_arr;
+    table_entry *hdrs;
+    int i;
+
+    hdrs_arr = table_elts(r->headers_in);
+    hdrs = (table_entry *)hdrs_arr->elts;
+    for (i = 0; i < hdrs_arr->nelts; ++i) {
+       if (hdrs[i].key == NULL)
+          continue;
+       if (strcasecmp(hdrs[i].key, name) == 0) 
+          return hdrs[i].val;
+    }
+    return NULL;
+}
+
+
+
+
+/*
+** +-------------------------------------------------------+
+** |                                                       |
+** |                    caching support
+** |                                                       |
+** +-------------------------------------------------------+
+*/
+
+
+static cache *init_cache(pool *p)
+{
+    cache *c;
+
+    c = (cache *)palloc(p, sizeof(cache));
+    c->pool = make_sub_pool(p);
+    c->lists = make_array(c->pool, 2, sizeof(cachelist));
+    return c;
+}
+
+static void set_cache_string(cache *c, char *res, int mode, time_t time, char *key, char *value)
+{
+    cacheentry ce;
+
+    ce.time  = time;
+    ce.key   = key;
+    ce.value = value;
+    store_cache_string(c, res, &ce);
+    return;
+}
+
+static char *get_cache_string(cache *c, char *res, int mode, time_t time, char *key)
+{
+    cacheentry *ce;
+
+    ce = retrieve_cache_string(c, res, key);
+    if (ce == NULL)
+        return NULL;
+    if (mode & CACHEMODE_TS) {
+        if (time != ce->time)
+            return NULL;
+    }
+    else if (mode & CACHEMODE_TTL) {
+        if (time > ce->time)
+            return NULL;
+    }
+    return pstrdup(c->pool, ce->value);
+}
+
+static void store_cache_string(cache *c, char *res, cacheentry *ce)
+{
+    int i;
+    int j;
+    cachelist *l;
+    cacheentry *e;
+    int found_list;
+
+    found_list = 0;
+    /* first try to edit an existing entry */
+    for (i = 0; i < c->lists->nelts; i++) {
+        l = &(((cachelist *)c->lists->elts)[i]);
+        if (strcmp(l->resource, res) == 0) {
+            found_list = 1;
+            for (j = 0; j < l->entries->nelts; j++) {
+                e = &(((cacheentry *)l->entries->elts)[j]);
+                if (strcmp(e->key, ce->key) == 0) {
+                    e->time  = ce->time;
+                    e->value = pstrdup(c->pool, ce->value);
+                    return;
+                }
+            }
+        }
+    }
+
+    /* create a needed new list */
+    if (!found_list) {
+        l = push_array(c->lists);
+        l->resource = pstrdup(c->pool, res);
+        l->entries  = make_array(c->pool, 2, sizeof(cacheentry));
+    }
+
+    /* create the new entry */
+    for (i = 0; i < c->lists->nelts; i++) {
+        l = &(((cachelist *)c->lists->elts)[i]);
+        if (strcmp(l->resource, res) == 0) {
+            e = push_array(l->entries);
+            e->time  = ce->time;
+            e->key   = pstrdup(c->pool, ce->key);
+            e->value = pstrdup(c->pool, ce->value);
+            return;
+        }
+    }
+
+    /* not reached, but when it is no problem... */
+    return;
+}
+
+static cacheentry *retrieve_cache_string(cache *c, char *res, char *key)
+{
+    int i;
+    int j;
+    cachelist *l;
+    cacheentry *e;
+
+    for (i = 0; i < c->lists->nelts; i++) {
+        l = &(((cachelist *)c->lists->elts)[i]);
+        if (strcmp(l->resource, res) == 0) {
+            for (j = 0; j < l->entries->nelts; j++) {
+                e = &(((cacheentry *)l->entries->elts)[j]);
+                if (strcmp(e->key, key) == 0) {
+                    return e;
+                }
+            }
+        }
+    }
+    return NULL;
+}
+
+
+
+
+/*
+** +-------------------------------------------------------+
+** |                                                       |
+** |                    misc functions
+** |                                                       |
+** +-------------------------------------------------------+
+*/
+
+static char *subst_prefix_path(request_rec *r, char *input, char *match, char *subst)
+{
+    char matchbuf[LONG_STRING_LEN];
+    char substbuf[LONG_STRING_LEN];
+    char *output;
+    int l;
+
+    output = input;
+
+    /* first create a match string which always has a trailing slash */
+    strncpy(matchbuf, match, sizeof(matchbuf)-1);
+    EOS_PARANOIA(matchbuf);
+    l = strlen(matchbuf);
+    if (matchbuf[l-1] != '/') {
+       matchbuf[l] = '/';
+       matchbuf[l+1] = '\0';
+       l++;
+    }
+    /* now compare the prefix */
+    if (strncmp(input, matchbuf, l) == 0) {
+        rewritelog(r, 5, "strip matching prefix: %s -> %s", output, output+l);
+        output = pstrdup(r->pool, output+l); 
+
+        /* and now add the base-URL as replacement prefix */
+        strncpy(substbuf, subst, sizeof(substbuf)-1);
+        EOS_PARANOIA(substbuf);
+        l = strlen(substbuf);
+        if (substbuf[l-1] != '/') {
+           substbuf[l] = '/';
+           substbuf[l+1] = '\0';
+           l++;
+        }
+        if (output[0] == '/') {
+            rewritelog(r, 4, "add subst prefix: %s -> %s%s", output, substbuf, output+1);
+            output = pstrcat(r->pool, substbuf, output+1, NULL);
+        }
+        else {
+            rewritelog(r, 4, "add subst prefix: %s -> %s%s", output, substbuf, output);
+            output = pstrcat(r->pool, substbuf, output, NULL);
+        }
+    }
+    return output;
+}
+
+
+/*
+**
+**  own command line parser which don't have the '\\' problem
+**
+*/
+
+static int parseargline(char *str, char **a1, char **a2, char **a3)
+{
+    char *cp;
+    int isquoted;
+
+#define SKIP_WHITESPACE(cp) \
+    for ( ; *cp == ' ' || *cp == '\t'; ) \
+        cp++;
+
+#define CHECK_QUOTATION(cp,isquoted) \
+    isquoted = 0; \
+    if (*cp == '"') { \
+        isquoted = 1; \
+        cp++; \
+    }
+
+#define DETERMINE_NEXTSTRING(cp,isquoted) \
+    for ( ; *cp != '\0'; cp++) { \
+        if (   (isquoted    && (*cp     == ' ' || *cp     == '\t')) \
+            || (*cp == '\\' && (*(cp+1) == ' ' || *(cp+1) == '\t'))) { \
+            cp++; \
+            continue; \
+        } \
+        if (   (!isquoted && (*cp == ' ' || *cp == '\t')) \
+            || (isquoted  && *cp == '"')                  ) \
+            break; \
+    } 
+
+    cp = str;
+    SKIP_WHITESPACE(cp);
+
+    /*  determine first argument */
+    CHECK_QUOTATION(cp, isquoted);
+    *a1 = cp;
+    DETERMINE_NEXTSTRING(cp, isquoted);
+    if (*cp == '\0')
+        return 1;
+    *cp++ = '\0';
+
+    SKIP_WHITESPACE(cp);
+
+    /*  determine second argument */
+    CHECK_QUOTATION(cp, isquoted);
+    *a2 = cp;
+    DETERMINE_NEXTSTRING(cp, isquoted);
+    if (*cp == '\0') {
+        *cp++ = '\0';
+        *a3 = NULL;
+        return 0;
+    }
+    *cp++ = '\0';
+
+    SKIP_WHITESPACE(cp);
+
+    /* again check if there are only two arguments */
+    if (*cp == '\0') {
+        *cp++ = '\0';
+        *a3 = NULL;
+        return 0;
+    }
+
+    /*  determine second argument */
+    CHECK_QUOTATION(cp, isquoted);
+    *a3 = cp;
+    DETERMINE_NEXTSTRING(cp, isquoted);
+    *cp++ = '\0';
+
+    return 0;
+}
+
+
+static void add_env_variable(request_rec *r, char *s)
+{
+    char var[MAX_STRING_LEN];
+    char val[MAX_STRING_LEN];
+    char *cp;
+    int n;
+
+    if ((cp = strchr(s, ':')) != NULL) {
+        n = ((cp-s) > MAX_STRING_LEN-1 ? MAX_STRING_LEN-1 : (cp-s));
+        memcpy(var, s, n);
+        var[n] = '\0';
+        strncpy(val, cp+1, sizeof(val)-1);
+        EOS_PARANOIA(val);
+        table_set(r->subprocess_env, pstrdup(r->pool, var), pstrdup(r->pool, val));
+        rewritelog(r, 5, "setting env variable '%s' to '%s'", var, val);
+    }
+}
+
+
+
+/*
+**
+**  stat() for only the prefix of a path
+**
+*/
+
+static int prefix_stat(const char *path, struct stat *sb)
+{
+    char curpath[LONG_STRING_LEN];
+    char *cp;
+
+    strncpy(curpath, path, sizeof(curpath)-1);
+    EOS_PARANOIA(curpath);
+    if (curpath[0] != '/') 
+        return 0;
+    if ((cp = strchr(curpath+1, '/')) != NULL)
+        *cp = '\0';
+    if (stat(curpath, sb) == 0)
+        return 1;
+    else
+        return 0;
+}
+
+
+/*
+**
+**  special DNS lookup functions
+**
+*/
+
+static int is_this_our_host(request_rec *r, char *testhost)
+{
+    char **cppHNLour;
+    char **cppHNLtest;
+    char *ourhostname;
+    char *ourhostip;
+    const char *names;
+    char *name;
+    int i, j;
+    server_addr_rec *sar;
+
+    /* we can check:
+       r->
+            char *hostname            Host, as set by full URI or Host: 
+            int hostlen               Length of http://host:port in full URI 
+       r->server->
+            int is_virtual            0=main, 1=ip-virtual, 2=non-ip-virtual
+            char *server_hostname     used on compare to r->hostname
+            inet_ntoa(r->connection->local_addr.sin_addr)
+                                      used on compare to r->hostname
+            unsigned short port       for redirects
+            char *path                name of ServerPath
+            int pathlen               len of ServerPath
+            char *names               Wildcarded names for ServerAlias servers 
+       r->server->addrs->
+            struct in_addr host_addr  The bound address, for this server
+            short host_port           The bound port, for this server 
+            char *virthost            The name given in <VirtualHost> 
+    */
+
+    ourhostname = r->server->server_hostname;
+    ourhostip   = inet_ntoa(r->connection->local_addr.sin_addr);
+
+    /* just a simple common case */
+    if (strcmp(testhost, ourhostname) == 0 ||
+        strcmp(testhost, ourhostip)   == 0   )
+       return YES;
+
+    /* now the complicated cases */
+    if (!r->server->is_virtual) {
+        /* main servers */
+
+        /* check for the alternative IP addresses */
+        if ((cppHNLour = resolv_ipaddr_list(r, ourhostname)) == NULL)
+            return NO;
+        if ((cppHNLtest = resolv_ipaddr_list(r, testhost)) == NULL)
+            return NO;
+        for (i = 0; cppHNLtest[i] != NULL; i++) {
+            for (j = 0; cppHNLour[j] != NULL; j++) {
+                if (strcmp(cppHNLtest[i], cppHNLour[j]) == 0) {
+                    return YES;
+                }
+            }
+        }
+    }
+    else if (r->server->is_virtual) {
+        /* virtual servers */
+
+        /* check for the names supplied in the VirtualHost directive */
+        for(sar = r->server->addrs; sar != NULL; sar = sar->next) {
+            if(strcasecmp(sar->virthost, testhost) == 0)
+                return YES;
+        }
+
+        /* check for the virtual-server aliases */
+        if (r->server->names != NULL && r->server->names[0] != '\0') {
+            names = r->server->names;
+            while (*names != '\0') {
+                name = getword_conf(r->pool, &names);
+                if ((is_matchexp(name) && !strcasecmp_match(testhost, name)) ||
+                    (strcasecmp(testhost, name) == 0)                          ) {
+                    return YES;
+                }
+            }
+        }
+    }
+    return NO;
+}
+
+static int isaddr(char *host)
+{
+    char *cp;
+
+    /* Null pointers and empty strings 
+       are not addresses. */
+    if (host == NULL)
+        return NO;
+    if (*host == '\0')
+        return NO;
+    /* Make sure it has only digits and dots. */
+    for (cp = host; *cp; cp++) {
+        if (!isdigit(*cp) && *cp != '.')
+            return NO;
+    }
+    /* If it has a trailing dot, 
+       don't treat it as an address. */
+    if (*(cp-1) == '.')
+       return NO;
+    return YES;
+}
+
+static char **resolv_ipaddr_list(request_rec *r, char *name)
+{
+    char **cppHNL;
+    struct hostent *hep;
+    int i;
+
+    if (isaddr(name)) 
+        hep = gethostbyaddr(name, sizeof(struct in_addr), AF_INET);
+    else
+        hep = gethostbyname(name);
+    if (hep == NULL)
+        return NULL;
+    for (i = 0; hep->h_addr_list[i]; i++)
+        ;
+    cppHNL = (char **)palloc(r->pool, sizeof(char *)*(i+1));
+    for (i = 0; hep->h_addr_list[i]; i++)
+        cppHNL[i] = pstrdup(r->pool, inet_ntoa(*((struct in_addr *)(hep->h_addr_list[i]))) );
+    cppHNL[i] = NULL;
+    return cppHNL;
+}
+
+
+/*
+**
+**  check if proxy module is available
+**  i.e. if it is compiled in and turned on
+**
+*/
+
+static int is_proxy_available(server_rec *s)
+{
+    extern module *preloaded_modules[];
+    command_rec *c;
+    int n;
+    
+    for (n = 0; preloaded_modules[n] != NULL; n++) {
+        for (c = preloaded_modules[n]->cmds; c && c->name; ++c) {
+            if (strcmp(c->name, "ProxyRequests") == 0) {
+                return 1;
+            }
+        }
+    }
+    return 0;
+}
+
+
+/*
+**
+**  File locking
+**
+*/
+
+#ifdef USE_FCNTL
+static struct flock   lock_it;
+static struct flock unlock_it;
+#endif 
+
+static void fd_lock(int fd)
+{
+    int rc;
+
+#ifdef USE_FCNTL
+    lock_it.l_whence = SEEK_SET; /* from current point */
+    lock_it.l_start  = 0;        /* -"- */
+    lock_it.l_len    = 0;        /* until end of file */
+    lock_it.l_type   = F_WRLCK;  /* set exclusive/write lock */
+    lock_it.l_pid    = 0;        /* pid not actually interesting */
+
+    while (   ((rc = fcntl(fd, F_SETLKW, &lock_it)) < 0) 
+           && (errno == EINTR)                               )
+        continue;
+#endif
+#ifdef USE_FLOCK
+    while (   ((rc = flock(fd, LOCK_EX)) < 0) 
+           && (errno == EINTR)               )
+        continue;
+#endif
+
+    if (rc < 0) {
+#ifdef USE_FLOCK
+        perror("flock");
+#else
+        perror("fcntl");
+#endif
+        fprintf(stderr, "Error getting lock. Exiting!");
+        exit(1);
+    }
+    return;
+}
+
+static void fd_unlock(int fd)
+{
+    int rc;
+
+#ifdef USE_FCNTL 
+    unlock_it.l_whence = SEEK_SET; /* from current point */
+    unlock_it.l_start  = 0;        /* -"- */
+    unlock_it.l_len    = 0;        /* until end of file */
+    unlock_it.l_type   = F_UNLCK;  /* unlock */
+    unlock_it.l_pid    = 0;        /* pid not actually interesting */
+
+    rc = fcntl(fd, F_SETLKW, &unlock_it);
+#endif
+#ifdef USE_FLOCK 
+    rc = flock(fd, LOCK_UN);
+#endif 
+
+    if (rc < 0) {
+#ifdef USE_FLOCK
+        perror("flock");
+#else
+        perror("fcntl");
+#endif
+        fprintf(stderr, "Error freeing lock. Exiting!");
+        exit(1);
+    }
+}
+
+/*
+**
+**  Lexicographic Compare
+**
+*/
+
+int compare_lexicography(char *cpNum1, char *cpNum2)
+{
+    int i;
+    int n1, n2;
+
+    n1 = strlen(cpNum1);
+    n2 = strlen(cpNum2);
+    if (n1 > n2)
+        return 1;
+    if (n1 < n2)
+        return -1;
+    for (i = 0; i < n1; i++) {
+        if (cpNum1[i] > cpNum2[i])
+            return 1;
+        if (cpNum1[i] < cpNum2[i])
+            return -1;
+    }
+    return 0;
+}
+
+
+/*EOF*/
diff --git a/APACHE_1_2_X/src/modules/standard/mod_rewrite.h b/APACHE_1_2_X/src/modules/standard/mod_rewrite.h
new file mode 100644 (file)
index 0000000..c8bec8b
--- /dev/null
@@ -0,0 +1,396 @@
+
+/* ====================================================================
+ * Copyright (c) 1996,1997 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/>.
+ *
+ */
+
+
+#ifndef _MOD_REWRITE_H
+#define _MOD_REWRITE_H 1
+
+/*
+**  mod_rewrite.h -- Common Header File
+**                       _                            _ _ 
+**   _ __ ___   ___   __| |    _ __ _____      ___ __(_) |_ ___ 
+**  | '_ ` _ \ / _ \ / _` |   | '__/ _ \ \ /\ / / '__| | __/ _ \
+**  | | | | | | (_) | (_| |   | | |  __/\ V  V /| |  | | ||  __/
+**  |_| |_| |_|\___/ \__,_|___|_|  \___| \_/\_/ |_|  |_|\__\___|
+**                       |_____|
+**
+**  URL Rewriting Module, Version 3.0.5 (16-Apr-1997)
+**
+**  This module uses a rule-based rewriting engine (based on a
+**  regular-expression parser) to rewrite requested URLs on the fly. 
+**  
+**  It supports an unlimited number of additional rule conditions (which can
+**  operate on a lot of variables, even on HTTP headers) for granular
+**  matching and even external database lookups (either via plain text
+**  tables, DBM hash files or even external processes) for advanced URL
+**  substitution.
+**  
+**  It operates on the full URLs (including the PATH_INFO part) both in
+**  per-server context (httpd.conf) and per-dir context (.htaccess) and even
+**  can generate QUERY_STRING parts on result.   The rewriting result finally
+**  can lead to internal subprocessing, external request redirection or even
+**  to internal proxy throughput.
+**
+**  The documentation and latest release can be found on
+**  http://www.engelschall.com/sw/mod_rewrite/
+**
+**  Copyright (c) 1996-1997 Ralf S. Engelschall, All rights reserved.
+**
+**  Written for The Apache Group by
+**      Ralf S. Engelschall
+**      rse@engelschall.com
+**      www.engelschall.com
+*/
+
+
+
+
+    /* The NDBM support:
+       We support only NDBM files. 
+       But we have to stat the file for the mtime,
+       so we also need to know the file extension */
+#if HAS_NDBM_LIB
+#include <ndbm.h>
+#if (__FreeBSD__)
+#define NDBM_FILE_SUFFIX ".db"
+#else 
+#define NDBM_FILE_SUFFIX ".pag"
+#endif
+#endif
+
+
+    /* The locking support:
+       Try to determine whether we should use fcntl() or flock().
+       Would be better conf.h could provide this... :-( */
+#if defined(USE_FCNTL_SERIALIZED_ACCEPT)
+#define USE_FCNTL 1
+#include <fcntl.h>
+#endif
+#if defined(USE_FLOCK_SERIALIZED_ACCEPT)
+#define USE_FLOCK 1
+#include <sys/file.h>
+#endif
+#if !defined(USE_FCNTL) && !defined(USE_FLOCK)
+#define USE_FLOCK 1
+#ifndef MPE
+#include <sys/file.h>
+#endif
+#ifndef LOCK_UN
+#undef USE_FLOCK
+#define USE_FCNTL 1
+#include <fcntl.h>
+#endif
+#endif
+#ifdef AIX
+#undef USE_FLOCK
+#define USE_FCNTL 1
+#include <fcntl.h>
+#endif
+
+
+
+
+/*
+**
+**  Some defines
+**
+*/
+
+#define ENVVAR_SCRIPT_URL "SCRIPT_URL"
+#define ENVVAR_SCRIPT_URI "SCRIPT_URI"
+
+#ifndef SUPPORT_DBM_REWRITEMAP
+#define SUPPORT_DBM_REWRITEMAP 0
+#endif
+
+#define REWRITE_FORCED_MIMETYPE_NOTEVAR "rewrite-forced-mimetype"
+
+#define CONDFLAG_NONE               1<<0
+#define CONDFLAG_NOCASE             1<<1
+#define CONDFLAG_NOTMATCH           1<<2
+#define CONDFLAG_ORNEXT             1<<3
+
+#define RULEFLAG_NONE               1<<0
+#define RULEFLAG_FORCEREDIRECT      1<<1
+#define RULEFLAG_LASTRULE           1<<2
+#define RULEFLAG_NEWROUND           1<<3
+#define RULEFLAG_CHAIN              1<<4
+#define RULEFLAG_IGNOREONSUBREQ     1<<5
+#define RULEFLAG_NOTMATCH           1<<6
+#define RULEFLAG_PROXY              1<<7
+#define RULEFLAG_PASSTHROUGH        1<<8
+#define RULEFLAG_FORBIDDEN          1<<9
+#define RULEFLAG_GONE               1<<10
+
+#define MAPTYPE_TXT                 1<<0
+#define MAPTYPE_DBM                 1<<1
+#define MAPTYPE_PRG                 1<<2
+
+#define ENGINE_DISABLED             1<<0
+#define ENGINE_ENABLED              1<<1
+
+#define OPTION_NONE                 1<<0
+#define OPTION_INHERIT              1<<1
+
+#define CACHEMODE_TS                1<<0
+#define CACHEMODE_TTL               1<<1
+
+#ifndef FALSE
+#define FALSE 0
+#define TRUE  !FALSE
+#endif
+
+#ifndef NO
+#define NO    FALSE
+#define YES   TRUE
+#endif
+
+#ifndef LONG_STRING_LEN
+#define LONG_STRING_LEN 2048
+#endif
+
+#define MAX_ENV_FLAGS 5
+
+#define EOS_PARANOIA(ca) ca[sizeof(ca)-1] = '\0'
+
+
+/*
+**
+**  our private data structures we handle with
+**
+*/
+
+    /* the list structures for holding the mapfile information
+       and the rewrite rules */
+
+typedef struct {
+    char *name;                    /* the name of the map */
+    char *datafile;                /* the file which contains the data of the map */
+    char *checkfile;               /* the file which stays for existence of the map */
+    int   type;                    /* the type of the map */
+    int   fpin;                    /* in  filepointer for program maps */
+    int   fpout;                   /* out filepointer for program maps */
+} rewritemap_entry;
+
+typedef struct {
+    char    *input;                /* Input string of RewriteCond */
+    char    *pattern;              /* the RegExp pattern string */
+    regex_t *regexp;
+    int      flags;                /* Flags which control the match */
+} rewritecond_entry;
+
+typedef struct {
+    array_header *rewriteconds;    /* the corresponding RewriteCond entries */
+    char         *pattern;         /* the RegExp pattern string */
+    regex_t      *regexp;          /* the RegExp pattern compilation */
+    char         *output;              /* the Substitution string */
+    int           flags;               /* Flags which control the substitution */
+    char         *forced_mimetype;     /* forced MIME type of substitution */
+    int           forced_responsecode; /* forced HTTP redirect response status */
+    char         *env[MAX_ENV_FLAGS+1];/* added environment variables */
+    int           skip;                /* number of next rules to skip */
+} rewriterule_entry;
+
+
+    /* the per-server or per-virtual-server configuration
+       statically generated once on startup for every server */
+
+typedef struct {
+    int           state;           /* the RewriteEngine state */
+    int           options;         /* the RewriteOption state */
+    char         *rewritelogfile;  /* the RewriteLog filename */
+    int           rewritelogfp;    /* the RewriteLog open filepointer */
+    int           rewriteloglevel; /* the RewriteLog level of verbosity */
+    array_header *rewritemaps;     /* the RewriteMap entries */
+    array_header *rewriteconds;    /* the RewriteCond entries (temporary) */
+    array_header *rewriterules;    /* the RewriteRule entries */
+} rewrite_server_conf;
+
+
+    /* the per-directory configuration
+       individually generated on-the-fly by Apache server for current request */
+
+typedef struct {
+    int           state;           /* the RewriteEngine state */
+    int           options;         /* the RewriteOption state */
+    array_header *rewriteconds;    /* the RewriteCond entries (temporary) */
+    array_header *rewriterules;    /* the RewriteRule entries */
+    char         *directory;       /* the directory where it applies */
+    char         *baseurl;         /* the base-URL  where it applies */
+} rewrite_perdir_conf;
+
+
+    /* the cache structures */
+
+typedef struct cacheentry {
+    time_t time;
+    char  *key;
+    char  *value;
+} cacheentry;
+
+typedef struct cachelist {
+    char         *resource;
+    array_header *entries;
+} cachelist;
+
+typedef struct cache {
+    pool         *pool;
+    array_header *lists;
+} cache;
+
+
+/*
+**
+**  forward declarations
+**
+*/
+
+    /* config structure handling */
+static void *config_server_create(pool *p, server_rec *s);
+static void *config_server_merge (pool *p, void *basev, void *overridesv);
+static void *config_perdir_create(pool *p, char *path);
+static void *config_perdir_merge (pool *p, void *basev, void *overridesv);
+
+    /* config directive handling */
+static const char *cmd_rewriteengine  (cmd_parms *cmd, rewrite_perdir_conf *dconf, int flag);
+static const char *cmd_rewriteoptions (cmd_parms *cmd, rewrite_perdir_conf *dconf, char *option);
+static const char *cmd_rewriteoptions_setoption(pool *p, int *options, char *name);
+static const char *cmd_rewritelog     (cmd_parms *cmd, void *dconf, char *a1);
+static const char *cmd_rewriteloglevel(cmd_parms *cmd, void *dconf, char *a1);
+static const char *cmd_rewritemap     (cmd_parms *cmd, void *dconf, char *a1, char *a2);
+
+static const char *cmd_rewritebase(cmd_parms *cmd, rewrite_perdir_conf *dconf, char *a1);
+
+static const char *cmd_rewritecond    (cmd_parms *cmd, rewrite_perdir_conf *dconf, char *str);
+static const char *cmd_rewritecond_parseflagfield(pool *p, rewritecond_entry *new, char *str);
+static const char *cmd_rewritecond_setflag       (pool *p, rewritecond_entry *cfg, char *key, char *val);
+
+extern const char *cmd_rewriterule    (cmd_parms *cmd, rewrite_perdir_conf *dconf, char *str);
+static const char *cmd_rewriterule_parseflagfield(pool *p, rewriterule_entry *new, char *str);
+static const char *cmd_rewriterule_setflag       (pool *p, rewriterule_entry *cfg, char *key, char *val);
+
+    /* initialisation */
+static void init_module(server_rec *s, pool *p);
+
+    /* runtime hooks */
+static int hook_uri2file   (request_rec *r);
+static int hook_mimetype   (request_rec *r);
+static int hook_fixup      (request_rec *r);
+static int handler_redirect(request_rec *r);
+
+    /* rewriting engine */
+static int apply_rewrite_list(request_rec *r, array_header *rewriterules, char *perdir);
+static int apply_rewrite_rule(request_rec *r, rewriterule_entry *p, char *perdir); 
+static int apply_rewrite_cond(request_rec *r, rewritecond_entry *p, char *perdir); 
+
+    /* URI transformation function */
+static void  splitout_queryargs(request_rec *r);
+static void  reduce_uri(request_rec *r);
+static char *expand_tildepaths(request_rec *r, char *uri);
+static void  expand_map_lookups(request_rec *r, char *uri, int uri_len);
+
+    /* DBM hashfile support functions */
+static char *lookup_map(request_rec *r, char *name, char *key);
+static char *lookup_map_txtfile(request_rec *r, char *file, char *key);
+#if HAS_NDBM_LIB
+static char *lookup_map_dbmfile(request_rec *r, char *file, char *key);
+#endif
+static char *lookup_map_program(request_rec *r, int fpin, int fpout, char *key);
+
+    /* rewriting logfile support */
+static void  open_rewritelog(server_rec *s, pool *p);
+static void  rewritelog_child(void *cmd);
+static void  rewritelog(request_rec *r, int level, const char *text, ...);
+static char *current_logtime(request_rec *r);
+
+    /* program map support */
+static void  run_rewritemap_programs(server_rec *s, pool *p);
+static void  rewritemap_program_child(void *cmd);
+
+    /* env variable support */
+static void  expand_variables_inbuffer(request_rec *r, char *buf, int buf_len);
+static char *expand_variables(request_rec *r, char *str);
+static char *lookup_variable(request_rec *r, char *var);
+static char *lookup_header(request_rec *r, const char *name);
+
+    /* caching functions */
+static cache      *init_cache(pool *p);
+static char       *get_cache_string(cache *c, char *res, int mode, time_t mtime, char *key);
+static void        set_cache_string(cache *c, char *res, int mode, time_t mtime, char *key, char *value);
+static cacheentry *retrieve_cache_string(cache *c, char *res, char *key);
+static void        store_cache_string(cache *c, char *res, cacheentry *ce);
+
+    /* misc functions */
+static char  *subst_prefix_path(request_rec *r, char *input, char *match, char *subst);
+static int    parseargline(char *str, char **a1, char **a2, char **a3);
+static int    prefix_stat(const char *path, struct stat *sb);
+static void   add_env_variable(request_rec *r, char *s);
+
+    /* DNS functions */
+static int    is_this_our_host(request_rec *r, char *testhost);
+static int    isaddr(char *host);
+static char **resolv_ipaddr_list(request_rec *r, char *name);
+
+    /* Proxy Module check */
+static int is_proxy_available(server_rec *s);
+
+    /* File locking */
+static void fd_lock(int fd);
+static void fd_unlock(int fd);
+
+    /* Lexicographic Comparison */
+int compare_lexicography(char *cpNum1, char *cpNum2);
+
+#endif /* _MOD_REWRITE_H */
+
+/*EOF*/
diff --git a/APACHE_1_2_X/src/modules/standard/mod_status.c b/APACHE_1_2_X/src/modules/standard/mod_status.c
new file mode 100644 (file)
index 0000000..da0073a
--- /dev/null
@@ -0,0 +1,636 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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.  Display lots of internal data about how Apache is
+ * performing and the state of all children processes.
+ *
+ * To enable this, add the following lines into any config file:
+ *
+ * <Location /server-status>
+ * SetHandler server-status
+ * </Location>
+ *
+ * You may want to protect this location by password or domain so no one
+ * else can look at it.  Then you can access the statistics with a URL like:
+ *
+ * http://your_server_name/server-status
+ *
+ * /server-status - Returns page using tables
+ * /server-status?notable - Returns page for browsers without table support
+ * /server-status?refresh - Returns page with 1 second refresh
+ * /server-status?refresh=6 - Returns page with refresh every 6 seconds
+ * /server-status?auto - Returns page with data for automatic parsing
+ *
+ * Mark Cox, mark@ukweb.com, November 1995
+ *
+ * 12.11.95 Initial version for www.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         64
+
+#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 format_kbyte_out(request_rec *r,unsigned long kbytes)
+{
+    if (kbytes < KBYTE)
+       rprintf(r,"%d kB",(int)kbytes);
+    else if (kbytes < MBYTE)
+       rprintf(r,"%.1f MB",(float)kbytes/KBYTE);
+    else
+       rprintf(r,"%.1f GB",(float)kbytes/MBYTE);
+}
+
+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;
+    unsigned long kbcount=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';
+    status[SERVER_GRACEFUL]='G';
+
+    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++;
+        }
+    }
+
+    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 ||
+                res == SERVER_GRACEFUL)
+           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;
+           if (bcount>=KBYTE) {
+               kbcount += (bcount >> 10);
+               bcount = bcount & 0x3ff;
+           }
+       }
+#endif /* STATUS */
+    }
+
+    up_time=nowtime-restart_time;
+
+    hard_timeout("send status info", r);
+
+    if (!short_report)
+    {
+        rputs("<HTML><HEAD>\n<TITLE>Apache Status</TITLE>\n</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 kBytes: %lu\n",count,kbcount);
+
+#ifndef __EMX__
+    /* Allow for OS/2 not having CPU stats */
+       if(ts || tu || tcu || tcs)
+           rprintf(r,"CPULoad: %g\n",(tu+ts+tcu+tcs)/tick/up_time*100.);
+#endif
+
+       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",KBYTE*(float)kbcount/(float)up_time);
+
+       if (count>0)
+           rprintf(r,"BytesPerReq: %g\n",KBYTE*(float)kbcount/(float)count);
+    } else /* !short_report */
+    {
+       rprintf(r,"Total accesses: %lu - Total Traffic: ", count);
+       format_kbyte_out(r,kbcount);
+
+#ifndef __EMX__
+       /* Allow for OS/2 not having CPU stats */
+       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.);
+#endif
+
+       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,KBYTE*(float)kbcount/(float)up_time);
+           rputs("/second - ",r);
+       }
+
+       if (count>0)
+       {
+           format_byte_out(r,KBYTE*(float)kbcount/(float)count);
+           rputs("/request",r);
+       }
+
+       rputs("<br>\n",r);
+    } /* short_report */
+#endif /* STATUS */
+
+    if (!short_report)
+        rprintf(r,"\n%d requests currently being processed, %d idle servers\n"
+               ,busy,ready);
+    else
+        rprintf(r,"BusyServers: %d\nIdleServers: %d\n",busy,ready);
+
+    /* send the scoreboard 'table' out */
+
+    if(!short_report)
+       rputs("<PRE>",r);
+    else
+        rputs("Scoreboard: ",r);
+
+    for (i = 0; i<HARD_SERVER_LIMIT; ++i)
+    {
+       rputc(stat_buffer[i], r);
+       if((i%STATUS_MAXLINE == (STATUS_MAXLINE - 1))&&!short_report)
+           rputs("\n",r);
+    }
+
+    if (short_report)
+        rputs("\n",r);
+    else {
+       rputs("</PRE>\n",r);
+       rputs("Scoreboard Key: <br>\n",r);
+       rputs("\"<B><code>_</code></B>\" Waiting for Connection, \n",r);
+       rputs("\"<B><code>S</code></B>\" Starting up, \n",r);
+       rputs("\"<B><code>R</code></B>\" Reading Request,<BR>\n",r);
+       rputs("\"<B><code>W</code></B>\" Sending Reply, \n",r);
+       rputs("\"<B><code>K</code></B>\" Keepalive (read), \n",r);
+       rputs("\"<B><code>D</code></B>\" DNS Lookup,<BR>\n",r);
+       rputs("\"<B><code>L</code></B>\" Logging, \n",r);
+       rputs("\"<B><code>G</code></B>\" Gracefully finishing, \n",r);
+       rputs("\"<B><code>.</code></B>\" Open slot with no current process<P>\n",r);
+    }
+
+#if defined(STATUS)
+    if (!short_report)
+       if(no_table_report)
+            rputs("<p><hr><h2>Server Details</h2>\n\n",r);
+       else
+#ifdef __EMX__
+            /* Allow for OS/2 not having CPU stats */
+            rputs("<p>\n\n<table border=0><tr><th>Srv<th>PID<th>Acc<th>M\n<th>SS<th>Conn<th>Child<th>Slot<th>Host<th>VHost<th>Request</tr>\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>VHost<th>Request</tr>\n\n",r);
+#endif
+
+
+    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;
+                       case SERVER_GRACEFUL:
+                           rputs("Graceful",r);
+                           break;
+                       default:
+                           rputs("?STATE?",r);
+                           break;
+                   }
+#ifdef __EMX__
+                    /* Allow for OS/2 not having CPU stats */
+                    rprintf(r,"]\n %s (",
+#else
+
+                   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,
+#endif
+                           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,
+                           escape_html(r->pool, 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;
+                       case SERVER_GRACEFUL:
+                           rputs("<td>G",r);
+                           break;
+                       default:
+                           rputs("<td>?",r);
+                           break;
+                   }
+#ifdef __EMX__
+                   /* Allow for OS/2 not having CPU stats */
+                   rprintf(r,"\n<td>%.0f",
+#else
+                   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,
+#endif
+                           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<td nowrap>%s</tr>\n\n",
+                           score_record.client, score_record.vhost,
+                           escape_html(r->pool, score_record.request));
+               }       /* no_table_report */
+           }           /* !short_report */
+       }               /* if (<active child>) */
+    }                  /* for () */
+
+    if (!(short_report || no_table_report))
+    {
+#ifdef __EMX__
+       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>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
+       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);
+#endif
+    }
+
+#else /* !defined(STATUS) */
+
+    rputs("<hr>To obtain a full report with current status information and",r);
+    rputs(" DNS and LOGGING status codes \n",r);
+    rputs("you need to recompile Apache after adding the line <pre>",r);
+    rputs("Rule STATUS=yes</pre>into the file <code>Configuration</code>\n",r);
+
+#endif /* STATUS */
+
+    if (!short_report)
+        rputs("</BODY></HTML>\n",r);
+
+    kill_timeout(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 */
+   NULL                                /* header parser */
+};
diff --git a/APACHE_1_2_X/src/modules/standard/mod_userdir.c b/APACHE_1_2_X/src/modules/standard/mod_userdir.c
new file mode 100644 (file)
index 0000000..d3edf65
--- /dev/null
@@ -0,0 +1,211 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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; 
+}
+
+const 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;
+    const char *userdirs = (char *)get_module_config(server_conf,
+                                                    &userdir_module);
+    char *name = r->uri;
+    const char *w, *dname, *redirect;
+    char *x = NULL;
+
+    if (userdirs == NULL || !strcasecmp(userdirs, "disabled") ||
+        (name[0] != '/') || (name[1] != '~')) {
+      return DECLINED;
+    }
+
+    while (*userdirs) {
+      const 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, '*');
+
+#ifdef __EMX__
+      /* Add support for OS/2 drive letters */
+      if ((userdir[0] == '/') || (userdir[1] == ':') || (userdir[0] == '\0')) {
+#else
+      if ((userdir[0] == '/') || (userdir[0] == '\0')) {
+#endif
+       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 */
+   NULL                                /* header parser */
+};
diff --git a/APACHE_1_2_X/src/modules/standard/mod_usertrack.c b/APACHE_1_2_X/src/modules/standard/mod_usertrack.c
new file mode 100644 (file)
index 0000000..a205aa5
--- /dev/null
@@ -0,0 +1,326 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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 (Was mod_cookies.c)
+ *
+ * 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.
+ *
+ * By matching up all the requests with the same cookie you can
+ * work out exactly what path a user took through your site.  To log
+ * the cookie use the " %{Cookie}n " directive in a custom access log;
+ *
+ * Example 1 : If you currently use the standard Log file format (CLF)
+ * and use the command "TransferLog somefilename", add the line
+ *       LogFormat "%h %l %u %t \"%r\" %s %b %{Cookie}n" 
+ * to your config file.
+ *
+ * Example 2 : If you used to use the old "CookieLog" directive, you
+ * can emulate it by adding the following command to your config file
+ *       CustomLog filename "%{Cookie}n \"%r\" %t"
+ *
+ * Notes:
+ * 1.  This code now logs the initial transaction (the one that created
+ *     the cookie to start with).  
+ * 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, 6 July 95
+ *
+ * This file replaces mod_cookies.c
+ */
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_core.h"
+#include <sys/time.h>
+
+module usertrack_module;
+
+typedef struct {
+    int always;
+    time_t expires;
+} cookie_log_state;
+
+/* Define this to allow post-2000 cookies. Cookies use two-digit dates,
+ * so it might be dicey. (Netscape does it correctly, but others may not)
+ */
+#define MILLENIAL_COOKIES
+
+/* 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)
+{
+    cookie_log_state *cls = get_module_config (r->server->module_config,
+                                              &usertrack_module);
+#ifdef MPE
+    clock_t mpe_times;
+    struct tms mpe_tms;
+#else
+    struct timeval tv;
+    struct timezone tz = { 0 , 0 };
+#endif
+    /* 1024 == hardcoded constants */
+    char *new_cookie = palloc( r->pool, 1024); 
+    char *cookiebuf = palloc( r->pool, 1024);
+    char *dot;
+    const char *rname = pstrdup(r->pool, 
+                           get_remote_host(r->connection, r->per_dir_config,
+                                               REMOTE_NAME));
+
+    if ((dot = strchr(rname,'.'))) *dot='\0';  /* First bit of hostname */
+
+#ifdef MPE
+/* MPE lacks gettimeofday(), so we must use time() to obtain the epoch
+   seconds, and then times() to obtain CPU clock ticks (milliseconds).
+   Combine this together to obtain a hopefully unique cookie ID. */
+
+    mpe_times=times(&mpe_tms);
+
+    ap_snprintf(cookiebuf, 1024, "%s%d%ld%ld", rname, (int)getpid(),
+              (long)time(NULL), (long)mpe_tms.tms_utime);
+#else
+    gettimeofday(&tv, &tz);
+
+    ap_snprintf(cookiebuf, 1024, "%s%d%ld%d", rname, (int)getpid(),
+             (long)tv.tv_sec, (int)tv.tv_usec/1000);       
+#endif
+
+    if (cls->expires) {
+      static const char *const days[7]=
+          {"Sun","Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
+      struct tm *tms;
+      time_t when = time(NULL) + cls->expires;
+
+#ifndef MILLENIAL_COOKIES      
+      /* Only two-digit date string, so we can't trust "00" or more.
+       * Therefore, we knock it all back to just before midnight on
+       * 1/1/2000 (which is 946684799)
+       */
+
+      if (when > 946684799)
+       when = 946684799;
+#endif
+      tms = gmtime(&when);
+
+      /* Cookie with date; as strftime '%a, %d-%h-%y %H:%M:%S GMT' */
+      ap_snprintf(new_cookie, 1024,
+          "%s%s; path=/; expires=%s, %.2d-%s-%.2d %.2d:%.2d:%.2d GMT",
+             COOKIE_NAME, cookiebuf, days[tms->tm_wday],
+             tms->tm_mday, month_snames[tms->tm_mon],
+             (tms->tm_year >= 100) ? tms->tm_year - 100 : tms->tm_year,
+             tms->tm_hour, tms->tm_min, tms->tm_sec);
+    }
+    else
+      ap_snprintf(new_cookie, 1024, "%s%s; path=/", COOKIE_NAME, cookiebuf);
+
+    table_set(r->headers_out,"Set-Cookie",new_cookie);
+    table_set(r->notes, "cookie", cookiebuf); /* log first time */
+    return;
+}
+
+int spot_cookie(request_rec *r)
+{
+    int *enable = (int *)get_module_config(r->per_dir_config,
+                                           &usertrack_module);
+    char *cookie;
+    char *value;
+
+    if (!*enable) return DECLINED;
+
+    if ((cookie = table_get (r->headers_in, "Cookie")))
+      if ((value=strstr(cookie,COOKIE_NAME))) {
+       char *cookiebuf, *cookieend;
+
+       value+=strlen(COOKIE_NAME);
+       cookiebuf=pstrdup( r->pool, value );
+       cookieend=strchr(cookiebuf,';');
+       if (cookieend) *cookieend='\0'; /* Ignore anything after a ; */
+
+       /* Set the cookie in a note, for logging */
+       table_set(r->notes, "cookie", cookiebuf);
+
+       return DECLINED;          /* Theres already a cookie, no new one */
+      }
+    make_cookie(r);
+    return OK;                        /* We set our cookie */
+}
+
+void *make_cookie_log_state (pool *p, server_rec *s)
+{
+    cookie_log_state *cls =
+      (cookie_log_state *)palloc (p, sizeof (cookie_log_state));
+
+    cls->expires = 0;
+
+    return (void *)cls;
+}
+
+void *make_cookie_dir (pool *p, char *d) {
+    return (void *)pcalloc(p, sizeof(int));
+}
+
+const char *set_cookie_enable (cmd_parms *cmd, int *c, int arg)
+{
+    *c = arg;
+    return NULL;
+}
+
+const char *set_cookie_exp (cmd_parms *parms, void *dummy, const char *arg)
+{
+    cookie_log_state *cls = get_module_config (parms->server->module_config,
+                           &usertrack_module);
+    time_t factor, modifier = 0;
+    time_t num = 0;
+    char *word;
+
+    /* The simple case first - all numbers (we assume) */
+    if (isdigit(arg[0]) && isdigit(arg[strlen(arg)-1])) {
+      cls->expires = atol(arg);
+      return NULL;
+    }
+
+    /* The harder case - stolen from mod_expires
+     * CookieExpires "[plus] {<num> <type>}*"
+     */
+
+    word = getword_conf( parms->pool, &arg );
+    if ( !strncasecmp( word, "plus", 1 ) ) {
+        word = getword_conf( parms->pool, &arg );
+    };
+
+    /* {<num> <type>}* */
+    while ( word[0] ) {
+        /* <num> */
+        if ( strchr("0123456789", word[0]) != NULL )
+         num = atoi( word );
+       else
+         return "bad expires code, numeric value expected.";
+      
+       /* <type> */
+       word = getword_conf( parms->pool, &arg );
+       if (!word[0] )
+         return "bad expires code, missing <type>";
+         
+       factor = 0;
+       if ( !strncasecmp( word, "years", 1 ) )
+         factor = 60*60*24*365;
+       else if ( !strncasecmp( word, "months", 2 ) )
+         factor = 60*60*24*30;
+       else if ( !strncasecmp( word, "weeks", 1 ) )
+         factor = 60*60*24*7;
+       else if ( !strncasecmp( word, "days", 1 ) )
+         factor = 60*60*24;
+       else if ( !strncasecmp( word, "hours", 1 ) )
+         factor = 60*60;
+       else if ( !strncasecmp( word, "minutes", 2 ) )
+         factor = 60;
+       else if ( !strncasecmp( word, "seconds", 1 ) )
+         factor = 1;
+       else
+         return "bad expires code, unrecognized type";
+
+       modifier = modifier + factor * num;
+
+       /* next <num> */
+       word = getword_conf( parms->pool, &arg );
+    }
+
+    cls->expires = modifier;
+
+    return NULL;
+}
+
+command_rec cookie_log_cmds[] = {
+{ "CookieExpires", set_cookie_exp, NULL, RSRC_CONF, TAKE1,
+    "an expiry date code" },
+{ "CookieTracking", set_cookie_enable, NULL, OR_FILEINFO, FLAG,
+    "whether or not to enable cookies" },
+{ NULL }
+};
+
+module usertrack_module = {
+   STANDARD_MODULE_STUFF,
+   NULL,                   /* initializer */
+   make_cookie_dir,               /* 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 */
+   NULL,                   /* logger */
+   NULL                           /* header parser */
+};
diff --git a/APACHE_1_2_X/src/regex/.cvsignore b/APACHE_1_2_X/src/regex/.cvsignore
new file mode 100644 (file)
index 0000000..b99cd82
--- /dev/null
@@ -0,0 +1,3 @@
+*.ih
+re
+
diff --git a/APACHE_1_2_X/src/regex/COPYRIGHT b/APACHE_1_2_X/src/regex/COPYRIGHT
new file mode 100644 (file)
index 0000000..d43362f
--- /dev/null
@@ -0,0 +1,20 @@
+Copyright 1992, 1993, 1994 Henry Spencer.  All rights reserved.
+This software is not subject to any license of the American Telephone
+and Telegraph Company or of the Regents of the University of California.
+
+Permission is granted to anyone to use this software for any purpose on
+any computer system, and to alter it and redistribute it, subject
+to the following restrictions:
+
+1. The author is not responsible for the consequences of use of this
+   software, no matter how awful, even if they arise from flaws in it.
+
+2. The origin of this software must not be misrepresented, either by
+   explicit claim or by omission.  Since few users ever read sources,
+   credits must appear in the documentation.
+
+3. Altered versions must be plainly marked as such, and must not be
+   misrepresented as being the original software.  Since few users
+   ever read sources, credits must appear in the documentation.
+
+4. This notice may not be removed or altered.
diff --git a/APACHE_1_2_X/src/regex/Makefile b/APACHE_1_2_X/src/regex/Makefile
new file mode 100644 (file)
index 0000000..e4ea015
--- /dev/null
@@ -0,0 +1,133 @@
+SHELL = /bin/sh
+
+# You probably want to take -DREDEBUG out of CFLAGS, and put something like
+# -O in, *after* testing (-DREDEBUG strengthens testing by enabling a lot of
+# internal assertion checking and some debugging facilities).
+# Put -Dconst= in for a pre-ANSI compiler.
+# Do not take -DPOSIX_MISTAKE out.
+# REGCFLAGS isn't important to you (it's for my use in some special contexts).
+CFLAGS=-I. -DPOSIX_MISTAKE $(AUX_CFLAGS)
+
+# If you have a pre-ANSI compiler, put -o into MKHFLAGS.  If you want
+# the Berkeley __P macro, put -b in.
+MKHFLAGS=
+
+# Flags for linking but not compiling, if any.
+LDFLAGS=
+
+# Extra libraries for linking, if any.
+LIBS=
+
+# Internal stuff, should not need changing.
+OBJPRODN=regcomp.o regexec.o regerror.o regfree.o
+OBJS=$(OBJPRODN) split.o debug.o main.o
+H=cclass.h cname.h regex2.h utils.h
+REGSRC=regcomp.c regerror.c regexec.c regfree.c
+ALLSRC=$(REGSRC) engine.c debug.c main.c split.c
+
+# Stuff that matters only if you're trying to lint the package.
+LINTFLAGS=-I. -Dstatic= -Dconst= -DREDEBUG
+LINTC=regcomp.c regexec.c regerror.c regfree.c debug.c main.c
+JUNKLINT=possible pointer alignment|null effect
+
+# arrangements to build forward-reference header files
+.SUFFIXES:     .ih .h
+.c.ih:
+       sh ./mkh $(MKHFLAGS) -p $< >$@
+
+default:       r
+
+lib:   purge $(OBJPRODN)
+       rm -f libregex.a
+       ar crv libregex.a $(OBJPRODN)
+       $(RANLIB) libregex.a
+
+purge:
+       rm -f *.o
+
+# stuff to build regex.h
+REGEXH=regex.h
+REGEXHSRC=regex2.h $(REGSRC)
+$(REGEXH):     $(REGEXHSRC) mkh
+       sh ./mkh $(MKHFLAGS) -i _REGEX_H_ $(REGEXHSRC) >regex.tmp
+       cmp -s regex.tmp regex.h 2>/dev/null || cp regex.tmp regex.h
+       rm -f regex.tmp
+
+# dependencies
+$(OBJPRODN) debug.o:   utils.h regex.h regex2.h
+regcomp.o:     cclass.h cname.h regcomp.ih
+regexec.o:     engine.c engine.ih
+regerror.o:    regerror.ih
+debug.o:       debug.ih
+main.o:        main.ih
+
+# tester
+re:    $(OBJS)
+       $(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) $(LIBS) -o $@
+
+# regression test
+r:     re tests
+       ./re <tests
+       ./re -el <tests
+       ./re -er <tests
+
+# 57 variants, and other stuff, for development use -- not useful to you
+ra:    ./re tests
+       -./re <tests
+       -./re -el <tests
+       -./re -er <tests
+
+rx:    ./re tests
+       ./re -x <tests
+       ./re -x -el <tests
+       ./re -x -er <tests
+
+t:     ./re tests
+       -time ./re <tests
+       -time ./re -cs <tests
+       -time ./re -el <tests
+       -time ./re -cs -el <tests
+
+l:     $(LINTC)
+       lint $(LINTFLAGS) -h $(LINTC) 2>&1 | egrep -v '$(JUNKLINT)' | tee lint
+
+fullprint:
+       ti README WHATSNEW notes todo | list
+       ti *.h | list
+       list *.c
+       list regex.3 regex.7
+
+print:
+       ti README WHATSNEW notes todo | list
+       ti *.h | list
+       list reg*.c engine.c
+
+
+mf.tmp:        Makefile
+       sed '/^REGEXH=/s/=.*/=regex.h/' Makefile | sed '/#DEL$$/d' >$@
+
+DTRH=cclass.h cname.h regex2.h utils.h
+PRE=COPYRIGHT README WHATSNEW
+POST=mkh regex.3 regex.7 tests $(DTRH) $(ALLSRC) fake/*.[ch]
+FILES=$(PRE) Makefile $(POST)
+DTR=$(PRE) Makefile=mf.tmp $(POST)
+dtr:   $(FILES) mf.tmp
+       makedtr $(DTR) >$@
+       rm mf.tmp
+
+cio:   $(FILES)
+       cio $(FILES)
+
+rdf:   $(FILES)
+       rcsdiff -c $(FILES) 2>&1 | p
+
+# various forms of cleanup
+tidy:
+       rm -f junk* core core.* *.core dtr *.tmp lint
+
+clean: tidy
+       rm -f *.o *.s *.ih re libregex.a
+
+# don't do this one unless you know what you're doing
+spotless:      clean
+       rm -f mkh regex.h
diff --git a/APACHE_1_2_X/src/regex/README b/APACHE_1_2_X/src/regex/README
new file mode 100644 (file)
index 0000000..cea9b67
--- /dev/null
@@ -0,0 +1,32 @@
+alpha3.4 release.
+Thu Mar 17 23:17:18 EST 1994
+henry@zoo.toronto.edu
+
+See WHATSNEW for change listing.
+
+installation notes:
+--------
+Read the comments at the beginning of Makefile before running.
+
+Utils.h contains some things that just might have to be modified on
+some systems, as well as a nested include (ugh) of <assert.h>.
+
+The "fake" directory contains quick-and-dirty fakes for some header
+files and routines that old systems may not have.  Note also that
+-DUSEBCOPY will make utils.h substitute bcopy() for memmove().
+
+After that, "make r" will build regcomp.o, regexec.o, regfree.o,
+and regerror.o (the actual routines), bundle them together into a test
+program, and run regression tests on them.  No output is good output.
+
+"make lib" builds just the .o files for the actual routines (when
+you're happy with testing and have adjusted CFLAGS for production),
+and puts them together into libregex.a.  You can pick up either the
+library or *.o ("make lib" makes sure there are no other .o files left
+around to confuse things).
+
+Main.c, debug.c, split.c are used for regression testing but are not part
+of the RE routines themselves.
+
+Regex.h goes in /usr/include.  All other .h files are internal only.
+--------
diff --git a/APACHE_1_2_X/src/regex/WHATSNEW b/APACHE_1_2_X/src/regex/WHATSNEW
new file mode 100644 (file)
index 0000000..6e82e1d
--- /dev/null
@@ -0,0 +1,92 @@
+New in alpha3.4:  The complex bug alluded to below has been fixed (in a
+slightly kludgey temporary way that may hurt efficiency a bit; this is
+another "get it out the door for 4.4" release).  The tests at the end of
+the tests file have accordingly been uncommented.  The primary sign of
+the bug was that something like a?b matching ab matched b rather than ab.
+(The bug was essentially specific to this exact situation, else it would
+have shown up earlier.)
+
+New in alpha3.3:  The definition of word boundaries has been altered
+slightly, to more closely match the usual programming notion that "_"
+is an alphabetic.  Stuff used for pre-ANSI systems is now in a subdir,
+and the makefile no longer alludes to it in mysterious ways.  The
+makefile has generally been cleaned up some.  Fixes have been made
+(again!) so that the regression test will run without -DREDEBUG, at
+the cost of weaker checking.  A workaround for a bug in some folks'
+<assert.h> has been added.  And some more things have been added to
+tests, including a couple right at the end which are commented out
+because the code currently flunks them (complex bug; fix coming).
+Plus the usual minor cleanup.
+
+New in alpha3.2:  Assorted bits of cleanup and portability improvement
+(the development base is now a BSDI system using GCC instead of an ancient
+Sun system, and the newer compiler exposed some glitches).  Fix for a
+serious bug that affected REs using many [] (including REG_ICASE REs
+because of the way they are implemented), *sometimes*, depending on
+memory-allocation patterns.  The header-file prototypes no longer name
+the parameters, avoiding possible name conflicts.  The possibility that
+some clot has defined CHAR_MIN as (say) `-128' instead of `(-128)' is
+now handled gracefully.  "uchar" is no longer used as an internal type
+name (too many people have the same idea).  Still the same old lousy
+performance, alas.
+
+New in alpha3.1:  Basically nothing, this release is just a bookkeeping
+convenience.  Stay tuned.
+
+New in alpha3.0:  Performance is no better, alas, but some fixes have been
+made and some functionality has been added.  (This is basically the "get
+it out the door in time for 4.4" release.)  One bug fix:  regfree() didn't
+free the main internal structure (how embarrassing).  It is now possible
+to put NULs in either the RE or the target string, using (resp.) a new
+REG_PEND flag and the old REG_STARTEND flag.  The REG_NOSPEC flag to
+regcomp() makes all characters ordinary, so you can match a literal
+string easily (this will become more useful when performance improves!).
+There are now primitives to match beginnings and ends of words, although
+the syntax is disgusting and so is the implementation.  The REG_ATOI
+debugging interface has changed a bit.  And there has been considerable
+internal cleanup of various kinds.
+
+New in alpha2.3:  Split change list out of README, and moved flags notes
+into Makefile.  Macro-ized the name of regex(7) in regex(3), since it has
+to change for 4.4BSD.  Cleanup work in engine.c, and some new regression
+tests to catch tricky cases thereof.
+
+New in alpha2.2:  Out-of-date manpages updated.  Regerror() acquires two
+small extensions -- REG_ITOA and REG_ATOI -- which avoid debugging kludges
+in my own test program and might be useful to others for similar purposes.
+The regression test will now compile (and run) without REDEBUG.  The
+BRE \$ bug is fixed.  Most uses of "uchar" are gone; it's all chars now.
+Char/uchar parameters are now written int/unsigned, to avoid possible
+portability problems with unpromoted parameters.  Some unsigned casts have
+been introduced to minimize portability problems with shifting into sign
+bits.
+
+New in alpha2.1:  Lots of little stuff, cleanup and fixes.  The one big
+thing is that regex.h is now generated, using mkh, rather than being
+supplied in the distribution; due to circularities in dependencies,
+you have to build regex.h explicitly by "make h".  The two known bugs
+have been fixed (and the regression test now checks for them), as has a
+problem with assertions not being suppressed in the absence of REDEBUG.
+No performance work yet.
+
+New in alpha2:  Backslash-anything is an ordinary character, not an
+error (except, of course, for the handful of backslashed metacharacters
+in BREs), which should reduce script breakage.  The regression test
+checks *where* null strings are supposed to match, and has generally
+been tightened up somewhat.  Small bug fixes in parameter passing (not
+harmful, but technically errors) and some other areas.  Debugging
+invoked by defining REDEBUG rather than not defining NDEBUG.
+
+New in alpha+3:  full prototyping for internal routines, using a little
+helper program, mkh, which extracts prototypes given in stylized comments.
+More minor cleanup.  Buglet fix:  it's CHAR_BIT, not CHAR_BITS.  Simple
+pre-screening of input when a literal string is known to be part of the
+RE; this does wonders for performance.
+
+New in alpha+2:  minor bits of cleanup.  Notably, the number "32" for the
+word width isn't hardwired into regexec.c any more, the public header
+file prototypes the functions if __STDC__ is defined, and some small typos
+in the manpages have been fixed.
+
+New in alpha+1:  improvements to the manual pages, and an important
+extension, the REG_STARTEND option to regexec().
diff --git a/APACHE_1_2_X/src/regex/cclass.h b/APACHE_1_2_X/src/regex/cclass.h
new file mode 100644 (file)
index 0000000..727cbb9
--- /dev/null
@@ -0,0 +1,31 @@
+/* character-class table */
+static struct cclass {
+       char *name;
+       char *chars;
+       char *multis;
+} cclasses[] = {
+       { "alnum",      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\
+0123456789",                           "" },
+       { "alpha",      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
+                                       "" },
+       { "blank",      " \t",          "" },
+       { "cntrl",      "\007\b\t\n\v\f\r\1\2\3\4\5\6\16\17\20\21\22\23\24\
+\25\26\27\30\31\32\33\34\35\36\37\177",        "" },
+       { "digit",      "0123456789",   "" },
+       { "graph",      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\
+0123456789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
+                                       "" },
+       { "lower",      "abcdefghijklmnopqrstuvwxyz",
+                                       "" },
+       { "print",      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\
+0123456789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~ ",
+                                       "" },
+       { "punct",      "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
+                                       "" },
+       { "space",      "\t\n\v\f\r ",  "" },
+       { "upper",      "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
+                                       "" },
+       { "xdigit",     "0123456789ABCDEFabcdef",
+                                       "" },
+       { NULL,         0,              "" }
+};
diff --git a/APACHE_1_2_X/src/regex/cname.h b/APACHE_1_2_X/src/regex/cname.h
new file mode 100644 (file)
index 0000000..ff116e5
--- /dev/null
@@ -0,0 +1,102 @@
+/* character-name table */
+static struct cname {
+       char *name;
+       char code;
+} cnames[] = {
+       { "NUL",        '\0' },
+       { "SOH",        '\001' },
+       { "STX",        '\002' },
+       { "ETX",        '\003' },
+       { "EOT",        '\004' },
+       { "ENQ",        '\005' },
+       { "ACK",        '\006' },
+       { "BEL",        '\007' },
+       { "alert",      '\007' },
+       { "BS",         '\010' },
+       { "backspace",  '\b' },
+       { "HT",         '\011' },
+       { "tab",                '\t' },
+       { "LF",         '\012' },
+       { "newline",    '\n' },
+       { "VT",         '\013' },
+       { "vertical-tab",       '\v' },
+       { "FF",         '\014' },
+       { "form-feed",  '\f' },
+       { "CR",         '\015' },
+       { "carriage-return",    '\r' },
+       { "SO", '\016' },
+       { "SI", '\017' },
+       { "DLE",        '\020' },
+       { "DC1",        '\021' },
+       { "DC2",        '\022' },
+       { "DC3",        '\023' },
+       { "DC4",        '\024' },
+       { "NAK",        '\025' },
+       { "SYN",        '\026' },
+       { "ETB",        '\027' },
+       { "CAN",        '\030' },
+       { "EM", '\031' },
+       { "SUB",        '\032' },
+       { "ESC",        '\033' },
+       { "IS4",        '\034' },
+       { "FS", '\034' },
+       { "IS3",        '\035' },
+       { "GS", '\035' },
+       { "IS2",        '\036' },
+       { "RS", '\036' },
+       { "IS1",        '\037' },
+       { "US", '\037' },
+       { "space",              ' ' },
+       { "exclamation-mark",   '!' },
+       { "quotation-mark",     '"' },
+       { "number-sign",                '#' },
+       { "dollar-sign",                '$' },
+       { "percent-sign",               '%' },
+       { "ampersand",          '&' },
+       { "apostrophe",         '\'' },
+       { "left-parenthesis",   '(' },
+       { "right-parenthesis",  ')' },
+       { "asterisk",   '*' },
+       { "plus-sign",  '+' },
+       { "comma",      ',' },
+       { "hyphen",     '-' },
+       { "hyphen-minus",       '-' },
+       { "period",     '.' },
+       { "full-stop",  '.' },
+       { "slash",      '/' },
+       { "solidus",    '/' },
+       { "zero",               '0' },
+       { "one",                '1' },
+       { "two",                '2' },
+       { "three",      '3' },
+       { "four",               '4' },
+       { "five",               '5' },
+       { "six",                '6' },
+       { "seven",      '7' },
+       { "eight",      '8' },
+       { "nine",               '9' },
+       { "colon",      ':' },
+       { "semicolon",  ';' },
+       { "less-than-sign",     '<' },
+       { "equals-sign",                '=' },
+       { "greater-than-sign",  '>' },
+       { "question-mark",      '?' },
+       { "commercial-at",      '@' },
+       { "left-square-bracket",        '[' },
+       { "backslash",          '\\' },
+       { "reverse-solidus",    '\\' },
+       { "right-square-bracket",       ']' },
+       { "circumflex",         '^' },
+       { "circumflex-accent",  '^' },
+       { "underscore",         '_' },
+       { "low-line",           '_' },
+       { "grave-accent",               '`' },
+       { "left-brace",         '{' },
+       { "left-curly-bracket", '{' },
+       { "vertical-line",      '|' },
+       { "right-brace",                '}' },
+       { "right-curly-bracket",        '}' },
+       { "tilde",              '~' },
+       { "DEL",        '\177' },
+       { NULL, 0 }
+};
diff --git a/APACHE_1_2_X/src/regex/debug.c b/APACHE_1_2_X/src/regex/debug.c
new file mode 100644 (file)
index 0000000..c0feaeb
--- /dev/null
@@ -0,0 +1,242 @@
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <regex.h>
+
+#include "utils.h"
+#include "regex2.h"
+#include "debug.ih"
+
+/*
+ - regprint - print a regexp for debugging
+ == void regprint(regex_t *r, FILE *d);
+ */
+void
+regprint(r, d)
+regex_t *r;
+FILE *d;
+{
+       register struct re_guts *g = r->re_g;
+       register int i;
+       register int c;
+       register int last;
+       int nincat[NC];
+
+       fprintf(d, "%ld states, %d categories", (long)g->nstates,
+                                                       g->ncategories);
+       fprintf(d, ", first %ld last %ld", (long)g->firststate,
+                                               (long)g->laststate);
+       if (g->iflags&USEBOL)
+               fprintf(d, ", USEBOL");
+       if (g->iflags&USEEOL)
+               fprintf(d, ", USEEOL");
+       if (g->iflags&BAD)
+               fprintf(d, ", BAD");
+       if (g->nsub > 0)
+               fprintf(d, ", nsub=%ld", (long)g->nsub);
+       if (g->must != NULL)
+               fprintf(d, ", must(%ld) `%*s'", (long)g->mlen, (int)g->mlen,
+                                                               g->must);
+       if (g->backrefs)
+               fprintf(d, ", backrefs");
+       if (g->nplus > 0)
+               fprintf(d, ", nplus %ld", (long)g->nplus);
+       fprintf(d, "\n");
+       s_print(g, d);
+       for (i = 0; i < g->ncategories; i++) {
+               nincat[i] = 0;
+               for (c = CHAR_MIN; c <= CHAR_MAX; c++)
+                       if (g->categories[c] == i)
+                               nincat[i]++;
+       }
+       fprintf(d, "cc0#%d", nincat[0]);
+       for (i = 1; i < g->ncategories; i++)
+               if (nincat[i] == 1) {
+                       for (c = CHAR_MIN; c <= CHAR_MAX; c++)
+                               if (g->categories[c] == i)
+                                       break;
+                       fprintf(d, ", %d=%s", i, regchar(c));
+               }
+       fprintf(d, "\n");
+       for (i = 1; i < g->ncategories; i++)
+               if (nincat[i] != 1) {
+                       fprintf(d, "cc%d\t", i);
+                       last = -1;
+                       for (c = CHAR_MIN; c <= CHAR_MAX+1; c++)        /* +1 does flush */
+                               if (c <= CHAR_MAX && g->categories[c] == i) {
+                                       if (last < 0) {
+                                               fprintf(d, "%s", regchar(c));
+                                               last = c;
+                                       }
+                               } else {
+                                       if (last >= 0) {
+                                               if (last != c-1)
+                                                       fprintf(d, "-%s",
+                                                               regchar(c-1));
+                                               last = -1;
+                                       }
+                               }
+                       fprintf(d, "\n");
+               }
+}
+
+/*
+ - s_print - print the strip for debugging
+ == static void s_print(register struct re_guts *g, FILE *d);
+ */
+static void
+s_print(g, d)
+register struct re_guts *g;
+FILE *d;
+{
+       register sop *s;
+       register cset *cs;
+       register int i;
+       register int done = 0;
+       register sop opnd;
+       register int col = 0;
+       register int last;
+       register sopno offset = 2;
+#      define  GAP()   {       if (offset % 5 == 0) { \
+                                       if (col > 40) { \
+                                               fprintf(d, "\n\t"); \
+                                               col = 0; \
+                                       } else { \
+                                               fprintf(d, " "); \
+                                               col++; \
+                                       } \
+                               } else \
+                                       col++; \
+                               offset++; \
+                       }
+
+       if (OP(g->strip[0]) != OEND)
+               fprintf(d, "missing initial OEND!\n");
+       for (s = &g->strip[1]; !done; s++) {
+               opnd = OPND(*s);
+               switch (OP(*s)) {
+               case OEND:
+                       fprintf(d, "\n");
+                       done = 1;
+                       break;
+               case OCHAR:
+                       if (strchr("\\|()^$.[+*?{}!<> ", (char)opnd) != NULL)
+                               fprintf(d, "\\%c", (char)opnd);
+                       else
+                               fprintf(d, "%s", regchar((char)opnd));
+                       break;
+               case OBOL:
+                       fprintf(d, "^");
+                       break;
+               case OEOL:
+                       fprintf(d, "$");
+                       break;
+               case OBOW:
+                       fprintf(d, "\\{");
+                       break;
+               case OEOW:
+                       fprintf(d, "\\}");
+                       break;
+               case OANY:
+                       fprintf(d, ".");
+                       break;
+               case OANYOF:
+                       fprintf(d, "[(%ld)", (long)opnd);
+                       cs = &g->sets[opnd];
+                       last = -1;
+                       for (i = 0; i < g->csetsize+1; i++)     /* +1 flushes */
+                               if (CHIN(cs, i) && i < g->csetsize) {
+                                       if (last < 0) {
+                                               fprintf(d, "%s", regchar(i));
+                                               last = i;
+                                       }
+                               } else {
+                                       if (last >= 0) {
+                                               if (last != i-1)
+                                                       fprintf(d, "-%s",
+                                                               regchar(i-1));
+                                               last = -1;
+                                       }
+                               }
+                       fprintf(d, "]");
+                       break;
+               case OBACK_:
+                       fprintf(d, "(\\<%ld>", (long)opnd);
+                       break;
+               case O_BACK:
+                       fprintf(d, "<%ld>\\)", (long)opnd);
+                       break;
+               case OPLUS_:
+                       fprintf(d, "(+");
+                       if (OP(*(s+opnd)) != O_PLUS)
+                               fprintf(d, "<%ld>", (long)opnd);
+                       break;
+               case O_PLUS:
+                       if (OP(*(s-opnd)) != OPLUS_)
+                               fprintf(d, "<%ld>", (long)opnd);
+                       fprintf(d, "+)");
+                       break;
+               case OQUEST_:
+                       fprintf(d, "(?");
+                       if (OP(*(s+opnd)) != O_QUEST)
+                               fprintf(d, "<%ld>", (long)opnd);
+                       break;
+               case O_QUEST:
+                       if (OP(*(s-opnd)) != OQUEST_)
+                               fprintf(d, "<%ld>", (long)opnd);
+                       fprintf(d, "?)");
+                       break;
+               case OLPAREN:
+                       fprintf(d, "((<%ld>", (long)opnd);
+                       break;
+               case ORPAREN:
+                       fprintf(d, "<%ld>))", (long)opnd);
+                       break;
+               case OCH_:
+                       fprintf(d, "<");
+                       if (OP(*(s+opnd)) != OOR2)
+                               fprintf(d, "<%ld>", (long)opnd);
+                       break;
+               case OOR1:
+                       if (OP(*(s-opnd)) != OOR1 && OP(*(s-opnd)) != OCH_)
+                               fprintf(d, "<%ld>", (long)opnd);
+                       fprintf(d, "|");
+                       break;
+               case OOR2:
+                       fprintf(d, "|");
+                       if (OP(*(s+opnd)) != OOR2 && OP(*(s+opnd)) != O_CH)
+                               fprintf(d, "<%ld>", (long)opnd);
+                       break;
+               case O_CH:
+                       if (OP(*(s-opnd)) != OOR1)
+                               fprintf(d, "<%ld>", (long)opnd);
+                       fprintf(d, ">");
+                       break;
+               default:
+                       fprintf(d, "!%ld(%ld)!", OP(*s), opnd);
+                       break;
+               }
+               if (!done)
+                       GAP();
+       }
+}
+
+/*
+ - regchar - make a character printable
+ == static char *regchar(int ch);
+ */
+static char *                  /* -> representation */
+regchar(ch)
+int ch;
+{
+       static char buf[10];
+
+       if (isprint(ch) || ch == ' ')
+               sprintf(buf, "%c", ch);
+       else
+               sprintf(buf, "\\%o", ch);
+       return(buf);
+}
diff --git a/APACHE_1_2_X/src/regex/engine.c b/APACHE_1_2_X/src/regex/engine.c
new file mode 100644 (file)
index 0000000..f3b36b3
--- /dev/null
@@ -0,0 +1,1019 @@
+/*
+ * The matching engine and friends.  This file is #included by regexec.c
+ * after suitable #defines of a variety of macros used herein, so that
+ * different state representations can be used without duplicating masses
+ * of code.
+ */
+
+#ifdef SNAMES
+#define        matcher smatcher
+#define        fast    sfast
+#define        slow    sslow
+#define        dissect sdissect
+#define        backref sbackref
+#define        step    sstep
+#define        print   sprint
+#define        at      sat
+#define        match   smat
+#endif
+#ifdef LNAMES
+#define        matcher lmatcher
+#define        fast    lfast
+#define        slow    lslow
+#define        dissect ldissect
+#define        backref lbackref
+#define        step    lstep
+#define        print   lprint
+#define        at      lat
+#define        match   lmat
+#endif
+
+/* another structure passed up and down to avoid zillions of parameters */
+struct match {
+       struct re_guts *g;
+       int eflags;
+       regmatch_t *pmatch;     /* [nsub+1] (0 element unused) */
+       char *offp;             /* offsets work from here */
+       char *beginp;           /* start of string -- virtual NUL precedes */
+       char *endp;             /* end of string -- virtual NUL here */
+       char *coldp;            /* can be no match starting before here */
+       char **lastpos;         /* [nplus+1] */
+       STATEVARS;
+       states st;              /* current states */
+       states fresh;           /* states for a fresh start */
+       states tmp;             /* temporary */
+       states empty;           /* empty set of states */
+};
+
+#include "engine.ih"
+
+#ifdef REDEBUG
+#define        SP(t, s, c)     print(m, t, s, c, stdout)
+#define        AT(t, p1, p2, s1, s2)   at(m, t, p1, p2, s1, s2)
+#define        NOTE(str)       { if (m->eflags&REG_TRACE) printf("=%s\n", (str)); }
+#else
+#define        SP(t, s, c)     /* nothing */
+#define        AT(t, p1, p2, s1, s2)   /* nothing */
+#define        NOTE(s) /* nothing */
+#endif
+
+/*
+ - matcher - the actual matching engine
+ == static int matcher(register struct re_guts *g, char *string, \
+ ==    size_t nmatch, regmatch_t pmatch[], int eflags);
+ */
+static int                     /* 0 success, REG_NOMATCH failure */
+matcher(g, string, nmatch, pmatch, eflags)
+register struct re_guts *g;
+char *string;
+size_t nmatch;
+regmatch_t pmatch[];
+int eflags;
+{
+       register char *endp;
+       register int i;
+       struct match mv;
+       register struct match *m = &mv;
+       register char *dp;
+       register const sopno gf = g->firststate+1;      /* +1 for OEND */
+       register const sopno gl = g->laststate;
+       char *start;
+       char *stop;
+
+       /* simplify the situation where possible */
+       if (g->cflags&REG_NOSUB)
+               nmatch = 0;
+       if (eflags&REG_STARTEND) {
+               start = string + pmatch[0].rm_so;
+               stop = string + pmatch[0].rm_eo;
+       } else {
+               start = string;
+               stop = start + strlen(start);
+       }
+       if (stop < start)
+               return(REG_INVARG);
+
+       /* prescreening; this does wonders for this rather slow code */
+       if (g->must != NULL) {
+               for (dp = start; dp < stop; dp++)
+                       if (*dp == g->must[0] && stop - dp >= g->mlen &&
+                               memcmp(dp, g->must, (size_t)g->mlen) == 0)
+                               break;
+               if (dp == stop)         /* we didn't find g->must */
+                       return(REG_NOMATCH);
+       }
+
+       /* match struct setup */
+       m->g = g;
+       m->eflags = eflags;
+       m->pmatch = NULL;
+       m->lastpos = NULL;
+       m->offp = string;
+       m->beginp = start;
+       m->endp = stop;
+       STATESETUP(m, 4);
+       SETUP(m->st);
+       SETUP(m->fresh);
+       SETUP(m->tmp);
+       SETUP(m->empty);
+       CLEAR(m->empty);
+
+       /* this loop does only one repetition except for backrefs */
+       for (;;) {
+               endp = fast(m, start, stop, gf, gl);
+               if (endp == NULL) {             /* a miss */
+                       STATETEARDOWN(m);
+                       return(REG_NOMATCH);
+               }
+               if (nmatch == 0 && !g->backrefs)
+                       break;          /* no further info needed */
+
+               /* where? */
+               assert(m->coldp != NULL);
+               for (;;) {
+                       NOTE("finding start");
+                       endp = slow(m, m->coldp, stop, gf, gl);
+                       if (endp != NULL)
+                               break;
+                       assert(m->coldp < m->endp);
+                       m->coldp++;
+               }
+               if (nmatch == 1 && !g->backrefs)
+                       break;          /* no further info needed */
+
+               /* oh my, he wants the subexpressions... */
+               if (m->pmatch == NULL)
+                       m->pmatch = (regmatch_t *)malloc((m->g->nsub + 1) *
+                                                       sizeof(regmatch_t));
+               if (m->pmatch == NULL) {
+                       STATETEARDOWN(m);
+                       return(REG_ESPACE);
+               }
+               for (i = 1; i <= m->g->nsub; i++)
+                       m->pmatch[i].rm_so = m->pmatch[i].rm_eo = -1;
+               if (!g->backrefs && !(m->eflags&REG_BACKR)) {
+                       NOTE("dissecting");
+                       dp = dissect(m, m->coldp, endp, gf, gl);
+               } else {
+                       if (g->nplus > 0 && m->lastpos == NULL)
+                               m->lastpos = (char **)malloc((g->nplus+1) *
+                                                       sizeof(char *));
+                       if (g->nplus > 0 && m->lastpos == NULL) {
+                               free(m->pmatch);
+                               STATETEARDOWN(m);
+                               return(REG_ESPACE);
+                       }
+                       NOTE("backref dissect");
+                       dp = backref(m, m->coldp, endp, gf, gl, (sopno)0);
+               }
+               if (dp != NULL)
+                       break;
+
+               /* uh-oh... we couldn't find a subexpression-level match */
+               assert(g->backrefs);    /* must be back references doing it */
+               assert(g->nplus == 0 || m->lastpos != NULL);
+               for (;;) {
+                       if (dp != NULL || endp <= m->coldp)
+                               break;          /* defeat */
+                       NOTE("backoff");
+                       endp = slow(m, m->coldp, endp-1, gf, gl);
+                       if (endp == NULL)
+                               break;          /* defeat */
+                       /* try it on a shorter possibility */
+#ifndef NDEBUG
+                       for (i = 1; i <= m->g->nsub; i++) {
+                               assert(m->pmatch[i].rm_so == -1);
+                               assert(m->pmatch[i].rm_eo == -1);
+                       }
+#endif
+                       NOTE("backoff dissect");
+                       dp = backref(m, m->coldp, endp, gf, gl, (sopno)0);
+               }
+               assert(dp == NULL || dp == endp);
+               if (dp != NULL)         /* found a shorter one */
+                       break;
+
+               /* despite initial appearances, there is no match here */
+               NOTE("false alarm");
+               start = m->coldp + 1;   /* recycle starting later */
+               assert(start <= stop);
+       }
+
+       /* fill in the details if requested */
+       if (nmatch > 0) {
+               pmatch[0].rm_so = m->coldp - m->offp;
+               pmatch[0].rm_eo = endp - m->offp;
+       }
+       if (nmatch > 1) {
+               assert(m->pmatch != NULL);
+               for (i = 1; i < nmatch; i++)
+                       if (i <= m->g->nsub)
+                               pmatch[i] = m->pmatch[i];
+                       else {
+                               pmatch[i].rm_so = -1;
+                               pmatch[i].rm_eo = -1;
+                       }
+       }
+
+       if (m->pmatch != NULL)
+               free((char *)m->pmatch);
+       if (m->lastpos != NULL)
+               free((char *)m->lastpos);
+       STATETEARDOWN(m);
+       return(0);
+}
+
+/*
+ - dissect - figure out what matched what, no back references
+ == static char *dissect(register struct match *m, char *start, \
+ ==    char *stop, sopno startst, sopno stopst);
+ */
+static char *                  /* == stop (success) always */
+dissect(m, start, stop, startst, stopst)
+register struct match *m;
+char *start;
+char *stop;
+sopno startst;
+sopno stopst;
+{
+       register int i;
+       register sopno ss;      /* start sop of current subRE */
+       register sopno es;      /* end sop of current subRE */
+       register char *sp;      /* start of string matched by it */
+       register char *stp;     /* string matched by it cannot pass here */
+       register char *rest;    /* start of rest of string */
+       register char *tail;    /* string unmatched by rest of RE */
+       register sopno ssub;    /* start sop of subsubRE */
+       register sopno esub;    /* end sop of subsubRE */
+       register char *ssp;     /* start of string matched by subsubRE */
+       register char *sep;     /* end of string matched by subsubRE */
+       register char *oldssp;  /* previous ssp */
+       register char *dp;
+
+       AT("diss", start, stop, startst, stopst);
+       sp = start;
+       for (ss = startst; ss < stopst; ss = es) {
+               /* identify end of subRE */
+               es = ss;
+               switch (OP(m->g->strip[es])) {
+               case OPLUS_:
+               case OQUEST_:
+                       es += OPND(m->g->strip[es]);
+                       break;
+               case OCH_:
+                       while (OP(m->g->strip[es]) != O_CH)
+                               es += OPND(m->g->strip[es]);
+                       break;
+               }
+               es++;
+
+               /* figure out what it matched */
+               switch (OP(m->g->strip[ss])) {
+               case OEND:
+                       assert(nope);
+                       break;
+               case OCHAR:
+                       sp++;
+                       break;
+               case OBOL:
+               case OEOL:
+               case OBOW:
+               case OEOW:
+                       break;
+               case OANY:
+               case OANYOF:
+                       sp++;
+                       break;
+               case OBACK_:
+               case O_BACK:
+                       assert(nope);
+                       break;
+               /* cases where length of match is hard to find */
+               case OQUEST_:
+                       stp = stop;
+                       for (;;) {
+                               /* how long could this one be? */
+                               rest = slow(m, sp, stp, ss, es);
+                               assert(rest != NULL);   /* it did match */
+                               /* could the rest match the rest? */
+                               tail = slow(m, rest, stop, es, stopst);
+                               if (tail == stop)
+                                       break;          /* yes! */
+                               /* no -- try a shorter match for this one */
+                               stp = rest - 1;
+                               assert(stp >= sp);      /* it did work */
+                       }
+                       ssub = ss + 1;
+                       esub = es - 1;
+                       /* did innards match? */
+                       if (slow(m, sp, rest, ssub, esub) != NULL) {
+                               dp = dissect(m, sp, rest, ssub, esub);
+                               assert(dp == rest);
+                       } else          /* no */
+                               assert(sp == rest);
+                       sp = rest;
+                       break;
+               case OPLUS_:
+                       stp = stop;
+                       for (;;) {
+                               /* how long could this one be? */
+                               rest = slow(m, sp, stp, ss, es);
+                               assert(rest != NULL);   /* it did match */
+                               /* could the rest match the rest? */
+                               tail = slow(m, rest, stop, es, stopst);
+                               if (tail == stop)
+                                       break;          /* yes! */
+                               /* no -- try a shorter match for this one */
+                               stp = rest - 1;
+                               assert(stp >= sp);      /* it did work */
+                       }
+                       ssub = ss + 1;
+                       esub = es - 1;
+                       ssp = sp;
+                       oldssp = ssp;
+                       for (;;) {      /* find last match of innards */
+                               sep = slow(m, ssp, rest, ssub, esub);
+                               if (sep == NULL || sep == ssp)
+                                       break;  /* failed or matched null */
+                               oldssp = ssp;   /* on to next try */
+                               ssp = sep;
+                       }
+                       if (sep == NULL) {
+                               /* last successful match */
+                               sep = ssp;
+                               ssp = oldssp;
+                       }
+                       assert(sep == rest);    /* must exhaust substring */
+                       assert(slow(m, ssp, sep, ssub, esub) == rest);
+                       dp = dissect(m, ssp, sep, ssub, esub);
+                       assert(dp == sep);
+                       sp = rest;
+                       break;
+               case OCH_:
+                       stp = stop;
+                       for (;;) {
+                               /* how long could this one be? */
+                               rest = slow(m, sp, stp, ss, es);
+                               assert(rest != NULL);   /* it did match */
+                               /* could the rest match the rest? */
+                               tail = slow(m, rest, stop, es, stopst);
+                               if (tail == stop)
+                                       break;          /* yes! */
+                               /* no -- try a shorter match for this one */
+                               stp = rest - 1;
+                               assert(stp >= sp);      /* it did work */
+                       }
+                       ssub = ss + 1;
+                       esub = ss + OPND(m->g->strip[ss]) - 1;
+                       assert(OP(m->g->strip[esub]) == OOR1);
+                       for (;;) {      /* find first matching branch */
+                               if (slow(m, sp, rest, ssub, esub) == rest)
+                                       break;  /* it matched all of it */
+                               /* that one missed, try next one */
+                               assert(OP(m->g->strip[esub]) == OOR1);
+                               esub++;
+                               assert(OP(m->g->strip[esub]) == OOR2);
+                               ssub = esub + 1;
+                               esub += OPND(m->g->strip[esub]);
+                               if (OP(m->g->strip[esub]) == OOR2)
+                                       esub--;
+                               else
+                                       assert(OP(m->g->strip[esub]) == O_CH);
+                       }
+                       dp = dissect(m, sp, rest, ssub, esub);
+                       assert(dp == rest);
+                       sp = rest;
+                       break;
+               case O_PLUS:
+               case O_QUEST:
+               case OOR1:
+               case OOR2:
+               case O_CH:
+                       assert(nope);
+                       break;
+               case OLPAREN:
+                       i = OPND(m->g->strip[ss]);
+                       assert(0 < i && i <= m->g->nsub);
+                       m->pmatch[i].rm_so = sp - m->offp;
+                       break;
+               case ORPAREN:
+                       i = OPND(m->g->strip[ss]);
+                       assert(0 < i && i <= m->g->nsub);
+                       m->pmatch[i].rm_eo = sp - m->offp;
+                       break;
+               default:                /* uh oh */
+                       assert(nope);
+                       break;
+               }
+       }
+
+       assert(sp == stop);
+       return(sp);
+}
+
+/*
+ - backref - figure out what matched what, figuring in back references
+ == static char *backref(register struct match *m, char *start, \
+ ==    char *stop, sopno startst, sopno stopst, sopno lev);
+ */
+static char *                  /* == stop (success) or NULL (failure) */
+backref(m, start, stop, startst, stopst, lev)
+register struct match *m;
+char *start;
+char *stop;
+sopno startst;
+sopno stopst;
+sopno lev;                     /* PLUS nesting level */
+{
+       register int i;
+       register sopno ss;      /* start sop of current subRE */
+       register char *sp;      /* start of string matched by it */
+       register sopno ssub;    /* start sop of subsubRE */
+       register sopno esub;    /* end sop of subsubRE */
+       register char *ssp;     /* start of string matched by subsubRE */
+       register char *dp;
+       register size_t len;
+       register int hard;
+       register sop s;
+       register regoff_t offsave;
+       register cset *cs;
+
+       AT("back", start, stop, startst, stopst);
+       sp = start;
+
+       /* get as far as we can with easy stuff */
+       hard = 0;
+       for (ss = startst; !hard && ss < stopst; ss++)
+               switch (OP(s = m->g->strip[ss])) {
+               case OCHAR:
+                       if (sp == stop || *sp++ != (char)OPND(s))
+                               return(NULL);
+                       break;
+               case OANY:
+                       if (sp == stop)
+                               return(NULL);
+                       sp++;
+                       break;
+               case OANYOF:
+                       cs = &m->g->sets[OPND(s)];
+                       if (sp == stop || !CHIN(cs, *sp++))
+                               return(NULL);
+                       break;
+               case OBOL:
+                       if ( (sp == m->beginp && !(m->eflags&REG_NOTBOL)) ||
+                                       (sp < m->endp && *(sp-1) == '\n' &&
+                                               (m->g->cflags&REG_NEWLINE)) )
+                               { /* yes */ }
+                       else
+                               return(NULL);
+                       break;
+               case OEOL:
+                       if ( (sp == m->endp && !(m->eflags&REG_NOTEOL)) ||
+                                       (sp < m->endp && *sp == '\n' &&
+                                               (m->g->cflags&REG_NEWLINE)) )
+                               { /* yes */ }
+                       else
+                               return(NULL);
+                       break;
+               case OBOW:
+                       if (( (sp == m->beginp && !(m->eflags&REG_NOTBOL)) ||
+                                       (sp < m->endp && *(sp-1) == '\n' &&
+                                               (m->g->cflags&REG_NEWLINE)) ||
+                                       (sp > m->beginp &&
+                                                       !ISWORD(*(sp-1))) ) &&
+                                       (sp < m->endp && ISWORD(*sp)) )
+                               { /* yes */ }
+                       else
+                               return(NULL);
+                       break;
+               case OEOW:
+                       if (( (sp == m->endp && !(m->eflags&REG_NOTEOL)) ||
+                                       (sp < m->endp && *sp == '\n' &&
+                                               (m->g->cflags&REG_NEWLINE)) ||
+                                       (sp < m->endp && !ISWORD(*sp)) ) &&
+                                       (sp > m->beginp && ISWORD(*(sp-1))) )
+                               { /* yes */ }
+                       else
+                               return(NULL);
+                       break;
+               case O_QUEST:
+                       break;
+               case OOR1:      /* matches null but needs to skip */
+                       ss++;
+                       s = m->g->strip[ss];
+                       do {
+                               assert(OP(s) == OOR2);
+                               ss += OPND(s);
+                       } while (OP(s = m->g->strip[ss]) != O_CH);
+                       /* note that the ss++ gets us past the O_CH */
+                       break;
+               default:        /* have to make a choice */
+                       hard = 1;
+                       break;
+               }
+       if (!hard) {            /* that was it! */
+               if (sp != stop)
+                       return(NULL);
+               return(sp);
+       }
+       ss--;                   /* adjust for the for's final increment */
+
+       /* the hard stuff */
+       AT("hard", sp, stop, ss, stopst);
+       s = m->g->strip[ss];
+       switch (OP(s)) {
+       case OBACK_:            /* the vilest depths */
+               i = OPND(s);
+               assert(0 < i && i <= m->g->nsub);
+               if (m->pmatch[i].rm_eo == -1)
+                       return(NULL);
+               assert(m->pmatch[i].rm_so != -1);
+               len = m->pmatch[i].rm_eo - m->pmatch[i].rm_so;
+               assert(stop - m->beginp >= len);
+               if (sp > stop - len)
+                       return(NULL);   /* not enough left to match */
+               ssp = m->offp + m->pmatch[i].rm_so;
+               if (memcmp(sp, ssp, len) != 0)
+                       return(NULL);
+               while (m->g->strip[ss] != SOP(O_BACK, i))
+                       ss++;
+               return(backref(m, sp+len, stop, ss+1, stopst, lev));
+               break;
+       case OQUEST_:           /* to null or not */
+               dp = backref(m, sp, stop, ss+1, stopst, lev);
+               if (dp != NULL)
+                       return(dp);     /* not */
+               return(backref(m, sp, stop, ss+OPND(s)+1, stopst, lev));
+               break;
+       case OPLUS_:
+               assert(m->lastpos != NULL);
+               assert(lev+1 <= m->g->nplus);
+               m->lastpos[lev+1] = sp;
+               return(backref(m, sp, stop, ss+1, stopst, lev+1));
+               break;
+       case O_PLUS:
+               if (sp == m->lastpos[lev])      /* last pass matched null */
+                       return(backref(m, sp, stop, ss+1, stopst, lev-1));
+               /* try another pass */
+               m->lastpos[lev] = sp;
+               dp = backref(m, sp, stop, ss-OPND(s)+1, stopst, lev);
+               if (dp == NULL)
+                       return(backref(m, sp, stop, ss+1, stopst, lev-1));
+               else
+                       return(dp);
+               break;
+       case OCH_:              /* find the right one, if any */
+               ssub = ss + 1;
+               esub = ss + OPND(s) - 1;
+               assert(OP(m->g->strip[esub]) == OOR1);
+               for (;;) {      /* find first matching branch */
+                       dp = backref(m, sp, stop, ssub, esub, lev);
+                       if (dp != NULL)
+                               return(dp);
+                       /* that one missed, try next one */
+                       if (OP(m->g->strip[esub]) == O_CH)
+                               return(NULL);   /* there is none */
+                       esub++;
+                       assert(OP(m->g->strip[esub]) == OOR2);
+                       ssub = esub + 1;
+                       esub += OPND(m->g->strip[esub]);
+                       if (OP(m->g->strip[esub]) == OOR2)
+                               esub--;
+                       else
+                               assert(OP(m->g->strip[esub]) == O_CH);
+               }
+               break;
+       case OLPAREN:           /* must undo assignment if rest fails */
+               i = OPND(s);
+               assert(0 < i && i <= m->g->nsub);
+               offsave = m->pmatch[i].rm_so;
+               m->pmatch[i].rm_so = sp - m->offp;
+               dp = backref(m, sp, stop, ss+1, stopst, lev);
+               if (dp != NULL)
+                       return(dp);
+               m->pmatch[i].rm_so = offsave;
+               return(NULL);
+               break;
+       case ORPAREN:           /* must undo assignment if rest fails */
+               i = OPND(s);
+               assert(0 < i && i <= m->g->nsub);
+               offsave = m->pmatch[i].rm_eo;
+               m->pmatch[i].rm_eo = sp - m->offp;
+               dp = backref(m, sp, stop, ss+1, stopst, lev);
+               if (dp != NULL)
+                       return(dp);
+               m->pmatch[i].rm_eo = offsave;
+               return(NULL);
+               break;
+       default:                /* uh oh */
+               assert(nope);
+               break;
+       }
+
+       /* "can't happen" */
+       assert(nope);
+       /* NOTREACHED */
+       return( NULL );
+}
+
+/*
+ - fast - step through the string at top speed
+ == static char *fast(register struct match *m, char *start, \
+ ==    char *stop, sopno startst, sopno stopst);
+ */
+static char *                  /* where tentative match ended, or NULL */
+fast(m, start, stop, startst, stopst)
+register struct match *m;
+char *start;
+char *stop;
+sopno startst;
+sopno stopst;
+{
+       register states st = m->st;
+       register states fresh = m->fresh;
+       register states tmp = m->tmp;
+       register char *p = start;
+       register int c = (start == m->beginp) ? OUT : *(start-1);
+       register int lastc;     /* previous c */
+       register int flagch;
+       register int i;
+       register char *coldp;   /* last p after which no match was underway */
+
+       CLEAR(st);
+       SET1(st, startst);
+       st = step(m->g, startst, stopst, st, NOTHING, st);
+       ASSIGN(fresh, st);
+       SP("start", st, *p);
+       coldp = NULL;
+       for (;;) {
+               /* next character */
+               lastc = c;
+               c = (p == m->endp) ? OUT : *p;
+               if (EQ(st, fresh))
+                       coldp = p;
+
+               /* is there an EOL and/or BOL between lastc and c? */
+               flagch = '\0';
+               i = 0;
+               if ( (lastc == '\n' && m->g->cflags&REG_NEWLINE) ||
+                               (lastc == OUT && !(m->eflags&REG_NOTBOL)) ) {
+                       flagch = BOL;
+                       i = m->g->nbol;
+               }
+               if ( (c == '\n' && m->g->cflags&REG_NEWLINE) ||
+                               (c == OUT && !(m->eflags&REG_NOTEOL)) ) {
+                       flagch = (flagch == BOL) ? BOLEOL : EOL;
+                       i += m->g->neol;
+               }
+               if (i != 0) {
+                       for (; i > 0; i--)
+                               st = step(m->g, startst, stopst, st, flagch, st);
+                       SP("boleol", st, c);
+               }
+
+               /* how about a word boundary? */
+               if ( (flagch == BOL || (lastc != OUT && !ISWORD(lastc))) &&
+                                       (c != OUT && ISWORD(c)) ) {
+                       flagch = BOW;
+               }
+               if ( (lastc != OUT && ISWORD(lastc)) &&
+                               (flagch == EOL || (c != OUT && !ISWORD(c))) ) {
+                       flagch = EOW;
+               }
+               if (flagch == BOW || flagch == EOW) {
+                       st = step(m->g, startst, stopst, st, flagch, st);
+                       SP("boweow", st, c);
+               }
+
+               /* are we done? */
+               if (ISSET(st, stopst) || p == stop)
+                       break;          /* NOTE BREAK OUT */
+
+               /* no, we must deal with this character */
+               ASSIGN(tmp, st);
+               ASSIGN(st, fresh);
+               assert(c != OUT);
+               st = step(m->g, startst, stopst, tmp, c, st);
+               SP("aft", st, c);
+               assert(EQ(step(m->g, startst, stopst, st, NOTHING, st), st));
+               p++;
+       }
+
+       assert(coldp != NULL);
+       m->coldp = coldp;
+       if (ISSET(st, stopst))
+               return(p+1);
+       else
+               return(NULL);
+}
+
+/*
+ - slow - step through the string more deliberately
+ == static char *slow(register struct match *m, char *start, \
+ ==    char *stop, sopno startst, sopno stopst);
+ */
+static char *                  /* where it ended */
+slow(m, start, stop, startst, stopst)
+register struct match *m;
+char *start;
+char *stop;
+sopno startst;
+sopno stopst;
+{
+       register states st = m->st;
+       register states empty = m->empty;
+       register states tmp = m->tmp;
+       register char *p = start;
+       register int c = (start == m->beginp) ? OUT : *(start-1);
+       register int lastc;     /* previous c */
+       register int flagch;
+       register int i;
+       register char *matchp;  /* last p at which a match ended */
+
+       AT("slow", start, stop, startst, stopst);
+       CLEAR(st);
+       SET1(st, startst);
+       SP("sstart", st, *p);
+       st = step(m->g, startst, stopst, st, NOTHING, st);
+       matchp = NULL;
+       for (;;) {
+               /* next character */
+               lastc = c;
+               c = (p == m->endp) ? OUT : *p;
+
+               /* is there an EOL and/or BOL between lastc and c? */
+               flagch = '\0';
+               i = 0;
+               if ( (lastc == '\n' && m->g->cflags&REG_NEWLINE) ||
+                               (lastc == OUT && !(m->eflags&REG_NOTBOL)) ) {
+                       flagch = BOL;
+                       i = m->g->nbol;
+               }
+               if ( (c == '\n' && m->g->cflags&REG_NEWLINE) ||
+                               (c == OUT && !(m->eflags&REG_NOTEOL)) ) {
+                       flagch = (flagch == BOL) ? BOLEOL : EOL;
+                       i += m->g->neol;
+               }
+               if (i != 0) {
+                       for (; i > 0; i--)
+                               st = step(m->g, startst, stopst, st, flagch, st);
+                       SP("sboleol", st, c);
+               }
+
+               /* how about a word boundary? */
+               if ( (flagch == BOL || (lastc != OUT && !ISWORD(lastc))) &&
+                                       (c != OUT && ISWORD(c)) ) {
+                       flagch = BOW;
+               }
+               if ( (lastc != OUT && ISWORD(lastc)) &&
+                               (flagch == EOL || (c != OUT && !ISWORD(c))) ) {
+                       flagch = EOW;
+               }
+               if (flagch == BOW || flagch == EOW) {
+                       st = step(m->g, startst, stopst, st, flagch, st);
+                       SP("sboweow", st, c);
+               }
+
+               /* are we done? */
+               if (ISSET(st, stopst))
+                       matchp = p;
+               if (EQ(st, empty) || p == stop)
+                       break;          /* NOTE BREAK OUT */
+
+               /* no, we must deal with this character */
+               ASSIGN(tmp, st);
+               ASSIGN(st, empty);
+               assert(c != OUT);
+               st = step(m->g, startst, stopst, tmp, c, st);
+               SP("saft", st, c);
+               assert(EQ(step(m->g, startst, stopst, st, NOTHING, st), st));
+               p++;
+       }
+
+       return(matchp);
+}
+
+
+/*
+ - step - map set of states reachable before char to set reachable after
+ == static states step(register struct re_guts *g, sopno start, sopno stop, \
+ ==    register states bef, int ch, register states aft);
+ == #define    BOL     (OUT+1)
+ == #define    EOL     (BOL+1)
+ == #define    BOLEOL  (BOL+2)
+ == #define    NOTHING (BOL+3)
+ == #define    BOW     (BOL+4)
+ == #define    EOW     (BOL+5)
+ == #define    CODEMAX (BOL+5)         // highest code used
+ == #define    NONCHAR(c)      ((c) > CHAR_MAX)
+ == #define    NNONCHAR        (CODEMAX-CHAR_MAX)
+ */
+static states
+step(g, start, stop, bef, ch, aft)
+register struct re_guts *g;
+sopno start;                   /* start state within strip */
+sopno stop;                    /* state after stop state within strip */
+register states bef;           /* states reachable before */
+int ch;                                /* character or NONCHAR code */
+register states aft;           /* states already known reachable after */
+{
+       register cset *cs;
+       register sop s;
+       register sopno pc;
+       register onestate here;         /* note, macros know this name */
+       register sopno look;
+       register int i;
+
+       for (pc = start, INIT(here, pc); pc != stop; pc++, INC(here)) {
+               s = g->strip[pc];
+               switch (OP(s)) {
+               case OEND:
+                       assert(pc == stop-1);
+                       break;
+               case OCHAR:
+                       /* only characters can match */
+                       assert(!NONCHAR(ch) || ch != (char)OPND(s));
+                       if (ch == (char)OPND(s))
+                               FWD(aft, bef, 1);
+                       break;
+               case OBOL:
+                       if (ch == BOL || ch == BOLEOL)
+                               FWD(aft, bef, 1);
+                       break;
+               case OEOL:
+                       if (ch == EOL || ch == BOLEOL)
+                               FWD(aft, bef, 1);
+                       break;
+               case OBOW:
+                       if (ch == BOW)
+                               FWD(aft, bef, 1);
+                       break;
+               case OEOW:
+                       if (ch == EOW)
+                               FWD(aft, bef, 1);
+                       break;
+               case OANY:
+                       if (!NONCHAR(ch))
+                               FWD(aft, bef, 1);
+                       break;
+               case OANYOF:
+                       cs = &g->sets[OPND(s)];
+                       if (!NONCHAR(ch) && CHIN(cs, ch))
+                               FWD(aft, bef, 1);
+                       break;
+               case OBACK_:            /* ignored here */
+               case O_BACK:
+                       FWD(aft, aft, 1);
+                       break;
+               case OPLUS_:            /* forward, this is just an empty */
+                       FWD(aft, aft, 1);
+                       break;
+               case O_PLUS:            /* both forward and back */
+                       FWD(aft, aft, 1);
+                       i = ISSETBACK(aft, OPND(s));
+                       BACK(aft, aft, OPND(s));
+                       if (!i && ISSETBACK(aft, OPND(s))) {
+                               /* oho, must reconsider loop body */
+                               pc -= OPND(s) + 1;
+                               INIT(here, pc);
+                       }
+                       break;
+               case OQUEST_:           /* two branches, both forward */
+                       FWD(aft, aft, 1);
+                       FWD(aft, aft, OPND(s));
+                       break;
+               case O_QUEST:           /* just an empty */
+                       FWD(aft, aft, 1);
+                       break;
+               case OLPAREN:           /* not significant here */
+               case ORPAREN:
+                       FWD(aft, aft, 1);
+                       break;
+               case OCH_:              /* mark the first two branches */
+                       FWD(aft, aft, 1);
+                       assert(OP(g->strip[pc+OPND(s)]) == OOR2);
+                       FWD(aft, aft, OPND(s));
+                       break;
+               case OOR1:              /* done a branch, find the O_CH */
+                       if (ISSTATEIN(aft, here)) {
+                               for (look = 1;
+                                               OP(s = g->strip[pc+look]) != O_CH;
+                                               look += OPND(s))
+                                       assert(OP(s) == OOR2);
+                               FWD(aft, aft, look);
+                       }
+                       break;
+               case OOR2:              /* propagate OCH_'s marking */
+                       FWD(aft, aft, 1);
+                       if (OP(g->strip[pc+OPND(s)]) != O_CH) {
+                               assert(OP(g->strip[pc+OPND(s)]) == OOR2);
+                               FWD(aft, aft, OPND(s));
+                       }
+                       break;
+               case O_CH:              /* just empty */
+                       FWD(aft, aft, 1);
+                       break;
+               default:                /* ooooops... */
+                       assert(nope);
+                       break;
+               }
+       }
+
+       return(aft);
+}
+
+#ifdef REDEBUG
+/*
+ - print - print a set of states
+ == #ifdef REDEBUG
+ == static void print(struct match *m, char *caption, states st, \
+ ==    int ch, FILE *d);
+ == #endif
+ */
+static void
+print(m, caption, st, ch, d)
+struct match *m;
+char *caption;
+states st;
+int ch;
+FILE *d;
+{
+       register struct re_guts *g = m->g;
+       register int i;
+       register int first = 1;
+
+       if (!(m->eflags&REG_TRACE))
+               return;
+
+       fprintf(d, "%s", caption);
+       if (ch != '\0')
+               fprintf(d, " %s", pchar(ch));
+       for (i = 0; i < g->nstates; i++)
+               if (ISSET(st, i)) {
+                       fprintf(d, "%s%d", (first) ? "\t" : ", ", i);
+                       first = 0;
+               }
+       fprintf(d, "\n");
+}
+
+/* 
+ - at - print current situation
+ == #ifdef REDEBUG
+ == static void at(struct match *m, char *title, char *start, char *stop, \
+ ==                                            sopno startst, sopno stopst);
+ == #endif
+ */
+static void
+at(m, title, start, stop, startst, stopst)
+struct match *m;
+char *title;
+char *start;
+char *stop;
+sopno startst;
+sopno stopst;
+{
+       if (!(m->eflags&REG_TRACE))
+               return;
+
+       printf("%s %s-", title, pchar(*start));
+       printf("%s ", pchar(*stop));
+       printf("%ld-%ld\n", (long)startst, (long)stopst);
+}
+
+#ifndef PCHARDONE
+#define        PCHARDONE       /* never again */
+/*
+ - pchar - make a character printable
+ == #ifdef REDEBUG
+ == static char *pchar(int ch);
+ == #endif
+ *
+ * Is this identical to regchar() over in debug.c?  Well, yes.  But a
+ * duplicate here avoids having a debugging-capable regexec.o tied to
+ * a matching debug.o, and this is convenient.  It all disappears in
+ * the non-debug compilation anyway, so it doesn't matter much.
+ */
+static char *                  /* -> representation */
+pchar(ch)
+int ch;
+{
+       static char pbuf[10];
+
+       if (isprint(ch) || ch == ' ')
+               sprintf(pbuf, "%c", ch);
+       else
+               sprintf(pbuf, "\\%o", ch);
+       return(pbuf);
+}
+#endif
+#endif
+
+#undef matcher
+#undef fast
+#undef slow
+#undef dissect
+#undef backref
+#undef step
+#undef print
+#undef at
+#undef match
diff --git a/APACHE_1_2_X/src/regex/main.c b/APACHE_1_2_X/src/regex/main.c
new file mode 100644 (file)
index 0000000..657338a
--- /dev/null
@@ -0,0 +1,510 @@
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <regex.h>
+#include <assert.h>
+#include <stdlib.h>
+
+#include "main.ih"
+
+char *progname;
+int debug = 0;
+int line = 0;
+int status = 0;
+
+int copts = REG_EXTENDED;
+int eopts = 0;
+regoff_t startoff = 0;
+regoff_t endoff = 0;
+
+
+extern int split();
+extern void regprint();
+
+/*
+ - main - do the simple case, hand off to regress() for regression
+ */
+int main(argc, argv)
+int argc;
+char *argv[];
+{
+       regex_t re;
+#      define  NS      10
+       regmatch_t subs[NS];
+       char erbuf[100];
+       int err;
+       size_t len;
+       int c;
+       int errflg = 0;
+       register int i;
+       extern int optind;
+       extern char *optarg;
+
+       progname = argv[0];
+
+       while ((c = getopt(argc, argv, "c:e:S:E:x")) != EOF)
+               switch (c) {
+               case 'c':       /* compile options */
+                       copts = options('c', optarg);
+                       break;
+               case 'e':       /* execute options */
+                       eopts = options('e', optarg);
+                       break;
+               case 'S':       /* start offset */
+                       startoff = (regoff_t)atoi(optarg);
+                       break;
+               case 'E':       /* end offset */
+                       endoff = (regoff_t)atoi(optarg);
+                       break;
+               case 'x':       /* Debugging. */
+                       debug++;
+                       break;
+               case '?':
+               default:
+                       errflg++;
+                       break;
+               }
+       if (errflg) {
+               fprintf(stderr, "usage: %s ", progname);
+               fprintf(stderr, "[-c copt][-C][-d] [re]\n");
+               exit(2);
+       }
+
+       if (optind >= argc) {
+               regress(stdin);
+               exit(status);
+       }
+
+       err = regcomp(&re, argv[optind++], copts);
+       if (err) {
+               len = regerror(err, &re, erbuf, sizeof(erbuf));
+               fprintf(stderr, "error %s, %d/%d `%s'\n",
+                       eprint(err), len, sizeof(erbuf), erbuf);
+               exit(status);
+       }
+       regprint(&re, stdout);  
+
+       if (optind >= argc) {
+               regfree(&re);
+               exit(status);
+       }
+
+       if (eopts&REG_STARTEND) {
+               subs[0].rm_so = startoff;
+               subs[0].rm_eo = strlen(argv[optind]) - endoff;
+       }
+       err = regexec(&re, argv[optind], (size_t)NS, subs, eopts);
+       if (err) {
+               len = regerror(err, &re, erbuf, sizeof(erbuf));
+               fprintf(stderr, "error %s, %d/%d `%s'\n",
+                       eprint(err), len, sizeof(erbuf), erbuf);
+               exit(status);
+       }
+       if (!(copts&REG_NOSUB)) {
+               len = (int)(subs[0].rm_eo - subs[0].rm_so);
+               if (subs[0].rm_so != -1) {
+                       if (len != 0)
+                               printf("match `%.*s'\n", (int)len,
+                                       argv[optind] + subs[0].rm_so);
+                       else
+                               printf("match `'@%.1s\n",
+                                       argv[optind] + subs[0].rm_so);
+               }
+               for (i = 1; i < NS; i++)
+                       if (subs[i].rm_so != -1)
+                               printf("(%d) `%.*s'\n", i,
+                                       (int)(subs[i].rm_eo - subs[i].rm_so),
+                                       argv[optind] + subs[i].rm_so);
+       }
+       exit(status);
+}
+
+/*
+ - regress - main loop of regression test
+ == void regress(FILE *in);
+ */
+void
+regress(in)
+FILE *in;
+{
+       char inbuf[1000];
+#      define  MAXF    10
+       char *f[MAXF];
+       int nf;
+       int i;
+       char erbuf[100];
+       size_t ne;
+       char *badpat = "invalid regular expression";
+#      define  SHORT   10
+       char *bpname = "REG_BADPAT";
+       regex_t re;
+
+       while (fgets(inbuf, sizeof(inbuf), in) != NULL) {
+               line++;
+               if (inbuf[0] == '#' || inbuf[0] == '\n')
+                       continue;                       /* NOTE CONTINUE */
+               inbuf[strlen(inbuf)-1] = '\0';  /* get rid of stupid \n */
+               if (debug)
+                       fprintf(stdout, "%d:\n", line);
+               nf = split(inbuf, f, MAXF, "\t\t");
+               if (nf < 3) {
+                       fprintf(stderr, "bad input, line %d\n", line);
+                       exit(1);
+               }
+               for (i = 0; i < nf; i++)
+                       if (strcmp(f[i], "\"\"") == 0)
+                               f[i] = "";
+               if (nf <= 3)
+                       f[3] = NULL;
+               if (nf <= 4)
+                       f[4] = NULL;
+               try(f[0], f[1], f[2], f[3], f[4], options('c', f[1]));
+               if (opt('&', f[1]))     /* try with either type of RE */
+                       try(f[0], f[1], f[2], f[3], f[4],
+                                       options('c', f[1]) &~ REG_EXTENDED);
+       }
+
+       ne = regerror(REG_BADPAT, (regex_t *)NULL, erbuf, sizeof(erbuf));
+       if (strcmp(erbuf, badpat) != 0 || ne != strlen(badpat)+1) {
+               fprintf(stderr, "end: regerror() test gave `%s' not `%s'\n",
+                                                       erbuf, badpat);
+               status = 1;
+       }
+       ne = regerror(REG_BADPAT, (regex_t *)NULL, erbuf, (size_t)SHORT);
+       if (strncmp(erbuf, badpat, SHORT-1) != 0 || erbuf[SHORT-1] != '\0' ||
+                                               ne != strlen(badpat)+1) {
+               fprintf(stderr, "end: regerror() short test gave `%s' not `%.*s'\n",
+                                               erbuf, SHORT-1, badpat);
+               status = 1;
+       }
+       ne = regerror(REG_ITOA|REG_BADPAT, (regex_t *)NULL, erbuf, sizeof(erbuf));
+       if (strcmp(erbuf, bpname) != 0 || ne != strlen(bpname)+1) {
+               fprintf(stderr, "end: regerror() ITOA test gave `%s' not `%s'\n",
+                                               erbuf, bpname);
+               status = 1;
+       }
+       re.re_endp = bpname;
+       ne = regerror(REG_ATOI, &re, erbuf, sizeof(erbuf));
+       if (atoi(erbuf) != (int)REG_BADPAT) {
+               fprintf(stderr, "end: regerror() ATOI test gave `%s' not `%ld'\n",
+                                               erbuf, (long)REG_BADPAT);
+               status = 1;
+       } else if (ne != strlen(erbuf)+1) {
+               fprintf(stderr, "end: regerror() ATOI test len(`%s') = %ld\n",
+                                               erbuf, (long)REG_BADPAT);
+               status = 1;
+       }
+}
+
+/*
+ - try - try it, and report on problems
+ == void try(char *f0, char *f1, char *f2, char *f3, char *f4, int opts);
+ */
+void
+try(f0, f1, f2, f3, f4, opts)
+char *f0;
+char *f1;
+char *f2;
+char *f3;
+char *f4;
+int opts;                      /* may not match f1 */
+{
+       regex_t re;
+#      define  NSUBS   10
+       regmatch_t subs[NSUBS];
+#      define  NSHOULD 15
+       char *should[NSHOULD];
+       int nshould;
+       char erbuf[100];
+       int err;
+       int len;
+       char *type = (opts & REG_EXTENDED) ? "ERE" : "BRE";
+       register int i;
+       char *grump;
+       char f0copy[1000];
+       char f2copy[1000];
+
+       strcpy(f0copy, f0);
+       re.re_endp = (opts&REG_PEND) ? f0copy + strlen(f0copy) : NULL;
+       fixstr(f0copy);
+       err = regcomp(&re, f0copy, opts);
+       if (err != 0 && (!opt('C', f1) || err != efind(f2))) {
+               /* unexpected error or wrong error */
+               len = regerror(err, &re, erbuf, sizeof(erbuf));
+               fprintf(stderr, "%d: %s error %s, %d/%d `%s'\n",
+                                       line, type, eprint(err), len,
+                                       sizeof(erbuf), erbuf);
+               status = 1;
+       } else if (err == 0 && opt('C', f1)) {
+               /* unexpected success */
+               fprintf(stderr, "%d: %s should have given REG_%s\n",
+                                               line, type, f2);
+               status = 1;
+               err = 1;        /* so we won't try regexec */
+       }
+
+       if (err != 0) {
+               regfree(&re);
+               return;
+       }
+
+       strcpy(f2copy, f2);
+       fixstr(f2copy);
+
+       if (options('e', f1)&REG_STARTEND) {
+               if (strchr(f2, '(') == NULL || strchr(f2, ')') == NULL)
+                       fprintf(stderr, "%d: bad STARTEND syntax\n", line);
+               subs[0].rm_so = strchr(f2, '(') - f2 + 1;
+               subs[0].rm_eo = strchr(f2, ')') - f2;
+       }
+       err = regexec(&re, f2copy, NSUBS, subs, options('e', f1));
+
+       if (err != 0 && (f3 != NULL || err != REG_NOMATCH)) {
+               /* unexpected error or wrong error */
+               len = regerror(err, &re, erbuf, sizeof(erbuf));
+               fprintf(stderr, "%d: %s exec error %s, %d/%d `%s'\n",
+                                       line, type, eprint(err), len,
+                                       sizeof(erbuf), erbuf);
+               status = 1;
+       } else if (err != 0) {
+               /* nothing more to check */
+       } else if (f3 == NULL) {
+               /* unexpected success */
+               fprintf(stderr, "%d: %s exec should have failed\n",
+                                               line, type);
+               status = 1;
+               err = 1;                /* just on principle */
+       } else if (opts&REG_NOSUB) {
+               /* nothing more to check */
+       } else if ((grump = check(f2, subs[0], f3)) != NULL) {
+               fprintf(stderr, "%d: %s %s\n", line, type, grump);
+               status = 1;
+               err = 1;
+       }
+
+       if (err != 0 || f4 == NULL) {
+               regfree(&re);
+               return;
+       }
+
+       for (i = 1; i < NSHOULD; i++)
+               should[i] = NULL;
+       nshould = split(f4, should+1, NSHOULD-1, ",");
+       if (nshould == 0) {
+               nshould = 1;
+               should[1] = "";
+       }
+       for (i = 1; i < NSUBS; i++) {
+               grump = check(f2, subs[i], should[i]);
+               if (grump != NULL) {
+                       fprintf(stderr, "%d: %s $%d %s\n", line,
+                                                       type, i, grump);
+                       status = 1;
+                       err = 1;
+               }
+       }
+
+       regfree(&re);
+}
+
+/*
+ - options - pick options out of a regression-test string
+ == int options(int type, char *s);
+ */
+int
+options(type, s)
+int type;                      /* 'c' compile, 'e' exec */
+char *s;
+{
+       register char *p;
+       register int o = (type == 'c') ? copts : eopts;
+       register char *legal = (type == 'c') ? "bisnmp" : "^$#tl";
+
+       for (p = s; *p != '\0'; p++)
+               if (strchr(legal, *p) != NULL)
+                       switch (*p) {
+                       case 'b':
+                               o &= ~REG_EXTENDED;
+                               break;
+                       case 'i':
+                               o |= REG_ICASE;
+                               break;
+                       case 's':
+                               o |= REG_NOSUB;
+                               break;
+                       case 'n':
+                               o |= REG_NEWLINE;
+                               break;
+                       case 'm':
+                               o &= ~REG_EXTENDED;
+                               o |= REG_NOSPEC;
+                               break;
+                       case 'p':
+                               o |= REG_PEND;
+                               break;
+                       case '^':
+                               o |= REG_NOTBOL;
+                               break;
+                       case '$':
+                               o |= REG_NOTEOL;
+                               break;
+                       case '#':
+                               o |= REG_STARTEND;
+                               break;
+                       case 't':       /* trace */
+                               o |= REG_TRACE;
+                               break;
+                       case 'l':       /* force long representation */
+                               o |= REG_LARGE;
+                               break;
+                       case 'r':       /* force backref use */
+                               o |= REG_BACKR;
+                               break;
+                       }
+       return(o);
+}
+
+/*
+ - opt - is a particular option in a regression string?
+ == int opt(int c, char *s);
+ */
+int                            /* predicate */
+opt(c, s)
+int c;
+char *s;
+{
+       return(strchr(s, c) != NULL);
+}
+
+/*
+ - fixstr - transform magic characters in strings
+ == void fixstr(register char *p);
+ */
+void
+fixstr(p)
+register char *p;
+{
+       if (p == NULL)
+               return;
+
+       for (; *p != '\0'; p++)
+               if (*p == 'N')
+                       *p = '\n';
+               else if (*p == 'T')
+                       *p = '\t';
+               else if (*p == 'S')
+                       *p = ' ';
+               else if (*p == 'Z')
+                       *p = '\0';
+}
+
+/*
+ - check - check a substring match
+ == char *check(char *str, regmatch_t sub, char *should);
+ */
+char *                         /* NULL or complaint */
+check(str, sub, should)
+char *str;
+regmatch_t sub;
+char *should;
+{
+       register int len;
+       register int shlen;
+       register char *p;
+       static char grump[500];
+       register char *at = NULL;
+
+       if (should != NULL && strcmp(should, "-") == 0)
+               should = NULL;
+       if (should != NULL && should[0] == '@') {
+               at = should + 1;
+               should = "";
+       }
+
+       /* check rm_so and rm_eo for consistency */
+       if (sub.rm_so > sub.rm_eo || (sub.rm_so == -1 && sub.rm_eo != -1) ||
+                               (sub.rm_so != -1 && sub.rm_eo == -1) ||
+                               (sub.rm_so != -1 && sub.rm_so < 0) ||
+                               (sub.rm_eo != -1 && sub.rm_eo < 0) ) {
+               sprintf(grump, "start %ld end %ld", (long)sub.rm_so,
+                                                       (long)sub.rm_eo);
+               return(grump);
+       }
+
+       /* check for no match */
+       if (sub.rm_so == -1 && should == NULL)
+               return(NULL);
+       if (sub.rm_so == -1)
+               return("did not match");
+
+       /* check for in range */
+       if (sub.rm_eo > strlen(str)) {
+               sprintf(grump, "start %ld end %ld, past end of string",
+                                       (long)sub.rm_so, (long)sub.rm_eo);
+               return(grump);
+       }
+
+       len = (int)(sub.rm_eo - sub.rm_so);
+       shlen = (int)strlen(should);
+       p = str + sub.rm_so;
+
+       /* check for not supposed to match */
+       if (should == NULL) {
+               sprintf(grump, "matched `%.*s'", len, p);
+               return(grump);
+       }
+
+       /* check for wrong match */
+       if (len != shlen || strncmp(p, should, (size_t)shlen) != 0) {
+               sprintf(grump, "matched `%.*s' instead", len, p);
+               return(grump);
+       }
+       if (shlen > 0)
+               return(NULL);
+
+       /* check null match in right place */
+       if (at == NULL)
+               return(NULL);
+       shlen = strlen(at);
+       if (shlen == 0)
+               shlen = 1;      /* force check for end-of-string */
+       if (strncmp(p, at, shlen) != 0) {
+               sprintf(grump, "matched null at `%.20s'", p);
+               return(grump);
+       }
+       return(NULL);
+}
+
+/*
+ - eprint - convert error number to name
+ == static char *eprint(int err);
+ */
+static char *
+eprint(err)
+int err;
+{
+       static char epbuf[100];
+       size_t len;
+
+       len = regerror(REG_ITOA|err, (regex_t *)NULL, epbuf, sizeof(epbuf));
+       assert(len <= sizeof(epbuf));
+       return(epbuf);
+}
+
+/*
+ - efind - convert error name to number
+ == static int efind(char *name);
+ */
+static int
+efind(name)
+char *name;
+{
+       static char efbuf[100];
+       regex_t re;
+
+       sprintf(efbuf, "REG_%s", name);
+       assert(strlen(efbuf) < sizeof(efbuf));
+       re.re_endp = efbuf;
+       (void) regerror(REG_ATOI, &re, efbuf, sizeof(efbuf));
+       return(atoi(efbuf));
+}
diff --git a/APACHE_1_2_X/src/regex/mkh b/APACHE_1_2_X/src/regex/mkh
new file mode 100644 (file)
index 0000000..252b246
--- /dev/null
@@ -0,0 +1,76 @@
+#! /bin/sh
+# mkh - pull headers out of C source
+PATH=/bin:/usr/bin ; export PATH
+
+# egrep pattern to pick out marked lines
+egrep='^ =([   ]|$)'
+
+# Sed program to process marked lines into lines for the header file.
+# The markers have already been removed.  Two things are done here:  removal
+# of backslashed newlines, and some fudging of comments.  The first is done
+# because -o needs to have prototypes on one line to strip them down.
+# Getting comments into the output is tricky; we turn C++-style // comments
+# into /* */ comments, after altering any existing */'s to avoid trouble.
+peel=' /\\$/N
+       /\\\n[  ]*/s///g
+       /\/\//s;\*/;* /;g
+       /\/\//s;//\(.*\);/*\1 */;'
+
+for a
+do
+       case "$a" in
+       -o)     # old (pre-function-prototype) compiler
+               # add code to comment out argument lists
+               peel="$peel
+                       "'/^\([^#\/][^\/]*[a-zA-Z0-9_)]\)(\(.*\))/s;;\1(/*\2*/);'
+               shift
+               ;;
+       -b)     # funny Berkeley __P macro
+               peel="$peel
+                       "'/^\([^#\/][^\/]*[a-zA-Z0-9_)]\)(\(.*\))/s;;\1 __P((\2));'
+               shift
+               ;;
+       -s)     # compiler doesn't like `static foo();'
+               # add code to get rid of the `static'
+               peel="$peel
+                       "'/^static[     ][^\/]*[a-zA-Z0-9_)](.*)/s;static.;;'
+               shift
+               ;;
+       -p)     # private declarations
+               egrep='^ ==([   ]|$)'
+               shift
+               ;;
+       -i)     # wrap in #ifndef, argument is name
+               ifndef="$2"
+               shift ; shift
+               ;;
+       *)      break
+               ;;
+       esac
+done
+
+if test " $ifndef" != " "
+then
+       echo "#ifndef $ifndef"
+       echo "#define   $ifndef /* never again */"
+fi
+echo "/* ========= begin header generated by $0 ========= */"
+echo '#ifdef __cplusplus'
+echo 'extern "C" {'
+echo '#endif'
+for f
+do
+       echo
+       echo "/* === $f === */"
+       egrep "$egrep" $f | sed 's/^ ==*[       ]//;s/^ ==*$//' | sed "$peel"
+       echo
+done
+echo '#ifdef __cplusplus'
+echo '}'
+echo '#endif'
+echo "/* ========= end header generated by $0 ========= */"
+if test " $ifndef" != " "
+then
+       echo "#endif"
+fi
+exit 0
diff --git a/APACHE_1_2_X/src/regex/regcomp.c b/APACHE_1_2_X/src/regex/regcomp.c
new file mode 100644 (file)
index 0000000..c3a7b1a
--- /dev/null
@@ -0,0 +1,1546 @@
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <regex.h>
+
+#include "utils.h"
+#include "regex2.h"
+
+#include "cclass.h"
+#include "cname.h"
+
+/*
+ * parse structure, passed up and down to avoid global variables and
+ * other clumsinesses
+ */
+struct parse {
+       char *next;             /* next character in RE */
+       char *end;              /* end of string (-> NUL normally) */
+       int error;              /* has an error been seen? */
+       sop *strip;             /* malloced strip */
+       sopno ssize;            /* malloced strip size (allocated) */
+       sopno slen;             /* malloced strip length (used) */
+       int ncsalloc;           /* number of csets allocated */
+       struct re_guts *g;
+#      define  NPAREN  10      /* we need to remember () 1-9 for back refs */
+       sopno pbegin[NPAREN];   /* -> ( ([0] unused) */
+       sopno pend[NPAREN];     /* -> ) ([0] unused) */
+};
+
+#include "regcomp.ih"
+
+static char nuls[10];          /* place to point scanner in event of error */
+
+/*
+ * macros for use with parse structure
+ * BEWARE:  these know that the parse structure is named `p' !!!
+ */
+#define        PEEK()  (*p->next)
+#define        PEEK2() (*(p->next+1))
+#define        MORE()  (p->next < p->end)
+#define        MORE2() (p->next+1 < p->end)
+#define        SEE(c)  (MORE() && PEEK() == (c))
+#define        SEETWO(a, b)    (MORE() && MORE2() && PEEK() == (a) && PEEK2() == (b))
+#define        EAT(c)  ((SEE(c)) ? (NEXT1(), 1) : 0)
+#define        EATTWO(a, b)    ((SEETWO(a, b)) ? (NEXT2(), 1) : 0)
+#define        NEXT1() (p->next++)
+#define        NEXT2() (p->next += 2)
+#define        NEXTn(n)        (p->next += (n))
+#define        GETNEXT()       (*p->next++)
+#define        SETERROR(e)     seterr(p, (e))
+#define        REQUIRE(co, e)  ((void)((co) || SETERROR(e)))
+#define        MUSTSEE(c, e)   (REQUIRE(MORE() && PEEK() == (c), e))
+#define        MUSTEAT(c, e)   (REQUIRE(MORE() && GETNEXT() == (c), e))
+#define        MUSTNOTSEE(c, e)        (REQUIRE(!MORE() || PEEK() != (c), e))
+#define        EMIT(op, sopnd) doemit(p, (sop)(op), (size_t)(sopnd))
+#define        INSERT(op, pos) doinsert(p, (sop)(op), HERE()-(pos)+1, pos)
+#define        AHEAD(pos)              dofwd(p, pos, HERE()-(pos))
+#define        ASTERN(sop, pos)        EMIT(sop, HERE()-pos)
+#define        HERE()          (p->slen)
+#define        THERE()         (p->slen - 1)
+#define        THERETHERE()    (p->slen - 2)
+#define        DROP(n) (p->slen -= (n))
+
+#ifndef NDEBUG
+static int never = 0;          /* for use in asserts; shuts lint up */
+#else
+#define        never   0               /* some <assert.h>s have bugs too */
+#endif
+
+/*
+ - regcomp - interface for parser and compilation
+ = extern int regcomp(regex_t *, const char *, int);
+ = #define     REG_BASIC       0000
+ = #define     REG_EXTENDED    0001
+ = #define     REG_ICASE       0002
+ = #define     REG_NOSUB       0004
+ = #define     REG_NEWLINE     0010
+ = #define     REG_NOSPEC      0020
+ = #define     REG_PEND        0040
+ = #define     REG_DUMP        0200
+ */
+int                            /* 0 success, otherwise REG_something */
+regcomp(preg, pattern, cflags)
+regex_t *preg;
+const char *pattern;
+int cflags;
+{
+       struct parse pa;
+       register struct re_guts *g;
+       register struct parse *p = &pa;
+       register int i;
+       register size_t len;
+#ifdef REDEBUG
+#      define  GOODFLAGS(f)    (f)
+#else
+#      define  GOODFLAGS(f)    ((f)&~REG_DUMP)
+#endif
+
+       cflags = GOODFLAGS(cflags);
+       if ((cflags&REG_EXTENDED) && (cflags&REG_NOSPEC))
+               return(REG_INVARG);
+
+       if (cflags&REG_PEND) {
+               if (preg->re_endp < pattern)
+                       return(REG_INVARG);
+               len = preg->re_endp - pattern;
+       } else
+               len = strlen((char *)pattern);
+
+       /* do the mallocs early so failure handling is easy */
+       g = (struct re_guts *)malloc(sizeof(struct re_guts) +
+                                                       (NC-1)*sizeof(cat_t));
+       if (g == NULL)
+               return(REG_ESPACE);
+       p->ssize = len/(size_t)2*(size_t)3 + (size_t)1; /* ugh */
+       p->strip = (sop *)malloc(p->ssize * sizeof(sop));
+       p->slen = 0;
+       if (p->strip == NULL) {
+               free((char *)g);
+               return(REG_ESPACE);
+       }
+
+       /* set things up */
+       p->g = g;
+       p->next = (char *)pattern;      /* convenience; we do not modify it */
+       p->end = p->next + len;
+       p->error = 0;
+       p->ncsalloc = 0;
+       for (i = 0; i < NPAREN; i++) {
+               p->pbegin[i] = 0;
+               p->pend[i] = 0;
+       }
+       g->csetsize = NC;
+       g->sets = NULL;
+       g->setbits = NULL;
+       g->ncsets = 0;
+       g->cflags = cflags;
+       g->iflags = 0;
+       g->nbol = 0;
+       g->neol = 0;
+       g->must = NULL;
+       g->mlen = 0;
+       g->nsub = 0;
+       g->ncategories = 1;     /* category 0 is "everything else" */
+       g->categories = &g->catspace[-(CHAR_MIN)];
+       (void) memset((char *)g->catspace, 0, NC*sizeof(cat_t));
+       g->backrefs = 0;
+
+       /* do it */
+       EMIT(OEND, 0);
+       g->firststate = THERE();
+       if (cflags&REG_EXTENDED)
+               p_ere(p, OUT);
+       else if (cflags&REG_NOSPEC)
+               p_str(p);
+       else
+               p_bre(p, OUT, OUT);
+       EMIT(OEND, 0);
+       g->laststate = THERE();
+
+       /* tidy up loose ends and fill things in */
+       categorize(p, g);
+       stripsnug(p, g);
+       findmust(p, g);
+       g->nplus = pluscount(p, g);
+       g->magic = MAGIC2;
+       preg->re_nsub = g->nsub;
+       preg->re_g = g;
+       preg->re_magic = MAGIC1;
+#ifndef REDEBUG
+       /* not debugging, so can't rely on the assert() in regexec() */
+       if (g->iflags&BAD)
+               SETERROR(REG_ASSERT);
+#endif
+
+       /* win or lose, we're done */
+       if (p->error != 0)      /* lose */
+               regfree(preg);
+       return(p->error);
+}
+
+/*
+ - p_ere - ERE parser top level, concatenation and alternation
+ == static void p_ere(register struct parse *p, int stop);
+ */
+static void
+p_ere(p, stop)
+register struct parse *p;
+int stop;                      /* character this ERE should end at */
+{
+       register char c;
+       register sopno prevback = 0;
+       register sopno prevfwd = 0;
+       register sopno conc;
+       register int first = 1;         /* is this the first alternative? */
+
+       for (;;) {
+               /* do a bunch of concatenated expressions */
+               conc = HERE();
+               while (MORE() && (c = PEEK()) != '|' && c != stop)
+                       p_ere_exp(p);
+               REQUIRE(HERE() != conc, REG_EMPTY);     /* require nonempty */
+
+               if (!EAT('|'))
+                       break;          /* NOTE BREAK OUT */
+
+               if (first) {
+                       INSERT(OCH_, conc);     /* offset is wrong */
+                       prevfwd = conc;
+                       prevback = conc;
+                       first = 0;
+               }
+               ASTERN(OOR1, prevback);
+               prevback = THERE();
+               AHEAD(prevfwd);                 /* fix previous offset */
+               prevfwd = HERE();
+               EMIT(OOR2, 0);                  /* offset is very wrong */
+       }
+
+       if (!first) {           /* tail-end fixups */
+               AHEAD(prevfwd);
+               ASTERN(O_CH, prevback);
+       }
+
+       assert(!MORE() || SEE(stop));
+}
+
+/*
+ - p_ere_exp - parse one subERE, an atom possibly followed by a repetition op
+ == static void p_ere_exp(register struct parse *p);
+ */
+static void
+p_ere_exp(p)
+register struct parse *p;
+{
+       register char c;
+       register sopno pos;
+       register int count;
+       register int count2;
+       register sopno subno;
+       int wascaret = 0;
+
+       assert(MORE());         /* caller should have ensured this */
+       c = GETNEXT();
+
+       pos = HERE();
+       switch (c) {
+       case '(':
+               REQUIRE(MORE(), REG_EPAREN);
+               p->g->nsub++;
+               subno = p->g->nsub;
+               if (subno < NPAREN)
+                       p->pbegin[subno] = HERE();
+               EMIT(OLPAREN, subno);
+               if (!SEE(')'))
+                       p_ere(p, ')');
+               if (subno < NPAREN) {
+                       p->pend[subno] = HERE();
+                       assert(p->pend[subno] != 0);
+               }
+               EMIT(ORPAREN, subno);
+               MUSTEAT(')', REG_EPAREN);
+               break;
+#ifndef POSIX_MISTAKE
+       case ')':               /* happens only if no current unmatched ( */
+               /*
+                * You may ask, why the ifndef?  Because I didn't notice
+                * this until slightly too late for 1003.2, and none of the
+                * other 1003.2 regular-expression reviewers noticed it at
+                * all.  So an unmatched ) is legal POSIX, at least until
+                * we can get it fixed.
+                */
+               SETERROR(REG_EPAREN);
+               break;
+#endif
+       case '^':
+               EMIT(OBOL, 0);
+               p->g->iflags |= USEBOL;
+               p->g->nbol++;
+               wascaret = 1;
+               break;
+       case '$':
+               EMIT(OEOL, 0);
+               p->g->iflags |= USEEOL;
+               p->g->neol++;
+               break;
+       case '|':
+               SETERROR(REG_EMPTY);
+               break;
+       case '*':
+       case '+':
+       case '?':
+               SETERROR(REG_BADRPT);
+               break;
+       case '.':
+               if (p->g->cflags&REG_NEWLINE)
+                       nonnewline(p);
+               else
+                       EMIT(OANY, 0);
+               break;
+       case '[':
+               p_bracket(p);
+               break;
+       case '\\':
+               REQUIRE(MORE(), REG_EESCAPE);
+               c = GETNEXT();
+               ordinary(p, c);
+               break;
+       case '{':               /* okay as ordinary except if digit follows */
+               REQUIRE(!MORE() || !isdigit(PEEK()), REG_BADRPT);
+               /* FALLTHROUGH */
+       default:
+               ordinary(p, c);
+               break;
+       }
+
+       if (!MORE())
+               return;
+       c = PEEK();
+       /* we call { a repetition if followed by a digit */
+       if (!( c == '*' || c == '+' || c == '?' ||
+                               (c == '{' && MORE2() && isdigit(PEEK2())) ))
+               return;         /* no repetition, we're done */
+       NEXT1();
+
+       REQUIRE(!wascaret, REG_BADRPT);
+       switch (c) {
+       case '*':       /* implemented as +? */
+               /* this case does not require the (y|) trick, noKLUDGE */
+               INSERT(OPLUS_, pos);
+               ASTERN(O_PLUS, pos);
+               INSERT(OQUEST_, pos);
+               ASTERN(O_QUEST, pos);
+               break;
+       case '+':
+               INSERT(OPLUS_, pos);
+               ASTERN(O_PLUS, pos);
+               break;
+       case '?':
+               /* KLUDGE: emit y? as (y|) until subtle bug gets fixed */
+               INSERT(OCH_, pos);              /* offset slightly wrong */
+               ASTERN(OOR1, pos);              /* this one's right */
+               AHEAD(pos);                     /* fix the OCH_ */
+               EMIT(OOR2, 0);                  /* offset very wrong... */
+               AHEAD(THERE());                 /* ...so fix it */
+               ASTERN(O_CH, THERETHERE());
+               break;
+       case '{':
+               count = p_count(p);
+               if (EAT(',')) {
+                       if (isdigit(PEEK())) {
+                               count2 = p_count(p);
+                               REQUIRE(count <= count2, REG_BADBR);
+                       } else          /* single number with comma */
+                               count2 = INFINITY;
+               } else          /* just a single number */
+                       count2 = count;
+               repeat(p, pos, count, count2);
+               if (!EAT('}')) {        /* error heuristics */
+                       while (MORE() && PEEK() != '}')
+                               NEXT1();
+                       REQUIRE(MORE(), REG_EBRACE);
+                       SETERROR(REG_BADBR);
+               }
+               break;
+       }
+
+       if (!MORE())
+               return;
+       c = PEEK();
+       if (!( c == '*' || c == '+' || c == '?' ||
+                               (c == '{' && MORE2() && isdigit(PEEK2())) ) )
+               return;
+       SETERROR(REG_BADRPT);
+}
+
+/*
+ - p_str - string (no metacharacters) "parser"
+ == static void p_str(register struct parse *p);
+ */
+static void
+p_str(p)
+register struct parse *p;
+{
+       REQUIRE(MORE(), REG_EMPTY);
+       while (MORE())
+               ordinary(p, GETNEXT());
+}
+
+/*
+ - p_bre - BRE parser top level, anchoring and concatenation
+ == static void p_bre(register struct parse *p, register int end1, \
+ ==    register int end2);
+ * Giving end1 as OUT essentially eliminates the end1/end2 check.
+ *
+ * This implementation is a bit of a kludge, in that a trailing $ is first
+ * taken as an ordinary character and then revised to be an anchor.  The
+ * only undesirable side effect is that '$' gets included as a character
+ * category in such cases.  This is fairly harmless; not worth fixing.
+ * The amount of lookahead needed to avoid this kludge is excessive.
+ */
+static void
+p_bre(p, end1, end2)
+register struct parse *p;
+register int end1;             /* first terminating character */
+register int end2;             /* second terminating character */
+{
+       register sopno start = HERE();
+       register int first = 1;                 /* first subexpression? */
+       register int wasdollar = 0;
+
+       if (EAT('^')) {
+               EMIT(OBOL, 0);
+               p->g->iflags |= USEBOL;
+               p->g->nbol++;
+       }
+       while (MORE() && !SEETWO(end1, end2)) {
+               wasdollar = p_simp_re(p, first);
+               first = 0;
+       }
+       if (wasdollar) {        /* oops, that was a trailing anchor */
+               DROP(1);
+               EMIT(OEOL, 0);
+               p->g->iflags |= USEEOL;
+               p->g->neol++;
+       }
+
+       REQUIRE(HERE() != start, REG_EMPTY);    /* require nonempty */
+}
+
+/*
+ - p_simp_re - parse a simple RE, an atom possibly followed by a repetition
+ == static int p_simp_re(register struct parse *p, int starordinary);
+ */
+static int                     /* was the simple RE an unbackslashed $? */
+p_simp_re(p, starordinary)
+register struct parse *p;
+int starordinary;              /* is a leading * an ordinary character? */
+{
+       register int c;
+       register int count;
+       register int count2;
+       register sopno pos;
+       register int i;
+       register sopno subno;
+#      define  BACKSL  (1<<CHAR_BIT)
+
+       pos = HERE();           /* repetion op, if any, covers from here */
+
+       assert(MORE());         /* caller should have ensured this */
+       c = GETNEXT();
+       if (c == '\\') {
+               REQUIRE(MORE(), REG_EESCAPE);
+               c = BACKSL | (unsigned char)GETNEXT();
+       }
+       switch (c) {
+       case '.':
+               if (p->g->cflags&REG_NEWLINE)
+                       nonnewline(p);
+               else
+                       EMIT(OANY, 0);
+               break;
+       case '[':
+               p_bracket(p);
+               break;
+       case BACKSL|'{':
+               SETERROR(REG_BADRPT);
+               break;
+       case BACKSL|'(':
+               p->g->nsub++;
+               subno = p->g->nsub;
+               if (subno < NPAREN)
+                       p->pbegin[subno] = HERE();
+               EMIT(OLPAREN, subno);
+               /* the MORE here is an error heuristic */
+               if (MORE() && !SEETWO('\\', ')'))
+                       p_bre(p, '\\', ')');
+               if (subno < NPAREN) {
+                       p->pend[subno] = HERE();
+                       assert(p->pend[subno] != 0);
+               }
+               EMIT(ORPAREN, subno);
+               REQUIRE(EATTWO('\\', ')'), REG_EPAREN);
+               break;
+       case BACKSL|')':        /* should not get here -- must be user */
+       case BACKSL|'}':
+               SETERROR(REG_EPAREN);
+               break;
+       case BACKSL|'1':
+       case BACKSL|'2':
+       case BACKSL|'3':
+       case BACKSL|'4':
+       case BACKSL|'5':
+       case BACKSL|'6':
+       case BACKSL|'7':
+       case BACKSL|'8':
+       case BACKSL|'9':
+               i = (c&~BACKSL) - '0';
+               assert(i < NPAREN);
+               if (p->pend[i] != 0) {
+                       assert(i <= p->g->nsub);
+                       EMIT(OBACK_, i);
+                       assert(p->pbegin[i] != 0);
+                       assert(OP(p->strip[p->pbegin[i]]) == OLPAREN);
+                       assert(OP(p->strip[p->pend[i]]) == ORPAREN);
+                       (void) dupl(p, p->pbegin[i]+1, p->pend[i]);
+                       EMIT(O_BACK, i);
+               } else
+                       SETERROR(REG_ESUBREG);
+               p->g->backrefs = 1;
+               break;
+       case '*':
+               REQUIRE(starordinary, REG_BADRPT);
+               /* FALLTHROUGH */
+       default:
+               ordinary(p, c &~ BACKSL);
+               break;
+       }
+
+       if (EAT('*')) {         /* implemented as +? */
+               /* this case does not require the (y|) trick, noKLUDGE */
+               INSERT(OPLUS_, pos);
+               ASTERN(O_PLUS, pos);
+               INSERT(OQUEST_, pos);
+               ASTERN(O_QUEST, pos);
+       } else if (EATTWO('\\', '{')) {
+               count = p_count(p);
+               if (EAT(',')) {
+                       if (MORE() && isdigit(PEEK())) {
+                               count2 = p_count(p);
+                               REQUIRE(count <= count2, REG_BADBR);
+                       } else          /* single number with comma */
+                               count2 = INFINITY;
+               } else          /* just a single number */
+                       count2 = count;
+               repeat(p, pos, count, count2);
+               if (!EATTWO('\\', '}')) {       /* error heuristics */
+                       while (MORE() && !SEETWO('\\', '}'))
+                               NEXT1();
+                       REQUIRE(MORE(), REG_EBRACE);
+                       SETERROR(REG_BADBR);
+               }
+       } else if (c == (unsigned char)'$')     /* $ (but not \$) ends it */
+               return(1);
+
+       return(0);
+}
+
+/*
+ - p_count - parse a repetition count
+ == static int p_count(register struct parse *p);
+ */
+static int                     /* the value */
+p_count(p)
+register struct parse *p;
+{
+       register int count = 0;
+       register int ndigits = 0;
+
+       while (MORE() && isdigit(PEEK()) && count <= DUPMAX) {
+               count = count*10 + (GETNEXT() - '0');
+               ndigits++;
+       }
+
+       REQUIRE(ndigits > 0 && count <= DUPMAX, REG_BADBR);
+       return(count);
+}
+
+/*
+ - p_bracket - parse a bracketed character list
+ == static void p_bracket(register struct parse *p);
+ *
+ * Note a significant property of this code:  if the allocset() did SETERROR,
+ * no set operations are done.
+ */
+static void
+p_bracket(p)
+register struct parse *p;
+{
+       register cset *cs = allocset(p);
+       register int invert = 0;
+
+       /* Dept of Truly Sickening Special-Case Kludges */
+       if (p->next + 5 < p->end && strncmp(p->next, "[:<:]]", 6) == 0) {
+               EMIT(OBOW, 0);
+               NEXTn(6);
+               return;
+       }
+       if (p->next + 5 < p->end && strncmp(p->next, "[:>:]]", 6) == 0) {
+               EMIT(OEOW, 0);
+               NEXTn(6);
+               return;
+       }
+
+       if (EAT('^'))
+               invert++;       /* make note to invert set at end */
+       if (EAT(']'))
+               CHadd(cs, ']');
+       else if (EAT('-'))
+               CHadd(cs, '-');
+       while (MORE() && PEEK() != ']' && !SEETWO('-', ']'))
+               p_b_term(p, cs);
+       if (EAT('-'))
+               CHadd(cs, '-');
+       MUSTEAT(']', REG_EBRACK);
+
+       if (p->error != 0)      /* don't mess things up further */
+               return;
+
+       if (p->g->cflags&REG_ICASE) {
+               register int i;
+               register int ci;
+
+               for (i = p->g->csetsize - 1; i >= 0; i--)
+                       if (CHIN(cs, i) && isalpha(i)) {
+                               ci = othercase(i);
+                               if (ci != i)
+                                       CHadd(cs, ci);
+                       }
+               if (cs->multis != NULL)
+                       mccase(p, cs);
+       }
+       if (invert) {
+               register int i;
+
+               for (i = p->g->csetsize - 1; i >= 0; i--)
+                       if (CHIN(cs, i))
+                               CHsub(cs, i);
+                       else
+                               CHadd(cs, i);
+               if (p->g->cflags&REG_NEWLINE)
+                       CHsub(cs, '\n');
+               if (cs->multis != NULL)
+                       mcinvert(p, cs);
+       }
+
+       assert(cs->multis == NULL);             /* xxx */
+
+       if (nch(p, cs) == 1) {          /* optimize singleton sets */
+               ordinary(p, firstch(p, cs));
+               freeset(p, cs);
+       } else
+               EMIT(OANYOF, freezeset(p, cs));
+}
+
+/*
+ - p_b_term - parse one term of a bracketed character list
+ == static void p_b_term(register struct parse *p, register cset *cs);
+ */
+static void
+p_b_term(p, cs)
+register struct parse *p;
+register cset *cs;
+{
+       register char c;
+       register char start, finish;
+       register int i;
+
+       /* classify what we've got */
+       switch ((MORE()) ? PEEK() : '\0') {
+       case '[':
+               c = (MORE2()) ? PEEK2() : '\0';
+               break;
+       case '-':
+               SETERROR(REG_ERANGE);
+               return;                 /* NOTE RETURN */
+               break;
+       default:
+               c = '\0';
+               break;
+       }
+
+       switch (c) {
+       case ':':               /* character class */
+               NEXT2();
+               REQUIRE(MORE(), REG_EBRACK);
+               c = PEEK();
+               REQUIRE(c != '-' && c != ']', REG_ECTYPE);
+               p_b_cclass(p, cs);
+               REQUIRE(MORE(), REG_EBRACK);
+               REQUIRE(EATTWO(':', ']'), REG_ECTYPE);
+               break;
+       case '=':               /* equivalence class */
+               NEXT2();
+               REQUIRE(MORE(), REG_EBRACK);
+               c = PEEK();
+               REQUIRE(c != '-' && c != ']', REG_ECOLLATE);
+               p_b_eclass(p, cs);
+               REQUIRE(MORE(), REG_EBRACK);
+               REQUIRE(EATTWO('=', ']'), REG_ECOLLATE);
+               break;
+       default:                /* symbol, ordinary character, or range */
+/* xxx revision needed for multichar stuff */
+               start = p_b_symbol(p);
+               if (SEE('-') && MORE2() && PEEK2() != ']') {
+                       /* range */
+                       NEXT1();
+                       if (EAT('-'))
+                               finish = '-';
+                       else
+                               finish = p_b_symbol(p);
+               } else
+                       finish = start;
+/* xxx what about signed chars here... */
+               REQUIRE(start <= finish, REG_ERANGE);
+               for (i = start; i <= finish; i++)
+                       CHadd(cs, i);
+               break;
+       }
+}
+
+/*
+ - p_b_cclass - parse a character-class name and deal with it
+ == static void p_b_cclass(register struct parse *p, register cset *cs);
+ */
+static void
+p_b_cclass(p, cs)
+register struct parse *p;
+register cset *cs;
+{
+       register char *sp = p->next;
+       register struct cclass *cp;
+       register size_t len;
+       register char *u;
+       register char c;
+
+       while (MORE() && isalpha(PEEK()))
+               NEXT1();
+       len = p->next - sp;
+       for (cp = cclasses; cp->name != NULL; cp++)
+               if (strncmp(cp->name, sp, len) == 0 && cp->name[len] == '\0')
+                       break;
+       if (cp->name == NULL) {
+               /* oops, didn't find it */
+               SETERROR(REG_ECTYPE);
+               return;
+       }
+
+       u = cp->chars;
+       while ((c = *u++) != '\0')
+               CHadd(cs, c);
+       for (u = cp->multis; *u != '\0'; u += strlen(u) + 1)
+               MCadd(p, cs, u);
+}
+
+/*
+ - p_b_eclass - parse an equivalence-class name and deal with it
+ == static void p_b_eclass(register struct parse *p, register cset *cs);
+ *
+ * This implementation is incomplete. xxx
+ */
+static void
+p_b_eclass(p, cs)
+register struct parse *p;
+register cset *cs;
+{
+       register char c;
+
+       c = p_b_coll_elem(p, '=');
+       CHadd(cs, c);
+}
+
+/*
+ - p_b_symbol - parse a character or [..]ed multicharacter collating symbol
+ == static char p_b_symbol(register struct parse *p);
+ */
+static char                    /* value of symbol */
+p_b_symbol(p)
+register struct parse *p;
+{
+       register char value;
+
+       REQUIRE(MORE(), REG_EBRACK);
+       if (!EATTWO('[', '.'))
+               return(GETNEXT());
+
+       /* collating symbol */
+       value = p_b_coll_elem(p, '.');
+       REQUIRE(EATTWO('.', ']'), REG_ECOLLATE);
+       return(value);
+}
+
+/*
+ - p_b_coll_elem - parse a collating-element name and look it up
+ == static char p_b_coll_elem(register struct parse *p, int endc);
+ */
+static char                    /* value of collating element */
+p_b_coll_elem(p, endc)
+register struct parse *p;
+int endc;                      /* name ended by endc,']' */
+{
+       register char *sp = p->next;
+       register struct cname *cp;
+       register int len;
+
+       while (MORE() && !SEETWO(endc, ']'))
+               NEXT1();
+       if (!MORE()) {
+               SETERROR(REG_EBRACK);
+               return(0);
+       }
+       len = p->next - sp;
+       for (cp = cnames; cp->name != NULL; cp++)
+               if (strncmp(cp->name, sp, len) == 0 && cp->name[len] == '\0')
+                       return(cp->code);       /* known name */
+       if (len == 1)
+               return(*sp);    /* single character */
+       SETERROR(REG_ECOLLATE);                 /* neither */
+       return(0);
+}
+
+/*
+ - othercase - return the case counterpart of an alphabetic
+ == static char othercase(int ch);
+ */
+static char                    /* if no counterpart, return ch */
+othercase(ch)
+int ch;
+{
+       assert(isalpha(ch));
+       if (isupper(ch))
+               return(tolower(ch));
+       else if (islower(ch))
+               return(toupper(ch));
+       else                    /* peculiar, but could happen */
+               return(ch);
+}
+
+/*
+ - bothcases - emit a dualcase version of a two-case character
+ == static void bothcases(register struct parse *p, int ch);
+ *
+ * Boy, is this implementation ever a kludge...
+ */
+static void
+bothcases(p, ch)
+register struct parse *p;
+int ch;
+{
+       register char *oldnext = p->next;
+       register char *oldend = p->end;
+       char bracket[3];
+
+       assert(othercase(ch) != ch);    /* p_bracket() would recurse */
+       p->next = bracket;
+       p->end = bracket+2;
+       bracket[0] = ch;
+       bracket[1] = ']';
+       bracket[2] = '\0';
+       p_bracket(p);
+       assert(p->next == bracket+2);
+       p->next = oldnext;
+       p->end = oldend;
+}
+
+/*
+ - ordinary - emit an ordinary character
+ == static void ordinary(register struct parse *p, register int ch);
+ */
+static void
+ordinary(p, ch)
+register struct parse *p;
+register int ch;
+{
+       register cat_t *cap = p->g->categories;
+
+       if ((p->g->cflags&REG_ICASE) && isalpha(ch) && othercase(ch) != ch)
+               bothcases(p, ch);
+       else {
+               EMIT(OCHAR, (unsigned char)ch);
+               if (cap[ch] == 0)
+                       cap[ch] = p->g->ncategories++;
+       }
+}
+
+/*
+ - nonnewline - emit REG_NEWLINE version of OANY
+ == static void nonnewline(register struct parse *p);
+ *
+ * Boy, is this implementation ever a kludge...
+ */
+static void
+nonnewline(p)
+register struct parse *p;
+{
+       register char *oldnext = p->next;
+       register char *oldend = p->end;
+       char bracket[4];
+
+       p->next = bracket;
+       p->end = bracket+3;
+       bracket[0] = '^';
+       bracket[1] = '\n';
+       bracket[2] = ']';
+       bracket[3] = '\0';
+       p_bracket(p);
+       assert(p->next == bracket+3);
+       p->next = oldnext;
+       p->end = oldend;
+}
+
+/*
+ - repeat - generate code for a bounded repetition, recursively if needed
+ == static void repeat(register struct parse *p, sopno start, int from, int to);
+ */
+static void
+repeat(p, start, from, to)
+register struct parse *p;
+sopno start;                   /* operand from here to end of strip */
+int from;                      /* repeated from this number */
+int to;                                /* to this number of times (maybe INFINITY) */
+{
+       register sopno finish = HERE();
+#      define  N       2
+#      define  INF     3
+#      define  REP(f, t)       ((f)*8 + (t))
+#      define  MAP(n)  (((n) <= 1) ? (n) : ((n) == INFINITY) ? INF : N)
+       register sopno copy;
+
+       if (p->error != 0)      /* head off possible runaway recursion */
+               return;
+
+       assert(from <= to);
+
+       switch (REP(MAP(from), MAP(to))) {
+       case REP(0, 0):                 /* must be user doing this */
+               DROP(finish-start);     /* drop the operand */
+               break;
+       case REP(0, 1):                 /* as x{1,1}? */
+       case REP(0, N):                 /* as x{1,n}? */
+       case REP(0, INF):               /* as x{1,}? */
+               /* KLUDGE: emit y? as (y|) until subtle bug gets fixed */
+               INSERT(OCH_, start);            /* offset is wrong... */
+               repeat(p, start+1, 1, to);
+               ASTERN(OOR1, start);
+               AHEAD(start);                   /* ... fix it */
+               EMIT(OOR2, 0);
+               AHEAD(THERE());
+               ASTERN(O_CH, THERETHERE());
+               break;
+       case REP(1, 1):                 /* trivial case */
+               /* done */
+               break;
+       case REP(1, N):                 /* as x?x{1,n-1} */
+               /* KLUDGE: emit y? as (y|) until subtle bug gets fixed */
+               INSERT(OCH_, start);
+               ASTERN(OOR1, start);
+               AHEAD(start);
+               EMIT(OOR2, 0);                  /* offset very wrong... */
+               AHEAD(THERE());                 /* ...so fix it */
+               ASTERN(O_CH, THERETHERE());
+               copy = dupl(p, start+1, finish+1);
+               assert(copy == finish+4);
+               repeat(p, copy, 1, to-1);
+               break;
+       case REP(1, INF):               /* as x+ */
+               INSERT(OPLUS_, start);
+               ASTERN(O_PLUS, start);
+               break;
+       case REP(N, N):                 /* as xx{m-1,n-1} */
+               copy = dupl(p, start, finish);
+               repeat(p, copy, from-1, to-1);
+               break;
+       case REP(N, INF):               /* as xx{n-1,INF} */
+               copy = dupl(p, start, finish);
+               repeat(p, copy, from-1, to);
+               break;
+       default:                        /* "can't happen" */
+               SETERROR(REG_ASSERT);   /* just in case */
+               break;
+       }
+}
+
+/*
+ - seterr - set an error condition
+ == static int seterr(register struct parse *p, int e);
+ */
+static int                     /* useless but makes type checking happy */
+seterr(p, e)
+register struct parse *p;
+int e;
+{
+       if (p->error == 0)      /* keep earliest error condition */
+               p->error = e;
+       p->next = nuls;         /* try to bring things to a halt */
+       p->end = nuls;
+       return(0);              /* make the return value well-defined */
+}
+
+/*
+ - allocset - allocate a set of characters for []
+ == static cset *allocset(register struct parse *p);
+ */
+static cset *
+allocset(p)
+register struct parse *p;
+{
+       register int no = p->g->ncsets++;
+       register size_t nc;
+       register size_t nbytes;
+       register cset *cs;
+       register size_t css = (size_t)p->g->csetsize;
+       register int i;
+
+       if (no >= p->ncsalloc) {        /* need another column of space */
+               p->ncsalloc += CHAR_BIT;
+               nc = p->ncsalloc;
+               assert(nc % CHAR_BIT == 0);
+               nbytes = nc / CHAR_BIT * css;
+               if (p->g->sets == NULL)
+                       p->g->sets = (cset *)malloc(nc * sizeof(cset));
+               else
+                       p->g->sets = (cset *)realloc((char *)p->g->sets,
+                                                       nc * sizeof(cset));
+               if (p->g->setbits == NULL)
+                       p->g->setbits = (uch *)malloc(nbytes);
+               else {
+                       p->g->setbits = (uch *)realloc((char *)p->g->setbits,
+                                                               nbytes);
+                       /* xxx this isn't right if setbits is now NULL */
+                       for (i = 0; i < no; i++)
+                               p->g->sets[i].ptr = p->g->setbits + css*(i/CHAR_BIT);
+               }
+               if (p->g->sets != NULL && p->g->setbits != NULL)
+                       (void) memset((char *)p->g->setbits + (nbytes - css),
+                                                               0, css);
+               else {
+                       no = 0;
+                       SETERROR(REG_ESPACE);
+                       /* caller's responsibility not to do set ops */
+               }
+       }
+
+       assert(p->g->sets != NULL);     /* xxx */
+       cs = &p->g->sets[no];
+       cs->ptr = p->g->setbits + css*((no)/CHAR_BIT);
+       cs->mask = 1 << ((no) % CHAR_BIT);
+       cs->hash = 0;
+       cs->smultis = 0;
+       cs->multis = NULL;
+
+       return(cs);
+}
+
+/*
+ - freeset - free a now-unused set
+ == static void freeset(register struct parse *p, register cset *cs);
+ */
+static void
+freeset(p, cs)
+register struct parse *p;
+register cset *cs;
+{
+       register int i;
+       register cset *top = &p->g->sets[p->g->ncsets];
+       register size_t css = (size_t)p->g->csetsize;
+
+       for (i = 0; i < css; i++)
+               CHsub(cs, i);
+       if (cs == top-1)        /* recover only the easy case */
+               p->g->ncsets--;
+}
+
+/*
+ - freezeset - final processing on a set of characters
+ == static int freezeset(register struct parse *p, register cset *cs);
+ *
+ * The main task here is merging identical sets.  This is usually a waste
+ * of time (although the hash code minimizes the overhead), but can win
+ * big if REG_ICASE is being used.  REG_ICASE, by the way, is why the hash
+ * is done using addition rather than xor -- all ASCII [aA] sets xor to
+ * the same value!
+ */
+static int                     /* set number */
+freezeset(p, cs)
+register struct parse *p;
+register cset *cs;
+{
+       register uch h = cs->hash;
+       register int i;
+       register cset *top = &p->g->sets[p->g->ncsets];
+       register cset *cs2;
+       register size_t css = (size_t)p->g->csetsize;
+
+       /* look for an earlier one which is the same */
+       for (cs2 = &p->g->sets[0]; cs2 < top; cs2++)
+               if (cs2->hash == h && cs2 != cs) {
+                       /* maybe */
+                       for (i = 0; i < css; i++)
+                               if (!!CHIN(cs2, i) != !!CHIN(cs, i))
+                                       break;          /* no */
+                       if (i == css)
+                               break;                  /* yes */
+               }
+
+       if (cs2 < top) {        /* found one */
+               freeset(p, cs);
+               cs = cs2;
+       }
+
+       return((int)(cs - p->g->sets));
+}
+
+/*
+ - firstch - return first character in a set (which must have at least one)
+ == static int firstch(register struct parse *p, register cset *cs);
+ */
+static int                     /* character; there is no "none" value */
+firstch(p, cs)
+register struct parse *p;
+register cset *cs;
+{
+       register int i;
+       register size_t css = (size_t)p->g->csetsize;
+
+       for (i = 0; i < css; i++)
+               if (CHIN(cs, i))
+                       return((char)i);
+       assert(never);
+       return(0);              /* arbitrary */
+}
+
+/*
+ - nch - number of characters in a set
+ == static int nch(register struct parse *p, register cset *cs);
+ */
+static int
+nch(p, cs)
+register struct parse *p;
+register cset *cs;
+{
+       register int i;
+       register size_t css = (size_t)p->g->csetsize;
+       register int n = 0;
+
+       for (i = 0; i < css; i++)
+               if (CHIN(cs, i))
+                       n++;
+       return(n);
+}
+
+/*
+ - mcadd - add a collating element to a cset
+ == static void mcadd(register struct parse *p, register cset *cs, \
+ ==    register char *cp);
+ */
+static void
+mcadd(p, cs, cp)
+register struct parse *p;
+register cset *cs;
+register char *cp;
+{
+       register size_t oldend = cs->smultis;
+
+       cs->smultis += strlen(cp) + 1;
+       if (cs->multis == NULL)
+               cs->multis = malloc(cs->smultis);
+       else
+               cs->multis = realloc(cs->multis, cs->smultis);
+       if (cs->multis == NULL) {
+               SETERROR(REG_ESPACE);
+               return;
+       }
+
+       (void) strcpy(cs->multis + oldend - 1, cp);
+       cs->multis[cs->smultis - 1] = '\0';
+}
+
+
+/*
+ - mcinvert - invert the list of collating elements in a cset
+ == static void mcinvert(register struct parse *p, register cset *cs);
+ *
+ * This would have to know the set of possibilities.  Implementation
+ * is deferred.
+ */
+static void
+mcinvert(p, cs)
+register struct parse *p;
+register cset *cs;
+{
+       assert(cs->multis == NULL);     /* xxx */
+}
+
+/*
+ - mccase - add case counterparts of the list of collating elements in a cset
+ == static void mccase(register struct parse *p, register cset *cs);
+ *
+ * This would have to know the set of possibilities.  Implementation
+ * is deferred.
+ */
+static void
+mccase(p, cs)
+register struct parse *p;
+register cset *cs;
+{
+       assert(cs->multis == NULL);     /* xxx */
+}
+
+/*
+ - isinsets - is this character in any sets?
+ == static int isinsets(register struct re_guts *g, int c);
+ */
+static int                     /* predicate */
+isinsets(g, c)
+register struct re_guts *g;
+int c;
+{
+       register uch *col;
+       register int i;
+       register int ncols = (g->ncsets+(CHAR_BIT-1)) / CHAR_BIT;
+       register unsigned uc = (unsigned char)c;
+
+       for (i = 0, col = g->setbits; i < ncols; i++, col += g->csetsize)
+               if (col[uc] != 0)
+                       return(1);
+       return(0);
+}
+
+/*
+ - samesets - are these two characters in exactly the same sets?
+ == static int samesets(register struct re_guts *g, int c1, int c2);
+ */
+static int                     /* predicate */
+samesets(g, c1, c2)
+register struct re_guts *g;
+int c1;
+int c2;
+{
+       register uch *col;
+       register int i;
+       register int ncols = (g->ncsets+(CHAR_BIT-1)) / CHAR_BIT;
+       register unsigned uc1 = (unsigned char)c1;
+       register unsigned uc2 = (unsigned char)c2;
+
+       for (i = 0, col = g->setbits; i < ncols; i++, col += g->csetsize)
+               if (col[uc1] != col[uc2])
+                       return(0);
+       return(1);
+}
+
+/*
+ - categorize - sort out character categories
+ == static void categorize(struct parse *p, register struct re_guts *g);
+ */
+static void
+categorize(p, g)
+struct parse *p;
+register struct re_guts *g;
+{
+       register cat_t *cats = g->categories;
+       register int c;
+       register int c2;
+       register cat_t cat;
+
+       /* avoid making error situations worse */
+       if (p->error != 0)
+               return;
+
+       for (c = CHAR_MIN; c <= CHAR_MAX; c++)
+               if (cats[c] == 0 && isinsets(g, c)) {
+                       cat = g->ncategories++;
+                       cats[c] = cat;
+                       for (c2 = c+1; c2 <= CHAR_MAX; c2++)
+                               if (cats[c2] == 0 && samesets(g, c, c2))
+                                       cats[c2] = cat;
+               }
+}
+
+/*
+ - dupl - emit a duplicate of a bunch of sops
+ == static sopno dupl(register struct parse *p, sopno start, sopno finish);
+ */
+static sopno                   /* start of duplicate */
+dupl(p, start, finish)
+register struct parse *p;
+sopno start;                   /* from here */
+sopno finish;                  /* to this less one */
+{
+       register sopno ret = HERE();
+       register sopno len = finish - start;
+
+       assert(finish >= start);
+       if (len == 0)
+               return(ret);
+       enlarge(p, p->ssize + len);     /* this many unexpected additions */
+       assert(p->ssize >= p->slen + len);
+       (void) memcpy((char *)(p->strip + p->slen),
+               (char *)(p->strip + start), (size_t)len*sizeof(sop));
+       p->slen += len;
+       return(ret);
+}
+
+/*
+ - doemit - emit a strip operator
+ == static void doemit(register struct parse *p, sop op, size_t opnd);
+ *
+ * It might seem better to implement this as a macro with a function as
+ * hard-case backup, but it's just too big and messy unless there are
+ * some changes to the data structures.  Maybe later.
+ */
+static void
+doemit(p, op, opnd)
+register struct parse *p;
+sop op;
+size_t opnd;
+{
+       /* avoid making error situations worse */
+       if (p->error != 0)
+               return;
+
+       /* deal with oversize operands ("can't happen", more or less) */
+       assert(opnd < 1<<OPSHIFT);
+
+       /* deal with undersized strip */
+       if (p->slen >= p->ssize)
+               enlarge(p, (p->ssize+1) / 2 * 3);       /* +50% */
+       assert(p->slen < p->ssize);
+
+       /* finally, it's all reduced to the easy case */
+       p->strip[p->slen++] = SOP(op, opnd);
+}
+
+/*
+ - doinsert - insert a sop into the strip
+ == static void doinsert(register struct parse *p, sop op, size_t opnd, sopno pos);
+ */
+static void
+doinsert(p, op, opnd, pos)
+register struct parse *p;
+sop op;
+size_t opnd;
+sopno pos;
+{
+       register sopno sn;
+       register sop s;
+       register int i;
+
+       /* avoid making error situations worse */
+       if (p->error != 0)
+               return;
+
+       sn = HERE();
+       EMIT(op, opnd);         /* do checks, ensure space */
+       assert(HERE() == sn+1);
+       s = p->strip[sn];
+
+       /* adjust paren pointers */
+       assert(pos > 0);
+       for (i = 1; i < NPAREN; i++) {
+               if (p->pbegin[i] >= pos) {
+                       p->pbegin[i]++;
+               }
+               if (p->pend[i] >= pos) {
+                       p->pend[i]++;
+               }
+       }
+
+       memmove((char *)&p->strip[pos+1], (char *)&p->strip[pos],
+                                               (HERE()-pos-1)*sizeof(sop));
+       p->strip[pos] = s;
+}
+
+/*
+ - dofwd - complete a forward reference
+ == static void dofwd(register struct parse *p, sopno pos, sop value);
+ */
+static void
+dofwd(p, pos, value)
+register struct parse *p;
+register sopno pos;
+sop value;
+{
+       /* avoid making error situations worse */
+       if (p->error != 0)
+               return;
+
+       assert(value < 1<<OPSHIFT);
+       p->strip[pos] = OP(p->strip[pos]) | value;
+}
+
+/*
+ - enlarge - enlarge the strip
+ == static void enlarge(register struct parse *p, sopno size);
+ */
+static void
+enlarge(p, size)
+register struct parse *p;
+register sopno size;
+{
+       register sop *sp;
+
+       if (p->ssize >= size)
+               return;
+
+       sp = (sop *)realloc(p->strip, size*sizeof(sop));
+       if (sp == NULL) {
+               SETERROR(REG_ESPACE);
+               return;
+       }
+       p->strip = sp;
+       p->ssize = size;
+}
+
+/*
+ - stripsnug - compact the strip
+ == static void stripsnug(register struct parse *p, register struct re_guts *g);
+ */
+static void
+stripsnug(p, g)
+register struct parse *p;
+register struct re_guts *g;
+{
+       g->nstates = p->slen;
+       g->strip = (sop *)realloc((char *)p->strip, p->slen * sizeof(sop));
+       if (g->strip == NULL) {
+               SETERROR(REG_ESPACE);
+               g->strip = p->strip;
+       }
+}
+
+/*
+ - findmust - fill in must and mlen with longest mandatory literal string
+ == static void findmust(register struct parse *p, register struct re_guts *g);
+ *
+ * This algorithm could do fancy things like analyzing the operands of |
+ * for common subsequences.  Someday.  This code is simple and finds most
+ * of the interesting cases.
+ *
+ * Note that must and mlen got initialized during setup.
+ */
+static void
+findmust(p, g)
+struct parse *p;
+register struct re_guts *g;
+{
+       register sop *scan;
+       sop *start = NULL;
+       register sop *newstart = NULL;
+       register sopno newlen;
+       register sop s;
+       register char *cp;
+       register sopno i;
+
+       /* avoid making error situations worse */
+       if (p->error != 0)
+               return;
+
+       /* find the longest OCHAR sequence in strip */
+       newlen = 0;
+       scan = g->strip + 1;
+       do {
+               s = *scan++;
+               switch (OP(s)) {
+               case OCHAR:             /* sequence member */
+                       if (newlen == 0)                /* new sequence */
+                               newstart = scan - 1;
+                       newlen++;
+                       break;
+               case OPLUS_:            /* things that don't break one */
+               case OLPAREN:
+               case ORPAREN:
+                       break;
+               case OQUEST_:           /* things that must be skipped */
+               case OCH_:
+                       scan--;
+                       do {
+                               scan += OPND(s);
+                               s = *scan;
+                               /* assert() interferes w debug printouts */
+                               if (OP(s) != O_QUEST && OP(s) != O_CH &&
+                                                       OP(s) != OOR2) {
+                                       g->iflags |= BAD;
+                                       return;
+                               }
+                       } while (OP(s) != O_QUEST && OP(s) != O_CH);
+                       /* fallthrough */
+               default:                /* things that break a sequence */
+                       if (newlen > g->mlen) {         /* ends one */
+                               start = newstart;
+                               g->mlen = newlen;
+                       }
+                       newlen = 0;
+                       break;
+               }
+       } while (OP(s) != OEND);
+
+       if (g->mlen == 0)               /* there isn't one */
+               return;
+
+       /* turn it into a character string */
+       g->must = malloc((size_t)g->mlen + 1);
+       if (g->must == NULL) {          /* argh; just forget it */
+               g->mlen = 0;
+               return;
+       }
+       cp = g->must;
+       scan = start;
+       for (i = g->mlen; i > 0; i--) {
+               while (OP(s = *scan++) != OCHAR)
+                       continue;
+               assert(cp < g->must + g->mlen);
+               *cp++ = (char)OPND(s);
+       }
+       assert(cp == g->must + g->mlen);
+       *cp++ = '\0';           /* just on general principles */
+}
+
+/*
+ - pluscount - count + nesting
+ == static sopno pluscount(register struct parse *p, register struct re_guts *g);
+ */
+static sopno                   /* nesting depth */
+pluscount(p, g)
+struct parse *p;
+register struct re_guts *g;
+{
+       register sop *scan;
+       register sop s;
+       register sopno plusnest = 0;
+       register sopno maxnest = 0;
+
+       if (p->error != 0)
+               return(0);      /* there may not be an OEND */
+
+       scan = g->strip + 1;
+       do {
+               s = *scan++;
+               switch (OP(s)) {
+               case OPLUS_:
+                       plusnest++;
+                       break;
+               case O_PLUS:
+                       if (plusnest > maxnest)
+                               maxnest = plusnest;
+                       plusnest--;
+                       break;
+               }
+       } while (OP(s) != OEND);
+       if (plusnest != 0)
+               g->iflags |= BAD;
+       return(maxnest);
+}
diff --git a/APACHE_1_2_X/src/regex/regerror.c b/APACHE_1_2_X/src/regex/regerror.c
new file mode 100644 (file)
index 0000000..850b0e6
--- /dev/null
@@ -0,0 +1,124 @@
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <regex.h>
+
+#include "utils.h"
+#include "regerror.ih"
+
+/*
+ = #define     REG_NOMATCH      1
+ = #define     REG_BADPAT       2
+ = #define     REG_ECOLLATE     3
+ = #define     REG_ECTYPE       4
+ = #define     REG_EESCAPE      5
+ = #define     REG_ESUBREG      6
+ = #define     REG_EBRACK       7
+ = #define     REG_EPAREN       8
+ = #define     REG_EBRACE       9
+ = #define     REG_BADBR       10
+ = #define     REG_ERANGE      11
+ = #define     REG_ESPACE      12
+ = #define     REG_BADRPT      13
+ = #define     REG_EMPTY       14
+ = #define     REG_ASSERT      15
+ = #define     REG_INVARG      16
+ = #define     REG_ATOI        255     // convert name to number (!)
+ = #define     REG_ITOA        0400    // convert number to name (!)
+ */
+static struct rerr {
+       int code;
+       char *name;
+       char *explain;
+} rerrs[] = {
+       { REG_NOMATCH,  "REG_NOMATCH",  "regexec() failed to match" },
+       { REG_BADPAT,   "REG_BADPAT",   "invalid regular expression" },
+       { REG_ECOLLATE, "REG_ECOLLATE", "invalid collating element" },
+       { REG_ECTYPE,   "REG_ECTYPE",   "invalid character class" },
+       { REG_EESCAPE,  "REG_EESCAPE",  "trailing backslash (\\)" },
+       { REG_ESUBREG,  "REG_ESUBREG",  "invalid backreference number" },
+       { REG_EBRACK,   "REG_EBRACK",   "brackets ([ ]) not balanced" },
+       { REG_EPAREN,   "REG_EPAREN",   "parentheses not balanced" },
+       { REG_EBRACE,   "REG_EBRACE",   "braces not balanced" },
+       { REG_BADBR,    "REG_BADBR",    "invalid repetition count(s)" },
+       { REG_ERANGE,   "REG_ERANGE",   "invalid character range" },
+       { REG_ESPACE,   "REG_ESPACE",   "out of memory" },
+       { REG_BADRPT,   "REG_BADRPT",   "repetition-operator operand invalid" },
+       { REG_EMPTY,    "REG_EMPTY",    "empty (sub)expression" },
+       { REG_ASSERT,   "REG_ASSERT",   "\"can't happen\" -- you found a bug" },
+       { REG_INVARG,   "REG_INVARG",   "invalid argument to regex routine" },
+       { 0,            "",             "*** unknown regexp error code ***" }
+};
+
+/*
+ - regerror - the interface to error numbers
+ = extern size_t regerror(int, const regex_t *, char *, size_t);
+ */
+/* ARGSUSED */
+size_t
+regerror(errcode, preg, errbuf, errbuf_size)
+int errcode;
+const regex_t *preg;
+char *errbuf;
+size_t errbuf_size;
+{
+       register struct rerr *r;
+       register size_t len;
+       register int target = errcode &~ REG_ITOA;
+       register char *s;
+       char convbuf[50];
+
+       if (errcode == REG_ATOI)
+               s = regatoi(preg, convbuf);
+       else {
+               for (r = rerrs; r->code != 0; r++)
+                       if (r->code == target)
+                               break;
+       
+               if (errcode&REG_ITOA) {
+                       if (r->code != 0)
+                               (void) strcpy(convbuf, r->name);
+                       else
+                               sprintf(convbuf, "REG_0x%x", target);
+                       assert(strlen(convbuf) < sizeof(convbuf));
+                       s = convbuf;
+               } else
+                       s = r->explain;
+       }
+
+       len = strlen(s) + 1;
+       if (errbuf_size > 0) {
+               if (errbuf_size > len)
+                       (void) strcpy(errbuf, s);
+               else {
+                       (void) strncpy(errbuf, s, errbuf_size-1);
+                       errbuf[errbuf_size-1] = '\0';
+               }
+       }
+
+       return(len);
+}
+
+/*
+ - regatoi - internal routine to implement REG_ATOI
+ == static char *regatoi(const regex_t *preg, char *localbuf);
+ */
+static char *
+regatoi(preg, localbuf)
+const regex_t *preg;
+char *localbuf;
+{
+       register struct rerr *r;
+
+       for (r = rerrs; r->code != 0; r++)
+               if (strcmp(r->name, preg->re_endp) == 0)
+                       break;
+       if (r->code == 0)
+               return("0");
+
+       sprintf(localbuf, "%d", r->code);
+       return(localbuf);
+}
diff --git a/APACHE_1_2_X/src/regex/regex.3 b/APACHE_1_2_X/src/regex/regex.3
new file mode 100644 (file)
index 0000000..100c8a7
--- /dev/null
@@ -0,0 +1,502 @@
+.TH REGEX 3 "17 May 1993"
+.BY "Henry Spencer"
+.de ZR
+.\" one other place knows this name:  the SEE ALSO section
+.IR regex (7) \\$1
+..
+.SH NAME
+regcomp, regexec, regerror, regfree \- regular-expression library
+.SH SYNOPSIS
+.ft B
+.\".na
+#include <sys/types.h>
+.br
+#include <regex.h>
+.HP 10
+int regcomp(regex_t\ *preg, const\ char\ *pattern, int\ cflags);
+.HP
+int\ regexec(const\ regex_t\ *preg, const\ char\ *string,
+size_t\ nmatch, regmatch_t\ pmatch[], int\ eflags);
+.HP
+size_t\ regerror(int\ errcode, const\ regex_t\ *preg,
+char\ *errbuf, size_t\ errbuf_size);
+.HP
+void\ regfree(regex_t\ *preg);
+.\".ad
+.ft
+.SH DESCRIPTION
+These routines implement POSIX 1003.2 regular expressions (``RE''s);
+see
+.ZR .
+.I Regcomp
+compiles an RE written as a string into an internal form,
+.I regexec
+matches that internal form against a string and reports results,
+.I regerror
+transforms error codes from either into human-readable messages,
+and
+.I regfree
+frees any dynamically-allocated storage used by the internal form
+of an RE.
+.PP
+The header
+.I <regex.h>
+declares two structure types,
+.I regex_t
+and
+.IR regmatch_t ,
+the former for compiled internal forms and the latter for match reporting.
+It also declares the four functions,
+a type
+.IR regoff_t ,
+and a number of constants with names starting with ``REG_''.
+.PP
+.I Regcomp
+compiles the regular expression contained in the
+.I pattern
+string,
+subject to the flags in
+.IR cflags ,
+and places the results in the
+.I regex_t
+structure pointed to by
+.IR preg .
+.I Cflags
+is the bitwise OR of zero or more of the following flags:
+.IP REG_EXTENDED \w'REG_EXTENDED'u+2n
+Compile modern (``extended'') REs,
+rather than the obsolete (``basic'') REs that
+are the default.
+.IP REG_BASIC
+This is a synonym for 0,
+provided as a counterpart to REG_EXTENDED to improve readability.
+.IP REG_NOSPEC
+Compile with recognition of all special characters turned off.
+All characters are thus considered ordinary,
+so the ``RE'' is a literal string.
+This is an extension,
+compatible with but not specified by POSIX 1003.2,
+and should be used with
+caution in software intended to be portable to other systems.
+REG_EXTENDED and REG_NOSPEC may not be used
+in the same call to
+.IR regcomp .
+.IP REG_ICASE
+Compile for matching that ignores upper/lower case distinctions.
+See
+.ZR .
+.IP REG_NOSUB
+Compile for matching that need only report success or failure,
+not what was matched.
+.IP REG_NEWLINE
+Compile for newline-sensitive matching.
+By default, newline is a completely ordinary character with no special
+meaning in either REs or strings.
+With this flag,
+`[^' bracket expressions and `.' never match newline,
+a `^' anchor matches the null string after any newline in the string
+in addition to its normal function,
+and the `$' anchor matches the null string before any newline in the
+string in addition to its normal function.
+.IP REG_PEND
+The regular expression ends,
+not at the first NUL,
+but just before the character pointed to by the
+.I re_endp
+member of the structure pointed to by
+.IR preg .
+The
+.I re_endp
+member is of type
+.IR const\ char\ * .
+This flag permits inclusion of NULs in the RE;
+they are considered ordinary characters.
+This is an extension,
+compatible with but not specified by POSIX 1003.2,
+and should be used with
+caution in software intended to be portable to other systems.
+.PP
+When successful,
+.I regcomp
+returns 0 and fills in the structure pointed to by
+.IR preg .
+One member of that structure
+(other than
+.IR re_endp )
+is publicized:
+.IR re_nsub ,
+of type
+.IR size_t ,
+contains the number of parenthesized subexpressions within the RE
+(except that the value of this member is undefined if the
+REG_NOSUB flag was used).
+If
+.I regcomp
+fails, it returns a non-zero error code;
+see DIAGNOSTICS.
+.PP
+.I Regexec
+matches the compiled RE pointed to by
+.I preg
+against the
+.IR string ,
+subject to the flags in
+.IR eflags ,
+and reports results using
+.IR nmatch ,
+.IR pmatch ,
+and the returned value.
+The RE must have been compiled by a previous invocation of
+.IR regcomp .
+The compiled form is not altered during execution of
+.IR regexec ,
+so a single compiled RE can be used simultaneously by multiple threads.
+.PP
+By default,
+the NUL-terminated string pointed to by
+.I string
+is considered to be the text of an entire line, minus any terminating
+newline.
+The
+.I eflags
+argument is the bitwise OR of zero or more of the following flags:
+.IP REG_NOTBOL \w'REG_STARTEND'u+2n
+The first character of
+the string
+is not the beginning of a line, so the `^' anchor should not match before it.
+This does not affect the behavior of newlines under REG_NEWLINE.
+.IP REG_NOTEOL
+The NUL terminating
+the string
+does not end a line, so the `$' anchor should not match before it.
+This does not affect the behavior of newlines under REG_NEWLINE.
+.IP REG_STARTEND
+The string is considered to start at
+\fIstring\fR\ + \fIpmatch\fR[0].\fIrm_so\fR
+and to have a terminating NUL located at
+\fIstring\fR\ + \fIpmatch\fR[0].\fIrm_eo\fR
+(there need not actually be a NUL at that location),
+regardless of the value of
+.IR nmatch .
+See below for the definition of
+.IR pmatch
+and
+.IR nmatch .
+This is an extension,
+compatible with but not specified by POSIX 1003.2,
+and should be used with
+caution in software intended to be portable to other systems.
+Note that a non-zero \fIrm_so\fR does not imply REG_NOTBOL;
+REG_STARTEND affects only the location of the string,
+not how it is matched.
+.PP
+See
+.ZR
+for a discussion of what is matched in situations where an RE or a
+portion thereof could match any of several substrings of
+.IR string .
+.PP
+Normally,
+.I regexec
+returns 0 for success and the non-zero code REG_NOMATCH for failure.
+Other non-zero error codes may be returned in exceptional situations;
+see DIAGNOSTICS.
+.PP
+If REG_NOSUB was specified in the compilation of the RE,
+or if
+.I nmatch
+is 0,
+.I regexec
+ignores the
+.I pmatch
+argument (but see below for the case where REG_STARTEND is specified).
+Otherwise,
+.I pmatch
+points to an array of
+.I nmatch
+structures of type
+.IR regmatch_t .
+Such a structure has at least the members
+.I rm_so
+and
+.IR rm_eo ,
+both of type
+.I regoff_t
+(a signed arithmetic type at least as large as an
+.I off_t
+and a
+.IR ssize_t ),
+containing respectively the offset of the first character of a substring
+and the offset of the first character after the end of the substring.
+Offsets are measured from the beginning of the
+.I string
+argument given to
+.IR regexec .
+An empty substring is denoted by equal offsets,
+both indicating the character following the empty substring.
+.PP
+The 0th member of the
+.I pmatch
+array is filled in to indicate what substring of
+.I string
+was matched by the entire RE.
+Remaining members report what substring was matched by parenthesized
+subexpressions within the RE;
+member
+.I i
+reports subexpression
+.IR i ,
+with subexpressions counted (starting at 1) by the order of their opening
+parentheses in the RE, left to right.
+Unused entries in the array\(emcorresponding either to subexpressions that
+did not participate in the match at all, or to subexpressions that do not
+exist in the RE (that is, \fIi\fR\ > \fIpreg\fR\->\fIre_nsub\fR)\(emhave both
+.I rm_so
+and
+.I rm_eo
+set to \-1.
+If a subexpression participated in the match several times,
+the reported substring is the last one it matched.
+(Note, as an example in particular, that when the RE `(b*)+' matches `bbb',
+the parenthesized subexpression matches each of the three `b's and then
+an infinite number of empty strings following the last `b',
+so the reported substring is one of the empties.)
+.PP
+If REG_STARTEND is specified,
+.I pmatch
+must point to at least one
+.I regmatch_t
+(even if
+.I nmatch
+is 0 or REG_NOSUB was specified),
+to hold the input offsets for REG_STARTEND.
+Use for output is still entirely controlled by
+.IR nmatch ;
+if
+.I nmatch
+is 0 or REG_NOSUB was specified,
+the value of
+.IR pmatch [0]
+will not be changed by a successful
+.IR regexec .
+.PP
+.I Regerror
+maps a non-zero
+.I errcode
+from either
+.I regcomp
+or
+.I regexec
+to a human-readable, printable message.
+If
+.I preg
+is non-NULL,
+the error code should have arisen from use of
+the
+.I regex_t
+pointed to by
+.IR preg ,
+and if the error code came from
+.IR regcomp ,
+it should have been the result from the most recent
+.I regcomp
+using that
+.IR regex_t .
+.RI ( Regerror
+may be able to supply a more detailed message using information
+from the
+.IR regex_t .)
+.I Regerror
+places the NUL-terminated message into the buffer pointed to by
+.IR errbuf ,
+limiting the length (including the NUL) to at most
+.I errbuf_size
+bytes.
+If the whole message won't fit,
+as much of it as will fit before the terminating NUL is supplied.
+In any case,
+the returned value is the size of buffer needed to hold the whole
+message (including terminating NUL).
+If
+.I errbuf_size
+is 0,
+.I errbuf
+is ignored but the return value is still correct.
+.PP
+If the
+.I errcode
+given to
+.I regerror
+is first ORed with REG_ITOA,
+the ``message'' that results is the printable name of the error code,
+e.g. ``REG_NOMATCH'',
+rather than an explanation thereof.
+If
+.I errcode
+is REG_ATOI,
+then
+.I preg
+shall be non-NULL and the
+.I re_endp
+member of the structure it points to
+must point to the printable name of an error code;
+in this case, the result in
+.I errbuf
+is the decimal digits of
+the numeric value of the error code
+(0 if the name is not recognized).
+REG_ITOA and REG_ATOI are intended primarily as debugging facilities;
+they are extensions,
+compatible with but not specified by POSIX 1003.2,
+and should be used with
+caution in software intended to be portable to other systems.
+Be warned also that they are considered experimental and changes are possible.
+.PP
+.I Regfree
+frees any dynamically-allocated storage associated with the compiled RE
+pointed to by
+.IR preg .
+The remaining
+.I regex_t
+is no longer a valid compiled RE
+and the effect of supplying it to
+.I regexec
+or
+.I regerror
+is undefined.
+.PP
+None of these functions references global variables except for tables
+of constants;
+all are safe for use from multiple threads if the arguments are safe.
+.SH IMPLEMENTATION CHOICES
+There are a number of decisions that 1003.2 leaves up to the implementor,
+either by explicitly saying ``undefined'' or by virtue of them being
+forbidden by the RE grammar.
+This implementation treats them as follows.
+.PP
+See
+.ZR
+for a discussion of the definition of case-independent matching.
+.PP
+There is no particular limit on the length of REs,
+except insofar as memory is limited.
+Memory usage is approximately linear in RE size, and largely insensitive
+to RE complexity, except for bounded repetitions.
+See BUGS for one short RE using them
+that will run almost any system out of memory.
+.PP
+A backslashed character other than one specifically given a magic meaning
+by 1003.2 (such magic meanings occur only in obsolete [``basic''] REs)
+is taken as an ordinary character.
+.PP
+Any unmatched [ is a REG_EBRACK error.
+.PP
+Equivalence classes cannot begin or end bracket-expression ranges.
+The endpoint of one range cannot begin another.
+.PP
+RE_DUP_MAX, the limit on repetition counts in bounded repetitions, is 255.
+.PP
+A repetition operator (?, *, +, or bounds) cannot follow another
+repetition operator.
+A repetition operator cannot begin an expression or subexpression
+or follow `^' or `|'.
+.PP
+`|' cannot appear first or last in a (sub)expression or after another `|',
+i.e. an operand of `|' cannot be an empty subexpression.
+An empty parenthesized subexpression, `()', is legal and matches an
+empty (sub)string.
+An empty string is not a legal RE.
+.PP
+A `{' followed by a digit is considered the beginning of bounds for a
+bounded repetition, which must then follow the syntax for bounds.
+A `{' \fInot\fR followed by a digit is considered an ordinary character.
+.PP
+`^' and `$' beginning and ending subexpressions in obsolete (``basic'')
+REs are anchors, not ordinary characters.
+.SH SEE ALSO
+grep(1), regex(7)
+.PP
+POSIX 1003.2, sections 2.8 (Regular Expression Notation)
+and
+B.5 (C Binding for Regular Expression Matching).
+.SH DIAGNOSTICS
+Non-zero error codes from
+.I regcomp
+and
+.I regexec
+include the following:
+.PP
+.nf
+.ta \w'REG_ECOLLATE'u+3n
+REG_NOMATCH    regexec() failed to match
+REG_BADPAT     invalid regular expression
+REG_ECOLLATE   invalid collating element
+REG_ECTYPE     invalid character class
+REG_EESCAPE    \e applied to unescapable character
+REG_ESUBREG    invalid backreference number
+REG_EBRACK     brackets [ ] not balanced
+REG_EPAREN     parentheses ( ) not balanced
+REG_EBRACE     braces { } not balanced
+REG_BADBR      invalid repetition count(s) in { }
+REG_ERANGE     invalid character range in [ ]
+REG_ESPACE     ran out of memory
+REG_BADRPT     ?, *, or + operand invalid
+REG_EMPTY      empty (sub)expression
+REG_ASSERT     ``can't happen''\(emyou found a bug
+REG_INVARG     invalid argument, e.g. negative-length string
+.fi
+.SH HISTORY
+Written by Henry Spencer at University of Toronto,
+henry@zoo.toronto.edu.
+.SH BUGS
+This is an alpha release with known defects.
+Please report problems.
+.PP
+There is one known functionality bug.
+The implementation of internationalization is incomplete:
+the locale is always assumed to be the default one of 1003.2,
+and only the collating elements etc. of that locale are available.
+.PP
+The back-reference code is subtle and doubts linger about its correctness
+in complex cases.
+.PP
+.I Regexec
+performance is poor.
+This will improve with later releases.
+.I Nmatch
+exceeding 0 is expensive;
+.I nmatch
+exceeding 1 is worse.
+.I Regexec
+is largely insensitive to RE complexity \fIexcept\fR that back
+references are massively expensive.
+RE length does matter; in particular, there is a strong speed bonus
+for keeping RE length under about 30 characters,
+with most special characters counting roughly double.
+.PP
+.I Regcomp
+implements bounded repetitions by macro expansion,
+which is costly in time and space if counts are large
+or bounded repetitions are nested.
+An RE like, say,
+`((((a{1,100}){1,100}){1,100}){1,100}){1,100}'
+will (eventually) run almost any existing machine out of swap space.
+.PP
+There are suspected problems with response to obscure error conditions.
+Notably,
+certain kinds of internal overflow,
+produced only by truly enormous REs or by multiply nested bounded repetitions,
+are probably not handled well.
+.PP
+Due to a mistake in 1003.2, things like `a)b' are legal REs because `)' is
+a special character only in the presence of a previous unmatched `('.
+This can't be fixed until the spec is fixed.
+.PP
+The standard's definition of back references is vague.
+For example, does
+`a\e(\e(b\e)*\e2\e)*d' match `abbbd'?
+Until the standard is clarified,
+behavior in such cases should not be relied on.
+.PP
+The implementation of word-boundary matching is a bit of a kludge,
+and bugs may lurk in combinations of word-boundary matching and anchoring.
diff --git a/APACHE_1_2_X/src/regex/regex.7 b/APACHE_1_2_X/src/regex/regex.7
new file mode 100644 (file)
index 0000000..d89012b
--- /dev/null
@@ -0,0 +1,233 @@
+.TH REGEX 7 "7 Feb 1994"
+.BY "Henry Spencer"
+.SH NAME
+regex \- POSIX 1003.2 regular expressions
+.SH DESCRIPTION
+Regular expressions (``RE''s),
+as defined in POSIX 1003.2, come in two forms:
+modern REs (roughly those of
+.IR egrep ;
+1003.2 calls these ``extended'' REs)
+and obsolete REs (roughly those of
+.IR ed ;
+1003.2 ``basic'' REs).
+Obsolete REs mostly exist for backward compatibility in some old programs;
+they will be discussed at the end.
+1003.2 leaves some aspects of RE syntax and semantics open;
+`\(dg' marks decisions on these aspects that
+may not be fully portable to other 1003.2 implementations.
+.PP
+A (modern) RE is one\(dg or more non-empty\(dg \fIbranches\fR,
+separated by `|'.
+It matches anything that matches one of the branches.
+.PP
+A branch is one\(dg or more \fIpieces\fR, concatenated.
+It matches a match for the first, followed by a match for the second, etc.
+.PP
+A piece is an \fIatom\fR possibly followed
+by a single\(dg `*', `+', `?', or \fIbound\fR.
+An atom followed by `*' matches a sequence of 0 or more matches of the atom.
+An atom followed by `+' matches a sequence of 1 or more matches of the atom.
+An atom followed by `?' matches a sequence of 0 or 1 matches of the atom.
+.PP
+A \fIbound\fR is `{' followed by an unsigned decimal integer,
+possibly followed by `,'
+possibly followed by another unsigned decimal integer,
+always followed by `}'.
+The integers must lie between 0 and RE_DUP_MAX (255\(dg) inclusive,
+and if there are two of them, the first may not exceed the second.
+An atom followed by a bound containing one integer \fIi\fR
+and no comma matches
+a sequence of exactly \fIi\fR matches of the atom.
+An atom followed by a bound
+containing one integer \fIi\fR and a comma matches
+a sequence of \fIi\fR or more matches of the atom.
+An atom followed by a bound
+containing two integers \fIi\fR and \fIj\fR matches
+a sequence of \fIi\fR through \fIj\fR (inclusive) matches of the atom.
+.PP
+An atom is a regular expression enclosed in `()' (matching a match for the
+regular expression),
+an empty set of `()' (matching the null string)\(dg,
+a \fIbracket expression\fR (see below), `.'
+(matching any single character), `^' (matching the null string at the
+beginning of a line), `$' (matching the null string at the
+end of a line), a `\e' followed by one of the characters
+`^.[$()|*+?{\e'
+(matching that character taken as an ordinary character),
+a `\e' followed by any other character\(dg
+(matching that character taken as an ordinary character,
+as if the `\e' had not been present\(dg),
+or a single character with no other significance (matching that character).
+A `{' followed by a character other than a digit is an ordinary
+character, not the beginning of a bound\(dg.
+It is illegal to end an RE with `\e'.
+.PP
+A \fIbracket expression\fR is a list of characters enclosed in `[]'.
+It normally matches any single character from the list (but see below).
+If the list begins with `^',
+it matches any single character
+(but see below) \fInot\fR from the rest of the list.
+If two characters in the list are separated by `\-', this is shorthand
+for the full \fIrange\fR of characters between those two (inclusive) in the
+collating sequence,
+e.g. `[0-9]' in ASCII matches any decimal digit.
+It is illegal\(dg for two ranges to share an
+endpoint, e.g. `a-c-e'.
+Ranges are very collating-sequence-dependent,
+and portable programs should avoid relying on them.
+.PP
+To include a literal `]' in the list, make it the first character
+(following a possible `^').
+To include a literal `\-', make it the first or last character,
+or the second endpoint of a range.
+To use a literal `\-' as the first endpoint of a range,
+enclose it in `[.' and `.]' to make it a collating element (see below).
+With the exception of these and some combinations using `[' (see next
+paragraphs), all other special characters, including `\e', lose their
+special significance within a bracket expression.
+.PP
+Within a bracket expression, a collating element (a character,
+a multi-character sequence that collates as if it were a single character,
+or a collating-sequence name for either)
+enclosed in `[.' and `.]' stands for the
+sequence of characters of that collating element.
+The sequence is a single element of the bracket expression's list.
+A bracket expression containing a multi-character collating element 
+can thus match more than one character,
+e.g. if the collating sequence includes a `ch' collating element,
+then the RE `[[.ch.]]*c' matches the first five characters
+of `chchcc'.
+.PP
+Within a bracket expression, a collating element enclosed in `[=' and
+`=]' is an equivalence class, standing for the sequences of characters
+of all collating elements equivalent to that one, including itself.
+(If there are no other equivalent collating elements,
+the treatment is as if the enclosing delimiters were `[.' and `.]'.)
+For example, if o and \o'o^' are the members of an equivalence class,
+then `[[=o=]]', `[[=\o'o^'=]]', and `[o\o'o^']' are all synonymous.
+An equivalence class may not\(dg be an endpoint
+of a range.
+.PP
+Within a bracket expression, the name of a \fIcharacter class\fR enclosed
+in `[:' and `:]' stands for the list of all characters belonging to that
+class.
+Standard character class names are:
+.PP
+.RS
+.nf
+.ta 3c 6c 9c
+alnum  digit   punct
+alpha  graph   space
+blank  lower   upper
+cntrl  print   xdigit
+.fi
+.RE
+.PP
+These stand for the character classes defined in
+.IR ctype (3).
+A locale may provide others.
+A character class may not be used as an endpoint of a range.
+.PP
+There are two special cases\(dg of bracket expressions:
+the bracket expressions `[[:<:]]' and `[[:>:]]' match the null string at
+the beginning and end of a word respectively.
+A word is defined as a sequence of
+word characters
+which is neither preceded nor followed by
+word characters.
+A word character is an
+.I alnum
+character (as defined by
+.IR ctype (3))
+or an underscore.
+This is an extension,
+compatible with but not specified by POSIX 1003.2,
+and should be used with
+caution in software intended to be portable to other systems.
+.PP
+In the event that an RE could match more than one substring of a given
+string,
+the RE matches the one starting earliest in the string.
+If the RE could match more than one substring starting at that point,
+it matches the longest.
+Subexpressions also match the longest possible substrings, subject to
+the constraint that the whole match be as long as possible,
+with subexpressions starting earlier in the RE taking priority over
+ones starting later.
+Note that higher-level subexpressions thus take priority over
+their lower-level component subexpressions.
+.PP
+Match lengths are measured in characters, not collating elements.
+A null string is considered longer than no match at all.
+For example,
+`bb*' matches the three middle characters of `abbbc',
+`(wee|week)(knights|nights)' matches all ten characters of `weeknights',
+when `(.*).*' is matched against `abc' the parenthesized subexpression
+matches all three characters, and
+when `(a*)*' is matched against `bc' both the whole RE and the parenthesized
+subexpression match the null string.
+.PP
+If case-independent matching is specified,
+the effect is much as if all case distinctions had vanished from the
+alphabet.
+When an alphabetic that exists in multiple cases appears as an
+ordinary character outside a bracket expression, it is effectively
+transformed into a bracket expression containing both cases,
+e.g. `x' becomes `[xX]'.
+When it appears inside a bracket expression, all case counterparts
+of it are added to the bracket expression, so that (e.g.) `[x]'
+becomes `[xX]' and `[^x]' becomes `[^xX]'.
+.PP
+No particular limit is imposed on the length of REs\(dg.
+Programs intended to be portable should not employ REs longer
+than 256 bytes,
+as an implementation can refuse to accept such REs and remain
+POSIX-compliant.
+.PP
+Obsolete (``basic'') regular expressions differ in several respects.
+`|', `+', and `?' are ordinary characters and there is no equivalent
+for their functionality.
+The delimiters for bounds are `\e{' and `\e}',
+with `{' and `}' by themselves ordinary characters.
+The parentheses for nested subexpressions are `\e(' and `\e)',
+with `(' and `)' by themselves ordinary characters.
+`^' is an ordinary character except at the beginning of the
+RE or\(dg the beginning of a parenthesized subexpression,
+`$' is an ordinary character except at the end of the
+RE or\(dg the end of a parenthesized subexpression,
+and `*' is an ordinary character if it appears at the beginning of the
+RE or the beginning of a parenthesized subexpression
+(after a possible leading `^').
+Finally, there is one new type of atom, a \fIback reference\fR:
+`\e' followed by a non-zero decimal digit \fId\fR
+matches the same sequence of characters
+matched by the \fId\fRth parenthesized subexpression
+(numbering subexpressions by the positions of their opening parentheses,
+left to right),
+so that (e.g.) `\e([bc]\e)\e1' matches `bb' or `cc' but not `bc'.
+.SH SEE ALSO
+regex(3)
+.PP
+POSIX 1003.2, section 2.8 (Regular Expression Notation).
+.SH BUGS
+Having two kinds of REs is a botch.
+.PP
+The current 1003.2 spec says that `)' is an ordinary character in
+the absence of an unmatched `(';
+this was an unintentional result of a wording error,
+and change is likely.
+Avoid relying on it.
+.PP
+Back references are a dreadful botch,
+posing major problems for efficient implementations.
+They are also somewhat vaguely defined
+(does
+`a\e(\e(b\e)*\e2\e)*d' match `abbbd'?).
+Avoid using them.
+.PP
+1003.2's specification of case-independent matching is vague.
+The ``one case implies all cases'' definition given above
+is current consensus among implementors as to the right interpretation.
+.PP
+The syntax for word boundaries is incredibly ugly.
diff --git a/APACHE_1_2_X/src/regex/regex.h b/APACHE_1_2_X/src/regex/regex.h
new file mode 100644 (file)
index 0000000..dde954d
--- /dev/null
@@ -0,0 +1,73 @@
+#ifndef _REGEX_H_
+#define        _REGEX_H_       /* never again */
+/* ========= begin header generated by ./mkh ========= */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* === regex2.h === */
+typedef off_t regoff_t;
+typedef struct {
+       int re_magic;
+       size_t re_nsub;         /* number of parenthesized subexpressions */
+       const char *re_endp;    /* end pointer for REG_PEND */
+       struct re_guts *re_g;   /* none of your business :-) */
+} regex_t;
+typedef struct {
+       regoff_t rm_so;         /* start of match */
+       regoff_t rm_eo;         /* end of match */
+} regmatch_t;
+
+
+/* === regcomp.c === */
+extern int regcomp(regex_t *, const char *, int);
+#define        REG_BASIC       0000
+#define        REG_EXTENDED    0001
+#define        REG_ICASE       0002
+#define        REG_NOSUB       0004
+#define        REG_NEWLINE     0010
+#define        REG_NOSPEC      0020
+#define        REG_PEND        0040
+#define        REG_DUMP        0200
+
+
+/* === regerror.c === */
+#define        REG_NOMATCH      1
+#define        REG_BADPAT       2
+#define        REG_ECOLLATE     3
+#define        REG_ECTYPE       4
+#define        REG_EESCAPE      5
+#define        REG_ESUBREG      6
+#define        REG_EBRACK       7
+#define        REG_EPAREN       8
+#define        REG_EBRACE       9
+#define        REG_BADBR       10
+#define        REG_ERANGE      11
+#define        REG_ESPACE      12
+#define        REG_BADRPT      13
+#define        REG_EMPTY       14
+#define        REG_ASSERT      15
+#define        REG_INVARG      16
+#define        REG_ATOI        255     /* convert name to number (!) */
+#define        REG_ITOA        0400    /* convert number to name (!) */
+extern size_t regerror(int, const regex_t *, char *, size_t);
+
+
+/* === regexec.c === */
+extern int regexec(const regex_t *, const char *, size_t, regmatch_t [], int);
+#define        REG_NOTBOL      00001
+#define        REG_NOTEOL      00002
+#define        REG_STARTEND    00004
+#define        REG_TRACE       00400   /* tracing of execution */
+#define        REG_LARGE       01000   /* force large representation */
+#define        REG_BACKR       02000   /* force use of backref code */
+
+
+/* === regfree.c === */
+extern void regfree(regex_t *);
+
+#ifdef __cplusplus
+}
+#endif
+/* ========= end header generated by ./mkh ========= */
+#endif
diff --git a/APACHE_1_2_X/src/regex/regex2.h b/APACHE_1_2_X/src/regex/regex2.h
new file mode 100644 (file)
index 0000000..6ec57b2
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * First, the stuff that ends up in the outside-world include file
+ = typedef off_t regoff_t;
+ = typedef struct {
+ =     int re_magic;
+ =     size_t re_nsub;         // number of parenthesized subexpressions
+ =     const char *re_endp;    // end pointer for REG_PEND
+ =     struct re_guts *re_g;   // none of your business :-)
+ = } regex_t;
+ = typedef struct {
+ =     regoff_t rm_so;         // start of match
+ =     regoff_t rm_eo;         // end of match
+ = } regmatch_t;
+ */
+/*
+ * internals of regex_t
+ */
+#define        MAGIC1  ((('r'^0200)<<8) | 'e')
+
+/*
+ * The internal representation is a *strip*, a sequence of
+ * operators ending with an endmarker.  (Some terminology etc. is a
+ * historical relic of earlier versions which used multiple strips.)
+ * Certain oddities in the representation are there to permit running
+ * the machinery backwards; in particular, any deviation from sequential
+ * flow must be marked at both its source and its destination.  Some
+ * fine points:
+ *
+ * - OPLUS_ and O_PLUS are *inside* the loop they create.
+ * - OQUEST_ and O_QUEST are *outside* the bypass they create.
+ * - OCH_ and O_CH are *outside* the multi-way branch they create, while
+ *   OOR1 and OOR2 are respectively the end and the beginning of one of
+ *   the branches.  Note that there is an implicit OOR2 following OCH_
+ *   and an implicit OOR1 preceding O_CH.
+ *
+ * In state representations, an operator's bit is on to signify a state
+ * immediately *preceding* "execution" of that operator.
+ */
+typedef unsigned long sop;     /* strip operator */
+typedef long sopno;
+#define        OPRMASK 0xf8000000
+#define        OPDMASK 0x07ffffff
+#define        OPSHIFT ((unsigned)27)
+#define        OP(n)   ((n)&OPRMASK)
+#define        OPND(n) ((n)&OPDMASK)
+#define        SOP(op, opnd)   ((op)|(opnd))
+/* operators                      meaning      operand                 */
+/*                                             (back, fwd are offsets) */
+#define        OEND    (1<<OPSHIFT)    /* endmarker    -                       */
+#define        OCHAR   (2<<OPSHIFT)    /* character    unsigned char           */
+#define        OBOL    (3<<OPSHIFT)    /* left anchor  -                       */
+#define        OEOL    (4<<OPSHIFT)    /* right anchor -                       */
+#define        OANY    (5<<OPSHIFT)    /* .            -                       */
+#define        OANYOF  (6<<OPSHIFT)    /* [...]        set number              */
+#define        OBACK_  (7<<OPSHIFT)    /* begin \d     paren number            */
+#define        O_BACK  (8<<OPSHIFT)    /* end \d       paren number            */
+#define        OPLUS_  (9<<OPSHIFT)    /* + prefix     fwd to suffix           */
+#define        O_PLUS  (10<<OPSHIFT)   /* + suffix     back to prefix          */
+#define        OQUEST_ (11<<OPSHIFT)   /* ? prefix     fwd to suffix           */
+#define        O_QUEST (12<<OPSHIFT)   /* ? suffix     back to prefix          */
+#define        OLPAREN (13<<OPSHIFT)   /* (            fwd to )                */
+#define        ORPAREN (14<<OPSHIFT)   /* )            back to (               */
+#define        OCH_    (15<<OPSHIFT)   /* begin choice fwd to OOR2             */
+#define        OOR1    (16u<<OPSHIFT)  /* | pt. 1      back to OOR1 or OCH_    */
+#define        OOR2    (17u<<OPSHIFT)  /* | pt. 2      fwd to OOR2 or O_CH     */
+#define        O_CH    (18u<<OPSHIFT)  /* end choice   back to OOR1            */
+#define        OBOW    (19u<<OPSHIFT)  /* begin word   -                       */
+#define        OEOW    (20u<<OPSHIFT)  /* end word     -                       */
+
+/*
+ * Structure for [] character-set representation.  Character sets are
+ * done as bit vectors, grouped 8 to a byte vector for compactness.
+ * The individual set therefore has both a pointer to the byte vector
+ * and a mask to pick out the relevant bit of each byte.  A hash code
+ * simplifies testing whether two sets could be identical.
+ *
+ * This will get trickier for multicharacter collating elements.  As
+ * preliminary hooks for dealing with such things, we also carry along
+ * a string of multi-character elements, and decide the size of the
+ * vectors at run time.
+ */
+typedef struct {
+       uch *ptr;               /* -> uch [csetsize] */
+       uch mask;               /* bit within array */
+       uch hash;               /* hash code */
+       size_t smultis;
+       char *multis;           /* -> char[smulti]  ab\0cd\0ef\0\0 */
+} cset;
+/* note that CHadd and CHsub are unsafe, and CHIN doesn't yield 0/1 */
+#define        CHadd(cs, c)    ((cs)->ptr[(uch)(c)] |= (cs)->mask, (cs)->hash += (c))
+#define        CHsub(cs, c)    ((cs)->ptr[(uch)(c)] &= ~(cs)->mask, (cs)->hash -= (c))
+#define        CHIN(cs, c)     ((cs)->ptr[(uch)(c)] & (cs)->mask)
+#define        MCadd(p, cs, cp)        mcadd(p, cs, cp)        /* regcomp() internal fns */
+
+/* stuff for character categories */
+typedef unsigned char cat_t;
+
+/*
+ * main compiled-expression structure
+ */
+struct re_guts {
+       int magic;
+#              define  MAGIC2  ((('R'^0200)<<8)|'E')
+       sop *strip;             /* malloced area for strip */
+       int csetsize;           /* number of bits in a cset vector */
+       int ncsets;             /* number of csets in use */
+       cset *sets;             /* -> cset [ncsets] */
+       uch *setbits;           /* -> uch[csetsize][ncsets/CHAR_BIT] */
+       int cflags;             /* copy of regcomp() cflags argument */
+       sopno nstates;          /* = number of sops */
+       sopno firststate;       /* the initial OEND (normally 0) */
+       sopno laststate;        /* the final OEND */
+       int iflags;             /* internal flags */
+#              define  USEBOL  01      /* used ^ */
+#              define  USEEOL  02      /* used $ */
+#              define  BAD     04      /* something wrong */
+       int nbol;               /* number of ^ used */
+       int neol;               /* number of $ used */
+       int ncategories;        /* how many character categories */
+       cat_t *categories;      /* ->catspace[-CHAR_MIN] */
+       char *must;             /* match must contain this string */
+       int mlen;               /* length of must */
+       size_t nsub;            /* copy of re_nsub */
+       int backrefs;           /* does it use back references? */
+       sopno nplus;            /* how deep does it nest +s? */
+       /* catspace must be last */
+       cat_t catspace[1];      /* actually [NC] */
+};
+
+/* misc utilities */
+#define        OUT     (CHAR_MAX+1)    /* a non-character value */
+#define        ISWORD(c)       (isalnum(c) || (c) == '_')
diff --git a/APACHE_1_2_X/src/regex/regexec.c b/APACHE_1_2_X/src/regex/regexec.c
new file mode 100644 (file)
index 0000000..63bb1c3
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * the outer shell of regexec()
+ *
+ * This file includes engine.c *twice*, after muchos fiddling with the
+ * macros that code uses.  This lets the same code operate on two different
+ * representations for state sets.
+ */
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <ctype.h>
+#include <regex.h>
+
+#include "utils.h"
+#include "regex2.h"
+
+#ifndef NDEBUG
+static int nope = 0;           /* for use in asserts; shuts lint up */
+#endif
+
+/* macros for manipulating states, small version */
+#define        states  long
+#define        states1 states          /* for later use in regexec() decision */
+#define        CLEAR(v)        ((v) = 0)
+#define        SET0(v, n)      ((v) &= ~(1 << (n)))
+#define        SET1(v, n)      ((v) |= 1 << (n))
+#define        ISSET(v, n)     ((v) & (1 << (n)))
+#define        ASSIGN(d, s)    ((d) = (s))
+#define        EQ(a, b)        ((a) == (b))
+#define        STATEVARS       int dummy       /* dummy version */
+#define        STATESETUP(m, n)        /* nothing */
+#define        STATETEARDOWN(m)        /* nothing */
+#define        SETUP(v)        ((v) = 0)
+#define        onestate        int
+#define        INIT(o, n)      ((o) = (unsigned)1 << (n))
+#define        INC(o)  ((o) <<= 1)
+#define        ISSTATEIN(v, o) ((v) & (o))
+/* some abbreviations; note that some of these know variable names! */
+/* do "if I'm here, I can also be there" etc without branches */
+#define        FWD(dst, src, n)        ((dst) |= ((unsigned)(src)&(here)) << (n))
+#define        BACK(dst, src, n)       ((dst) |= ((unsigned)(src)&(here)) >> (n))
+#define        ISSETBACK(v, n) ((v) & ((unsigned)here >> (n)))
+/* function names */
+#define SNAMES                 /* engine.c looks after details */
+
+#include "engine.c"
+
+/* now undo things */
+#undef states
+#undef CLEAR
+#undef SET0
+#undef SET1
+#undef ISSET
+#undef ASSIGN
+#undef EQ
+#undef STATEVARS
+#undef STATESETUP
+#undef STATETEARDOWN
+#undef SETUP
+#undef onestate
+#undef INIT
+#undef INC
+#undef ISSTATEIN
+#undef FWD
+#undef BACK
+#undef ISSETBACK
+#undef SNAMES
+
+/* macros for manipulating states, large version */
+#define        states  char *
+#define        CLEAR(v)        memset(v, 0, m->g->nstates)
+#define        SET0(v, n)      ((v)[n] = 0)
+#define        SET1(v, n)      ((v)[n] = 1)
+#define        ISSET(v, n)     ((v)[n])
+#define        ASSIGN(d, s)    memcpy(d, s, m->g->nstates)
+#define        EQ(a, b)        (memcmp(a, b, m->g->nstates) == 0)
+#define        STATEVARS       int vn; char *space
+#define        STATESETUP(m, nv)       { (m)->space = malloc((nv)*(m)->g->nstates); \
+                               if ((m)->space == NULL) return(REG_ESPACE); \
+                               (m)->vn = 0; }
+#define        STATETEARDOWN(m)        { free((m)->space); }
+#define        SETUP(v)        ((v) = &m->space[m->vn++ * m->g->nstates])
+#define        onestate        int
+#define        INIT(o, n)      ((o) = (n))
+#define        INC(o)  ((o)++)
+#define        ISSTATEIN(v, o) ((v)[o])
+/* some abbreviations; note that some of these know variable names! */
+/* do "if I'm here, I can also be there" etc without branches */
+#define        FWD(dst, src, n)        ((dst)[here+(n)] |= (src)[here])
+#define        BACK(dst, src, n)       ((dst)[here-(n)] |= (src)[here])
+#define        ISSETBACK(v, n) ((v)[here - (n)])
+/* function names */
+#define        LNAMES                  /* flag */
+
+#include "engine.c"
+
+/*
+ - regexec - interface for matching
+ = extern int regexec(const regex_t *, const char *, size_t, \
+ =                                     regmatch_t [], int);
+ = #define     REG_NOTBOL      00001
+ = #define     REG_NOTEOL      00002
+ = #define     REG_STARTEND    00004
+ = #define     REG_TRACE       00400   // tracing of execution
+ = #define     REG_LARGE       01000   // force large representation
+ = #define     REG_BACKR       02000   // force use of backref code
+ *
+ * We put this here so we can exploit knowledge of the state representation
+ * when choosing which matcher to call.  Also, by this point the matchers
+ * have been prototyped.
+ */
+int                            /* 0 success, REG_NOMATCH failure */
+regexec(preg, string, nmatch, pmatch, eflags)
+const regex_t *preg;
+const char *string;
+size_t nmatch;
+regmatch_t pmatch[];
+int eflags;
+{
+       register struct re_guts *g = preg->re_g;
+#ifdef REDEBUG
+#      define  GOODFLAGS(f)    (f)
+#else
+#      define  GOODFLAGS(f)    ((f)&(REG_NOTBOL|REG_NOTEOL|REG_STARTEND))
+#endif
+
+       if (preg->re_magic != MAGIC1 || g->magic != MAGIC2)
+               return(REG_BADPAT);
+       assert(!(g->iflags&BAD));
+       if (g->iflags&BAD)              /* backstop for no-debug case */
+               return(REG_BADPAT);
+       eflags = GOODFLAGS(eflags);
+
+       if (g->nstates <= CHAR_BIT*sizeof(states1) && !(eflags&REG_LARGE))
+               return(smatcher(g, (char *)string, nmatch, pmatch, eflags));
+       else
+               return(lmatcher(g, (char *)string, nmatch, pmatch, eflags));
+}
diff --git a/APACHE_1_2_X/src/regex/regfree.c b/APACHE_1_2_X/src/regex/regfree.c
new file mode 100644 (file)
index 0000000..9a6acf1
--- /dev/null
@@ -0,0 +1,37 @@
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <regex.h>
+
+#include "utils.h"
+#include "regex2.h"
+
+/*
+ - regfree - free everything
+ = extern void regfree(regex_t *);
+ */
+void
+regfree(preg)
+regex_t *preg;
+{
+       register struct re_guts *g;
+
+       if (preg->re_magic != MAGIC1)   /* oops */
+               return;                 /* nice to complain, but hard */
+
+       g = preg->re_g;
+       if (g == NULL || g->magic != MAGIC2)    /* oops again */
+               return;
+       preg->re_magic = 0;             /* mark it invalid */
+       g->magic = 0;                   /* mark it invalid */
+
+       if (g->strip != NULL)
+               free((char *)g->strip);
+       if (g->sets != NULL)
+               free((char *)g->sets);
+       if (g->setbits != NULL)
+               free((char *)g->setbits);
+       if (g->must != NULL)
+               free(g->must);
+       free((char *)g);
+}
diff --git a/APACHE_1_2_X/src/regex/split.c b/APACHE_1_2_X/src/regex/split.c
new file mode 100644 (file)
index 0000000..188bdb7
--- /dev/null
@@ -0,0 +1,316 @@
+#include <stdio.h>
+#include <string.h>
+
+/*
+ - split - divide a string into fields, like awk split()
+ = int split(char *string, char *fields[], int nfields, char *sep);
+ */
+int                            /* number of fields, including overflow */
+split(string, fields, nfields, sep)
+char *string;
+char *fields[];                        /* list is not NULL-terminated */
+int nfields;                   /* number of entries available in fields[] */
+char *sep;                     /* "" white, "c" single char, "ab" [ab]+ */
+{
+       register char *p = string;
+       register char c;                        /* latest character */
+       register char sepc = sep[0];
+       register char sepc2;
+       register int fn;
+       register char **fp = fields;
+       register char *sepp;
+       register int trimtrail;
+
+       /* white space */
+       if (sepc == '\0') {
+               while ((c = *p++) == ' ' || c == '\t')
+                       continue;
+               p--;
+               trimtrail = 1;
+               sep = " \t";    /* note, code below knows this is 2 long */
+               sepc = ' ';
+       } else
+               trimtrail = 0;
+       sepc2 = sep[1];         /* now we can safely pick this up */
+
+       /* catch empties */
+       if (*p == '\0')
+               return(0);
+
+       /* single separator */
+       if (sepc2 == '\0') {
+               fn = nfields;
+               for (;;) {
+                       *fp++ = p;
+                       fn--;
+                       if (fn == 0)
+                               break;
+                       while ((c = *p++) != sepc)
+                               if (c == '\0')
+                                       return(nfields - fn);
+                       *(p-1) = '\0';
+               }
+               /* we have overflowed the fields vector -- just count them */
+               fn = nfields;
+               for (;;) {
+                       while ((c = *p++) != sepc)
+                               if (c == '\0')
+                                       return(fn);
+                       fn++;
+               }
+               /* not reached */
+       }
+
+       /* two separators */
+       if (sep[2] == '\0') {
+               fn = nfields;
+               for (;;) {
+                       *fp++ = p;
+                       fn--;
+                       while ((c = *p++) != sepc && c != sepc2)
+                               if (c == '\0') {
+                                       if (trimtrail && **(fp-1) == '\0')
+                                               fn++;
+                                       return(nfields - fn);
+                               }
+                       if (fn == 0)
+                               break;
+                       *(p-1) = '\0';
+                       while ((c = *p++) == sepc || c == sepc2)
+                               continue;
+                       p--;
+               }
+               /* we have overflowed the fields vector -- just count them */
+               fn = nfields;
+               while (c != '\0') {
+                       while ((c = *p++) == sepc || c == sepc2)
+                               continue;
+                       p--;
+                       fn++;
+                       while ((c = *p++) != '\0' && c != sepc && c != sepc2)
+                               continue;
+               }
+               /* might have to trim trailing white space */
+               if (trimtrail) {
+                       p--;
+                       while ((c = *--p) == sepc || c == sepc2)
+                               continue;
+                       p++;
+                       if (*p != '\0') {
+                               if (fn == nfields+1)
+                                       *p = '\0';
+                               fn--;
+                       }
+               }
+               return(fn);
+       }
+
+       /* n separators */
+       fn = 0;
+       for (;;) {
+               if (fn < nfields)
+                       *fp++ = p;
+               fn++;
+               for (;;) {
+                       c = *p++;
+                       if (c == '\0')
+                               return(fn);
+                       sepp = sep;
+                       while ((sepc = *sepp++) != '\0' && sepc != c)
+                               continue;
+                       if (sepc != '\0')       /* it was a separator */
+                               break;
+               }
+               if (fn < nfields)
+                       *(p-1) = '\0';
+               for (;;) {
+                       c = *p++;
+                       sepp = sep;
+                       while ((sepc = *sepp++) != '\0' && sepc != c)
+                               continue;
+                       if (sepc == '\0')       /* it wasn't a separator */
+                               break;
+               }
+               p--;
+       }
+
+       /* not reached */
+}
+
+#ifdef TEST_SPLIT
+
+
+/*
+ * test program
+ * pgm         runs regression
+ * pgm sep     splits stdin lines by sep
+ * pgm str sep splits str by sep
+ * pgm str sep n       splits str by sep n times
+ */
+int
+main(argc, argv)
+int argc;
+char *argv[];
+{
+       char buf[512];
+       register int n;
+#      define  MNF     10
+       char *fields[MNF];
+
+       if (argc > 4)
+               for (n = atoi(argv[3]); n > 0; n--) {
+                       (void) strcpy(buf, argv[1]);
+               }
+       else if (argc > 3)
+               for (n = atoi(argv[3]); n > 0; n--) {
+                       (void) strcpy(buf, argv[1]);
+                       (void) split(buf, fields, MNF, argv[2]);
+               }
+       else if (argc > 2)
+               dosplit(argv[1], argv[2]);
+       else if (argc > 1)
+               while (fgets(buf, sizeof(buf), stdin) != NULL) {
+                       buf[strlen(buf)-1] = '\0';      /* stomp newline */
+                       dosplit(buf, argv[1]);
+               }
+       else
+               regress();
+
+       exit(0);
+}
+
+dosplit(string, seps)
+char *string;
+char *seps;
+{
+#      define  NF      5
+       char *fields[NF];
+       register int nf;
+
+       nf = split(string, fields, NF, seps);
+       print(nf, NF, fields);
+}
+
+print(nf, nfp, fields)
+int nf;
+int nfp;
+char *fields[];
+{
+       register int fn;
+       register int bound;
+
+       bound = (nf > nfp) ? nfp : nf;
+       printf("%d:\t", nf);
+       for (fn = 0; fn < bound; fn++)
+               printf("\"%s\"%s", fields[fn], (fn+1 < nf) ? ", " : "\n");
+}
+
+#define        RNF     5               /* some table entries know this */
+struct {
+       char *str;
+       char *seps;
+       int nf;
+       char *fi[RNF];
+} tests[] = {
+       "",             " ",    0,      { "" },
+       " ",            " ",    2,      { "", "" },
+       "x",            " ",    1,      { "x" },
+       "xy",           " ",    1,      { "xy" },
+       "x y",          " ",    2,      { "x", "y" },
+       "abc def  g ",  " ",    5,      { "abc", "def", "", "g", "" },
+       "  a bcd",      " ",    4,      { "", "", "a", "bcd" },
+       "a b c d e f",  " ",    6,      { "a", "b", "c", "d", "e f" },
+       " a b c d ",    " ",    6,      { "", "a", "b", "c", "d " },
+
+       "",             " _",   0,      { "" },
+       " ",            " _",   2,      { "", "" },
+       "x",            " _",   1,      { "x" },
+       "x y",          " _",   2,      { "x", "y" },
+       "ab _ cd",      " _",   2,      { "ab", "cd" },
+       " a_b  c ",     " _",   5,      { "", "a", "b", "c", "" },
+       "a b c_d e f",  " _",   6,      { "a", "b", "c", "d", "e f" },
+       " a b c d ",    " _",   6,      { "", "a", "b", "c", "d " },
+
+       "",             " _~",  0,      { "" },
+       " ",            " _~",  2,      { "", "" },
+       "x",            " _~",  1,      { "x" },
+       "x y",          " _~",  2,      { "x", "y" },
+       "ab _~ cd",     " _~",  2,      { "ab", "cd" },
+       " a_b  c~",     " _~",  5,      { "", "a", "b", "c", "" },
+       "a b_c d~e f",  " _~",  6,      { "a", "b", "c", "d", "e f" },
+       "~a b c d ",    " _~",  6,      { "", "a", "b", "c", "d " },
+
+       "",             " _~-", 0,      { "" },
+       " ",            " _~-", 2,      { "", "" },
+       "x",            " _~-", 1,      { "x" },
+       "x y",          " _~-", 2,      { "x", "y" },
+       "ab _~- cd",    " _~-", 2,      { "ab", "cd" },
+       " a_b  c~",     " _~-", 5,      { "", "a", "b", "c", "" },
+       "a b_c-d~e f",  " _~-", 6,      { "a", "b", "c", "d", "e f" },
+       "~a-b c d ",    " _~-", 6,      { "", "a", "b", "c", "d " },
+
+       "",             "  ",   0,      { "" },
+       " ",            "  ",   2,      { "", "" },
+       "x",            "  ",   1,      { "x" },
+       "xy",           "  ",   1,      { "xy" },
+       "x y",          "  ",   2,      { "x", "y" },
+       "abc def  g ",  "  ",   4,      { "abc", "def", "g", "" },
+       "  a bcd",      "  ",   3,      { "", "a", "bcd" },
+       "a b c d e f",  "  ",   6,      { "a", "b", "c", "d", "e f" },
+       " a b c d ",    "  ",   6,      { "", "a", "b", "c", "d " },
+
+       "",             "",     0,      { "" },
+       " ",            "",     0,      { "" },
+       "x",            "",     1,      { "x" },
+       "xy",           "",     1,      { "xy" },
+       "x y",          "",     2,      { "x", "y" },
+       "abc def  g ",  "",     3,      { "abc", "def", "g" },
+       "\t a bcd",     "",     2,      { "a", "bcd" },
+       "  a \tb\t c ", "",     3,      { "a", "b", "c" },
+       "a b c d e ",   "",     5,      { "a", "b", "c", "d", "e" },
+       "a b\tc d e f", "",     6,      { "a", "b", "c", "d", "e f" },
+       " a b c d e f ",        "",     6,      { "a", "b", "c", "d", "e f " },
+
+       NULL,           NULL,   0,      { NULL },
+};
+
+regress()
+{
+       char buf[512];
+       register int n;
+       char *fields[RNF+1];
+       register int nf;
+       register int i;
+       register int printit;
+       register char *f;
+
+       for (n = 0; tests[n].str != NULL; n++) {
+               (void) strcpy(buf, tests[n].str);
+               fields[RNF] = NULL;
+               nf = split(buf, fields, RNF, tests[n].seps);
+               printit = 0;
+               if (nf != tests[n].nf) {
+                       printf("split `%s' by `%s' gave %d fields, not %d\n",
+                               tests[n].str, tests[n].seps, nf, tests[n].nf);
+                       printit = 1;
+               } else if (fields[RNF] != NULL) {
+                       printf("split() went beyond array end\n");
+                       printit = 1;
+               } else {
+                       for (i = 0; i < nf && i < RNF; i++) {
+                               f = fields[i];
+                               if (f == NULL)
+                                       f = "(NULL)";
+                               if (strcmp(f, tests[n].fi[i]) != 0) {
+                                       printf("split `%s' by `%s', field %d is `%s', not `%s'\n",
+                                               tests[n].str, tests[n].seps,
+                                               i, fields[i], tests[n].fi[i]);
+                                       printit = 1;
+                               }
+                       }
+               }
+               if (printit)
+                       print(nf, RNF, fields);
+       }
+}
+#endif
diff --git a/APACHE_1_2_X/src/regex/tests b/APACHE_1_2_X/src/regex/tests
new file mode 100644 (file)
index 0000000..c058461
--- /dev/null
@@ -0,0 +1,475 @@
+# regular expression test set
+# Lines are at least three fields, separated by one or more tabs.  "" stands
+# for an empty field.  First field is an RE.  Second field is flags.  If
+# C flag given, regcomp() is expected to fail, and the third field is the
+# error name (minus the leading REG_).
+#
+# Otherwise it is expected to succeed, and the third field is the string to
+# try matching it against.  If there is no fourth field, the match is
+# expected to fail.  If there is a fourth field, it is the substring that
+# the RE is expected to match.  If there is a fifth field, it is a comma-
+# separated list of what the subexpressions should match, with - indicating
+# no match for that one.  In both the fourth and fifth fields, a (sub)field
+# starting with @ indicates that the (sub)expression is expected to match
+# a null string followed by the stuff after the @; this provides a way to
+# test where null strings match.  The character `N' in REs and strings
+# is newline, `S' is space, `T' is tab, `Z' is NUL.
+#
+# The full list of flags:
+#      -       placeholder, does nothing
+#      b       RE is a BRE, not an ERE
+#      &       try it as both an ERE and a BRE
+#      C       regcomp() error expected, third field is error name
+#      i       REG_ICASE
+#      m       ("mundane") REG_NOSPEC
+#      s       REG_NOSUB (not really testable)
+#      n       REG_NEWLINE
+#      ^       REG_NOTBOL
+#      $       REG_NOTEOL
+#      #       REG_STARTEND (see below)
+#      p       REG_PEND
+#
+# For REG_STARTEND, the start/end offsets are those of the substring
+# enclosed in ().
+
+# basics
+a              &       a       a
+abc            &       abc     abc
+abc|de         -       abc     abc
+a|b|c          -       abc     a
+
+# parentheses and perversions thereof
+a(b)c          -       abc     abc
+a\(b\)c                b       abc     abc
+a(             C       EPAREN
+a(             b       a(      a(
+a\(            -       a(      a(
+a\(            bC      EPAREN
+a\(b           bC      EPAREN
+a(b            C       EPAREN
+a(b            b       a(b     a(b
+# gag me with a right parenthesis -- 1003.2 goofed here (my fault, partly)
+a)             -       a)      a)
+)              -       )       )
+# end gagging (in a just world, those *should* give EPAREN)
+a)             b       a)      a)
+a\)            bC      EPAREN
+\)             bC      EPAREN
+a()b           -       ab      ab
+a\(\)b         b       ab      ab
+
+# anchoring and REG_NEWLINE
+^abc$          &       abc     abc
+a^b            -       a^b
+a^b            b       a^b     a^b
+a$b            -       a$b
+a$b            b       a$b     a$b
+^              &       abc     @abc
+$              &       abc     @
+^$             &       ""      @
+$^             -       ""      @
+\($\)\(^\)     b       ""      @
+# stop retching, those are legitimate (although disgusting)
+^^             -       ""      @
+$$             -       ""      @
+b$             &       abNc
+b$             &n      abNc    b
+^b$            &       aNbNc
+^b$            &n      aNbNc   b
+^$             &n      aNNb    @Nb
+^$             n       abc
+^$             n       abcN    @
+$^             n       aNNb    @Nb
+\($\)\(^\)     bn      aNNb    @Nb
+^^             n^      aNNb    @Nb
+$$             n       aNNb    @NN
+^a             ^       a
+a$             $       a
+^a             ^n      aNb
+^b             ^n      aNb     b
+a$             $n      bNa
+b$             $n      bNa     b
+a*(^b$)c*      -       b       b
+a*\(^b$\)c*    b       b       b
+
+# certain syntax errors and non-errors
+|              C       EMPTY
+|              b       |       |
+*              C       BADRPT
+*              b       *       *
++              C       BADRPT
+?              C       BADRPT
+""             &C      EMPTY
+()             -       abc     @abc
+\(\)           b       abc     @abc
+a||b           C       EMPTY
+|ab            C       EMPTY
+ab|            C       EMPTY
+(|a)b          C       EMPTY
+(a|)b          C       EMPTY
+(*a)           C       BADRPT
+(+a)           C       BADRPT
+(?a)           C       BADRPT
+({1}a)         C       BADRPT
+\(\{1\}a\)     bC      BADRPT
+(a|*b)         C       BADRPT
+(a|+b)         C       BADRPT
+(a|?b)         C       BADRPT
+(a|{1}b)       C       BADRPT
+^*             C       BADRPT
+^*             b       *       *
+^+             C       BADRPT
+^?             C       BADRPT
+^{1}           C       BADRPT
+^\{1\}         bC      BADRPT
+
+# metacharacters, backslashes
+a.c            &       abc     abc
+a[bc]d         &       abd     abd
+a\*c           &       a*c     a*c
+a\\b           &       a\b     a\b
+a\\\*b         &       a\*b    a\*b
+a\bc           &       abc     abc
+a\             &C      EESCAPE
+a\\bc          &       a\bc    a\bc
+\{             bC      BADRPT
+a\[b           &       a[b     a[b
+a[b            &C      EBRACK
+# trailing $ is a peculiar special case for the BRE code
+a$             &       a       a
+a$             &       a$
+a\$            &       a
+a\$            &       a$      a$
+a\\$           &       a
+a\\$           &       a$
+a\\$           &       a\$
+a\\$           &       a\      a\
+
+# back references, ugh
+a\(b\)\2c      bC      ESUBREG
+a\(b\1\)c      bC      ESUBREG
+a\(b*\)c\1d    b       abbcbbd abbcbbd bb
+a\(b*\)c\1d    b       abbcbd
+a\(b*\)c\1d    b       abbcbbbd
+^\(.\)\1       b       abc
+a\([bc]\)\1d   b       abcdabbd        abbd    b
+a\(\([bc]\)\2\)*d      b       abbccd  abbccd
+a\(\([bc]\)\2\)*d      b       abbcbd
+# actually, this next one probably ought to fail, but the spec is unclear
+a\(\(b\)*\2\)*d                b       abbbd   abbbd
+# here is a case that no NFA implementation does right
+\(ab*\)[ab]*\1 b       ababaaa ababaaa a
+# check out normal matching in the presence of back refs
+\(a\)\1bcd     b       aabcd   aabcd
+\(a\)\1bc*d    b       aabcd   aabcd
+\(a\)\1bc*d    b       aabd    aabd
+\(a\)\1bc*d    b       aabcccd aabcccd
+\(a\)\1bc*[ce]d        b       aabcccd aabcccd
+^\(a\)\1b\(c\)*cd$     b       aabcccd aabcccd
+
+# ordinary repetitions
+ab*c           &       abc     abc
+ab+c           -       abc     abc
+ab?c           -       abc     abc
+a\(*\)b                b       a*b     a*b
+a\(**\)b       b       ab      ab
+a\(***\)b      bC      BADRPT
+*a             b       *a      *a
+**a            b       a       a
+***a           bC      BADRPT
+
+# the dreaded bounded repetitions
+{              &       {       {
+{abc           &       {abc    {abc
+{1             C       BADRPT
+{1}            C       BADRPT
+a{b            &       a{b     a{b
+a{1}b          -       ab      ab
+a\{1\}b                b       ab      ab
+a{1,}b         -       ab      ab
+a\{1,\}b       b       ab      ab
+a{1,2}b                -       aab     aab
+a\{1,2\}b      b       aab     aab
+a{1            C       EBRACE
+a\{1           bC      EBRACE
+a{1a           C       EBRACE
+a\{1a          bC      EBRACE
+a{1a}          C       BADBR
+a\{1a\}                bC      BADBR
+a{,2}          -       a{,2}   a{,2}
+a\{,2\}                bC      BADBR
+a{,}           -       a{,}    a{,}
+a\{,\}         bC      BADBR
+a{1,x}         C       BADBR
+a\{1,x\}       bC      BADBR
+a{1,x          C       EBRACE
+a\{1,x         bC      EBRACE
+a{300}         C       BADBR
+a\{300\}       bC      BADBR
+a{1,0}         C       BADBR
+a\{1,0\}       bC      BADBR
+ab{0,0}c       -       abcac   ac
+ab\{0,0\}c     b       abcac   ac
+ab{0,1}c       -       abcac   abc
+ab\{0,1\}c     b       abcac   abc
+ab{0,3}c       -       abbcac  abbc
+ab\{0,3\}c     b       abbcac  abbc
+ab{1,1}c       -       acabc   abc
+ab\{1,1\}c     b       acabc   abc
+ab{1,3}c       -       acabc   abc
+ab\{1,3\}c     b       acabc   abc
+ab{2,2}c       -       abcabbc abbc
+ab\{2,2\}c     b       abcabbc abbc
+ab{2,4}c       -       abcabbc abbc
+ab\{2,4\}c     b       abcabbc abbc
+((a{1,10}){1,10}){1,10}        -       a       a       a,a
+
+# multiple repetitions
+a**            &C      BADRPT
+a++            C       BADRPT
+a??            C       BADRPT
+a*+            C       BADRPT
+a*?            C       BADRPT
+a+*            C       BADRPT
+a+?            C       BADRPT
+a?*            C       BADRPT
+a?+            C       BADRPT
+a{1}{1}                C       BADRPT
+a*{1}          C       BADRPT
+a+{1}          C       BADRPT
+a?{1}          C       BADRPT
+a{1}*          C       BADRPT
+a{1}+          C       BADRPT
+a{1}?          C       BADRPT
+a*{b}          -       a{b}    a{b}
+a\{1\}\{1\}    bC      BADRPT
+a*\{1\}                bC      BADRPT
+a\{1\}*                bC      BADRPT
+
+# brackets, and numerous perversions thereof
+a[b]c          &       abc     abc
+a[ab]c         &       abc     abc
+a[^ab]c                &       adc     adc
+a[]b]c         &       a]c     a]c
+a[[b]c         &       a[c     a[c
+a[-b]c         &       a-c     a-c
+a[^]b]c                &       adc     adc
+a[^-b]c                &       adc     adc
+a[b-]c         &       a-c     a-c
+a[b            &C      EBRACK
+a[]            &C      EBRACK
+a[1-3]c                &       a2c     a2c
+a[3-1]c                &C      ERANGE
+a[1-3-5]c      &C      ERANGE
+a[[.-.]--]c    &       a-c     a-c
+a[1-           &C      ERANGE
+a[[.           &C      EBRACK
+a[[.x          &C      EBRACK
+a[[.x.         &C      EBRACK
+a[[.x.]                &C      EBRACK
+a[[.x.]]       &       ax      ax
+a[[.x,.]]      &C      ECOLLATE
+a[[.one.]]b    &       a1b     a1b
+a[[.notdef.]]b &C      ECOLLATE
+a[[.].]]b      &       a]b     a]b
+a[[:alpha:]]c  &       abc     abc
+a[[:notdef:]]c &C      ECTYPE
+a[[:           &C      EBRACK
+a[[:alpha      &C      EBRACK
+a[[:alpha:]    &C      EBRACK
+a[[:alpha,:]   &C      ECTYPE
+a[[:]:]]b      &C      ECTYPE
+a[[:-:]]b      &C      ECTYPE
+a[[:alph:]]    &C      ECTYPE
+a[[:alphabet:]]        &C      ECTYPE
+[[:alnum:]]+   -       -%@a0X- a0X
+[[:alpha:]]+   -       -%@aX0- aX
+[[:blank:]]+   -       aSSTb   SST
+[[:cntrl:]]+   -       aNTb    NT
+[[:digit:]]+   -       a019b   019
+[[:graph:]]+   -       Sa%bS   a%b
+[[:lower:]]+   -       AabC    ab
+[[:print:]]+   -       NaSbN   aSb
+[[:punct:]]+   -       S%-&T   %-&
+[[:space:]]+   -       aSNTb   SNT
+[[:upper:]]+   -       aBCd    BC
+[[:xdigit:]]+  -       p0f3Cq  0f3C
+a[[=b=]]c      &       abc     abc
+a[[=           &C      EBRACK
+a[[=b          &C      EBRACK
+a[[=b=         &C      EBRACK
+a[[=b=]                &C      EBRACK
+a[[=b,=]]      &C      ECOLLATE
+a[[=one=]]b    &       a1b     a1b
+
+# complexities
+a(((b)))c      -       abc     abc
+a(b|(c))d      -       abd     abd
+a(b*|c)d       -       abbd    abbd
+# just gotta have one DFA-buster, of course
+a[ab]{20}      -       aaaaabaaaabaaaabaaaab   aaaaabaaaabaaaabaaaab
+# and an inline expansion in case somebody gets tricky
+a[ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab]      -       aaaaabaaaabaaaabaaaab   aaaaabaaaabaaaabaaaab
+# and in case somebody just slips in an NFA...
+a[ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab](wee|week)(knights|night)     -       aaaaabaaaabaaaabaaaabweeknights aaaaabaaaabaaaabaaaabweeknights
+# fish for anomalies as the number of states passes 32
+12345678901234567890123456789  -       a12345678901234567890123456789b 12345678901234567890123456789
+123456789012345678901234567890 -       a123456789012345678901234567890b        123456789012345678901234567890
+1234567890123456789012345678901        -       a1234567890123456789012345678901b       1234567890123456789012345678901
+12345678901234567890123456789012       -       a12345678901234567890123456789012b      12345678901234567890123456789012
+123456789012345678901234567890123      -       a123456789012345678901234567890123b     123456789012345678901234567890123
+# and one really big one, beyond any plausible word width
+1234567890123456789012345678901234567890123456789012345678901234567890 -       a1234567890123456789012345678901234567890123456789012345678901234567890b        1234567890123456789012345678901234567890123456789012345678901234567890
+# fish for problems as brackets go past 8
+[ab][cd][ef][gh][ij][kl][mn]   -       xacegikmoq      acegikm
+[ab][cd][ef][gh][ij][kl][mn][op]       -       xacegikmoq      acegikmo
+[ab][cd][ef][gh][ij][kl][mn][op][qr]   -       xacegikmoqy     acegikmoq
+[ab][cd][ef][gh][ij][kl][mn][op][q]    -       xacegikmoqy     acegikmoq
+
+# subtleties of matching
+abc            &       xabcy   abc
+a\(b\)?c\1d    b       acd
+aBc            i       Abc     Abc
+a[Bc]*d                i       abBCcd  abBCcd
+0[[:upper:]]1  &i      0a1     0a1
+0[[:lower:]]1  &i      0A1     0A1
+a[^b]c         &i      abc
+a[^b]c         &i      aBc
+a[^b]c         &i      adc     adc
+[a]b[c]                -       abc     abc
+[a]b[a]                -       aba     aba
+[abc]b[abc]    -       abc     abc
+[abc]b[abd]    -       abd     abd
+a(b?c)+d       -       accd    accd
+(wee|week)(knights|night)      -       weeknights      weeknights
+(we|wee|week|frob)(knights|night|day)  -       weeknights      weeknights
+a[bc]d         -       xyzaaabcaababdacd       abd
+a[ab]c         -       aaabc   abc
+abc            s       abc     abc
+a*             &       b       @b
+
+# Let's have some fun -- try to match a C comment.
+# first the obvious, which looks okay at first glance...
+/\*.*\*/       -       /*x*/   /*x*/
+# but...
+/\*.*\*/       -       /*x*/y/*z*/     /*x*/y/*z*/
+# okay, we must not match */ inside; try to do that...
+/\*([^*]|\*[^/])*\*/   -       /*x*/   /*x*/
+/\*([^*]|\*[^/])*\*/   -       /*x*/y/*z*/     /*x*/
+# but...
+/\*([^*]|\*[^/])*\*/   -       /*x**/y/*z*/    /*x**/y/*z*/
+# and a still fancier version, which does it right (I think)...
+/\*([^*]|\*+[^*/])*\*+/        -       /*x*/   /*x*/
+/\*([^*]|\*+[^*/])*\*+/        -       /*x*/y/*z*/     /*x*/
+/\*([^*]|\*+[^*/])*\*+/        -       /*x**/y/*z*/    /*x**/
+/\*([^*]|\*+[^*/])*\*+/        -       /*x****/y/*z*/  /*x****/
+/\*([^*]|\*+[^*/])*\*+/        -       /*x**x*/y/*z*/  /*x**x*/
+/\*([^*]|\*+[^*/])*\*+/        -       /*x***x/y/*z*/  /*x***x/y/*z*/
+
+# subexpressions
+a(b)(c)d       -       abcd    abcd    b,c
+a(((b)))c      -       abc     abc     b,b,b
+a(b|(c))d      -       abd     abd     b,-
+a(b*|c|e)d     -       abbd    abbd    bb
+a(b*|c|e)d     -       acd     acd     c
+a(b*|c|e)d     -       ad      ad      @d
+a(b?)c         -       abc     abc     b
+a(b?)c         -       ac      ac      @c
+a(b+)c         -       abc     abc     b
+a(b+)c         -       abbbc   abbbc   bbb
+a(b*)c         -       ac      ac      @c
+(a|ab)(bc([de]+)f|cde) -       abcdef  abcdef  a,bcdef,de
+# the regression tester only asks for 9 subexpressions
+a(b)(c)(d)(e)(f)(g)(h)(i)(j)k  -       abcdefghijk     abcdefghijk     b,c,d,e,f,g,h,i,j
+a(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)l       -       abcdefghijkl    abcdefghijkl    b,c,d,e,f,g,h,i,j,k
+a([bc]?)c      -       abc     abc     b
+a([bc]?)c      -       ac      ac      @c
+a([bc]+)c      -       abc     abc     b
+a([bc]+)c      -       abcc    abcc    bc
+a([bc]+)bc     -       abcbc   abcbc   bc
+a(bb+|b)b      -       abb     abb     b
+a(bbb+|bb+|b)b -       abb     abb     b
+a(bbb+|bb+|b)b -       abbb    abbb    bb
+a(bbb+|bb+|b)bb        -       abbb    abbb    b
+(.*).*         -       abcdef  abcdef  abcdef
+(a*)*          -       bc      @b      @b
+
+# do we get the right subexpression when it is used more than once?
+a(b|c)*d       -       ad      ad      -
+a(b|c)*d       -       abcd    abcd    c
+a(b|c)+d       -       abd     abd     b
+a(b|c)+d       -       abcd    abcd    c
+a(b|c?)+d      -       ad      ad      @d
+a(b|c?)+d      -       abcd    abcd    @d
+a(b|c){0,0}d   -       ad      ad      -
+a(b|c){0,1}d   -       ad      ad      -
+a(b|c){0,1}d   -       abd     abd     b
+a(b|c){0,2}d   -       ad      ad      -
+a(b|c){0,2}d   -       abcd    abcd    c
+a(b|c){0,}d    -       ad      ad      -
+a(b|c){0,}d    -       abcd    abcd    c
+a(b|c){1,1}d   -       abd     abd     b
+a(b|c){1,1}d   -       acd     acd     c
+a(b|c){1,2}d   -       abd     abd     b
+a(b|c){1,2}d   -       abcd    abcd    c
+a(b|c){1,}d    -       abd     abd     b
+a(b|c){1,}d    -       abcd    abcd    c
+a(b|c){2,2}d   -       acbd    acbd    b
+a(b|c){2,2}d   -       abcd    abcd    c
+a(b|c){2,4}d   -       abcd    abcd    c
+a(b|c){2,4}d   -       abcbd   abcbd   b
+a(b|c){2,4}d   -       abcbcd  abcbcd  c
+a(b|c){2,}d    -       abcd    abcd    c
+a(b|c){2,}d    -       abcbd   abcbd   b
+a(b+|((c)*))+d -       abd     abd     @d,@d,-
+a(b+|((c)*))+d -       abcd    abcd    @d,@d,-
+
+# check out the STARTEND option
+[abc]          &#      a(b)c   b
+[abc]          &#      a(d)c
+[abc]          &#      a(bc)d  b
+[abc]          &#      a(dc)d  c
+.              &#      a()c
+b.*c           &#      b(bc)c  bc
+b.*            &#      b(bc)c  bc
+.*c            &#      b(bc)c  bc
+
+# plain strings, with the NOSPEC flag
+abc            m       abc     abc
+abc            m       xabcy   abc
+abc            m       xyz
+a*b            m       aba*b   a*b
+a*b            m       ab
+""             mC      EMPTY
+
+# cases involving NULs
+aZb            &       a       a
+aZb            &p      a
+aZb            &p#     (aZb)   aZb
+aZ*b           &p#     (ab)    ab
+a.b            &#      (aZb)   aZb
+a.*            &#      (aZb)c  aZb
+
+# word boundaries (ick)
+[[:<:]]a       &       a       a
+[[:<:]]a       &       ba
+[[:<:]]a       &       -a      a
+a[[:>:]]       &       a       a
+a[[:>:]]       &       ab
+a[[:>:]]       &       a-      a
+[[:<:]]a.c[[:>:]]      &       axcd-dayc-dazce-abc     abc
+[[:<:]]a.c[[:>:]]      &       axcd-dayc-dazce-abc-q   abc
+[[:<:]]a.c[[:>:]]      &       axc-dayc-dazce-abc      axc
+[[:<:]]b.c[[:>:]]      &       a_bxc-byc_d-bzc-q       bzc
+[[:<:]].x..[[:>:]]     &       y_xa_-_xb_y-_xc_-axdc   _xc_
+[[:<:]]a_b[[:>:]]      &       x_a_b
+
+# past problems, and suspected problems
+(A[1])|(A[2])|(A[3])|(A[4])|(A[5])|(A[6])|(A[7])|(A[8])|(A[9])|(A[A])  -       A1      A1
+abcdefghijklmnop       i       abcdefghijklmnop        abcdefghijklmnop
+abcdefghijklmnopqrstuv i       abcdefghijklmnopqrstuv  abcdefghijklmnopqrstuv
+(ALAK)|(ALT[AB])|(CC[123]1)|(CM[123]1)|(GAMC)|(LC[23][EO ])|(SEM[1234])|(SL[ES][12])|(SLWW)|(SLF )|(SLDT)|(VWH[12])|(WH[34][EW])|(WP1[ESN])    -       CC11    CC11
+CC[13]1|a{21}[23][EO][123][Es][12]a{15}aa[34][EW]aaaaaaa[X]a   -       CC11    CC11
+Char \([a-z0-9_]*\)\[.*        b       Char xyz[k      Char xyz[k      xyz
+a?b    -       ab      ab
+-\{0,1\}[0-9]*$        b       -5      -5
diff --git a/APACHE_1_2_X/src/regex/utils.h b/APACHE_1_2_X/src/regex/utils.h
new file mode 100644 (file)
index 0000000..f271f75
--- /dev/null
@@ -0,0 +1,22 @@
+/* utility definitions */
+#ifndef _POSIX2_RE_DUP_MAX
+#define _POSIX2_RE_DUP_MAX   255
+#endif
+
+#define        DUPMAX          _POSIX2_RE_DUP_MAX      /* xxx is this right? */
+#define        INFINITY        (DUPMAX + 1)
+#define        NC              (CHAR_MAX - CHAR_MIN + 1)
+typedef unsigned char uch;
+
+/* switch off assertions (if not already off) if no REDEBUG */
+#ifndef REDEBUG
+#ifndef NDEBUG
+#define        NDEBUG  /* no assertions please */
+#endif
+#endif
+#include <assert.h>
+
+/* for old systems with bcopy() but no memmove() */
+#ifdef USEBCOPY
+#define        memmove(d, s, c)        bcopy(s, d, c)
+#endif
diff --git a/APACHE_1_2_X/src/support/.cvsignore b/APACHE_1_2_X/src/support/.cvsignore
new file mode 100644 (file)
index 0000000..48ded15
--- /dev/null
@@ -0,0 +1,9 @@
+Makefile
+rotatelogs
+htpasswd
+htdigest
+unescape
+inc2shtml
+httpd_monitor
+suexec
+logresolve
diff --git a/APACHE_1_2_X/src/support/Makefile.tmpl b/APACHE_1_2_X/src/support/Makefile.tmpl
new file mode 100644 (file)
index 0000000..84aebc0
--- /dev/null
@@ -0,0 +1,35 @@
+# Apache makefile template (well, suffix).
+
+# This is combined with the information in the "Configuration" file
+# by the configure script to make the actual Makefile.
+
+CFLAGS=$(OPTIM) $(CFLAGS1) $(EXTRA_CFLAGS)
+LIBS=$(EXTRA_LIBS) $(LIBS1)
+INCLUDES=-I../src -I../src/regex $(INCLUDES1) $(EXTRA_INCLUDES)
+LFLAGS=$(LFLAGS1) $(EXTRA_LFLAGS)
+
+.c.o: 
+       $(CC) -c $(CFLAGS) $(INCLUDES) $<
+
+TARGETS=htpasswd htdigest httpd_monitor rotatelogs logresolve
+
+all: $(TARGETS)
+
+htpasswd: htpasswd.c
+       $(CC) $(CFLAGS) htpasswd.c -o htpasswd $(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 $(LIBS)
+
+clean:
+       rm -f $(TARGETS)
+
diff --git a/APACHE_1_2_X/src/support/cls.c b/APACHE_1_2_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/APACHE_1_2_X/src/support/dbmmanage b/APACHE_1_2_X/src/support/dbmmanage
new file mode 100644 (file)
index 0000000..8afc45f
--- /dev/null
@@ -0,0 +1,126 @@
+#!/usr/local/bin/perl
+
+# ====================================================================
+# Copyright (c) 1995-1997 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;
+}
+
+$file=$ARGV[0];
+$command=$ARGV[1];
+$key=$ARGV[2];
+$value=$ARGV[3];
+$group=$ARGV[4];
+
+# create a random salt
+@range=('0'..'9','a'..'z','A'..'Z');
+srand($$|time);
+$salt=$range[rand(int($#range)+1)] . $range[rand(int($#range)+1)];
+
+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/APACHE_1_2_X/src/support/dbmmanage.new b/APACHE_1_2_X/src/support/dbmmanage.new
new file mode 100644 (file)
index 0000000..48d9f26
--- /dev/null
@@ -0,0 +1,140 @@
+#!/usr/local/bin/perl
+
+# ====================================================================
+# Copyright (c) 1995-1997 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>
+
+if (@ARGV < 2) {
+    die "Too few arguments.\
+   Usage: dbmmanage <DBMfile> <command> [<key> [<value>]]\
+   where command is add, delete, view or adduser.\
+   No value required for \"delete\", no key or value for \"view\".\
+   To change a value, simply use \"add\".\
+   \"adduser\" encrypts the value and uses it as the user's password\n";
+}
+
+($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);
+  }
+  $str;
+}
diff --git a/APACHE_1_2_X/src/support/dbmmanage.readme b/APACHE_1_2_X/src/support/dbmmanage.readme
new file mode 100644 (file)
index 0000000..8ef9e68
--- /dev/null
@@ -0,0 +1,7 @@
+
+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/APACHE_1_2_X/src/support/htdigest.c b/APACHE_1_2_X/src/support/htdigest.c
new file mode 100644 (file)
index 0000000..9d35b44
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * 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>
+#ifdef MPE
+#include <signal.h>
+#else
+#include <sys/signal.h>
+#endif
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.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;
+    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, (unsigned char *) 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/APACHE_1_2_X/src/support/htpasswd.1 b/APACHE_1_2_X/src/support/htpasswd.1
new file mode 100644 (file)
index 0000000..a3819ca
--- /dev/null
@@ -0,0 +1,88 @@
+.TH htpasswd 1 "February 1997"
+.\" Copyright (c) 1997 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/>.
+.SH NAME
+htpasswd \- Create and update user authentication files
+.SH SYNOPSIS
+.B htpasswd 
+[
+.B \-c
+] 
+.I passwdfile
+.I username
+.SH DESCRIPTION
+.B htpasswd
+is used to create and update the flat-files used to store
+usernames and password for basic authentication of HTTP users.
+Resources available from the
+.B httpd
+Apache web server can be restricted to just the users listed
+in the files created by htpasswd. This program can only be used
+when the usernames are stored in a flat-file. To use a
+DBM database see 
+\fBdbmmanage\fP and \fBdbmmanage.new\fP.
+.PP
+This manual page only lists the command line arguments. For details of
+the directives necessary to configure user authentication in httpd see
+the Apache manual, which is part of the Apache distribution or can be
+found at http://www.apache.org/.
+.SH OPTIONS
+.IP \-c 
+Create the \fIpasswdfile\fP. If \fIpasswdfile\fP already exists, it
+is deleted first. 
+.IP \fB\fIpasswdfile\fP
+Name of the file to contain the user name and password. If \-c
+is given, this file is created if it does not already exist,
+or deleted and recreated if it does exist. 
+.IP \fB\fIusername\fP
+The username to create or update in \fBpasswdfile\fP. If
+\fIusername\fP does not exist is this file, an entry is added. If it
+does exist, the password is changed.
+.SH SEE ALSO
+httpd(8)
diff --git a/APACHE_1_2_X/src/support/htpasswd.c b/APACHE_1_2_X/src/support/htpasswd.c
new file mode 100644 (file)
index 0000000..17efe5b
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ * htpasswd.c: simple program for manipulating password file for NCSA httpd
+ * 
+ * Rob McCool
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#ifdef MPE
+#include <signal.h>
+#else
+#include <sys/signal.h>
+#endif
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.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";
+
+void to64(register char *s, register long v, register int n) {
+    while (--n >= 0) {
+        *s++ = itoa64[v&0x3f];
+        v >>= 6;
+    }
+}
+
+#ifdef MPE
+/* MPE lacks getpass() and a way to suppress stdin echo.  So for now, just
+issue the prompt and read the results with echo.  (Ugh). */
+
+char *getpass(const char *prompt) {
+
+static char password[81];
+
+fputs(prompt,stderr);
+gets((char *)&password);
+
+if (strlen((char *)&password) > 8) {
+  password[8]='\0';
+}
+
+return (char *)&password;
+}
+#endif
+
+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);
+}
+
+void 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/APACHE_1_2_X/src/support/httpd.8 b/APACHE_1_2_X/src/support/httpd.8
new file mode 100644 (file)
index 0000000..d456e38
--- /dev/null
@@ -0,0 +1,125 @@
+.TH httpd 8 "February 1997"
+.\" Copyright (c) 1995-1997 David Robinson. All rights reserved.
+.\" Copyright (c) 1997 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/>.
+.SH NAME
+httpd \- Apache hypertext transfer protocol server
+.SH SYNOPSIS
+.B httpd 
+[
+.B \-hlvX?
+] [
+.BI \-d " serverroot"
+] [
+.BI \-f " config"
+]
+.SH DESCRIPTION
+.B httpd
+is the Apache HyperText Transfer Protocol (HTTP) server program. It is
+designed to be run as a standalone daemon process. When used like this
+is will create a pool of child processes to handle requests. To stop
+it, send a TERM signal to the initial (parent) process. The PID of
+this process is written to a file as given in the configuration file.
+Alternatively 
+.B httpd 
+may be invoked by the Internet daemon inetd(8) each
+time a connection to the HTTP service is made.
+.PP
+This manual page only lists the command line arguments. For details
+of the directives necessary to configure httpd see the Apache manual,
+which is part of the Apache distribution or can be found at
+http://www.apache.org/. Paths in this manual may not reflect those
+compiled into httpd.
+.SH OPTIONS
+.TP 12
+.BI \-d " serverroot"
+Set the initial value for the ServerRoot directive 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 \-h
+Output a list of directives together with expected arguments and
+places where the directive is valid.
+.TP
+.B \-l
+Output a list of modules compiled into the server.
+.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 (8).
diff --git a/APACHE_1_2_X/src/support/httpd_monitor.c b/APACHE_1_2_X/src/support/httpd_monitor.c
new file mode 100644 (file)
index 0000000..847a03a
--- /dev/null
@@ -0,0 +1,307 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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 [ -d serverdir | -f conffile ] [ -s sleep_time ]
+ *                -d/-f options specify server dir or config files, as per
+ *                      httpd.
+ *                -s specifies how long to pause between screen updates
+ *                If you choose 0, it might chew up lots of CPU time.
+ *
+ * Output explanation..
+ *
+ *  s = sleeping but "ready to go" child (this is '_' in mod_status)
+ *  R = active child - writing to client
+ *  W = active child - reading from client
+ *  K = active child - waiting for additional request on kept-alive connection
+ *  D = active child - doing DNS lookup
+ *  L = active child - logging
+ *  _ = dead child (no longer needed) (this is '.' in mod_status)
+ *  t = just starting (this is 'S' in mod_status)
+ *
+ *
+ *  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
+ *
+ *   v1.2:
+ *    Handles Apache 1.1.* scoreboard format (W/K/D/L states) -- PCS 09Jul96
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "../src/httpd.h"
+#include "../src/scoreboard.h"
+
+#define DEFAULT_SLEEPTIME      2
+#define ASIZE                  1024
+#define MAX_PROC               HARD_SERVER_LIMIT
+
+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', 'W', 'K', 'L', 'D' };
+    int 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 (scoreboard_image.status != SERVER_DEAD &&
+                   scoreboard_image.status != SERVER_READY)
+                   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) {
+       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/APACHE_1_2_X/src/support/log_server_status b/APACHE_1_2_X/src/support/log_server_status
new file mode 100755 (executable)
index 0000000..4f97259
--- /dev/null
@@ -0,0 +1,110 @@
+#!/usr/local/bin/perl
+
+# ====================================================================
+# Copyright (c) 1995-1997 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/APACHE_1_2_X/src/support/logresolve.c b/APACHE_1_2_X/src/support/logresolve.c
new file mode 100644 (file)
index 0000000..c09cba9
--- /dev/null
@@ -0,0 +1,367 @@
+/***                                                                      ***\
+    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 <sys/types.h>
+
+#include <ctype.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#ifndef MPE
+#include <arpa/inet.h>
+#endif
+
+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
+
+#ifdef MPE
+char *strdup (const char *str)
+{
+  char *dup; 
+             
+  if(!(dup = (char *)malloc (strlen (str) + 1)))
+      return NULL;
+  dup = strcpy (dup, str);
+     
+  return dup; 
+}
+#endif
+
+/*
+ * 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/APACHE_1_2_X/src/support/phf_abuse_log.cgi b/APACHE_1_2_X/src/support/phf_abuse_log.cgi
new file mode 100755 (executable)
index 0000000..9ce2749
--- /dev/null
@@ -0,0 +1,21 @@
+#!/usr/local/bin/perl
+
+# This script can be used to detect people trying to abuse the security hole which
+# existed in A CGI script direstributed with Apache 1.0.3 and earlier versions.
+# You can redirect them to here using the "<Location /cgi-bin/phf*>" suggestion in
+# httpd.conf.  
+#
+# The format logged to is "[date] remote_addr remote_host [date] referrer user_agent".
+
+$LOG = "/var/log/phf_log";
+
+require "ctime.pl";
+$when = &ctime(time);
+$when =~ s/\n//go;
+$ENV{HTTP_USER_AGENT} .= " via $ENV{HTTP_VIA}" if($ENV{HTTP_VIA});
+
+open(LOG, ">>$LOG") || die "boo hoo, phf_log $!";
+print LOG "[$when] $ENV{REMOTE_ADDR} $ENV{REMOTE_HOST} $ENV{$HTTP_REFERER} $ENV{HTTP_USER_AGENT}\n";
+close(LOG);
+
+print "Content-type: text/html\r\n\r\n<BLINK>Smile, you're on Candid Camera.</BLINK>\n";
diff --git a/APACHE_1_2_X/src/support/rotatelogs.c b/APACHE_1_2_X/src/support/rotatelogs.c
new file mode 100644 (file)
index 0000000..0806692
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+
+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 <stdlib.h>
+#include <time.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.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.%010d",szLogRoot,(int)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/APACHE_1_2_X/src/support/suexec.c b/APACHE_1_2_X/src/support/suexec.c
new file mode 100644 (file)
index 0000000..18d2327
--- /dev/null
@@ -0,0 +1,489 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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/>.
+ *
+ */
+
+/*
+ * suexec.c -- "Wrapper" support program for suEXEC behaviour for Apache
+ *
+ ***********************************************************************
+ *
+ * NOTE! : DO NOT edit this code!!!  Unless you know what you are doing,
+ *         editing this code might open up your system in unexpected 
+ *         ways to would-be crackers.  Every precaution has been taken 
+ *         to make this code as safe as possible; alter it at your own
+ *         risk.
+ *
+ ***********************************************************************
+ *
+ *
+ */
+
+
+#include "suexec.h"
+
+#include <sys/param.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <strings.h>
+#include <pwd.h>
+#include <grp.h>
+#include <time.h>
+#include <sys/stat.h>
+
+#if defined(PATH_MAX)
+#define AP_MAXPATH PATH_MAX
+#elif defined(MAXPATHLEN)
+#define AP_MAXPATH MAXPATHLEN
+#else
+#define AP_MAXPATH 8192
+#endif
+
+#define AP_ENVBUF 256
+
+extern char **environ;
+static FILE *log;
+
+char *safe_env_lst[] =
+{
+    "AUTH_TYPE",
+    "CONTENT_LENGTH",
+    "CONTENT_TYPE",
+    "DATE_GMT",
+    "DATE_LOCAL",
+    "DOCUMENT_NAME",
+    "DOCUMENT_PATH_INFO",
+    "DOCUMENT_ROOT",
+    "DOCUMENT_URI",
+    "FILEPATH_INFO",
+    "GATEWAY_INTERFACE",
+    "LAST_MODIFIED",
+    "PATH_INFO",
+    "PATH_TRANSLATED",
+    "QUERY_STRING",
+    "QUERY_STRING_UNESCAPED",
+    "REMOTE_ADDR",
+    "REMOTE_HOST",
+    "REMOTE_IDENT",
+    "REMOTE_PORT",
+    "REMOTE_USER",
+    "REDIRECT_QUERY_STRING",
+    "REDIRECT_STATUS",
+    "REDIRECT_URL",
+    "REQUEST_METHOD",
+    "SCRIPT_FILENAME",
+    "SCRIPT_NAME",
+    "SCRIPT_URI",
+    "SCRIPT_URL",
+    "SERVER_ADMIN",
+    "SERVER_NAME",
+    "SERVER_PORT",
+    "SERVER_PROTOCOL",
+    "SERVER_SOFTWARE",
+    "USER_NAME",
+    "TZ",
+    NULL
+};
+
+
+static void err_output(const char *fmt, va_list ap)
+{
+    time_t timevar;
+    struct tm *lt;
+
+    if (!log)
+       if ((log = fopen(LOG_EXEC, "a")) == NULL) {
+           fprintf(stderr, "failed to open log file\n");
+           perror("fopen");
+           exit(1);
+       }
+
+    time(&timevar);
+    lt = localtime(&timevar);
+    
+    fprintf(log, "[%.2d:%.2d:%.2d %.2d-%.2d-%.2d]: ", lt->tm_hour, lt->tm_min,
+           lt->tm_sec, lt->tm_mday, (lt->tm_mon + 1), lt->tm_year);
+    
+    vfprintf(log, fmt, ap);
+
+    fflush(log);
+    return;
+}
+
+void log_err(const char *fmt, ...)
+{
+#ifdef LOG_EXEC
+    va_list     ap;
+
+    va_start(ap, fmt);
+    err_output(fmt, ap);
+    va_end(ap);
+#endif /* LOG_EXEC */
+    return;
+}
+
+void clean_env() 
+{
+    char pathbuf[512];
+    char **cleanenv;
+    char **ep;
+    int cidx = 0;
+    int idx;
+    
+
+    if ((cleanenv = (char **)calloc(AP_ENVBUF, sizeof(char *))) == NULL) {
+       log_err("failed to malloc env mem\n");
+       exit(120);
+    }
+    
+    for (ep = environ; *ep && cidx < AP_ENVBUF; ep++) {
+       if (!strncmp(*ep, "HTTP_", 5)) {
+           cleanenv[cidx] = *ep;
+           cidx++;
+       }
+       else {
+           for (idx = 0; safe_env_lst[idx]; idx++) {
+               if (!strncmp(*ep, safe_env_lst[idx], strlen(safe_env_lst[idx]))) {
+                   cleanenv[cidx] = *ep;
+                   cidx++;
+                   break;
+               }
+           }
+       }
+    }
+
+    sprintf(pathbuf, "PATH=%s", SAFE_PATH);
+    cleanenv[cidx] = strdup(pathbuf);
+    cleanenv[++cidx] = NULL;
+           
+    environ = cleanenv;
+}
+
+int main(int argc, char *argv[])
+{
+    int userdir = 0;        /* ~userdir flag             */
+    uid_t uid;              /* user information          */
+    gid_t gid;              /* target group placeholder  */
+    char *target_uname;     /* target user name          */
+    char *target_gname;     /* target group name         */
+    char *target_homedir;   /* target home directory     */
+    char *actual_uname;     /* actual user name            */
+    char *actual_gname;     /* actual group name           */
+    char *prog;             /* name of this program      */
+    char *cmd;              /* command to be executed    */
+    char cwd[AP_MAXPATH];   /* current working directory */
+    char dwd[AP_MAXPATH];   /* docroot working directory */
+    struct passwd *pw;      /* password entry holder     */
+    struct group *gr;       /* group entry holder        */
+    struct stat dir_info;   /* directory info holder     */
+    struct stat prg_info;   /* program info holder       */
+
+    
+
+    /*
+     * If there are a proper number of arguments, set
+     * all of them to variables.  Otherwise, error out.
+     */
+    prog = argv[0];
+    if (argc < 4) {
+       log_err("too few arguments\n");
+       exit(101);
+    }
+    target_uname = argv[1];
+    target_gname = argv[2];
+    cmd = argv[3];
+
+    /*
+     * Check existence/validity of the UID of the user
+     * running this program.  Error out if invalid.
+     */
+    uid = getuid();
+    if ((pw = getpwuid(uid)) == NULL) {
+       log_err("invalid uid: (%ld)\n", uid);
+       exit(102);
+    }
+    
+    /*
+     * Check to see if the user running this program
+     * is the user allowed to do so as defined in
+     * suexec.h.  If not the allowed user, error out.
+     */
+    if (strcmp(HTTPD_USER, pw->pw_name)) {
+       log_err("user mismatch (%s)\n", pw->pw_name);
+       exit(103);
+    }
+    
+    /*
+     * Check for a leading '/' (absolute path) in the command to be executed,
+     * or attempts to back up out of the current directory,
+     * to protect against attacks.  If any are
+     * found, error out.  Naughty naughty crackers.
+     */
+    if (
+           (cmd[0] == '/') ||
+           (! strncmp (cmd, "../", 3)) ||
+           (strstr (cmd, "/../") != NULL)
+       ) {
+       log_err("invalid command (%s)\n", cmd);
+       exit(104);
+    }
+
+    /*
+     * Check to see if this is a ~userdir request.  If
+     * so, set the flag, and remove the '~' from the
+     * target username.
+     */
+    if (!strncmp("~", target_uname, 1)) {
+       target_uname++;
+       userdir = 1;
+    }
+
+    /*
+     * Error out if the target username is invalid.
+     */
+    if ((pw = getpwnam(target_uname)) == NULL) {
+       log_err("invalid target user name: (%s)\n", target_uname);
+       exit(105);
+    }
+
+    /*
+     * Error out if the target group name is invalid.
+     */
+    if (strspn(target_gname, "1234567890") != strlen(target_gname)) {
+       if ((gr = getgrnam(target_gname)) == NULL) {
+           log_err("invalid target group name: (%s)\n", target_gname);
+           exit(106);
+       }
+       gid = gr->gr_gid;
+       actual_gname = strdup(gr->gr_name);
+    }
+    else {
+       gid = atoi(target_gname);
+       actual_gname = strdup(target_gname);
+    }
+
+    /*
+     * Save these for later since initgroups will hose the struct
+     */
+    uid = pw->pw_uid;
+    actual_uname = strdup(pw->pw_name);
+    target_homedir = strdup(pw->pw_dir);
+
+    /*
+     * Log the transaction here to be sure we have an open log 
+     * before we setuid().
+     */
+    log_err("uid: (%s/%s) gid: (%s/%s) %s\n",
+             target_uname, actual_uname,
+             target_gname, actual_gname,
+             cmd);
+
+    /*
+     * Error out if attempt is made to execute as root or as
+     * a UID less than UID_MIN.  Tsk tsk.
+     */
+    if ((uid == 0) ||
+        (uid < UID_MIN)) {
+       log_err("cannot run as forbidden uid (%d/%s)\n", uid, cmd);
+       exit(107);
+    }
+
+    /*
+     * Error out if attempt is made to execute as root group
+     * or as a GID less than GID_MIN.  Tsk tsk.
+     */
+    if ((gid == 0) ||
+        (gid < GID_MIN)) {
+       log_err("cannot run as forbidden gid (%d/%s)\n", gid, cmd);
+       exit(108);
+    }
+
+    /*
+     * Change UID/GID here so that the following tests work over NFS.
+     *
+     * Initialize the group access list for the target user,
+     * and setgid() to the target group. If unsuccessful, error out.
+     */
+    if (((setgid(gid)) != 0) || (initgroups(actual_uname,gid) != 0)) {
+        log_err("failed to setgid (%ld: %s/%s)\n", gid, cwd, cmd);
+        exit(109);
+    }
+
+    /*
+     * setuid() to the target user.  Error out on fail.
+     */
+    if ((setuid(uid)) != 0) {
+       log_err("failed to setuid (%ld: %s/%s)\n", uid, cwd, cmd);
+       exit(110);
+    }
+
+    /*
+     * Get the current working directory, as well as the proper
+     * document root (dependant upon whether or not it is a
+     * ~userdir request).  Error out if we cannot get either one,
+     * or if the current working directory is not in the docroot.
+     * Use chdir()s and getcwd()s to avoid problems with symlinked
+     * directories.  Yuck.
+     */
+    if (getcwd(cwd, AP_MAXPATH) == NULL) {
+        log_err("cannot get current working directory\n");
+        exit(111);
+    }
+    
+    if (userdir) {
+        if (((chdir(target_homedir)) != 0) ||
+            ((chdir(USERDIR_SUFFIX)) != 0) ||
+           ((getcwd(dwd, AP_MAXPATH)) == NULL) ||
+            ((chdir(cwd)) != 0))
+        {
+            log_err("cannot get docroot information (%s)\n", target_homedir);
+            exit(112);
+        }
+    }
+    else {
+        if (((chdir(DOC_ROOT)) != 0) ||
+           ((getcwd(dwd, AP_MAXPATH)) == NULL) ||
+           ((chdir(cwd)) != 0))
+        {
+            log_err("cannot get docroot information (%s)\n", DOC_ROOT);
+            exit(113);
+        }
+    }
+
+    if ((strncmp(cwd, dwd, strlen(dwd))) != 0) {
+        log_err("command not in docroot (%s/%s)\n", cwd, cmd);
+        exit(114);
+    }
+
+    /*
+     * Stat the cwd and verify it is a directory, or error out.
+     */
+    if (((lstat(cwd, &dir_info)) != 0) || !(S_ISDIR(dir_info.st_mode))) {
+       log_err("cannot stat directory: (%s)\n", cwd);
+       exit(115);
+    }
+
+    /*
+     * Error out if cwd is writable by others.
+     */
+    if ((dir_info.st_mode & S_IWOTH) || (dir_info.st_mode & S_IWGRP)) {
+       log_err("directory is writable by others: (%s)\n", cwd);
+       exit(116);
+    }
+
+    /*
+     * Error out if we cannot stat the program.
+     */
+    if (((lstat(cmd, &prg_info)) != 0) || (S_ISLNK(prg_info.st_mode))) {
+       log_err("cannot stat program: (%s)\n", cmd);
+       exit(117);
+    }
+
+    /*
+     * Error out if the program is writable by others.
+     */
+    if ((prg_info.st_mode & S_IWOTH) || (prg_info.st_mode & S_IWGRP)) {
+       log_err("file is writable by others: (%s/%s)\n", cwd, cmd);
+       exit(118);
+    }
+
+    /*
+     * Error out if the file is setuid or setgid.
+     */
+    if ((prg_info.st_mode & S_ISUID) || (prg_info.st_mode & S_ISGID)) {
+       log_err("file is either setuid or setgid: (%s/%s)\n",cwd,cmd);
+       exit(119);
+    }
+
+    /*
+     * Error out if the target name/group is different from
+     * the name/group of the cwd or the program.
+     */
+    if ((uid != dir_info.st_uid) ||
+       (gid != dir_info.st_gid) ||
+       (uid != prg_info.st_uid) ||
+       (gid != prg_info.st_gid))
+    {
+       log_err("target uid/gid (%ld/%ld) mismatch with directory (%ld/%ld) or program (%ld/%ld)\n",
+                uid, gid,
+                dir_info.st_uid, dir_info.st_gid,
+                prg_info.st_uid, prg_info.st_gid);
+       exit(120);
+    }
+
+    clean_env();
+
+    /* 
+     * Be sure to close the log file so the CGI can't
+     * mess with it.  If the exec fails, it will be reopened 
+     * automatically when log_err is called.
+     */
+    fclose(log);
+    log = NULL;
+    
+    /*
+     * Execute the command, replacing our image with its own.
+     */
+    execv(cmd, &argv[3]);
+
+    /*
+     * (I can't help myself...sorry.)
+     *
+     * Uh oh.  Still here.  Where's the kaboom?  There was supposed to be an
+     * EARTH-shattering kaboom!
+     *
+     * Oh well, log the failure and error out.
+     */
+    log_err("exec failed (%s)\n", cmd);
+    exit(255);
+}
diff --git a/APACHE_1_2_X/src/support/suexec.h b/APACHE_1_2_X/src/support/suexec.h
new file mode 100644 (file)
index 0000000..91cbc86
--- /dev/null
@@ -0,0 +1,137 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 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/>.
+ *
+ */
+
+/*
+ * suexec.h -- user-definable variables for the suexec wrapper code.
+ */
+
+
+#ifndef _SUEXEC_H
+#define _SUEXEC_H
+
+/*
+ * HTTPD_USER -- Define as the username under which Apache normally
+ *               runs.  This is the only user allowed to execute
+ *               this program.
+ */
+#ifndef HTTPD_USER
+#define HTTPD_USER "www"
+#endif
+
+/*
+ * UID_MIN -- Define this as the lowest UID allowed to be a target user
+ *            for suEXEC.  For most systems, 500 or 100 is common.
+ */
+#ifndef UID_MIN
+#define UID_MIN 100
+#endif
+
+/*
+ * GID_MIN -- Define this as the lowest GID allowed to be a target group
+ *            for suEXEC.  For most systems, 100 is common.
+ */
+#ifndef GID_MIN
+#define GID_MIN 100
+#endif
+
+/*
+ * USERDIR_SUFFIX -- Define to be the subdirectory under users' 
+ *                   home directories where suEXEC access should
+ *                   be allowed.  All executables under this directory
+ *                   will be executable by suEXEC as the user so 
+ *                   they should be "safe" programs.  If you are 
+ *                   using a "simple" UserDir directive (ie. one 
+ *                   without a "*" in it) this should be set to 
+ *                   the same value.  suEXEC will not work properly
+ *                   in cases where the UserDir directive points to 
+ *                   a location that is not the same as the user's
+ *                   home directory as referenced in the passwd file.
+ *
+ *                   If you have VirtualHosts with a different
+ *                   UserDir for each, you will need to define them to
+ *                   all reside in one parent directory; then name that
+ *                   parent directory here.  IF THIS IS NOT DEFINED
+ *                   PROPERLY, ~USERDIR CGI REQUESTS WILL NOT WORK!
+ *                   See the suEXEC documentation for more detailed
+ *                   information.
+ */
+#ifndef USERDIR_SUFFIX
+#define USERDIR_SUFFIX "public_html"
+#endif
+
+/*
+ * LOG_EXEC -- Define this as a filename if you want all suEXEC
+ *             transactions and errors logged for auditing and
+ *             debugging purposes.
+ */
+#ifndef LOG_EXEC
+#define LOG_EXEC "/usr/local/etc/httpd/logs/cgi.log" /* Need me? */
+#endif
+
+/*
+ * DOC_ROOT -- Define as the DocumentRoot set for Apache.  This
+ *             will be the only hierarchy (aside from UserDirs)
+ *             that can be used for suEXEC behavior.
+ */
+#ifndef DOC_ROOT
+#define DOC_ROOT "/usr/local/etc/httpd/htdocs"
+#endif
+
+/*
+ * SAFE_PATH -- Define a safe PATH environment to pass to CGI executables.
+ *
+ */
+#ifndef SAFE_PATH
+#define SAFE_PATH "/usr/local/bin:/usr/bin:/bin"
+#endif
+
+#endif  /* _SUEXEC_H */
diff --git a/APACHE_1_2_X/src/test/cls.c b/APACHE_1_2_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;
+}