diff options
author | 1998-10-11 19:44:59 +0000 | |
---|---|---|
committer | 1998-10-11 19:44:59 +0000 | |
commit | 0ad52bed66a21e2d9cde06cdbb2fa8563982553b (patch) | |
tree | 436beee31e9b2153b6be177e3461de7701b82945 /usr.sbin/httpd/src | |
parent | typo: Thuner != Thunder; spotted by theo. (diff) | |
download | wireguard-openbsd-0ad52bed66a21e2d9cde06cdbb2fa8563982553b.tar.xz wireguard-openbsd-0ad52bed66a21e2d9cde06cdbb2fa8563982553b.zip |
Apache 1.3.3 merge + proxy_segv fix
Diffstat (limited to 'usr.sbin/httpd/src')
33 files changed, 1140 insertions, 517 deletions
diff --git a/usr.sbin/httpd/src/CHANGES b/usr.sbin/httpd/src/CHANGES index 03bfe02f369..2d9899db077 100644 --- a/usr.sbin/httpd/src/CHANGES +++ b/usr.sbin/httpd/src/CHANGES @@ -1,3 +1,121 @@ +Changes with Apache 1.3.3 + + *) Added a complete implementation of the Expect header field as + specified in rev-05 of HTTP/1.1. Disabled the 100 Continue + response when we already know the final status, which is mighty + useful for PUT responses that result in 302 or 401. [Roy Fielding] + + *) Remove extra trailing whitespace from the getline results as part + of the protocol processing, which is extra nice because it works + between continuation lines, is almost no cost in the normal case + of no extra whitespace, and saves memory. [Roy Fielding] + + *) Added new HTTP status codes and default response bodies from the + revised HTTP/1.1 (307, 416, 417), WebDAV (102, 207, 422, 423), and + HTTP Extension Framework (510) specifications. Did not add the + WebDAV 424 and 425 codes because they are bogus. We don't use any + of these codes yet, but they are now available to 3rd-party modules. + [Roy Fielding] + + *) Fix a possible race condition between timed-out requests and the + ap_bhalfduplex select that might result in an infinite loop on + platforms that do not validate the descriptor. [Roy Fielding] + + *) WIN32: Add "-k shutdown" and "-k restart" options to signal a + running Apache server [Paul Sutton] + + *) Fix mod_autoindex bug where directories got a size of "0k" instead + of "-". [Martin Plechsmid <plechsmi@karlin.mff.cuni.cz>, Marc Slemko] + PR#3130 + + *) PORT: DRS 6000 machine. [Paul Debleecker <pdebleecker@jetair.be>] + + *) Add the server signature text (from the core ServerSignature directive) + to the list of envariables available to scripts, SSI, and the like. + [Ken Coar] + + *) PORT: Fix sys/resource.h handling for SCO 3.x platform. + [M. Laak <maert@proinv.ee>] PR#3108 + + *) Fallback from sysconf-based to plain HZ-based `ticks per second' + calculation in mod_status for all systems which don't have POSIX + sysconf() (like UTS 2.1) and not only for the NEXT platform. + [Dave Dykstra <dwd@bell-labs.com>] PR#3055 + + *) Fix `require ...' directive parsing in mod_auth, mod_auth_dbm and + mod_auth_db by using ap_getword_white() (which uses ap_isspace()) + instead of ap_getword(..., ' ') (which parses only according to spaces + but not tabs). [James Morris <jmorris@intercode.com.au>, + Ralf S. Engelschall] PR#3105 + + *) Fix the SERVER_NAME variable under sub-request situations (where + `UseCanonicalName off' is used) like CGI's called from SSI pages or + RewriteCond variables by adopting r->hostname to sub-requests. + [James Grinter <jrg@blodwen.demon.co.uk>] PR#3111 + + *) Fix stderr redirection under syslog-based error logging situation. + [Youichirou Koga <y-koga@jp.FreeBSD.org>] PR#3095 + + *) Document `ErrorLog syslog:facility' variant of error logging. + [Youichirou Koga <y-koga@jp.FreeBSD.org>] PR#3096 + + *) Fix http://localhost/ hints in top-level INSTALL document. + [Rob Jenson <robjen@spotch.com>, Ralf S. Engelschall] PR#3088 + + *) Quote paths in default configuration files. [Wilfredo Sanchez] + + *) PORT: Remove extra HAVE_SYS_RESOURCE_H define for RHAPSODY since + it is now taken care of properly by the header file tests. + [Wilfredo Sanchez <wsanchez@apple.com>] + + *) Fix problem with scripts and filehandle inheritance on Win32. + [Ken Parzygnat <kparz@raleigh.ibm.com>] PR#2884, 2910 + + *) Win32 name canonicalisation could end up using the server's + working directory to fill in some blanks. [Ken Parzygnat + <kparz@raleigh.ibm.com>] PR#3001 + + *) Correct invalid assumption by ap_sub_req_lookup_file() that all + absolute paths begin with "/" -- because they don't on Win32. + [Ken Parzygnat <kparz@raleigh.ibm.com>] PR#2976, 3074 + + *) Add [REDIRECT_]VARIANTS environment variable to mod_speling + so that ErrorDocument 300 processors can reformat the list + if desired. [Ken Coar] PR#2859 + + *) Add +/- incremental prefixes to IndexOptions keywords, and + enable merging of multiple IndexOptions directives. [Ken Coar] + + *) PORT: Allow GuessOS to recognize Unixware 7.0.1 [Steve Cameron + <steve.cameron@compaq.com>] + + *) Reconstructed the loop through multiple htaccess file names so + that missing files are not confused with unreadable files. + [Roy Fielding] + + *) The ap_pfopen and ap_pfdopen routines were failing to protect the + errno on an error, which leads to one error being mistaken for + another when reading non-existent .htaccess files. + [Jim Jagielski] + + *) OS/2: The new header tests get things right, need to update + ap_config.h. [Brian Havard] + + *) The Perl %ENV hash will now be setup by default when using the + mod_include `perl' command [Doug MacEachern] + + *) PORT: Add Pyramid DC/OSx support to configuration mechanism. + [Earle Ake <akee@wpdiss1.wpafb.af.mil>] + + *) PORT: Fix sys/resource.h handling for Amdahl's UTS 2.1 + [Dave Dykstra <dwd@bell-labs.com>] PR#3054 + + *) Correct comment in mod_log_config.c about its internals. + [Elf Sternberg <elf@halcyon.com>] + + *) Avoid possible line overflow in Configure: Use an awkfile to + handle the creation of modules.c [Jim Jagielski] + Changes with Apache 1.3.2 *) Fix bug in ap_remove_module(), which caused problems for dso's @@ -2129,7 +2247,7 @@ Changes with Apache 1.3b4 [robinton@amtrash.comlink.de (Soeren Ziehe), Martin Kraemer] *) PORT: Apache now compiles & runs on an EBCDIC mainframe - (the Siemens Nixdorf BS2000-OSD family) in the POSIX subsystem + (the Siemens BS2000/OSD family) in the POSIX subsystem [Martin Kraemer] *) PORT: Fix problem killing children when terminating. Allow ^C diff --git a/usr.sbin/httpd/src/Configure b/usr.sbin/httpd/src/Configure index a8822c7dcfe..e961d076187 100644 --- a/usr.sbin/httpd/src/Configure +++ b/usr.sbin/httpd/src/Configure @@ -618,6 +618,12 @@ case "$PLAT" in DEF_WANTHSREGEX=yes LIBS="$LIBS -lsocket -lnsl -lc" ;; + pyramid-pyramid-svr4) + OS='SVR4' + CFLAGS="$CFLAGS -DSVR4 -DNO_LONG_DOUBLE" + DEF_WANTHSREGEX=yes + LIBS="$LIBS -lsocket -lnsl -lc" + ;; DS/90\ 7000-*-sysv4*) OS='UXP/DS' CFLAGS="$CFLAGS -DUXPDS" @@ -708,6 +714,12 @@ case "$PLAT" in DEF_WANTHSREGEX=yes LIBS="$LIBS -lsocket -lnsl -lc -L/usr/ucblib -lucb" ;; + drs6000*) + OS='DRS6000' + CFLAGS="$CFLAGS -DSVR4" + DEF_WANTHSREGEX=yes + LIBS="$LIBS -lsocket -lnsl -lc -L/usr/ucblib -lucb" + ;; *) # default: Catch systems we don't know about OS='Unknown and unsupported OS' echo Sorry, but we cannot grok \"$PLAT\" @@ -1499,7 +1511,7 @@ if [ "x$using_shlib" = "x1" ] ; then # select the special subtarget for shared core generation SUBTARGET=target_shared # determine additional suffixes for libhttpd.so - V=1 R=3 P=2 + V=1 R=3 P=3 if [ ".$SHLIB_SUFFIX_DEPTH" = .0 ]; then SHLIB_SUFFIX_LIST="" fi @@ -1540,7 +1552,7 @@ fi #################################################################### ## Now create modules.c ## -cat $tmpfile | sed 's/_module//' | awk >modules.c ' +$CAT > $awkfile <<'EOFM' BEGIN { modules[n++] = "core" pmodules[pn++] = "core" @@ -1588,7 +1600,9 @@ cat $tmpfile | sed 's/_module//' | awk >modules.c ' print " NULL" print "};" print "" - }' + } +EOFM +$CAT $tmpfile | sed 's/_module//' | awk -f $awkfile > modules.c #################################################################### ## figure out which module dir require use to autocreate a Makefile. diff --git a/usr.sbin/httpd/src/README.EBCDIC b/usr.sbin/httpd/src/README.EBCDIC index 749ddc66765..e3361adadf3 100644 --- a/usr.sbin/httpd/src/README.EBCDIC +++ b/usr.sbin/httpd/src/README.EBCDIC @@ -2,8 +2,8 @@ This version of Apache comes with a first-cut (working, but not fully tested) port to a mainframe machine which uses the EBCDIC -character set as its native codeset (It is the SIEMENS NIXDORF -family of mainframes running the BS2000 operating system. This +character set as its native codeset (It is the SIEMENS family +of mainframes running the BS2000 operating system. This mainframe OS nowadays features a SVR4-like POSIX subsystem). The port was started initially to @@ -22,7 +22,7 @@ decisions of the port to this machine. #ifdef CHARSET_EBCDIC Code which is needed for any EBCDIC based machine #ifdef _OSD_POSIX Code which is needed for the BS2000 - SIEMENS NIXDORF mainframe platform only. + SIEMENS mainframe platform only. * The possibility to translate between ASCII and EBCDIC at the socket level (on BS2000 POSIX, there is a socket option which @@ -88,56 +88,6 @@ decisions of the port to this machine. An example for the latter case is the wwwcount program which we ported as well. -What works: -- In the following list, - + means: works, tested - - means: doesn't work for some reason - ? means: compiled-in, but untested - - http_core.c + - mod_access.c + - mod_actions.c ? - mod_alias.c + - mod_asis.c ? - mod_auth.c + - mod_auth_anon.c + - mod_auth_db.c ? with own libdb.a - mod_auth_dbm.c ? with own libdb.a - mod_autoindex.c + - mod_cern_meta.c ? - mod_cgi.c + - mod_digest.c - / MD5 not ported yet - mod_dir.c + - mod_env.c + - mod_example.c - / not tried yet - mod_expires.c + - mod_headers.c + - mod_imap.c + - mod_include.c + - mod_info.c + - mod_log_agent.c + - mod_log_config.c + - mod_log_referer.c + - mod_mime.c + - mod_mime_magic.c - / not tried yet - mod_negotiation.c + - mod_proxy.c + - mod_rewrite.c ? / untested - mod_setenvif.c + - mod_so.c - / no shared libs - mod_speling.c + - mod_status.c + - mod_unique_id.c + - mod_userdir.c + - mod_usertrack.c ? / untested - -Additional (third-party) modules: See: - mod_jserv.c - / JAVA still being ported http://java.apache.org/ - mod_php.c - / not ported yet http://www.php.net/ - mod_put.c ? / untested http://hpwww.ec-lyon.fr/~vincent/apache/mod_put.html - mod_session.c ? / untested ftp://hachiman.vidya.com/pub/apache/mod_session.tar.gz - - Notes: To use the mod_auth_db functionality, you will need a working libdb.a. On the system where I did the port none was available, so I ported the @@ -145,4 +95,6 @@ standard db-1.85.14 with little problems. Note however that you will need a working perl5 as well if you want to use Apache's dbmmanage script to maintain db user databases. - Martin Kraemer, 31-Mar-1998 +See also the ebcdic.html document which is part of the apache documentation. + + Martin Kraemer, 1-Oct-1998 diff --git a/usr.sbin/httpd/src/helpers/GuessOS b/usr.sbin/httpd/src/helpers/GuessOS index 5901305312d..096df4fd965 100644 --- a/usr.sbin/httpd/src/helpers/GuessOS +++ b/usr.sbin/httpd/src/helpers/GuessOS @@ -53,9 +53,11 @@ if [ "x$XREL" != "x" ]; then echo "whatever-whatever-unixware1"; exit 0 ;; 5) - if [ "x$VERSION" = "x7" ]; then - echo "${MACHINE}-whatever-unixware7"; exit 0 - fi + case "$VERSION" in + 7*) + echo "${MACHINE}-whatever-unixware7"; exit 0 + ;; + esac ;; esac fi @@ -246,6 +248,13 @@ case "${SYSTEM}:${RELEASE}:${VERSION}:${MACHINE}" in echo "whatever-unisys-sysv4"; exit 0; ;; + *:*:dcosx:NILE*) + echo "pyramid-pyramid-svr4"; exit 0; + ;; + + *:*:*:"DRS 6000") + echo "drs6000-whatever-whatever"; exit 0; + ;; esac # diff --git a/usr.sbin/httpd/src/include/ap_config.h b/usr.sbin/httpd/src/include/ap_config.h index e12639e81ab..60e35665ab6 100644 --- a/usr.sbin/httpd/src/include/ap_config.h +++ b/usr.sbin/httpd/src/include/ap_config.h @@ -372,7 +372,6 @@ typedef int pid_t; #define USE_MMAP_SCOREBOARD #define MAP_TMPFILE #define HAVE_RESOURCE -#define HAVE_SYS_RESOURCE_H /* apaci should catch this but doesn't */ #define HAVE_SNPRINTF #define JMP_BUF jmp_buf #define USE_LONGJMP @@ -466,6 +465,7 @@ typedef int rlim_t; #define NO_WRITEV #include <sys/time.h> #define HAVE_SYSLOG 1 +#undef HAVE_SYS_RESOURCE_H #elif defined(SCO5) @@ -615,6 +615,7 @@ extern char *crypt(); #define WEXITSTATUS(status) (int)((status).w_retcode) #define WTERMSIG(status) (int)((status).w_termsig) #define strftime(buf,bufsize,fmt,tm) ascftime(buf,fmt,tm) +#undef HAVE_SYS_RESOURCE_H /* exists but does not provide *rlimit funcs */ #include <sys/types.h> #include <sys/time.h> @@ -645,6 +646,7 @@ extern char *crypt(); typedef quad_t rlim_t; #endif #define USE_FLOCK_SERIALIZED_ACCEPT +#define SINGLE_LISTEN_UNSERIALIZED_ACCEPT #define HAVE_SYSLOG 1 #define SYS_SIGLIST sys_siglist @@ -706,8 +708,6 @@ typedef int rlim_t; #define NEED_STRNCASECMP #define NO_SETSID #define NO_TIMES -/* ap_config_auto.h gets this wrong, force sys/select.h to be included */ -#define HAVE_SYS_SELECT_H #define CASE_BLIND_FILESYSTEM /* Add some drive name support */ #define chdir _chdir2 diff --git a/usr.sbin/httpd/src/include/ap_mmn.h b/usr.sbin/httpd/src/include/ap_mmn.h index 718dcd21136..5ad482c319d 100644 --- a/usr.sbin/httpd/src/include/ap_mmn.h +++ b/usr.sbin/httpd/src/include/ap_mmn.h @@ -159,6 +159,9 @@ * 4. compat.h -> ap_compat.h * 5. apctype.h -> ap_ctype.h * 19980806 (1.3.2-dev) - add ap_log_rerror() + * - add ap_scan_script_header_err_core() + * - add ap_uuencode() + * - add ap_custom_response() * 19980811 (1.3.2-dev) - added limit_req_line, limit_req_fieldsize, and * limit_req_fields to server_rec. * added limit_req_body to core_dir_config and diff --git a/usr.sbin/httpd/src/include/httpd.h b/usr.sbin/httpd/src/include/httpd.h index 0323072bf0a..d93a896a2db 100644 --- a/usr.sbin/httpd/src/include/httpd.h +++ b/usr.sbin/httpd/src/include/httpd.h @@ -410,7 +410,7 @@ extern "C" { * Example: "Apache/1.1.0 MrWidget/0.1-alpha" */ -#define SERVER_BASEVERSION "Apache/1.3.2" /* SEE COMMENTS ABOVE */ +#define SERVER_BASEVERSION "Apache/1.3.3" /* SEE COMMENTS ABOVE */ #define SERVER_VERSION SERVER_BASEVERSION enum server_token_type { SrvTk_MIN, /* eg: Apache/1.3.0 */ @@ -427,7 +427,7 @@ API_EXPORT(const char *) ap_get_server_built(void); * For a final release, 'betaseq' should be set to '99'. * For example, Apache 1.4.2 should be '1040299' */ -#define APACHE_RELEASE 1030299 +#define APACHE_RELEASE 1030399 #define SERVER_PROTOCOL "HTTP/1.1" #ifndef SERVER_SUPPORT @@ -443,10 +443,15 @@ API_EXPORT(const char *) ap_get_server_built(void); /* ----------------------- HTTP Status Codes ------------------------- */ -#define RESPONSE_CODES 38 +/* The size of the static array in http_protocol.c for storing + * all of the potential response status-lines (a sparse table). + * A future version should dynamically generate the table at startup. + */ +#define RESPONSE_CODES 54 #define HTTP_CONTINUE 100 #define HTTP_SWITCHING_PROTOCOLS 101 +#define HTTP_PROCESSING 102 #define HTTP_OK 200 #define HTTP_CREATED 201 #define HTTP_ACCEPTED 202 @@ -454,12 +459,14 @@ API_EXPORT(const char *) ap_get_server_built(void); #define HTTP_NO_CONTENT 204 #define HTTP_RESET_CONTENT 205 #define HTTP_PARTIAL_CONTENT 206 +#define HTTP_MULTI_STATUS 207 #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_TEMPORARY_REDIRECT 307 #define HTTP_BAD_REQUEST 400 #define HTTP_UNAUTHORIZED 401 #define HTTP_PAYMENT_REQUIRED 402 @@ -476,6 +483,10 @@ API_EXPORT(const char *) ap_get_server_built(void); #define HTTP_REQUEST_ENTITY_TOO_LARGE 413 #define HTTP_REQUEST_URI_TOO_LARGE 414 #define HTTP_UNSUPPORTED_MEDIA_TYPE 415 +#define HTTP_RANGE_NOT_SATISFIABLE 416 +#define HTTP_EXPECTATION_FAILED 417 +#define HTTP_UNPROCESSABLE_ENTITY 422 +#define HTTP_LOCKED 423 #define HTTP_INTERNAL_SERVER_ERROR 500 #define HTTP_NOT_IMPLEMENTED 501 #define HTTP_BAD_GATEWAY 502 @@ -483,6 +494,7 @@ API_EXPORT(const char *) ap_get_server_built(void); #define HTTP_GATEWAY_TIME_OUT 504 #define HTTP_VERSION_NOT_SUPPORTED 505 #define HTTP_VARIANT_ALSO_VARIES 506 +#define HTTP_NOT_EXTENDED 510 #define DOCUMENT_FOLLOWS HTTP_OK #define PARTIAL_CONTENT HTTP_PARTIAL_CONTENT @@ -740,6 +752,13 @@ struct request_rec { * that way, a sub request's list can (temporarily) point to a parent's list */ const struct htaccess_result *htaccess; + +/* Things placed at the end of the record to avoid breaking binary + * compatibility. It would be nice to remember to reorder the entire + * record to improve 64bit alignment the next time we need to break + * binary compatibility for some other reason. + */ + unsigned expecting_100; /* is client waiting for a 100 response? */ }; diff --git a/usr.sbin/httpd/src/main/alloc.c b/usr.sbin/httpd/src/main/alloc.c index 67b4c224b67..e85a85aa3d2 100644 --- a/usr.sbin/httpd/src/main/alloc.c +++ b/usr.sbin/httpd/src/main/alloc.c @@ -1744,6 +1744,7 @@ API_EXPORT(FILE *) ap_pfopen(pool *a, const char *name, const char *mode) FILE *fd = NULL; int baseFlag, desc; int modeFlags = 0; + int saved_errno; #ifdef WIN32 modeFlags = _S_IREAD | _S_IWRITE; @@ -1766,22 +1767,26 @@ API_EXPORT(FILE *) ap_pfopen(pool *a, const char *name, const char *mode) else { fd = fopen(name, mode); } - + saved_errno = errno; if (fd != NULL) ap_note_cleanups_for_file(a, fd); ap_unblock_alarms(); + errno = saved_errno; return fd; } API_EXPORT(FILE *) ap_pfdopen(pool *a, int fd, const char *mode) { FILE *f; + int saved_errno; ap_block_alarms(); f = ap_fdopen(fd, mode); + saved_errno = errno; if (f != NULL) ap_note_cleanups_for_file(a, f); ap_unblock_alarms(); + errno = saved_errno; return f; } @@ -2217,6 +2222,10 @@ API_EXPORT(int) ap_bspawn_child(pool *p, int (*func) (void *, child_info *), voi HANDLE hPipeInputWrite = NULL; HANDLE hPipeErrorRead = NULL; HANDLE hPipeErrorWrite = NULL; + HANDLE hPipeInputWriteDup = NULL; + HANDLE hPipeOutputReadDup = NULL; + HANDLE hPipeErrorReadDup = NULL; + HANDLE hCurrentProcess; int pid = 0; child_info info; @@ -2255,6 +2264,57 @@ API_EXPORT(int) ap_bspawn_child(pool *p, int (*func) (void *, child_info *), voi } return 0; } + /* + * When the pipe handles are created, the security descriptor + * indicates that the handle can be inherited. However, we do not + * want the server side handles to the pipe to be inherited by the + * child CGI process. If the child CGI does inherit the server + * side handles, then the child may be left around if the server + * closes its handles (e.g. if the http connection is aborted), + * because the child will have a valid copy of handles to both + * sides of the pipes, and no I/O error will occur. Microsoft + * recommends using DuplicateHandle to turn off the inherit bit + * under NT and Win95. + */ + hCurrentProcess = GetCurrentProcess(); + if ((pipe_in && !DuplicateHandle(hCurrentProcess, hPipeInputWrite, + hCurrentProcess, + &hPipeInputWriteDup, 0, FALSE, + DUPLICATE_SAME_ACCESS)) + || (pipe_out && !DuplicateHandle(hCurrentProcess, hPipeOutputRead, + hCurrentProcess, &hPipeOutputReadDup, + 0, FALSE, DUPLICATE_SAME_ACCESS)) + || (pipe_err && !DuplicateHandle(hCurrentProcess, hPipeErrorRead, + hCurrentProcess, &hPipeErrorReadDup, + 0, FALSE, DUPLICATE_SAME_ACCESS))) { + if (pipe_in) { + CloseHandle(hPipeInputRead); + CloseHandle(hPipeInputWrite); + } + if (pipe_out) { + CloseHandle(hPipeOutputRead); + CloseHandle(hPipeOutputWrite); + } + if (pipe_err) { + CloseHandle(hPipeErrorRead); + CloseHandle(hPipeErrorWrite); + } + return 0; + } + else { + if (pipe_in) { + CloseHandle(hPipeInputWrite); + hPipeInputWrite = hPipeInputWriteDup; + } + if (pipe_out) { + CloseHandle(hPipeOutputRead); + hPipeOutputRead = hPipeOutputReadDup; + } + if (pipe_err) { + CloseHandle(hPipeErrorRead); + hPipeErrorRead = hPipeErrorReadDup; + } + } /* The script writes stdout to this pipe handle */ info.hPipeOutputWrite = hPipeOutputWrite; diff --git a/usr.sbin/httpd/src/main/buff.c b/usr.sbin/httpd/src/main/buff.c index 0501b1a7377..a8cb2515160 100644 --- a/usr.sbin/httpd/src/main/buff.c +++ b/usr.sbin/httpd/src/main/buff.c @@ -562,14 +562,22 @@ static int saferead(BUFF *fb, char *buf, int nbyte) #endif -/* note we assume the caller has ensured that fb->fd_in <= FD_SETSIZE */ +/* Test the descriptor and flush the output buffer if it looks like + * we will block on the next read. + * + * Note we assume the caller has ensured that fb->fd_in <= FD_SETSIZE + */ API_EXPORT(void) ap_bhalfduplex(BUFF *fb) { int rv; fd_set fds; struct timeval tv; - if (fb->incnt > 0 || fb->outcnt == 0) { + /* We don't need to do anything if the connection has been closed + * or there is something readable in the incoming buffer + * or there is nothing flushable in the output buffer. + */ + if (fb == NULL || fb->fd_in < 0 || fb->incnt > 0 || fb->outcnt == 0) { return; } /* test for a block */ @@ -579,7 +587,8 @@ API_EXPORT(void) ap_bhalfduplex(BUFF *fb) tv.tv_sec = 0; tv.tv_usec = 0; rv = ap_select(fb->fd_in + 1, &fds, NULL, NULL, &tv); - } while (rv < 0 && errno == EINTR); + } while (rv < 0 && errno == EINTR && !(fb->flags & B_EOUT)); + /* treat any error as if it would block as well */ if (rv != 1) { ap_bflush(fb); diff --git a/usr.sbin/httpd/src/main/http_config.c b/usr.sbin/httpd/src/main/http_config.c index 307e9044d1e..50f865712b1 100644 --- a/usr.sbin/httpd/src/main/http_config.c +++ b/usr.sbin/httpd/src/main/http_config.c @@ -1206,7 +1206,7 @@ int ap_parse_htaccess(void **result, request_rec *r, int override, char *filename = NULL; const struct htaccess_result *cache; struct htaccess_result *new; - void *dc; + void *dc = NULL; /* firstly, search cache */ for (cache = r->htaccess; cache != NULL; cache = cache->next) @@ -1224,41 +1224,39 @@ int ap_parse_htaccess(void **result, request_rec *r, int override, parms.path = ap_pstrdup(r->pool, d); /* loop through the access names and find the first one */ - while (!f && access_name[0]) { - char *w = ap_getword_conf(r->pool, &access_name); - filename = ap_make_full_path(r->pool, d, w); - f = ap_pcfg_openfile(r->pool, filename); - } - if (f) { - dc = ap_create_per_dir_config(r->pool); - parms.config_file = f; + while (access_name[0]) { + filename = ap_make_full_path(r->pool, d, + ap_getword_conf(r->pool, &access_name)); - errmsg = ap_srm_command_loop(&parms, dc); + if ((f = ap_pcfg_openfile(r->pool, filename)) != NULL) { - ap_cfg_closefile(f); + dc = ap_create_per_dir_config(r->pool); - if (errmsg) { - ap_log_rerror(APLOG_MARK, APLOG_ALERT|APLOG_NOERRNO, r, "%s: %s", - filename, errmsg); - ap_table_setn(r->notes, "error-notes", errmsg); - return HTTP_INTERNAL_SERVER_ERROR; - } + parms.config_file = f; - *result = dc; - } - else { - if (errno == ENOENT || errno == ENOTDIR) - dc = NULL; - else { - ap_log_rerror(APLOG_MARK, APLOG_CRIT, r, - "%s pcfg_openfile: unable to check htaccess file, ensure it is readable", - filename); - ap_table_setn(r->notes, "error-notes", - "Server unable to read htaccess file, denying " - "access to be safe"); - return HTTP_FORBIDDEN; - } + errmsg = ap_srm_command_loop(&parms, dc); + + ap_cfg_closefile(f); + + if (errmsg) { + ap_log_rerror(APLOG_MARK, APLOG_ALERT|APLOG_NOERRNO, r, + "%s: %s", filename, errmsg); + return HTTP_INTERNAL_SERVER_ERROR; + } + *result = dc; + break; + } + else if (errno != ENOENT && errno != ENOTDIR) { + ap_log_rerror(APLOG_MARK, APLOG_CRIT, r, + "%s pcfg_openfile: unable to check htaccess file, " + "ensure it is readable", + filename); + ap_table_setn(r->notes, "error-notes", + "Server unable to read htaccess file, denying " + "access to be safe"); + return HTTP_FORBIDDEN; + } } /* cache it */ diff --git a/usr.sbin/httpd/src/main/http_core.c b/usr.sbin/httpd/src/main/http_core.c index de5a7e04aab..320f907e6f1 100644 --- a/usr.sbin/httpd/src/main/http_core.c +++ b/usr.sbin/httpd/src/main/http_core.c @@ -2670,8 +2670,20 @@ static int core_translate(request_rec *r) (r->uri + r->server->pathlen), NULL); } else { - r->filename = ap_pstrcat(r->pool, conf->ap_document_root, r->uri, - NULL); + /* + * Make sure that we do not mess up the translation by adding two + * /'s in a row. This happens under windows when the document + * root ends with a / + */ + if ((conf->ap_document_root[strlen(conf->ap_document_root)-1] == '/') + && (*(r->uri) == '/')) { + r->filename = ap_pstrcat(r->pool, conf->ap_document_root, r->uri+1, + NULL); + } + else { + r->filename = ap_pstrcat(r->pool, conf->ap_document_root, r->uri, + NULL); + } } return OK; @@ -2743,7 +2755,6 @@ static int default_handler(request_rec *r) emsg = ap_pstrcat(r->pool, emsg, r->filename, r->path_info, NULL); } ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, r, emsg); - ap_table_setn(r->notes, "error-notes", emsg); return HTTP_NOT_FOUND; } if (r->method_number != M_GET) { diff --git a/usr.sbin/httpd/src/main/http_log.c b/usr.sbin/httpd/src/main/http_log.c index 094bbfc5746..3c380862563 100644 --- a/usr.sbin/httpd/src/main/http_log.c +++ b/usr.sbin/httpd/src/main/http_log.c @@ -154,7 +154,7 @@ static const TRANS priorities[] = { {NULL, -1}, }; -static int error_log_child (void *cmd, child_info *pinfo) +static int error_log_child(void *cmd, child_info *pinfo) { /* Child process code for 'ErrorLog "|..."'; * may want a common framework for this, since I expect it will @@ -165,23 +165,23 @@ static int error_log_child (void *cmd, child_info *pinfo) ap_cleanup_for_exec(); #ifdef SIGHUP /* No concept of a child process on Win32 */ - signal (SIGHUP, SIG_IGN); + signal(SIGHUP, SIG_IGN); #endif /* ndef SIGHUP */ #if defined(WIN32) - child_pid = spawnl (_P_NOWAIT, SHELL_PATH, SHELL_PATH, "/c", (char *)cmd, NULL); + child_pid = spawnl(_P_NOWAIT, SHELL_PATH, SHELL_PATH, "/c", (char *)cmd, NULL); return(child_pid); #elif defined(OS2) /* For OS/2 we need to use a '/' */ - execl (SHELL_PATH, SHELL_PATH, "/c", (char *)cmd, NULL); + execl(SHELL_PATH, SHELL_PATH, "/c", (char *)cmd, NULL); #else - execl (SHELL_PATH, SHELL_PATH, "-c", (char *)cmd, NULL); + execl(SHELL_PATH, SHELL_PATH, "-c", (char *)cmd, NULL); #endif - exit (1); + exit(1); /* NOT REACHED */ return(child_pid); } -static void open_error_log (server_rec *s, pool *p) +static void open_error_log(server_rec *s, pool *p) { char *fname; @@ -190,9 +190,9 @@ static void open_error_log (server_rec *s, pool *p) if (!ap_spawn_child(p, error_log_child, (void *)(s->error_fname+1), kill_after_timeout, &dummy, NULL, NULL)) { - perror ("ap_spawn_child"); - fprintf (stderr, "Couldn't fork child for ErrorLog process\n"); - exit (1); + perror("ap_spawn_child"); + fprintf(stderr, "Couldn't fork child for ErrorLog process\n"); + exit(1); } s->error_log = dummy; @@ -219,8 +219,8 @@ static void open_error_log (server_rec *s, pool *p) } #endif else { - fname = ap_server_root_relative (p, s->error_fname); - if(!(s->error_log = ap_pfopen(p, fname, "a"))) { + fname = ap_server_root_relative(p, s->error_fname); + if (!(s->error_log = ap_pfopen(p, fname, "a"))) { perror("fopen"); fprintf(stderr,"httpd: could not open error log file %s.\n", fname); exit(1); @@ -228,18 +228,18 @@ static void open_error_log (server_rec *s, pool *p) } } -void ap_open_logs (server_rec *s_main, pool *p) +void ap_open_logs(server_rec *s_main, pool *p) { server_rec *virt, *q; int replace_stderr; - open_error_log (s_main, p); + open_error_log(s_main, p); replace_stderr = 1; if (s_main->error_log) { /* replace stderr with this new log */ fflush(stderr); - if (dup2(fileno(s_main->error_log), 2) == -1) { + if (dup2(fileno(s_main->error_log), STDERR_FILENO) == -1) { ap_log_error(APLOG_MARK, APLOG_CRIT, s_main, "unable to replace stderr with error_log"); } else { @@ -262,20 +262,23 @@ void ap_open_logs (server_rec *s_main, pool *p) 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; + if (q == virt) + open_error_log(virt, p); + else + virt->error_log = q->error_log; } else virt->error_log = s_main->error_log; } } -API_EXPORT(void) ap_error_log2stderr (server_rec *s) { - if(fileno(s->error_log) != STDERR_FILENO) - dup2(fileno(s->error_log),STDERR_FILENO); +API_EXPORT(void) ap_error_log2stderr(server_rec *s) { + if ( s->error_log != NULL + && fileno(s->error_log) != STDERR_FILENO) + dup2(fileno(s->error_log), STDERR_FILENO); } -static void log_error_core (const char *file, int line, int level, +static void log_error_core(const char *file, int line, int level, const server_rec *s, const request_rec *r, const char *fmt, va_list args) { @@ -423,7 +426,7 @@ static void log_error_core (const char *file, int line, int level, #endif } -API_EXPORT(void) ap_log_error (const char *file, int line, int level, +API_EXPORT(void) ap_log_error(const char *file, int line, int level, const server_rec *s, const char *fmt, ...) { va_list args; @@ -440,27 +443,35 @@ API_EXPORT(void) ap_log_rerror(const char *file, int line, int level, va_start(args, fmt); log_error_core(file, line, level, r->server, r, fmt, args); - if (ap_table_get(r->notes, "error-notes") == NULL) { - char errstr[MAX_STRING_LEN]; - - ap_vsnprintf(errstr, sizeof(errstr), fmt, args); - ap_table_set(r->notes, "error-notes", errstr); + /* + * IF the error level is 'warning' or more severe, + * AND there isn't already error text associated with this request, + * THEN make the message text available to ErrorDocument and + * other error processors. This can be disabled by stuffing + * something, even an empty string, into the "error-notes" cell + * before calling this routine. + */ + if (((level & APLOG_LEVELMASK) <= APLOG_WARNING) + && (ap_table_get(r->notes, "error-notes") == NULL)) { + ap_table_setn(r->notes, "error-notes", + ap_pvsprintf(r->pool, fmt, args)); } va_end(args); } -void ap_log_pid (pool *p, char *fname) +void ap_log_pid(pool *p, char *fname) { FILE *pid_file; struct stat finfo; static pid_t saved_pid = -1; pid_t mypid; - if (!fname) return; + if (!fname) + return; - fname = ap_server_root_relative (p, fname); + fname = ap_server_root_relative(p, fname); mypid = getpid(); - if (mypid != saved_pid && stat(fname,&finfo) == 0) { + if (mypid != saved_pid && stat(fname, &finfo) == 0) { /* USR1 and HUP call this on each restart. * Only warn on first time through for this pid. * @@ -475,28 +486,28 @@ void ap_log_pid (pool *p, char *fname) ); } - if(!(pid_file = fopen(fname,"w"))) { + if(!(pid_file = fopen(fname, "w"))) { perror("fopen"); - fprintf(stderr,"httpd: could not log pid to file %s\n", fname); + fprintf(stderr, "httpd: could not log pid to file %s\n", fname); exit(1); } - fprintf(pid_file,"%ld\n",(long)mypid); + fprintf(pid_file, "%ld\n", (long)mypid); fclose(pid_file); saved_pid = mypid; } -API_EXPORT(void) ap_log_error_old (const char *err, server_rec *s) +API_EXPORT(void) ap_log_error_old(const char *err, server_rec *s) { ap_log_error(APLOG_MARK, APLOG_ERR, s, "%s", err); } -API_EXPORT(void) ap_log_unixerr (const char *routine, const char *file, +API_EXPORT(void) ap_log_unixerr(const char *routine, const char *file, const char *msg, server_rec *s) { ap_log_error(file, 0, APLOG_ERR, s, "%s", msg); } -API_EXPORT(void) ap_log_printf (const server_rec *s, const char *fmt, ...) +API_EXPORT(void) ap_log_printf(const server_rec *s, const char *fmt, ...) { va_list args; @@ -505,7 +516,7 @@ API_EXPORT(void) ap_log_printf (const server_rec *s, const char *fmt, ...) va_end(args); } -API_EXPORT(void) ap_log_reason (const char *reason, const char *file, request_rec *r) +API_EXPORT(void) ap_log_reason(const char *reason, const char *file, request_rec *r) { ap_log_error(APLOG_MARK, APLOG_ERR, r->server, "access to %s failed for %s, reason: %s", @@ -514,7 +525,7 @@ API_EXPORT(void) ap_log_reason (const char *reason, const char *file, request_re reason); } -API_EXPORT(void) ap_log_assert (const char *szExp, const char *szFile, int nLine) +API_EXPORT(void) ap_log_assert(const char *szExp, const char *szFile, int nLine) { fprintf(stderr, "[%s] file %s, line %d, assertion \"%s\" failed\n", ap_get_time(), szFile, nLine, szExp); @@ -530,9 +541,9 @@ API_EXPORT(void) ap_log_assert (const char *szExp, const char *szFile, int nLine #ifndef NO_RELIABLE_PIPED_LOGS /* forward declaration */ -static void piped_log_maintenance (int reason, void *data, ap_wait_t status); +static void piped_log_maintenance(int reason, void *data, ap_wait_t status); -static int piped_log_spawn (piped_log *pl) +static int piped_log_spawn(piped_log *pl) { int pid; @@ -545,32 +556,32 @@ static int piped_log_spawn (piped_log *pl) * XXX: close all the relevant stuff, but hey, it could be broken. */ RAISE_SIGSTOP(PIPED_LOG_SPAWN); /* we're now in the child */ - close (STDIN_FILENO); - dup2 (pl->fds[0], STDIN_FILENO); - - ap_cleanup_for_exec (); - signal (SIGCHLD, SIG_DFL); /* for HPUX */ - signal (SIGHUP, SIG_IGN); - execl (SHELL_PATH, SHELL_PATH, "-c", pl->program, NULL); - fprintf (stderr, + close(STDIN_FILENO); + dup2(pl->fds[0], STDIN_FILENO); + + ap_cleanup_for_exec(); + signal(SIGCHLD, SIG_DFL); /* for HPUX */ + signal(SIGHUP, SIG_IGN); + execl(SHELL_PATH, SHELL_PATH, "-c", pl->program, NULL); + fprintf(stderr, "piped_log_spawn: unable to exec %s -c '%s': %s\n", SHELL_PATH, pl->program, strerror (errno)); - exit (1); + exit(1); } if (pid == -1) { - fprintf (stderr, + fprintf(stderr, "piped_log_spawn: unable to fork(): %s\n", strerror (errno)); - ap_unblock_alarms (); + ap_unblock_alarms(); return -1; } ap_unblock_alarms(); pl->pid = pid; - ap_register_other_child (pid, piped_log_maintenance, pl, pl->fds[1]); + ap_register_other_child(pid, piped_log_maintenance, pl, pl->fds[1]); return 0; } -static void piped_log_maintenance (int reason, void *data, ap_wait_t status) +static void piped_log_maintenance(int reason, void *data, ap_wait_t status) { piped_log *pl = data; @@ -578,30 +589,30 @@ static void piped_log_maintenance (int reason, void *data, ap_wait_t status) case OC_REASON_DEATH: case OC_REASON_LOST: pl->pid = -1; - ap_unregister_other_child (pl); + ap_unregister_other_child(pl); if (pl->program == NULL) { /* during a restart */ break; } - if (piped_log_spawn (pl) == -1) { + if (piped_log_spawn(pl) == -1) { /* what can we do? This could be the error log we're having * problems opening up... */ - fprintf (stderr, + fprintf(stderr, "piped_log_maintenance: unable to respawn '%s': %s\n", - pl->program, strerror (errno)); + pl->program, strerror(errno)); } break; case OC_REASON_UNWRITABLE: if (pl->pid != -1) { - kill (pl->pid, SIGTERM); + kill(pl->pid, SIGTERM); } break; case OC_REASON_RESTART: pl->program = NULL; if (pl->pid != -1) { - kill (pl->pid, SIGTERM); + kill(pl->pid, SIGTERM); } break; @@ -611,67 +622,67 @@ static void piped_log_maintenance (int reason, void *data, ap_wait_t status) } -static void piped_log_cleanup (void *data) +static void piped_log_cleanup(void *data) { piped_log *pl = data; if (pl->pid != -1) { - kill (pl->pid, SIGTERM); + kill(pl->pid, SIGTERM); } - ap_unregister_other_child (pl); - close (pl->fds[0]); - close (pl->fds[1]); + ap_unregister_other_child(pl); + close(pl->fds[0]); + close(pl->fds[1]); } -static void piped_log_cleanup_for_exec (void *data) +static void piped_log_cleanup_for_exec(void *data) { piped_log *pl = data; - close (pl->fds[0]); - close (pl->fds[1]); + close(pl->fds[0]); + close(pl->fds[1]); } -API_EXPORT(piped_log *) ap_open_piped_log (pool *p, const char *program) +API_EXPORT(piped_log *) ap_open_piped_log(pool *p, const char *program) { piped_log *pl; - pl = ap_palloc (p, sizeof (*pl)); + pl = ap_palloc(p, sizeof (*pl)); pl->p = p; - pl->program = ap_pstrdup (p, program); + pl->program = ap_pstrdup(p, program); pl->pid = -1; ap_block_alarms (); - if (pipe (pl->fds) == -1) { + if (pipe(pl->fds) == -1) { int save_errno = errno; ap_unblock_alarms(); errno = save_errno; return NULL; } - ap_register_cleanup (p, pl, piped_log_cleanup, piped_log_cleanup_for_exec); - if (piped_log_spawn (pl) == -1) { + ap_register_cleanup(p, pl, piped_log_cleanup, piped_log_cleanup_for_exec); + if (piped_log_spawn(pl) == -1) { int save_errno = errno; - ap_kill_cleanup (p, pl, piped_log_cleanup); - close (pl->fds[0]); - close (pl->fds[1]); - ap_unblock_alarms (); + ap_kill_cleanup(p, pl, piped_log_cleanup); + close(pl->fds[0]); + close(pl->fds[1]); + ap_unblock_alarms(); errno = save_errno; return NULL; } - ap_unblock_alarms (); + ap_unblock_alarms(); return pl; } -API_EXPORT(void) ap_close_piped_log (piped_log *pl) +API_EXPORT(void) ap_close_piped_log(piped_log *pl) { - ap_block_alarms (); - piped_log_cleanup (pl); - ap_kill_cleanup (pl->p, pl, piped_log_cleanup); - ap_unblock_alarms (); + ap_block_alarms(); + piped_log_cleanup(pl); + ap_kill_cleanup(pl->p, pl, piped_log_cleanup); + ap_unblock_alarms(); } #else -static int piped_log_child (void *cmd, child_info *pinfo) +static int piped_log_child(void *cmd, child_info *pinfo) { /* Child process code for 'TransferLog "|..."'; * may want a common framework for this, since I expect it will @@ -681,10 +692,10 @@ static int piped_log_child (void *cmd, child_info *pinfo) ap_cleanup_for_exec(); #ifdef SIGHUP - signal (SIGHUP, SIG_IGN); + signal(SIGHUP, SIG_IGN); #endif #if defined(WIN32) - child_pid = spawnl (_P_NOWAIT, SHELL_PATH, SHELL_PATH, "/c", (char *)cmd, NULL); + child_pid = spawnl(_P_NOWAIT, SHELL_PATH, SHELL_PATH, "/c", (char *)cmd, NULL); return(child_pid); #elif defined(OS2) /* For OS/2 we need to use a '/' */ @@ -692,24 +703,24 @@ static int piped_log_child (void *cmd, child_info *pinfo) #else execl (SHELL_PATH, SHELL_PATH, "-c", (char *)cmd, NULL); #endif - perror ("exec"); - fprintf (stderr, "Exec of shell for logging failed!!!\n"); + perror("exec"); + fprintf(stderr, "Exec of shell for logging failed!!!\n"); return(child_pid); } -API_EXPORT(piped_log *) ap_open_piped_log (pool *p, const char *program) +API_EXPORT(piped_log *) ap_open_piped_log(pool *p, const char *program) { piped_log *pl; FILE *dummy; if (!ap_spawn_child(p, piped_log_child, (void *)program, kill_after_timeout, &dummy, NULL, NULL)) { - perror ("ap_spawn_child"); - fprintf (stderr, "Couldn't fork child for piped log process\n"); + perror("ap_spawn_child"); + fprintf(stderr, "Couldn't fork child for piped log process\n"); exit (1); } - pl = ap_palloc (p, sizeof (*pl)); + pl = ap_palloc(p, sizeof (*pl)); pl->p = p; pl->write_f = dummy; @@ -717,8 +728,8 @@ API_EXPORT(piped_log *) ap_open_piped_log (pool *p, const char *program) } -API_EXPORT(void) ap_close_piped_log (piped_log *pl) +API_EXPORT(void) ap_close_piped_log(piped_log *pl) { - ap_pfclose (pl->p, pl->write_f); + ap_pfclose(pl->p, pl->write_f); } #endif diff --git a/usr.sbin/httpd/src/main/http_main.c b/usr.sbin/httpd/src/main/http_main.c index 2b6833f1542..defbca0b5bf 100644 --- a/usr.sbin/httpd/src/main/http_main.c +++ b/usr.sbin/httpd/src/main/http_main.c @@ -999,6 +999,10 @@ static void usage(char *bin) fprintf(stderr, " -l : list compiled-in modules\n"); fprintf(stderr, " -S : show parsed settings (currently only vhost settings)\n"); fprintf(stderr, " -t : run syntax test for configuration files only\n"); +#ifdef WIN32 + fprintf(stderr, " -k shutdown : tell running Apache to shutdown\n"); + fprintf(stderr, " -k restart : tell running Apache to do a graceful restart\n"); +#endif exit(1); } @@ -2542,17 +2546,41 @@ static int volatile generation; #ifdef WIN32 /* - * signal_parent() tells the parent process to wake up and do something. - * Once woken it will look at shutdown_pending and restart_pending to decide - * what to do. If neither variable is set, it will do a shutdown. This function - * if called by start_shutdown() or start_restart() in the parent's process - * space, so that the variables get set. However it can also be called - * by child processes to force the parent to exit in an emergency. + * Signalling Apache on NT. + * + * Under Unix, Apache can be told to shutdown or restart by sending various + * signals (HUP, USR, TERM). On NT we don't have easy access to signals, so + * we use "events" instead. The parent apache process goes into a loop + * where it waits forever for a set of events. Two of those events are + * called + * + * apPID_shutdown + * apPID_restart + * + * (where PID is the PID of the apache parent process). When one of these + * is signalled, the Apache parent performs the appropriate action. The events + * can become signalled through internal Apache methods (e.g. if the child + * finds a fatal error and needs to kill its parent), via the service + * control manager (the control thread will signal the shutdown event when + * requested to stop the Apache service), from the -k Apache command line, + * or from any external program which finds the Apache PID from the + * httpd.pid file. + * + * The signal_parent() function, below, is used to signal one of these events. + * It can be called by any child or parent process, since it does not + * rely on global variables. + * + * On entry, type gives the event to signal. 0 means shutdown, 1 means + * graceful restart. */ -static void signal_parent(void) +static void signal_parent(int type) { HANDLE e; + char *signal_name; + extern char signal_shutdown_name[]; + extern char signal_restart_name[]; + /* after updating the shutdown_pending or restart flags, we need * to wake up the parent process so it can see the changes. The * parent will normally be waiting for either a child process @@ -2564,21 +2592,28 @@ static void signal_parent(void) return; } - APD1("*** SIGNAL_PARENT SET ***"); + switch(type) { + case 0: signal_name = signal_shutdown_name; break; + case 1: signal_name = signal_restart_name; break; + default: return; + } - e = OpenEvent(EVENT_ALL_ACCESS, FALSE, "apache-signal"); + APD2("signal_parent signalling event \"%s\"", signal_name); + + e = OpenEvent(EVENT_ALL_ACCESS, FALSE, signal_name); if (!e) { - /* Um, problem, can't signal the main loop, which means we can't + /* Um, problem, can't signal the parent, which means we can't * signal ourselves to die. Ignore for now... */ ap_log_error(APLOG_MARK, APLOG_EMERG|APLOG_WIN32ERROR, server_conf, - "OpenEvent on apache-signal event"); + "OpenEvent on %s event", signal_name); return; } if (SetEvent(e) == 0) { /* Same problem as above */ ap_log_error(APLOG_MARK, APLOG_EMERG|APLOG_WIN32ERROR, server_conf, - "SetEvent on apache-signal event"); + "SetEvent on %s event", signal_name); + CloseHandle(e); return; } CloseHandle(e); @@ -2586,24 +2621,19 @@ static void signal_parent(void) #endif /* - * start_shutdown() and start_restart(), below, are a first stab at + * ap_start_shutdown() and ap_start_restart(), below, are a first stab at * functions to initiate shutdown or restart without relying on signals. * Previously this was initiated in sig_term() and restart() signal handlers, * but we want to be able to start a shutdown/restart from other sources -- * e.g. on Win32, from the service manager. Now the service manager can - * call start_shutdown() or start_restart() as appropiate. - * - * These should only be called from the parent process itself, since the - * parent process will use the shutdown_pending and restart_pending variables - * to determine whether to shutdown or restart. The child process should - * call signal_parent() directly to tell the parent to die -- this will - * cause neither of those variable to be set, which the parent will - * assume means something serious is wrong (which it will be, for the - * child to force an exit) and so do an exit anyway. + * call ap_start_shutdown() or ap_start_restart() as appropiate. Note that + * these functions can also be called by the child processes, since global + * variables are no longer used to pass on the required action to the parent. */ void ap_start_shutdown(void) { +#ifndef WIN32 if (shutdown_pending == 1) { /* Um, is this _probably_ not an error, if the user has * tried to do a shutdown twice quickly, so we won't @@ -2612,24 +2642,23 @@ void ap_start_shutdown(void) return; } shutdown_pending = 1; - -#ifdef WIN32 - signal_parent(); /* get the parent process to wake up */ +#else + signal_parent(0); /* get the parent process to wake up */ #endif } /* do a graceful restart if graceful == 1 */ void ap_start_restart(int graceful) { +#ifndef WIN32 if (restart_pending == 1) { /* Probably not an error - don't bother reporting it */ return; } restart_pending = 1; is_graceful = graceful; - -#ifdef WIN32 - signal_parent(); /* get the parent process to wake up */ +#else + signal_parent(1); /* get the parent process to wake up */ #endif /* WIN32 */ } @@ -4633,11 +4662,13 @@ int REALMAIN(int argc, char *argv[]) * * Signalling between the parent and working process uses a Win32 * event. Each child has a unique name for the event, which is - * passed to it with the -c argument when the child is spawned. The + * passed to it with the -Z argument when the child is spawned. The * parent sets (signals) this event to tell the child to die. * At present all children do a graceful die - they finish all * current jobs _and_ empty the listen queue before they exit. - * A non-graceful die would need a second event. + * A non-graceful die would need a second event. The -Z argument in + * the child is also used to create the shutdown and restart events, + * since the prefix (apPID) contains the parent process PID. * * The code below starts with functions at the lowest level - * worker threads, and works up to the top level - the main() @@ -5001,17 +5032,37 @@ extern void main_control_server(void *); /* in hellop.c */ event *exit_event; mutex *start_mutex; +#define MAX_SIGNAL_NAME 30 /* Long enough for apPID_shutdown, where PID is an int */ +char signal_name_prefix[MAX_SIGNAL_NAME]; +char signal_restart_name[MAX_SIGNAL_NAME]; +char signal_shutdown_name[MAX_SIGNAL_NAME]; + #define MAX_SELECT_ERRORS 100 +/* + * Initialise the signal names, in the global variables signal_name_prefix, + * signal_restart_name and signal_shutdown_name. + */ + +void setup_signal_names(char *prefix) +{ + ap_snprintf(signal_name_prefix, sizeof(signal_name_prefix), prefix); + ap_snprintf(signal_shutdown_name, sizeof(signal_shutdown_name), + "%s_shutdown", signal_name_prefix); + ap_snprintf(signal_restart_name, sizeof(signal_restart_name), + "%s_restart", signal_name_prefix); + + APD2("signal prefix %s", signal_name_prefix); +} + +/* + * worker_main() is main loop for the child process. The loop in + * this function becomes the controlling thread for the actually working + * threads (which run in a loop in child_sub_main()). + */ + void worker_main(void) { - /* - * I am writing this stuff specifically for NT. - * have pulled out a lot of the restart and - * graceful restart stuff, because that is only - * useful on Unix (not sure it even makes sense - * in a multi-threaded env. - */ int nthreads; fd_set main_fds; int srv; @@ -5059,7 +5110,13 @@ void worker_main(void) reinit_scoreboard(pconf); - //ap_acquire_mutex(start_mutex); + /* + * Wait until we have permission to start accepting connections. + * start_mutex is used to ensure that only one child ever + * goes into the listen/accept loop at once. Also wait on exit_event, + * in case we (this child) is told to die before we get a chance to + * serve any requests. + */ hObjects[0] = (HANDLE)start_mutex; hObjects[1] = (HANDLE)exit_event; rv = WaitForMultipleObjects(2, hObjects, FALSE, INFINITE); @@ -5085,7 +5142,7 @@ void worker_main(void) ap_log_error(APLOG_MARK, APLOG_CRIT|APLOG_NOERRNO, NULL, "No sockets were created for listening"); - signal_parent(); /* tell parent to die */ + signal_parent(0); /* tell parent to die */ ap_destroy_pool(pchild); cleanup_scoreboard(); @@ -5114,15 +5171,11 @@ void worker_main(void) /* spawn off the threads */ child_handles = (thread *) alloca(nthreads * sizeof(int)); - { - int i; - - for (i = 0; i < nthreads; i++) { - child_handles[i] = create_thread((void (*)(void *)) child_main, (void *) i); - } - if (nthreads > max_daemons_limit) { - max_daemons_limit = nthreads; - } + for (i = 0; i < nthreads; i++) { + child_handles[i] = create_thread((void (*)(void *)) child_main, (void *) i); + } + if (nthreads > max_daemons_limit) { + max_daemons_limit = nthreads; } while (1) { @@ -5288,22 +5341,21 @@ void worker_main(void) clean_parent_exit(0); } /* standalone_main */ -/* Spawn a child Apache process. The child process has the command - * line arguments from argc and argv[], plus a -Z argument giving the - * name of an event. The child should open and poll or wait on this - * event. When it is signalled, the child should die. prefix is a - * prefix string for the event name. +/* + * Spawn a child Apache process. The child process has the command line arguments from + * argc and argv[], plus a -Z argument giving the name of an event. The child should + * open and poll or wait on this event. When it is signalled, the child should die. + * prefix is a prefix string for the event name. * - * The child_num argument on entry contains a serial number for this - * child (used to create a unique event name). On exit, this number - * will have been incremented by one, ready for the next call. + * The child_num argument on entry contains a serial number for this child (used to create + * a unique event name). On exit, this number will have been incremented by one, ready + * for the next call. * * On exit, the value pointed to be *ev will contain the event created * to signal the new child process. * - * The return value is the handle to the child process if successful, - * else -1. If -1 is returned the error will already have been logged - * by ap_log_error(). + * The return value is the handle to the child process if successful, else -1. If -1 is + * returned the error will already have been logged by ap_log_error(). */ int create_event_and_spawn(int argc, char **argv, event **ev, int *child_num, char *prefix) @@ -5311,8 +5363,15 @@ int create_event_and_spawn(int argc, char **argv, event **ev, int *child_num, ch char buf[40], mod[200]; int i, rv; char **pass_argv = (char **) alloca(sizeof(char *) * (argc + 3)); - - ap_snprintf(buf, sizeof(buf), "%s_%d", prefix, ++(*child_num)); + + /* We need an event to tell the child process to kill itself when + * the parent is doing a shutdown/restart. This will be named + * apPID_CN where PID is the parent Apache process PID and + * N is a unique child serial number. prefix contains + * the "apPID" part. The child will get the name of this + * event as its -Z command line argument. + */ + ap_snprintf(buf, sizeof(buf), "%s_C%d", prefix, ++(*child_num)); _flushall(); *ev = CreateEvent(NULL, TRUE, FALSE, buf); if (!*ev) { @@ -5409,10 +5468,11 @@ int master_main(int argc, char **argv) int *child; int child_num = 0; int rv, cld; - char buf[100]; + char signal_prefix_string[100]; int i; time_t tmstart; - HANDLE signal_event; /* used to signal shutdown/restart to parent */ + HANDLE signal_shutdown_event; /* used to signal shutdown to parent */ + HANDLE signal_restart_event; /* used to signal a restart to parent */ HANDLE process_handles[MAX_PROCESSES]; HANDLE process_kill_events[MAX_PROCESSES]; int current_live_processes = 0; /* number of child process we know about */ @@ -5425,22 +5485,34 @@ int master_main(int argc, char **argv) is_graceful = 0; ++generation; - signal_event = OpenEvent(EVENT_ALL_ACCESS, FALSE, "apache-signal"); - if (!signal_event) { + ap_snprintf(signal_prefix_string, sizeof(signal_prefix_string), + "ap%d", getpid()); + setup_signal_names(signal_prefix_string); + + signal_shutdown_event = CreateEvent(NULL, TRUE, FALSE, signal_shutdown_name); + if (!signal_shutdown_event) { + ap_log_error(APLOG_MARK, APLOG_EMERG|APLOG_WIN32ERROR, server_conf, + "Cannot create shutdown event %s", signal_shutdown_name); + exit(1); + } + APD2("master_main: created event %s", signal_shutdown_name); + signal_restart_event = CreateEvent(NULL, TRUE, FALSE, signal_restart_name); + if (!signal_restart_event) { + CloseHandle(signal_shutdown_event); ap_log_error(APLOG_MARK, APLOG_EMERG|APLOG_WIN32ERROR, server_conf, - "Cannot open apache-signal event"); + "Cannot create restart event %s", signal_restart_name); exit(1); } + APD2("master_main: created event %s", signal_restart_name); - sprintf(buf, "Apache%d", getpid()); - start_mutex = ap_create_mutex(buf); + start_mutex = ap_create_mutex(signal_prefix_string); ev = (event **) alloca(sizeof(event *) * nchild); child = (int *) alloca(sizeof(int) * (nchild+1)); while (processes_to_create--) { service_set_status(SERVICE_START_PENDING); if (create_process(process_handles, process_kill_events, - ¤t_live_processes, &child_num, buf, argc, argv) < 0) { + ¤t_live_processes, &child_num, signal_prefix_string, argc, argv) < 0) { goto die_now; } } @@ -5461,8 +5533,6 @@ int master_main(int argc, char **argv) ap_set_version(); ap_init_modules(pconf, server_conf); version_locked++; - if (!is_graceful) - reinit_scoreboard(pconf); restart_pending = shutdown_pending = 0; @@ -5478,15 +5548,17 @@ int master_main(int argc, char **argv) ap_log_error(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO, server_conf, "master_main: no child processes alive! creating one"); if (create_process(process_handles, process_kill_events, - ¤t_live_processes, &child_num, buf, argc, argv) < 0) { + ¤t_live_processes, &child_num, signal_prefix_string, + argc, argv) < 0) { goto die_now; } if (processes_to_create) { processes_to_create--; } } - process_handles[current_live_processes] = signal_event; - rv = WaitForMultipleObjects(current_live_processes+1, (HANDLE *)process_handles, + process_handles[current_live_processes] = signal_shutdown_event; + process_handles[current_live_processes+1] = signal_restart_event; + rv = WaitForMultipleObjects(current_live_processes+2, (HANDLE *)process_handles, FALSE, INFINITE); if (rv == WAIT_FAILED) { /* Something serious is wrong */ @@ -5495,13 +5567,35 @@ int master_main(int argc, char **argv) shutdown_pending = 1; break; } - ap_assert(rv != WAIT_TIMEOUT); + if (rv == WAIT_TIMEOUT) { + /* Hey, this cannot happen */ + ap_log_error(APLOG_MARK, APLOG_ERR, server_conf, + "WaitForMultipeObjects with INFINITE wait exited with WAIT_TIMEOUT"); + shutdown_pending = 1; + } + cld = rv - WAIT_OBJECT_0; APD4("main process: wait finished, cld=%d handle %d (max=%d)", cld, process_handles[cld], current_live_processes); if (cld == current_live_processes) { - /* stop_event is signalled, we should exit now */ - if (ResetEvent(signal_event) == 0) - APD1("main process: *** ERROR: ResetEvent(stop_event) failed ***"); + /* shutdown event signalled, we should exit now */ + if (ResetEvent(signal_shutdown_event) == 0) { + ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_WIN32ERROR, server_conf, + "ResetEvent(signal_shutdown_event)"); + /* Continue -- since we are doing a shutdown anyway */ + } + shutdown_pending = 1; + APD3("main process: stop_event signalled: shutdown_pending=%d, restart_pending=%d", + shutdown_pending, restart_pending); + break; + } + if (cld == current_live_processes+1) { + /* restart event signalled, we should exit now */ + if (ResetEvent(signal_restart_event) == 0) { + ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_WIN32ERROR, server_conf, + "ResetEvent(signal_restart_event)"); + /* Continue -- hopefully the restart will fix the problem */ + } + restart_pending = 1; APD3("main process: stop_event signalled: shutdown_pending=%d, restart_pending=%d", shutdown_pending, restart_pending); break; @@ -5510,7 +5604,8 @@ int master_main(int argc, char **argv) cleanup_process(process_handles, process_kill_events, cld, ¤t_live_processes); APD2("main_process: child in slot %d died", rv); if (processes_to_create) { - create_process(process_handles, process_kill_events, ¤t_live_processes, &child_num, buf, argc, argv); + create_process(process_handles, process_kill_events, ¤t_live_processes, + &child_num, signal_prefix_string, argc, argv); processes_to_create--; } } @@ -5527,7 +5622,6 @@ int master_main(int argc, char **argv) ap_log_error(APLOG_MARK,APLOG_WIN32ERROR, server_conf, "SetEvent for child process in slot #%d", i); } - break; } if (restart_pending) { @@ -5539,7 +5633,8 @@ int master_main(int argc, char **argv) for (i = 0; i < nchild; ++i) { if (current_live_processes >= MAX_PROCESSES) break; - create_process(process_handles, process_kill_events, ¤t_live_processes, &child_num, buf, argc, argv); + create_process(process_handles, process_kill_events, ¤t_live_processes, + &child_num, signal_prefix_string, argc, argv); processes_to_create--; } for (i = 0; i < children_to_kill; i++) { @@ -5559,7 +5654,8 @@ int master_main(int argc, char **argv) APD2("*** main process shutdown, processes=%d ***", current_live_processes); die_now: - CloseHandle(signal_event); + CloseHandle(signal_restart_event); + CloseHandle(signal_shutdown_event); tmstart = time(NULL); while (current_live_processes && ((tmstart+60) > time(NULL))) { @@ -5579,7 +5675,6 @@ die_now: "forcing termination of child #%d (handle %d)", i, process_handles[i]); TerminateProcess((HANDLE) process_handles[i], 1); } - service_set_status(SERVICE_STOPPED); /* cleanup pid file on normal shutdown */ { @@ -5597,9 +5692,61 @@ die_now: } ap_destroy_mutex(start_mutex); + + service_set_status(SERVICE_STOPPED); return (0); } +/* + * Send signal to a running Apache. On entry signal should contain + * either "shutdown" or "restart" + */ + +void send_signal(pool *p, char *signal) +{ + char prefix[20]; + FILE *fp; + int nread; + char *fname; + int end; + + fname = ap_server_root_relative (p, ap_pid_fname); + + fp = fopen(fname, "r"); + if (!fp) { + printf("Cannot read apache PID file %s\n", fname); + return; + } + prefix[0] = 'a'; + prefix[1] = 'p'; + + nread = fread(prefix+2, 1, sizeof(prefix)-3, fp); + if (nread == 0) { + fclose(fp); + printf("PID file %s was empty\n", fname); + return; + } + fclose(fp); + + /* Terminate the prefix string */ + end = 2 + nread - 1; + while (end > 0 && (prefix[end] == '\r' || prefix[end] == '\n')) + end--; + prefix[end + 1] = '\0'; + + setup_signal_names(prefix); + + if (!strcasecmp(signal, "shutdown")) + ap_start_shutdown(); + else if (!strcasecmp(signal, "restart")) + ap_start_restart(1); + else + printf("Unknown signal name \"%s\". Use either shutdown or restart.\n", + signal); + + return; +} + #ifdef WIN32 __declspec(dllexport) int apache_main(int argc, char *argv[]) @@ -5613,6 +5760,7 @@ int REALMAIN(int argc, char *argv[]) int run_as_service = 1; int install = 0; int configtestonly = 0; + char *signal_to_send = NULL; common_init(); @@ -5637,7 +5785,7 @@ int REALMAIN(int argc, char *argv[]) ap_setup_prelinked_modules(); - while ((c = getopt(argc, argv, "D:C:c:Xd:f:vVhlZ:iusSt")) != -1) { + while ((c = getopt(argc, argv, "D:C:c:Xd:f:vVhlZ:iusStk:")) != -1) { char **new; switch (c) { case 'c': @@ -5659,7 +5807,9 @@ int REALMAIN(int argc, char *argv[]) cp = strchr(optarg, '_'); ap_assert(cp); *cp = 0; - start_mutex = ap_open_mutex(optarg); + setup_signal_names(optarg); + start_mutex = ap_open_mutex(signal_name_prefix); + ap_assert(start_mutex); child = 1; break; case 'i': @@ -5674,6 +5824,9 @@ int REALMAIN(int argc, char *argv[]) case 'S': ap_dump_settings = 1; break; + case 'k': + signal_to_send = optarg; + break; #endif /* WIN32 */ case 'd': ap_cpystrn(ap_server_root, ap_os_canonical_filename(pconf, optarg), sizeof(ap_server_root)); @@ -5718,7 +5871,12 @@ int REALMAIN(int argc, char *argv[]) exit(0); } - if (!child) { + if (signal_to_send) { + send_signal(pconf, signal_to_send); + exit(0); + } + + if (!child && !ap_dump_settings && !install) { ap_log_pid(pconf, ap_pid_fname); } ap_set_version(); diff --git a/usr.sbin/httpd/src/main/http_protocol.c b/usr.sbin/httpd/src/main/http_protocol.c index 98f58517ea8..e28df5c4636 100644 --- a/usr.sbin/httpd/src/main/http_protocol.c +++ b/usr.sbin/httpd/src/main/http_protocol.c @@ -551,6 +551,17 @@ static int getline(char *s, int n, BUFF *in, int fold) total += retval; /* and how long s has become */ if (*pos == '\n') { /* Did we get a full line of input? */ + /* + * Trim any extra trailing spaces or tabs except for the first + * space or tab at the beginning of a blank string. This makes + * it much easier to check field values for exact matches, and + * saves memory as well. Terminate string at end of line. + */ + while (pos > (s + 1) && (*(pos - 1) == ' ' || *(pos - 1) == '\t')) { + --pos; /* trim extra trailing spaces or tabs */ + --total; /* but not one at the beginning of line */ + ++n; + } *pos = '\0'; --total; ++n; @@ -767,8 +778,6 @@ static void get_mime_headers(request_rec *r) while (*value == ' ' || *value == '\t') ++value; /* Skip to start of value */ - /* XXX: should strip trailing whitespace as well */ - ap_table_addn(tmp_headers, copy, value); } @@ -778,8 +787,9 @@ static void get_mime_headers(request_rec *r) request_rec *ap_read_request(conn_rec *conn) { request_rec *r; - int access_status; pool *p; + const char *expect; + int access_status; p = ap_make_sub_pool(conn->pool); r = ap_pcalloc(p, sizeof(request_rec)); @@ -846,6 +856,23 @@ request_rec *ap_read_request(conn_rec *conn) } else { ap_kill_timeout(r); + + if (r->header_only) { + /* + * Client asked for headers only with HTTP/0.9, which doesn't send + * headers! Have to dink things just to make sure the error message + * comes through... + */ + ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r, + "client sent invalid HTTP/0.9 request: HEAD %s", + r->uri); + r->header_only = 0; + r->status = HTTP_BAD_REQUEST; + ap_send_error_response(r, 0); + ap_bflush(r->connection->client); + ap_log_transaction(r); + return r; + } } r->status = HTTP_OK; /* Until further notice. */ @@ -860,6 +887,49 @@ request_rec *ap_read_request(conn_rec *conn) conn->keptalive = 0; /* We now have a request to play with */ + if ((!r->hostname && (r->proto_num >= HTTP_VERSION(1,1))) || + ((r->proto_num == HTTP_VERSION(1,1)) && + !ap_table_get(r->headers_in, "Host"))) { + /* + * Client sent us an 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. As a special case, + * HTTP/1.1 mentions twice (S9, S14.23) that a request MUST contain + * a Host: header, and the server MUST respond with 400 if it doesn't. + */ + r->status = HTTP_BAD_REQUEST; + ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r, + "client sent HTTP/1.1 request without hostname " + "(see RFC2068 section 9, and 14.23): %s", r->uri); + ap_send_error_response(r, 0); + ap_bflush(r->connection->client); + ap_log_transaction(r); + return r; + } + if (((expect = ap_table_get(r->headers_in, "Expect")) != NULL) && + (expect[0] != '\0')) { + /* + * The Expect header field was added to HTTP/1.1 after RFC 2068 + * as a means to signal when a 100 response is desired and, + * unfortunately, to signal a poor man's mandatory extension that + * the server must understand or return 417 Expectation Failed. + */ + if (strcasecmp(expect, "100-continue") == 0) { + r->expecting_100 = 1; + } + else { + r->status = HTTP_EXPECTATION_FAILED; + ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, r, + "client sent an unrecognized expectation value of " + "Expect: %s", expect); + ap_send_error_response(r, 0); + ap_bflush(r->connection->client); + (void) ap_discard_request_body(r); + ap_log_transaction(r); + return r; + } + } + if ((access_status = ap_run_post_read_request(r))) { ap_die(access_status, r); ap_log_transaction(r); @@ -895,6 +965,7 @@ void ap_set_sub_req_protocol(request_rec *rnew, const request_rec *r) rnew->err_headers_out = ap_make_table(rnew->pool, 5); rnew->notes = ap_make_table(rnew->pool, 5); + rnew->expecting_100 = r->expecting_100; rnew->read_length = r->read_length; rnew->read_body = REQUEST_NO_BODY; @@ -988,7 +1059,8 @@ API_EXPORT(int) ap_get_basic_auth_pw(request_rec *r, const char **pw) static char *status_lines[] = { "100 Continue", "101 Switching Protocols", -#define LEVEL_200 2 + "102 Processing", +#define LEVEL_200 3 "200 OK", "201 Created", "202 Accepted", @@ -996,14 +1068,17 @@ static char *status_lines[] = { "204 No Content", "205 Reset Content", "206 Partial Content", -#define LEVEL_300 9 + "207 Multi-Status", +#define LEVEL_300 11 "300 Multiple Choices", "301 Moved Permanently", - "302 Moved Temporarily", + "302 Found", "303 See Other", "304 Not Modified", "305 Use Proxy", -#define LEVEL_400 15 + "306 unused", + "307 Temporary Redirect", +#define LEVEL_400 19 "400 Bad Request", "401 Authorization Required", "402 Payment Required", @@ -1020,14 +1095,26 @@ static char *status_lines[] = { "413 Request Entity Too Large", "414 Request-URI Too Large", "415 Unsupported Media Type", -#define LEVEL_500 31 + "416 Requested Range Not Satisfiable", + "417 Expectation Failed", + "418 unused", + "419 unused", + "420 unused", + "421 unused", + "422 Unprocessable Entity", + "423 Locked", +#define LEVEL_500 43 "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" + "506 Variant Also Negotiates" + "507 unused", + "508 unused", + "509 unused", + "510 Not Extended", }; /* The index is found by its offset from the x00 code of each level. @@ -1441,7 +1528,7 @@ API_EXPORT(int) ap_should_client_block(request_rec *r) if (r->read_length || (!r->read_chunked && (r->remaining <= 0))) return 0; - if (r->proto_num >= HTTP_VERSION(1,1)) { + if (r->expecting_100 && r->proto_num >= HTTP_VERSION(1,1)) { /* sending 100 Continue interim response */ ap_bvputs(r->connection->client, SERVER_PROTOCOL, " ", status_lines[0], "\015\012\015\012", @@ -1653,6 +1740,11 @@ API_EXPORT(int) ap_discard_request_body(request_rec *r) if ((rv = ap_setup_client_block(r, REQUEST_CHUNKED_PASS))) return rv; + /* If we are discarding the request body, then we must already know + * the final status code, therefore disable the sending of 100 continue. + */ + r->expecting_100 = 0; + if (ap_should_client_block(r)) { char dumpbuf[HUGE_STRING_LEN]; @@ -2127,132 +2219,177 @@ void ap_send_error_response(request_rec *r, int recursive_error) "</TITLE>\n</HEAD><BODY>\n<H1>", h1, "</H1>\n", NULL); - if ((error_notes = ap_table_get(r->notes, "error-notes"))) { - ap_bputs(error_notes, fd); - } - else - switch (status) { - case REDIRECT: - case MOVED: - ap_bvputs(fd, "The document has moved <A HREF=\"", - ap_escape_html(r->pool, location), "\">here</A>.<P>\n", NULL); - break; - case HTTP_SEE_OTHER: - ap_bvputs(fd, "The answer to your request is located <A HREF=\"", - ap_escape_html(r->pool, location), "\">here</A>.<P>\n", NULL); - break; - case HTTP_USE_PROXY: - ap_bvputs(fd, "This resource is only accessible through the proxy\n", - ap_escape_html(r->pool, location), "<BR>\nYou will need to ", - "configure your client to use that proxy.<P>\n", NULL); - break; - case HTTP_PROXY_AUTHENTICATION_REQUIRED: - case AUTH_REQUIRED: - ap_bputs("This server could not verify that you\n", fd); - ap_bputs("are authorized to access the document you\n", fd); - ap_bputs("requested. Either you supplied the wrong\n", fd); - ap_bputs("credentials (e.g., bad password), or your\n", fd); - ap_bputs("browser doesn't understand how to supply\n", fd); - ap_bputs("the credentials required.<P>\n", fd); - break; - case BAD_REQUEST: - ap_bputs("Your browser sent a request that\n", fd); - ap_bputs("this server could not understand.<P>\n", fd); - break; - case HTTP_FORBIDDEN: - ap_bvputs(fd, "You don't have permission to access ", - ap_escape_html(r->pool, r->uri), "\non this server.<P>\n", - NULL); - break; - case NOT_FOUND: - ap_bvputs(fd, "The requested URL ", ap_escape_html(r->pool, r->uri), - " was not found on this server.<P>\n", NULL); - break; - case METHOD_NOT_ALLOWED: - ap_bvputs(fd, "The requested method ", r->method, " is not allowed " - "for the URL ", ap_escape_html(r->pool, r->uri), - ".<P>\n", NULL); - break; - case NOT_ACCEPTABLE: - ap_bvputs(fd, - "An appropriate representation of the requested resource ", - ap_escape_html(r->pool, r->uri), - " could not be found on this server.<P>\n", NULL); - /* fall through */ - case MULTIPLE_CHOICES: - { - const char *list; - if ((list = ap_table_get(r->notes, "variant-list"))) - ap_bputs(list, fd); - } - break; - case LENGTH_REQUIRED: - ap_bvputs(fd, "A request of the requested method ", r->method, - " requires a valid Content-length.<P>\n", NULL); - break; - case PRECONDITION_FAILED: - ap_bvputs(fd, "The precondition on the request for the URL ", - ap_escape_html(r->pool, r->uri), " evaluated to false.<P>\n", - NULL); - break; - case NOT_IMPLEMENTED: - ap_bvputs(fd, ap_escape_html(r->pool, r->method), " to ", - ap_escape_html(r->pool, r->uri), " not supported.<P>\n", NULL); - break; - case BAD_GATEWAY: - ap_bputs("The proxy server received an invalid\015\012", fd); - ap_bputs("response from an upstream server.<P>\015\012", fd); - break; - case VARIANT_ALSO_VARIES: - ap_bvputs(fd, "A variant for the requested entity ", - ap_escape_html(r->pool, r->uri), " is itself a ", - "transparently negotiable resource.<P>\n", NULL); - break; - case HTTP_REQUEST_TIME_OUT: - ap_bputs("I'm tired of waiting for your request.\n", fd); - break; - case HTTP_GONE: - ap_bvputs(fd, "The requested resource<BR>", - ap_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: - ap_bvputs(fd, "The requested resource<BR>", - ap_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: - ap_bputs("The requested URL's length exceeds the capacity\n", fd); - ap_bputs("limit for this server.\n", fd); - break; - case HTTP_UNSUPPORTED_MEDIA_TYPE: - ap_bputs("The supplied request data is not in a format\n", fd); - ap_bputs("acceptable for processing by this resource.\n", fd); - break; - case HTTP_SERVICE_UNAVAILABLE: - ap_bputs("The server is temporarily unable to service your\n", fd); - ap_bputs("request due to maintenance downtime or capacity\n", fd); - ap_bputs("problems. Please try again later.\n", fd); - break; - case HTTP_GATEWAY_TIME_OUT: - ap_bputs("The proxy server did not receive a timely response\n", fd); - ap_bputs("from the upstream server.<P>\n", fd); - break; - default: /* HTTP_INTERNAL_SERVER_ERROR */ - ap_bputs("The server encountered an internal error or\n", fd); - ap_bputs("misconfiguration and was unable to complete\n", fd); - ap_bputs("your request.<P>\n", fd); - ap_bputs("Please contact the server administrator,\n ", fd); - ap_bputs(ap_escape_html(r->pool, r->server->server_admin), fd); - ap_bputs(" and inform them of the time the error occurred,\n", fd); - ap_bputs("and anything you might have done that may have\n", fd); - ap_bputs("caused the error.<P>\n", fd); - break; - } + switch (status) { + case HTTP_MOVED_PERMANENTLY: + case HTTP_MOVED_TEMPORARILY: + case HTTP_TEMPORARY_REDIRECT: + ap_bvputs(fd, "The document has moved <A HREF=\"", + ap_escape_html(r->pool, location), "\">here</A>.<P>\n", + NULL); + break; + case HTTP_SEE_OTHER: + ap_bvputs(fd, "The answer to your request is located <A HREF=\"", + ap_escape_html(r->pool, location), "\">here</A>.<P>\n", + NULL); + break; + case HTTP_USE_PROXY: + ap_bvputs(fd, "This resource is only accessible " + "through the proxy\n", + ap_escape_html(r->pool, location), + "<BR>\nYou will need to ", + "configure your client to use that proxy.<P>\n", NULL); + break; + case HTTP_PROXY_AUTHENTICATION_REQUIRED: + case AUTH_REQUIRED: + ap_bputs("This server could not verify that you\n", fd); + ap_bputs("are authorized to access the document you\n", fd); + ap_bputs("requested. Either you supplied the wrong\n", fd); + ap_bputs("credentials (e.g., bad password), or your\n", fd); + ap_bputs("browser doesn't understand how to supply\n", fd); + ap_bputs("the credentials required.<P>\n", fd); + break; + case BAD_REQUEST: + ap_bputs("Your browser sent a request that\n", fd); + ap_bputs("this server could not understand.<P>\n", fd); + if ((error_notes = ap_table_get(r->notes, "error-notes")) != NULL) { + ap_bvputs(fd, error_notes, "<P>\n", NULL); + } + break; + case HTTP_FORBIDDEN: + ap_bvputs(fd, "You don't have permission to access ", + ap_escape_html(r->pool, r->uri), + "\non this server.<P>\n", NULL); + break; + case NOT_FOUND: + ap_bvputs(fd, "The requested URL ", + ap_escape_html(r->pool, r->uri), + " was not found on this server.<P>\n", NULL); + break; + case METHOD_NOT_ALLOWED: + ap_bvputs(fd, "The requested method ", r->method, + " is not allowed " + "for the URL ", ap_escape_html(r->pool, r->uri), + ".<P>\n", NULL); + break; + case NOT_ACCEPTABLE: + ap_bvputs(fd, + "An appropriate representation of the " + "requested resource ", + ap_escape_html(r->pool, r->uri), + " could not be found on this server.<P>\n", NULL); + /* fall through */ + case MULTIPLE_CHOICES: + { + const char *list; + if ((list = ap_table_get(r->notes, "variant-list"))) + ap_bputs(list, fd); + } + break; + case LENGTH_REQUIRED: + ap_bvputs(fd, "A request of the requested method ", r->method, + " requires a valid Content-length.<P>\n", NULL); + if ((error_notes = ap_table_get(r->notes, "error-notes")) != NULL) { + ap_bvputs(fd, error_notes, "<P>\n", NULL); + } + break; + case PRECONDITION_FAILED: + ap_bvputs(fd, "The precondition on the request for the URL ", + ap_escape_html(r->pool, r->uri), + " evaluated to false.<P>\n", NULL); + break; + case NOT_IMPLEMENTED: + ap_bvputs(fd, ap_escape_html(r->pool, r->method), " to ", + ap_escape_html(r->pool, r->uri), + " not supported.<P>\n", NULL); + break; + case BAD_GATEWAY: + ap_bputs("The proxy server received an invalid\015\012", fd); + ap_bputs("response from an upstream server.<P>\015\012", fd); + break; + case VARIANT_ALSO_VARIES: + ap_bvputs(fd, "A variant for the requested entity ", + ap_escape_html(r->pool, r->uri), " is itself a ", + "transparently negotiable resource.<P>\n", NULL); + break; + case HTTP_REQUEST_TIME_OUT: + ap_bputs("I'm tired of waiting for your request.\n", fd); + break; + case HTTP_GONE: + ap_bvputs(fd, "The requested resource<BR>", + ap_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: + ap_bvputs(fd, "The requested resource<BR>", + ap_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: + ap_bputs("The requested URL's length exceeds the capacity\n" + "limit for this server.<P>\n", fd); + if ((error_notes = ap_table_get(r->notes, "error-notes")) != NULL) { + ap_bvputs(fd, error_notes, "<P>\n", NULL); + } + break; + case HTTP_UNSUPPORTED_MEDIA_TYPE: + ap_bputs("The supplied request data is not in a format\n" + "acceptable for processing by this resource.\n", fd); + break; + case HTTP_RANGE_NOT_SATISFIABLE: + ap_bputs("None of the range-specifier values in the Range\n" + "request-header field overlap the current extent\n" + "of the selected resource.\n", fd); + break; + case HTTP_EXPECTATION_FAILED: + ap_bvputs(fd, "The expectation given in the Expect request-header" + "\nfield could not be met by this server.<P>\n" + "The client sent<PRE>\n Expect: ", + ap_table_get(r->headers_in, "Expect"), "\n</PRE>\n" + "but we only allow the 100-continue expectation.\n", + NULL); + break; + case HTTP_UNPROCESSABLE_ENTITY: + ap_bputs("The server understands the media type of the\n" + "request entity, but was unable to process the\n" + "contained instructions.\n", fd); + break; + case HTTP_LOCKED: + ap_bputs("The requested resource is currently locked.\n" + "The lock must be released or proper identification\n" + "given before the method can be applied.\n", fd); + break; + case HTTP_SERVICE_UNAVAILABLE: + ap_bputs("The server is temporarily unable to service your\n" + "request due to maintenance downtime or capacity\n" + "problems. Please try again later.\n", fd); + break; + case HTTP_GATEWAY_TIME_OUT: + ap_bputs("The proxy server did not receive a timely response\n" + "from the upstream server.\n", fd); + break; + case HTTP_NOT_EXTENDED: + ap_bputs("A mandatory extension policy in the request is not\n" + "accepted by the server for this resource.\n", fd); + break; + default: /* HTTP_INTERNAL_SERVER_ERROR */ + ap_bvputs(fd, "The server encountered an internal error or\n" + "misconfiguration and was unable to complete\n" + "your request.<P>\n" + "Please contact the server administrator,\n ", + ap_escape_html(r->pool, r->server->server_admin), + " and inform them of the time the error occurred,\n" + "and anything you might have done that may have\n" + "caused the error.<P>\n", NULL); + if ((error_notes = ap_table_get(r->notes, "error-notes")) != NULL) { + ap_bvputs(fd, error_notes, "<P>\n", NULL); + } + break; + } if (recursive_error) { ap_bvputs(fd, "<P>Additionally, a ", diff --git a/usr.sbin/httpd/src/main/http_request.c b/usr.sbin/httpd/src/main/http_request.c index 62918edc2ea..918dc9226bf 100644 --- a/usr.sbin/httpd/src/main/http_request.c +++ b/usr.sbin/httpd/src/main/http_request.c @@ -188,8 +188,10 @@ static int get_path_info(request_rec *r) } #ifdef WIN32 - /* If the path is x:/, then convert it to x:/., coz that's what stat needs to work properly */ - if(strlen(path) == 3 && path[1] == ':') { + /* If the path is x:/, then convert it to x:/., coz that's what stat + * needs to work properly + */ + if (strlen(path) == 3 && path[1] == ':') { strcpy(buf,path); buf[3]='.'; buf[4]='\0'; @@ -674,6 +676,7 @@ API_EXPORT(request_rec *) ap_sub_req_lookup_uri(const char *new_file, char *udir; rnew = make_sub_request(r); + rnew->hostname = r->hostname; rnew->request_time = r->request_time; rnew->connection = r->connection; rnew->server = r->server; @@ -751,6 +754,7 @@ API_EXPORT(request_rec *) ap_sub_req_lookup_file(const char *new_file, char *fdir; rnew = make_sub_request(r); + rnew->hostname = r->hostname; rnew->request_time = r->request_time; rnew->connection = r->connection; rnew->server = r->server; @@ -826,7 +830,14 @@ API_EXPORT(request_rec *) ap_sub_req_lookup_file(const char *new_file, * file may not have a uri associated with it -djg */ rnew->uri = "INTERNALLY GENERATED file-relative req"; +#ifdef WIN32 + rnew->filename = ((new_file[0] == '/' + || (ap_isalpha(new_file[0]) + && new_file[1] == ':' + && new_file[2] == '/')) ? +#else rnew->filename = ((new_file[0] == '/') ? +#endif ap_pstrdup(rnew->pool, new_file) : ap_make_full_path(rnew->pool, fdir, new_file)); rnew->per_dir_config = r->server->lookup_defaults; @@ -1013,39 +1024,6 @@ static void process_request_internal(request_rec *r) { int access_status; - /* - * Kluge 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... - */ - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r, - "client sent illegal HTTP/0.9 request: %s", r->uri); - r->header_only = 0; - ap_die(BAD_REQUEST, r); - return; - } - - if ((!r->hostname && (r->proto_num >= HTTP_VERSION(1,1))) || - ((r->proto_num == HTTP_VERSION(1,1)) && !ap_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. As a special case, - * HTTP/1.1 mentions twice (S9, S14.23) that a request MUST contain - * a Host: header, and the server MUST respond with 400 if it doesn't. - */ - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r, - "client sent HTTP/1.1 request without hostname (see RFC2068 section 9, and 14.23): %s", r->uri); - ap_die(BAD_REQUEST, r); - return; - } - /* Ignore embedded %2F's in path for proxy requests */ if (!r->proxyreq && r->parsed_uri.path) { access_status = ap_unescape_url(r->parsed_uri.path); diff --git a/usr.sbin/httpd/src/main/util.c b/usr.sbin/httpd/src/main/util.c index 6ea60371380..eee03233261 100644 --- a/usr.sbin/httpd/src/main/util.c +++ b/usr.sbin/httpd/src/main/util.c @@ -738,6 +738,7 @@ API_EXPORT(configfile_t *) ap_pcfg_openfile(pool *p, const char *name) poolfile_t *new_pfile; FILE *file; struct stat stbuf; + int saved_errno; if (name == NULL) { ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, NULL, @@ -747,9 +748,11 @@ API_EXPORT(configfile_t *) ap_pcfg_openfile(pool *p, const char *name) file = ap_pfopen(p, name, "r"); #ifdef DEBUG + saved_errno = errno; ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, NULL, "Opening config file %s (%s)", name, (file == NULL) ? strerror(errno) : "successful"); + errno = saved_errno; #endif if (file == NULL) return NULL; @@ -761,10 +764,12 @@ API_EXPORT(configfile_t *) ap_pcfg_openfile(pool *p, const char *name) #else strcmp(name, "/dev/null") != 0) { #endif + saved_errno = errno; ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, NULL, "Access to file %s denied by server: not a regular file", name); ap_pfclose(p, file); + errno = saved_errno; return NULL; } diff --git a/usr.sbin/httpd/src/main/util_script.c b/usr.sbin/httpd/src/main/util_script.c index 270d377867f..9ee38bf8edd 100644 --- a/usr.sbin/httpd/src/main/util_script.c +++ b/usr.sbin/httpd/src/main/util_script.c @@ -262,6 +262,7 @@ API_EXPORT(void) ap_add_common_vars(request_rec *r) #endif ap_table_addn(e, "PATH", env_path); + ap_table_setn(e, "SERVER_SIGNATURE", ap_psignature("", r)); ap_table_addn(e, "SERVER_SOFTWARE", ap_get_server_version()); ap_table_addn(e, "SERVER_NAME", ap_get_server_name(r)); ap_table_addn(e, "SERVER_PORT", @@ -458,8 +459,6 @@ API_EXPORT(int) ap_scan_script_header_err_core(request_rec *r, char *buffer, ap_kill_timeout(r); ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r, "Premature end of script headers: %s", r->filename); - ap_table_setn(r->notes, "error-notes", - "Premature end of script headers"); return HTTP_INTERNAL_SERVER_ERROR; } @@ -543,8 +542,6 @@ API_EXPORT(int) ap_scan_script_header_err_core(request_rec *r, char *buffer, ap_kill_timeout(r); ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r, "%s: %s", malformed, r->filename); - ap_table_setn(r->notes, "error-notes", - ap_pstrdup(r->pool, malformed)); return HTTP_INTERNAL_SERVER_ERROR; } diff --git a/usr.sbin/httpd/src/modules/proxy/proxy_util.c b/usr.sbin/httpd/src/modules/proxy/proxy_util.c index c917d7645fc..a2dfd0e8ed7 100644 --- a/usr.sbin/httpd/src/modules/proxy/proxy_util.c +++ b/usr.sbin/httpd/src/modules/proxy/proxy_util.c @@ -581,7 +581,7 @@ long int ap_proxy_send_fb(BUFF *f, request_rec *r, cache_req *c) ap_reset_timeout(r); if (w <= 0) { - if (c != NULL) { + if (c != NULL && c->fp != NULL) { /* when a send failure occurs, we need to decide * whether to continue loading and caching the * document, or to abort the whole thing diff --git a/usr.sbin/httpd/src/modules/standard/mod_auth.c b/usr.sbin/httpd/src/modules/standard/mod_auth.c index c4ca529cf63..605ef9cfa65 100644 --- a/usr.sbin/httpd/src/modules/standard/mod_auth.c +++ b/usr.sbin/httpd/src/modules/standard/mod_auth.c @@ -264,7 +264,7 @@ static int check_user_access(request_rec *r) method_restricted = 1; t = reqs[x].requirement; - w = ap_getword(r->pool, &t, ' '); + w = ap_getword_white(r->pool, &t); if (!strcmp(w, "valid-user")) return OK; if (!strcmp(w, "user")) { diff --git a/usr.sbin/httpd/src/modules/standard/mod_auth_db.c b/usr.sbin/httpd/src/modules/standard/mod_auth_db.c index 26a994b7367..a4b5da96ce5 100644 --- a/usr.sbin/httpd/src/modules/standard/mod_auth_db.c +++ b/usr.sbin/httpd/src/modules/standard/mod_auth_db.c @@ -281,7 +281,7 @@ static int db_check_auth(request_rec *r) continue; t = reqs[x].requirement; - w = ap_getword(r->pool, &t, ' '); + w = ap_getword_white(r->pool, &t); if (!strcmp(w, "group") && sec->auth_dbgrpfile) { const char *orig_groups, *groups; @@ -298,7 +298,7 @@ static int db_check_auth(request_rec *r) } orig_groups = groups; while (t[0]) { - w = ap_getword(r->pool, &t, ' '); + w = ap_getword_white(r->pool, &t); groups = orig_groups; while (groups[0]) { v = ap_getword(r->pool, &groups, ','); diff --git a/usr.sbin/httpd/src/modules/standard/mod_auth_dbm.c b/usr.sbin/httpd/src/modules/standard/mod_auth_dbm.c index b280513f232..d4a72b23977 100644 --- a/usr.sbin/httpd/src/modules/standard/mod_auth_dbm.c +++ b/usr.sbin/httpd/src/modules/standard/mod_auth_dbm.c @@ -266,7 +266,7 @@ static int dbm_check_auth(request_rec *r) continue; t = reqs[x].requirement; - w = ap_getword(r->pool, &t, ' '); + w = ap_getword_white(r->pool, &t); if (!strcmp(w, "group") && sec->auth_dbmgrpfile) { const char *orig_groups, *groups; @@ -283,7 +283,7 @@ static int dbm_check_auth(request_rec *r) } orig_groups = groups; while (t[0]) { - w = ap_getword(r->pool, &t, ' '); + w = ap_getword_white(r->pool, &t); groups = orig_groups; while (groups[0]) { v = ap_getword(r->pool, &groups, ','); diff --git a/usr.sbin/httpd/src/modules/standard/mod_autoindex.c b/usr.sbin/httpd/src/modules/standard/mod_autoindex.c index 691b78d09b2..18f35cecce3 100644 --- a/usr.sbin/httpd/src/modules/standard/mod_autoindex.c +++ b/usr.sbin/httpd/src/modules/standard/mod_autoindex.c @@ -93,6 +93,7 @@ module MODULE_VAR_EXPORT autoindex_module; #define SUPPRESS_DESC 32 #define SUPPRESS_PREAMBLE 64 #define SUPPRESS_COLSORT 128 +#define NO_OPTIONS 256 #define K_PAD 1 #define K_NOPAD 0 @@ -130,6 +131,8 @@ typedef struct autoindex_config_struct { char *default_icon; int opts; + int incremented_opts; + int decremented_opts; int name_width; int name_adjust; int icon_width; @@ -293,7 +296,11 @@ static const char *fancy_indexing(cmd_parms *cmd, void *d, int arg) cfg = (autoindex_config_rec *) d; curopts = cfg->opts; - newopts = (arg ? (curopts | FANCY_INDEXING) : (curopts & !FANCY_INDEXING)); + if (curopts & NO_OPTIONS) { + return "FancyIndexing directive conflicts with existing " + "IndexOptions None"; + } + newopts = (arg ? (curopts | FANCY_INDEXING) : (curopts & ~FANCY_INDEXING)); cfg->opts = newopts; return NULL; } @@ -301,51 +308,97 @@ static const char *fancy_indexing(cmd_parms *cmd, void *d, int arg) static const char *add_opts(cmd_parms *cmd, void *d, const char *optstr) { char *w; - int opts = 0; + int opts; + int opts_add; + int opts_remove; + char action; autoindex_config_rec *d_cfg = (autoindex_config_rec *) d; + opts = d_cfg->opts; + opts_add = d_cfg->incremented_opts; + opts_remove = d_cfg->decremented_opts; while (optstr[0]) { + int option = 0; + w = ap_getword_conf(cmd->pool, &optstr); + if ((*w == '+') || (*w == '-')) { + action = *(w++); + } + else { + action = '\0'; + } if (!strcasecmp(w, "FancyIndexing")) { - opts |= FANCY_INDEXING; + option = FANCY_INDEXING; } else if (!strcasecmp(w, "IconsAreLinks")) { - opts |= ICONS_ARE_LINKS; + option = ICONS_ARE_LINKS; } else if (!strcasecmp(w, "ScanHTMLTitles")) { - opts |= SCAN_HTML_TITLES; + option = SCAN_HTML_TITLES; } else if (!strcasecmp(w, "SuppressLastModified")) { - opts |= SUPPRESS_LAST_MOD; + option = SUPPRESS_LAST_MOD; } else if (!strcasecmp(w, "SuppressSize")) { - opts |= SUPPRESS_SIZE; + option = SUPPRESS_SIZE; } else if (!strcasecmp(w, "SuppressDescription")) { - opts |= SUPPRESS_DESC; + option = SUPPRESS_DESC; } else if (!strcasecmp(w, "SuppressHTMLPreamble")) { - opts |= SUPPRESS_PREAMBLE; + option = SUPPRESS_PREAMBLE; } else if (!strcasecmp(w, "SuppressColumnSorting")) { - opts |= SUPPRESS_COLSORT; + option = SUPPRESS_COLSORT; } else if (!strcasecmp(w, "None")) { - opts = 0; + if (action != '\0') { + return "Cannot combine '+' or '-' with 'None' keyword"; + } + opts = NO_OPTIONS; + opts_add = 0; + opts_remove = 0; } else if (!strcasecmp(w, "IconWidth")) { - d_cfg->icon_width = DEFAULT_ICON_WIDTH; + if (action != '-') { + d_cfg->icon_width = DEFAULT_ICON_WIDTH; + } + else { + d_cfg->icon_width = 0; + } } else if (!strncasecmp(w, "IconWidth=", 10)) { + if (action != '\0') { + return "Cannot combine '+' or '-' with IconWidth=n"; + } d_cfg->icon_width = atoi(&w[10]); } else if (!strcasecmp(w, "IconHeight")) { - d_cfg->icon_height = DEFAULT_ICON_HEIGHT; + if (action != '-') { + d_cfg->icon_height = DEFAULT_ICON_HEIGHT; + } + else { + d_cfg->icon_height = 0; + } } else if (!strncasecmp(w, "IconHeight=", 11)) { + if (action != '\0') { + return "Cannot combine '+' or '-' with IconHeight=n"; + } d_cfg->icon_height = atoi(&w[11]); } + else if (!strcasecmp(w, "NameWidth")) { + if (action != '-') { + return "NameWidth with no value may only appear as " + "'-NameWidth'"; + } + d_cfg->name_width = DEFAULT_NAME_WIDTH; + d_cfg->name_adjust = 0; + } else if (!strncasecmp(w, "NameWidth=", 10)) { + if (action != '\0') { + return "Cannot combine '+' or '-' with NameWidth=n"; + } if (w[10] == '*') { d_cfg->name_adjust = 1; } @@ -361,7 +414,25 @@ static const char *add_opts(cmd_parms *cmd, void *d, const char *optstr) else { return "Invalid directory indexing option"; } + if (action == '\0') { + opts |= option; + opts_add = 0; + opts_remove = 0; + } + else if (action == '+') { + opts_add |= option; + opts_remove &= ~option; + } + else { + opts_remove |= option; + opts_add &= ~option; + } + } + if ((opts & NO_OPTIONS) && (opts & ~NO_OPTIONS)) { + return "Cannot combine other IndexOptions keywords with 'None'"; } + d_cfg->incremented_opts = opts_add; + d_cfg->decremented_opts = opts_remove; d_cfg->opts = opts; return NULL; } @@ -414,6 +485,8 @@ static void *create_autoindex_config(pool *p, char *dummy) new->hdr_list = ap_make_array(p, 4, sizeof(struct item)); new->rdme_list = ap_make_array(p, 4, sizeof(struct item)); new->opts = 0; + new->incremented_opts = 0; + new->decremented_opts = 0; return (void *) new; } @@ -436,7 +509,48 @@ static void *merge_autoindex_configs(pool *p, void *basev, void *addv) new->desc_list = ap_append_arrays(p, add->desc_list, base->desc_list); new->icon_list = ap_append_arrays(p, add->icon_list, base->icon_list); new->rdme_list = ap_append_arrays(p, add->rdme_list, base->rdme_list); - new->opts = add->opts; + if (add->opts & NO_OPTIONS) { + /* + * If the current directory says 'no options' then we also + * clear any incremental mods from being inheritable further down. + */ + new->opts = NO_OPTIONS; + new->incremented_opts = 0; + new->decremented_opts = 0; + } + else { + /* + * If there were any non-incremental options selected for + * this directory, they dominate and we don't inherit *anything.* + * Contrariwise, we *do* inherit if the only settings here are + * incremental ones. + */ + if (add->opts == 0) { + new->incremented_opts = (base->incremented_opts + | add->incremented_opts) + & ~add->decremented_opts; + new->decremented_opts = (base->decremented_opts + | add->decremented_opts); + /* + * We may have incremental settings, so make sure we don't + * inadvertently inherit an IndexOptions None from above. + */ + new->opts = (base->opts & ~NO_OPTIONS); + } + else { + /* + * There are local non-incremental settings, which clear + * all inheritance from above. They *are* the new base settings. + */ + new->opts = add->opts;; + } + /* + * We're guaranteed that there'll be no overlap between + * the add-options and the remove-options. + */ + new->opts |= new->incremented_opts; + new->opts &= ~new->decremented_opts; + } new->name_width = add->name_width; new->name_adjust = add->name_adjust; @@ -455,7 +569,7 @@ struct ent { char *icon; char *alt; char *desc; - size_t size; + off_t size; time_t lm; struct ent *next; int ascending; @@ -745,7 +859,7 @@ static struct ent *make_autoindex_entry(char *name, int autoindex_opts, p = (struct ent *) ap_pcalloc(r->pool, sizeof(struct ent)); p->name = ap_pstrdup(r->pool, name); - p->size = 0; + p->size = -1; p->icon = NULL; p->alt = NULL; p->desc = NULL; @@ -765,7 +879,7 @@ static struct ent *make_autoindex_entry(char *name, int autoindex_opts, if (!(p->alt = find_alt(d, rr, 1))) { p->alt = "DIR"; } - p->size = 0; + p->size = -1; p->name = ap_pstrcat(r->pool, name, "/", NULL); } else { diff --git a/usr.sbin/httpd/src/modules/standard/mod_cgi.c b/usr.sbin/httpd/src/modules/standard/mod_cgi.c index fd5906c4ec2..70f7956228f 100644 --- a/usr.sbin/httpd/src/modules/standard/mod_cgi.c +++ b/usr.sbin/httpd/src/modules/standard/mod_cgi.c @@ -433,7 +433,6 @@ static int cgi_handler(request_rec *r) &script_out, &script_in, &script_err)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, r, "couldn't spawn child process: %s", r->filename); - ap_table_setn(r->notes, "error-notes", "Couldn't spawn child process"); return HTTP_INTERNAL_SERVER_ERROR; } diff --git a/usr.sbin/httpd/src/modules/standard/mod_digest.c b/usr.sbin/httpd/src/modules/standard/mod_digest.c index 08e52f4ecfe..f44e7e3edea 100644 --- a/usr.sbin/httpd/src/modules/standard/mod_digest.c +++ b/usr.sbin/httpd/src/modules/standard/mod_digest.c @@ -159,7 +159,7 @@ static int get_digest_rec(request_rec *r, digest_header_rec * response) return AUTH_REQUIRED; } - if (strcasecmp(scheme=ap_getword(r->pool, &auth_line, ' '), "Digest")) { + if (strcasecmp(scheme = ap_getword_white(r->pool, &auth_line), "Digest")) { /* Client tried to authenticate using wrong auth scheme */ ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r->server, "client used wrong authentication scheme: %s for %s", @@ -345,7 +345,7 @@ static int digest_check_auth(request_rec *r) method_restricted = 1; t = reqs[x].requirement; - w = ap_getword(r->pool, &t, ' '); + w = ap_getword_white(r->pool, &t); if (!strcmp(w, "valid-user")) return OK; else if (!strcmp(w, "user")) { diff --git a/usr.sbin/httpd/src/modules/standard/mod_include.c b/usr.sbin/httpd/src/modules/standard/mod_include.c index 612759ed6e9..3acc0c6f696 100644 --- a/usr.sbin/httpd/src/modules/standard/mod_include.c +++ b/usr.sbin/httpd/src/modules/standard/mod_include.c @@ -946,6 +946,7 @@ static int handle_perl(FILE *in, request_rec *r, const char *error) } } perl_stdout2client(r); + perl_setup_env(r); perl_call_handler(sub, r, av); return OK; } diff --git a/usr.sbin/httpd/src/modules/standard/mod_log_config.c b/usr.sbin/httpd/src/modules/standard/mod_log_config.c index 1fa8f498589..da6d2bcb458 100644 --- a/usr.sbin/httpd/src/modules/standard/mod_log_config.c +++ b/usr.sbin/httpd/src/modules/standard/mod_log_config.c @@ -202,10 +202,9 @@ static mode_t xfer_mode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); * 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. + * (backward compat. with mod_log_config). We also store for each virtual + * server a pointer to the logs specified for the main server, so that if this + * vhost has no 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 diff --git a/usr.sbin/httpd/src/modules/standard/mod_speling.c b/usr.sbin/httpd/src/modules/standard/mod_speling.c index 53f8c1da34d..7d1b976d639 100644 --- a/usr.sbin/httpd/src/modules/standard/mod_speling.c +++ b/usr.sbin/httpd/src/modules/standard/mod_speling.c @@ -453,18 +453,21 @@ static int check_speling(request_rec *r) t = ""; for (i = 0; i < candidates->nelts; ++i) { + char *vuri; + const char *reason; + reason = sp_reason_str[(int) (variant[i].quality)]; /* The format isn't very neat... */ - t = ap_pstrcat(p, t, "<li><a href=\"", url, - variant[i].name, r->path_info, - r->parsed_uri.query ? "?" : "", - r->parsed_uri.query ? r->parsed_uri.query : "", - "\">", variant[i].name, r->path_info, - r->parsed_uri.query ? "?" : "", - r->parsed_uri.query ? r->parsed_uri.query : "", - "</a> (", - sp_reason_str[(int) (variant[i].quality)], - ")\n", NULL); + vuri = ap_pstrcat(p, url, variant[i].name, r->path_info, + (r->parsed_uri.query != NULL) ? "?" : "", + (r->parsed_uri.query != NULL) + ? r->parsed_uri.query : "", + NULL); + ap_table_mergen(r->subprocess_env, "VARIANTS", + ap_pstrcat(p, "\"", vuri, "\";\"", + reason, "\"", NULL)); + t = ap_pstrcat(p, t, "<li><a href=\"", vuri, + "\">", vuri, "</a> (", reason, ")\n", NULL); /* * when we have printed the "close matches" and there are diff --git a/usr.sbin/httpd/src/modules/standard/mod_status.c b/usr.sbin/httpd/src/modules/standard/mod_status.c index 2c24df1ff51..31e9aa41abb 100644 --- a/usr.sbin/httpd/src/modules/standard/mod_status.c +++ b/usr.sbin/httpd/src/modules/standard/mod_status.c @@ -240,10 +240,12 @@ static int status_handler(request_rec *r) unsigned long bcount = 0; unsigned long kbcount = 0; long req_time; -#if defined(NEXT) - float tick = HZ; -#elif !defined(NO_TIMES) +#ifndef NO_TIMES +#ifdef _SC_CLK_TCK float tick = sysconf(_SC_CLK_TCK); +#else + float tick = HZ; +#endif #endif int short_report = 0; int no_table_report = 0; diff --git a/usr.sbin/httpd/src/os/bs2000/bs2login.c b/usr.sbin/httpd/src/os/bs2000/bs2login.c index 361c59d92f7..afba7fd928b 100644 --- a/usr.sbin/httpd/src/os/bs2000/bs2login.c +++ b/usr.sbin/httpd/src/os/bs2000/bs2login.c @@ -67,9 +67,6 @@ static const char *bs2000_account = NULL; /* It stores the account name for later use */ const char *os_set_account(pool *p, const char *account) { - if (bs2000_account != NULL && strcasecmp(bs2000_account, account) != 0) - return "BS2000Account: can be defined only once."; - bs2000_account = ap_pstrdup(p, account); return NULL; } diff --git a/usr.sbin/httpd/src/os/bs2000/ebcdic.c b/usr.sbin/httpd/src/os/bs2000/ebcdic.c index d8c650c0ebc..4a268488de8 100644 --- a/usr.sbin/httpd/src/os/bs2000/ebcdic.c +++ b/usr.sbin/httpd/src/os/bs2000/ebcdic.c @@ -62,8 +62,7 @@ /* Initial Port for Apache-1.3 by <Martin.Kraemer@Mch.SNI.De> -"BS2000 OSD" is a POSIX on a main frame. -It is made by Siemens Nixdorf AG, Germany. +"BS2000 OSD" is a POSIX on a main frame. It is made by Siemens AG, Germany. Within the POSIX subsystem, the same character set was chosen as in "native BS2000", namely EBCDIC. diff --git a/usr.sbin/httpd/src/os/win32/registry.c b/usr.sbin/httpd/src/os/win32/registry.c index 64aa72982a6..665f8ee67e7 100644 --- a/usr.sbin/httpd/src/os/win32/registry.c +++ b/usr.sbin/httpd/src/os/win32/registry.c @@ -28,7 +28,7 @@ #define VENDOR "Apache Group" #define SOFTWARE "Apache" -#define VERSION "1.3.2" +#define VERSION "1.3.3" #define REGKEY "SOFTWARE\\" VENDOR "\\" SOFTWARE "\\" VERSION diff --git a/usr.sbin/httpd/src/os/win32/util_win32.c b/usr.sbin/httpd/src/os/win32/util_win32.c index 47d8f7af9b5..3aac08767ce 100644 --- a/usr.sbin/httpd/src/os/win32/util_win32.c +++ b/usr.sbin/httpd/src/os/win32/util_win32.c @@ -23,7 +23,18 @@ static BOOL sub_canonical_filename(char *szCanon, unsigned nCanon, for (nSlashes = 0; s > szFile && s[-1] == '\\'; ++nSlashes, --s) ; - n = GetFullPathName(szFile, sizeof buf, buf, &szFilePart); + if (strlen(szFile)==2 && szFile[1]==':') { + /* + * If the file name is x:, do not call GetFullPathName + * because it will use the current path of the executable + */ + strcpy(buf,szFile); + n = strlen(buf); + szFilePart = buf + n; + } + else { + n = GetFullPathName(szFile, sizeof buf, buf, &szFilePart); + } ap_assert(n); ap_assert(n < sizeof buf); @@ -36,6 +47,8 @@ static BOOL sub_canonical_filename(char *szCanon, unsigned nCanon, * is no '\' in szInFile, it must just be a file name, so it should be * valid to use the name from GetFullPathName. Be sure to adjust the * 's' variable so the rest of the code functions normally. + * Note it is possible to get here when szFile == 'x:', but that is OK + * because we will bail out of this routine early. */ if (!s) { szFile = buf; @@ -180,9 +193,21 @@ API_EXPORT(char *) ap_os_canonical_filename(pool *pPool, const char *szFile) buf[0] = ap_tolower(buf[0]); - ap_assert(strlen(buf)+nSlashes < sizeof buf); - while (nSlashes--) { - strcat(buf, "/"); + if (nSlashes) { + /* + * If there were additional trailing slashes, add them back on. + * Be sure not to add more than were originally there though, + * by checking to see if sub_canonical_filename added one; + * this could happen in cases where the file name is 'd:/' + */ + ap_assert(strlen(buf)+nSlashes < sizeof buf); + + if (nSlashes && buf[strlen(buf)-1] == '/') + nSlashes--; + + while (nSlashes--) { + strcat(buf, "/"); + } } return ap_pstrdup(pPool, buf); @@ -233,8 +258,13 @@ API_EXPORT(int) os_stat(const char *szPath, struct stat *pStat) return stat(buf, pStat); } + /* + * Below removes the trailing /, however, do not remove + * it in the case of 'x:/' or stat will fail + */ n = strlen(szPath); - if (szPath[n - 1] == '\\' || szPath[n - 1] == '/') { + if ((szPath[n - 1] == '\\' || szPath[n - 1] == '/') && + !(n == 3 && szPath[1] == ':')) { char buf[_MAX_PATH]; ap_assert(n < _MAX_PATH); diff --git a/usr.sbin/httpd/src/support/dbmmanage b/usr.sbin/httpd/src/support/dbmmanage index 824cda540d6..042c686497e 100644 --- a/usr.sbin/httpd/src/support/dbmmanage +++ b/usr.sbin/httpd/src/support/dbmmanage @@ -89,9 +89,9 @@ my $Is_Win32 = $^O eq "MSWin32"; my %DB = (); my @range = (); my($mode, $flags) = $command =~ - /^(?:view|check)$/ ? (undef, O_RDONLY) : (0644, O_RDWR|O_CREAT); + /^(?:view|check)$/ ? (0644, O_RDONLY) : (0644, O_RDWR|O_CREAT); -tie %DB, "AnyDBM_File", $file, $flags, $mode; +tie %DB, "AnyDBM_File", $file, $flags, $mode || die "Can't tie $file: $!"; dbmc->$command(); untie %DB; |