? out
? apexit.patch
? arctic.patch
? timeouts.patch
? modules/php3
Index: include/http_core.h
===================================================================
RCS file: /export/home/cvs/apache-1.3/src/include/http_core.h,v
retrieving revision 1.47
diff -u -r1.47 http_core.h
--- http_core.h	1998/08/10 04:16:13	1.47
+++ http_core.h	1998/08/26 23:32:10
@@ -83,6 +83,7 @@
 #define OPT_INCNOEXEC 32
 #define OPT_SYM_OWNER 64
 #define OPT_MULTI 128
+#define OPT_SYM_GROUP 256
 #define OPT_ALL (OPT_INDEXES|OPT_INCLUDES|OPT_SYM_LINKS|OPT_EXECCGI)
 
 /* options for get_remote_host() */
@@ -165,7 +166,7 @@
 
 /* Per-directory configuration */
 
-typedef unsigned char allow_options_t;
+typedef unsigned short allow_options_t;
 typedef unsigned char overrides_t;
 
 typedef struct {
Index: include/httpd.h
===================================================================
RCS file: /export/home/cvs/apache-1.3/src/include/httpd.h,v
retrieving revision 1.238
diff -u -r1.238 httpd.h
--- httpd.h	1998/08/16 20:51:54	1.238
+++ httpd.h	1998/08/26 23:32:10
@@ -1042,6 +1042,14 @@
 #define OPTIMIZE_TIMEOUTS
 #endif
 
+#ifdef SHARED_TIME
+#ifndef OPTIMIZE_TIMEOUTS
+# error "you need OPTIMIZE_TIMEOUTS for SHARED_TIME"
+#endif
+extern time_t ap_shared_time(time_t *);
+#define time(x) ap_shared_time(x)
+#endif
+
 /* A set of flags which indicate places where the server should raise(SIGSTOP).
  * This is useful for debugging, because you can then attach to that process
  * with gdb and continue.  This is important in cases where one_process
Index: include/scoreboard.h
===================================================================
RCS file: /export/home/cvs/apache-1.3/src/include/scoreboard.h,v
retrieving revision 1.41
diff -u -r1.41 scoreboard.h
--- scoreboard.h	1998/08/11 00:09:43	1.41
+++ scoreboard.h	1998/08/26 23:32:10
@@ -136,6 +136,9 @@
 typedef struct {
     int exit_generation;	/* Set by the main process if a graceful
 				   restart is required */
+#ifdef SHARED_TIME
+    time_t right_now;          /* the current time */
+#endif
 } global_score;
 
 /* stuff which the parent generally writes and the children rarely read */
Index: main/buff.c
===================================================================
RCS file: /export/home/cvs/apache-1.3/src/main/buff.c,v
retrieving revision 1.81
diff -u -r1.81 buff.c
--- buff.c	1998/07/04 18:22:11	1.81
+++ buff.c	1998/08/26 23:32:10
@@ -967,7 +967,9 @@
  * chunk before proceeding onto anything else.  This routine either writes
  * nbytes and returns 0 or returns -1 indicating a failure.
  *
- * This is *seriously broken* if used on a non-blocking fd.  It will poll.
+ * XXX: When used on a non-blocking fd it may block until it can write.
+ * (This is somewhat easier to do than it is to remember all the appropriate
+ * state and return to the caller.)
  *
  * Deals with calling doerror and setting bytes_sent.
  */
@@ -985,6 +987,19 @@
 		doerror(fb, B_WR);
 		return -1;
 	    }
+	    if (errno == EAGAIN) {
+		/* hack hack: it's non-blocking, block until it's ready for
+		 * another write.
+		 */
+		fd_set fds;
+		int rv;
+
+		do {
+		    FD_ZERO(&fds);
+		    FD_SET(fb->fd, &fds);
+		    rv = ap_select(fb->fd + 1, NULL, &fds, NULL, NULL);
+		} while (rv == -1 && errno == EINTR);
+	    }
 	}
 	else {
 	    nbyte -= i;
@@ -1075,7 +1090,6 @@
  * an interim solution pending a complete rewrite of all this stuff in
  * 2.0, using something like sfio stacked disciplines or BSD's funopen().
  *
- * Can be used on non-blocking descriptors, but only if they're not chunked.
  * Deals with doerror() and bytes_sent.
  */
 static int bcwrite(BUFF *fb, const void *buf, int nbyte)
Index: main/http_core.c
===================================================================
RCS file: /export/home/cvs/apache-1.3/src/main/http_core.c,v
retrieving revision 1.224
diff -u -r1.224 http_core.c
--- http_core.c	1998/08/11 15:37:52	1.224
+++ http_core.c	1998/08/26 23:32:10
@@ -70,6 +70,8 @@
 #include "scoreboard.h"
 #include "fnmatch.h"
 
+#undef USE_MMAP_FILES
+
 #ifdef USE_MMAP_FILES
 #include <sys/mman.h>
 
@@ -965,6 +967,9 @@
 	else if (!strcasecmp(w, "SymLinksIfOwnerMatch")) {
 	    opt = OPT_SYM_OWNER;
 	}
+	else if(!strcasecmp(w,"SymLinksIfGroupMatch")) {
+	    opt = OPT_SYM_GROUP;
+	}
 	else if (!strcasecmp(w, "execCGI")) {
 	    opt = OPT_EXECCGI;
 	}
@@ -2758,7 +2763,32 @@
 
 	if (d->content_md5 & 1) {
 	    ap_table_setn(r->headers_out, "Content-MD5",
-			  ap_md5digest(r->pool, f));
+	                  ap_md5digest(r->pool, f));
+	}
+	/* Shameless hack: if the file to be sent is image/gif and
+	 * gif89-expires-hack is set then remove the Expires header.  This is
+	 * required because of a bug in Mozilla versions up through at least 4
+	 * which causes it to re-request the animation every loop.  You
+	 * probably want this in your config:
+	 *
+	 * BrowserMatch Mozilla/[0-4]\. gif89-expires-hack
+	 *
+	 * -djg
+	 */
+	if (r->content_type
+	    && strcasecmp (r->content_type, "image/gif") == 0
+	    && r->finfo.st_size > 6
+	    && ap_table_get (r->subprocess_env, "gif89-expires-hack")) {
+#define GIF_HEADER_LEN	(6)
+	    char gif_header[ GIF_HEADER_LEN ];
+
+	    if (fread (gif_header, 1, GIF_HEADER_LEN, f) == GIF_HEADER_LEN
+		&& memcmp (gif_header, "GIF89a", GIF_HEADER_LEN) == 0) {
+		ap_table_unset (r->headers_out, "Expires");
+		ap_table_unset (r->headers_out, "Cache-Control");
+	    }
+	    fseek (f, 0L, SEEK_SET);
+#undef GIF_HEADER_LEN
 	}
 
 	rangestatus = ap_set_byterange(r);
@@ -2806,6 +2836,15 @@
 	    ap_MD5Update(&context, (void *)mm, r->finfo.st_size);
 	    ap_table_setn(r->headers_out, "Content-MD5",
 			  ap_md5contextTo64(r->pool, &context));
+	}
+	/* Shameless gif89-expires-hack, see above */
+	if (r->content_type
+	    && strcasecmp (r->content_type, "image/gif") == 0
+	    && table_get (r->subprocess_env, "gif89-expires-hack")
+	    && r->finfo.st_size > 6
+	    && memcmp (mm, "GIF89a", 6) == 0) {
+	    table_unset (r->headers_out, "Expires");
+	    table_unset (r->headers_out, "Cache-Control");
 	}
 
 	rangestatus = ap_set_byterange(r);
Index: main/http_log.c
===================================================================
RCS file: /export/home/cvs/apache-1.3/src/main/http_log.c,v
retrieving revision 1.64
diff -u -r1.64 http_log.c
--- http_log.c	1998/08/10 16:17:54	1.64
+++ http_log.c	1998/08/26 23:32:11
@@ -69,6 +69,7 @@
 #include "http_core.h"
 #include "http_log.h"
 #include "http_main.h"
+#include "http_conf_globals.h"
 
 #include <stdarg.h>
 
@@ -510,6 +511,7 @@
 static int piped_log_spawn (piped_log *pl)
 {
     int pid;
+    int pgrp;
 
     ap_block_alarms();
     pid = fork();
@@ -520,6 +522,36 @@
 	 * XXX: close all the relevant stuff, but hey, it could be broken. */
 	RAISE_SIGSTOP(PIPED_LOG_SPAWN);
 	/* we're now in the child */
+	/* cd ServerRoot so that it's easy to construct portable logger
+	 * lines */
+	if (chdir(ap_server_root) == -1) {
+	    ap_log_error(APLOG_MARK, APLOG_CRIT, NULL,
+		"logger: unable to chdir(%s)", ap_server_root);
+	    exit (1);
+	}
+#ifndef NO_SETSID
+	if ((pgrp = setsid()) == -1) {
+	    ap_log_error(APLOG_MARK, APLOG_CRIT, NULL, "logger: setsid failed");
+	    exit(1);
+	}
+#elif defined(NEXT) || defined(NEWSOS)
+	if (setpgrp(0, getpid()) == -1 || (pgrp = getpgrp(0)) == -1) {
+	    ap_log_error(APLOG_MARK, APLOG_CRIT, NULL,
+		"logger: setpgrp or getpgrp failed");
+	    exit(1);
+	}
+#elif defined(__EMX__)
+	/* OS/2 don't support process group IDs */
+	pgrp = -getpid();
+#elif defined(MPE)
+	/* MPE uses negative pid for process group */
+	pgrp = -getpid();
+#else
+	if ((pgrp = setpgrp(getpid(), 0)) == -1) {
+	    ap_log_error(APLOG_MARK, APLOG_CRIT, NULL, "logger: setpgrp failed");
+	    exit(1);
+	}
+#endif
 	close (STDIN_FILENO);
 	dup2 (pl->fds[0], STDIN_FILENO);
 
@@ -549,6 +581,9 @@
 {
     piped_log *pl = data;
 
+    ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_DEBUG, NULL,
+		"piped_log_maintenance reason = %d, status = %d", reason,
+		status);
     switch (reason) {
     case OC_REASON_DEATH:
     case OC_REASON_LOST:
Index: main/http_main.c
===================================================================
RCS file: /export/home/cvs/apache-1.3/src/main/http_main.c,v
retrieving revision 1.387
diff -u -r1.387 http_main.c
--- http_main.c	1998/08/13 01:55:06	1.387
+++ http_main.c	1998/08/26 23:32:11
@@ -275,6 +275,7 @@
  */
 listen_rec *ap_listeners;
 static listen_rec *head_listener;
+static listen_rec *permanent_listeners;
 
 API_VAR_EXPORT char ap_server_root[MAX_STRING_LEN];
 char ap_server_confname[MAX_STRING_LEN];
@@ -1224,6 +1225,20 @@
     timeout_name = NULL;
 }
 
+#ifdef SHARED_TIME
+#undef time
+time_t ap_shared_time(time_t *t)
+{
+    time_t res;
+
+    if (child_timeouts || ap_scoreboard_image == NULL) {
+	return time(0);
+    }
+    res = ap_scoreboard_image->global.right_now;
+    if (t) *t = res;
+    return res;
+}
+#endif
 
 /*
  * More machine-dependent networking gooo... on some systems,
@@ -3061,6 +3076,9 @@
 {
     listen_rec *lr;
 
+    if (permanent_listeners) {
+	return;
+    }
     ap_assert(old_listeners == NULL);
     if (ap_listeners == NULL) {
 	return;
@@ -3116,6 +3134,20 @@
     listen_rec *lr;
     int fd;
 
+    if (permanent_listeners) {
+	lr = permanent_listeners;
+	ap_listeners = lr;
+	head_listener = lr;
+	do {
+	    if (lr->next == NULL) {
+		/* first time through, create the loop */
+		lr->next = permanent_listeners;
+		return;
+	    }
+	    lr = lr->next;
+	} while (lr != permanent_listeners);
+	return;
+    }
     listenmaxfd = -1;
     FD_ZERO(&listenfds);
     lr = ap_listeners;
@@ -3921,6 +3953,10 @@
     last_non_dead = -1;
     total_non_dead = 0;
 
+#ifdef SHARED_TIME
+    ap_scoreboard_image->global.right_now = now;
+#endif
+
     ap_sync_scoreboard_image();
     for (i = 0; i < ap_daemons_limit; ++i) {
 	int status;
@@ -3982,6 +4018,9 @@
 	 * shut down gracefully, in case it happened to pick up a request
 	 * while we were counting
 	 */
+	ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, server_conf,
+	    "server has %d children, %d are idle, killing one",
+	    total_non_dead, idle_count);
 	kill(ap_scoreboard_image->parent[to_kill].pid, SIGUSR1);
 	idle_spawn_rate = 1;
     }
@@ -4008,6 +4047,9 @@
 		    "%d total children", idle_spawn_rate,
 		    idle_count, total_non_dead);
 	    }
+	    ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, server_conf,
+		"server has %d children, %d are idle, spawning %d",
+		total_non_dead, idle_count, free_length);
 	    for (i = 0; i < free_length; ++i) {
 		make_child(server_conf, free_slots[i], now);
 	    }
@@ -4316,6 +4358,58 @@
 void STANDALONE_MAIN(int argc, char **argv);
 #endif /* STANDALONE_MAIN */
 
+static void pre_opened_socket(const char *arg)
+{
+    int fd;
+    struct sockaddr_in local_addr;
+    listen_rec *lr;
+    NET_SIZE_T clen;
+
+    fd = atoi(arg);
+
+    clen = sizeof(local_addr);
+    if (getsockname(fd, (struct sockaddr *)&local_addr, &clen) == -1) {
+	ap_log_error(APLOG_MARK, APLOG_ERR, NULL,
+	    "error parsing arg -p '%s', skipping", arg);
+	return;
+    }
+
+    if (local_addr.sin_family != AF_INET) {
+	ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, NULL,
+	    "arg -p %d is not an AF_INET socket, skipping", fd);
+	return;
+    }
+
+#ifdef LINUX
+    /* work around linux 2.0.x bug */
+    if (local_addr.sin_addr.s_addr == htonl(0x7f000001)) {
+	local_addr.sin_addr.s_addr = 0;
+    }
+#endif
+
+    /* We don't want these descriptors to be passed down to the
+     * grandchildren.  Since we're not going to manage them in pools
+     * we have to set the close-on-exec flag.
+     */
+    if (fcntl(fd, F_SETFD, 1)) {
+	ap_log_error(APLOG_MARK, APLOG_ERR, NULL,
+	    "arg -p %d, can't fcntl(%d, F_SETFD, 1), skipping", fd, fd);
+	return;
+    }
+
+    lr = malloc(sizeof(listen_rec));
+    if (lr == NULL) {
+	ap_log_error(APLOG_MARK, APLOG_CRIT, NULL,
+	    "out of memory allocating permanent_listener");
+	exit(1);
+    }
+    lr->local_addr = local_addr;
+    lr->fd = fd;
+    lr->used = 0;
+    lr->next = permanent_listeners;
+    permanent_listeners = lr;
+}
+
 extern char *optarg;
 extern int optind;
 
@@ -4353,6 +4447,7 @@
 #ifdef DEBUG_SIGSTOP
 				    "Z:"
 #endif
+			"p:"
 			)) != -1) {
 	char **new;
 	switch (c) {
@@ -4389,6 +4484,9 @@
 	case 'l':
 	    ap_show_modules();
 	    exit(0);
+	case 'p':
+	    pre_opened_socket(optarg);
+	    break;
 	case 'X':
 	    ++one_process;	/* Weird debugging mode. */
 	    break;
Index: main/http_request.c
===================================================================
RCS file: /export/home/cvs/apache-1.3/src/main/http_request.c,v
retrieving revision 1.130
diff -u -r1.130 http_request.c
--- http_request.c	1998/08/11 00:09:46	1.130
+++ http_request.c	1998/08/26 23:32:12
@@ -158,13 +158,19 @@
 
     /* OK, it's a symlink.  May still be OK with OPT_SYM_OWNER */
 
-    if (!(opts & OPT_SYM_OWNER))
+    if (!(opts & (OPT_SYM_OWNER|OPT_SYM_GROUP)))
         return HTTP_FORBIDDEN;
 
     if (stat(d, &fi) < 0)
         return HTTP_FORBIDDEN;
 
-    return (fi.st_uid == lfi.st_uid) ? OK : HTTP_FORBIDDEN;
+    if ((opts & OPT_SYM_OWNER) && fi.st_uid == lfi.st_uid)
+	return OK;
+
+    if ((opts & OPT_SYM_GROUP) && fi.st_gid == lfi.st_gid)
+	return OK;
+
+    return HTTP_FORBIDDEN;
 
 #endif
 }
Index: modules/standard/mod_autoindex.c
===================================================================
RCS file: /export/home/cvs/apache-1.3/src/modules/standard/mod_autoindex.c,v
retrieving revision 1.87
diff -u -r1.87 mod_autoindex.c
--- mod_autoindex.c	1998/08/06 17:30:56	1.87
+++ mod_autoindex.c	1998/08/26 23:32:13
@@ -865,15 +865,29 @@
 			       autoindex_config_rec * d, request_rec *r,
 			     int autoindex_opts, char keyid, char direction)
 {
-    int x, len;
+    int x;
     char *name = r->uri;
     char *tp;
     int static_columns = (autoindex_opts & SUPPRESS_COLSORT);
     pool *scratch = ap_make_sub_pool(r->pool);
+    int name_width;
+    char *name_scratch;
 
     if (name[0] == '\0')
 	name = "/";
 
+    name_width = 23;
+    for (x = 0; x < n; x++) {
+	int t = strlen(ar[x]->name);
+	if (t > name_width) {
+	    name_width = t;
+	}
+    }
+    ++name_width;
+    name_scratch = ap_palloc(r->pool, name_width + 1);
+    memset(name_scratch, ' ', name_width);
+    name_scratch[name_width] = 0;
+
     if (autoindex_opts & FANCY_INDEXING) {
 	ap_rputs("<PRE>", r);
 	if ((tp = find_default_icon(d, "^^BLANKICON^^"))) {
@@ -891,7 +905,7 @@
 	    ap_rputs("> ", r);
 	}
         emit_link(r, "Name", K_NAME, keyid, direction, static_columns);
-	ap_rputs("                   ", r);
+	ap_rputs(name_scratch + 4, r);
 	if (!(autoindex_opts & SUPPRESS_LAST_MOD)) {
             emit_link(r, "Last modified", K_LAST_MOD, keyid, direction,
                       static_columns);
@@ -912,7 +926,8 @@
     }
 
     for (x = 0; x < n; x++) {
-	char *anchor = NULL, *t = NULL, *t2 = NULL;
+	char *anchor, *t, *t2;
+	char *pad;
 
 	ap_clear_pool(scratch);
 
@@ -922,40 +937,21 @@
 	    if (t[0] == '\0') {
 		t = "/";
 	    }
-	    anchor = ap_pstrcat(scratch, "<A HREF=\"",
-				ap_escape_html(scratch,
-					       ap_os_escape_path(scratch, t,
-								 0)),
-				"\">", NULL);
-	    t2 = "Parent Directory</A>       ";
+	       /* 1234567890123456 */
+	    t2 = "Parent Directory";
+	    pad = name_scratch + 16;
+	    anchor = ap_escape_html(scratch, ap_os_escape_path(scratch, t, 0));
 	}
 	else {
 	    t = ar[x]->name;
-	    len = strlen(t);
-	    if (len > 23) {
-		t2 = ap_pstrdup(scratch, t);
-		t2[21] = '.';
-		t2[22] = '.';
-		t2[23] = '\0';
-		t2 = ap_escape_html(scratch, t2);
-		t2 = ap_pstrcat(scratch, t2, "</A>", NULL);
-	    }
-	    else {
-		char buff[24] = "                       ";
-		t2 = ap_escape_html(scratch, t);
-		buff[23 - len] = '\0';
-		t2 = ap_pstrcat(scratch, t2, "</A>", buff, NULL);
-	    }
-	    anchor = ap_pstrcat(scratch, "<A HREF=\"",
-				ap_escape_html(scratch,
-					       ap_os_escape_path(scratch, t,
-								 0)),
-				"\">", NULL);
+	    pad = name_scratch + strlen(t);
+	    t2 = ap_escape_html(scratch, t);
+	    anchor = ap_escape_html(scratch, ap_os_escape_path(scratch, t, 0));
 	}
 
 	if (autoindex_opts & FANCY_INDEXING) {
 	    if (autoindex_opts & ICONS_ARE_LINKS) {
-		ap_rputs(anchor, r);
+		ap_rvputs(r, "<A HREF=\"", anchor, "\">", NULL);
 	    }
 	    if ((ar[x]->icon) || d->default_icon) {
 		ap_rvputs(r, "<IMG SRC=\"",
@@ -974,7 +970,7 @@
 		ap_rputs("</A>", r);
 	    }
 
-	    ap_rvputs(r, " ", anchor, t2, NULL);
+	    ap_rvputs(r, " <A HREF=\"", anchor, "\">", t2, "</A>", pad, NULL);
 	    if (!(autoindex_opts & SUPPRESS_LAST_MOD)) {
 		if (ar[x]->lm != -1) {
 		    char time_str[MAX_STRING_LEN];
@@ -998,7 +994,7 @@
 	    }
 	}
 	else {
-	    ap_rvputs(r, "<LI> ", anchor, " ", t2, NULL);
+	    ap_rvputs(r, "<LI> <A HREF=\"", anchor, "\"> ", t2, "</A>", pad, NULL);
 	}
 	ap_rputc('\n', r);
     }
Index: modules/standard/mod_include.c
===================================================================
RCS file: /export/home/cvs/apache-1.3/src/modules/standard/mod_include.c,v
retrieving revision 1.102
diff -u -r1.102 mod_include.c
--- mod_include.c	1998/08/09 17:36:29	1.102
+++ mod_include.c	1998/08/26 23:32:13
@@ -94,6 +94,10 @@
 #include "util_script.h"
 #endif
 
+#ifndef WASTE_OF_TIME
+#define ap_chdir_file(x) do {} while(0)
+#endif
+
 #define STARTING_SEQUENCE "<!--#"
 #define ENDING_SEQUENCE "-->"
 #define DEFAULT_ERROR_MSG "[an error occurred while processing this directive]"
@@ -113,32 +117,57 @@
 
 /* ------------------------ Environment function -------------------------- */
 
-/* XXX: could use ap_table_overlap here */
-static void add_include_vars(request_rec *r, char *timefmt)
+static const char INCLUDE_TIME_FORMAT[] = "INCLUDE_TIME_FORMAT";
+
+static const char *get_envvar(request_rec *r, const char *name)
 {
+    const char *res;
+    table *e;
+
+    e = r->subprocess_env;
+    res = ap_table_get(e, name);
+    if (res) {
+	return res;
+    }
+    if (!strcmp(name, "LAST_MODIFIED")) {
+	res = ap_ht_time(r->pool, r->finfo.st_mtime,
+	    ap_table_get(e, INCLUDE_TIME_FORMAT), 0);
+    }
+    else if (!strcmp(name, "DATE_LOCAL")) {
+	res = ap_ht_time(r->pool, r->request_time,
+	    ap_table_get(e, INCLUDE_TIME_FORMAT), 0);
+    }
+    else if (!strcmp(name, "DATE_GMT")) {
+	res = ap_ht_time(r->pool, r->request_time,
+	    ap_table_get(e, INCLUDE_TIME_FORMAT), 1);
+    }
 #ifndef WIN32
-    struct passwd *pw;
+    else if (!strcmp(name, "USER_NAME")) {
+	struct passwd *pw;
+	pw = getpwuid(r->finfo.st_uid);
+	if (pw) {
+	    res = ap_pstrdup(r->pool, pw->pw_name);
+	}
+	else {
+	    res = ap_psprintf(r->pool, "user#%lu",
+			(unsigned long) r->finfo.st_uid);
+	}
+    }
 #endif /* ndef WIN32 */
+    if (res) {
+	ap_table_set(e, name, res);
+    }
+    return res;
+}
+
+static void add_include_vars(request_rec *r)
+{
     table *e = r->subprocess_env;
     char *t;
-    time_t date = r->request_time;
 
-    ap_table_setn(e, "DATE_LOCAL", ap_ht_time(r->pool, date, timefmt, 0));
-    ap_table_setn(e, "DATE_GMT", ap_ht_time(r->pool, date, timefmt, 1));
-    ap_table_setn(e, "LAST_MODIFIED",
-              ap_ht_time(r->pool, r->finfo.st_mtime, timefmt, 0));
+    ap_table_setn(e, INCLUDE_TIME_FORMAT, DEFAULT_TIME_FORMAT);
     ap_table_setn(e, "DOCUMENT_URI", r->uri);
     ap_table_setn(e, "DOCUMENT_PATH_INFO", r->path_info);
-#ifndef WIN32
-    pw = getpwuid(r->finfo.st_uid);
-    if (pw) {
-        ap_table_setn(e, "USER_NAME", ap_pstrdup(r->pool, pw->pw_name));
-    }
-    else {
-        ap_table_setn(e, "USER_NAME", ap_psprintf(r->pool, "user#%lu",
-                    (unsigned long) r->finfo.st_uid));
-    }
-#endif /* ndef WIN32 */
 
     if ((t = strrchr(r->filename, '/'))) {
         ap_table_setn(e, "DOCUMENT_NAME", ++t);
@@ -894,7 +923,7 @@
             return 1;
         }
         if (!strcmp(tag, "var")) {
-            const char *val = ap_table_get(r->subprocess_env, tag_val);
+	    const char *val = get_envvar(r, tag_val);
 
             if (val) {
                 ap_rputs(val, r);
@@ -951,16 +980,26 @@
 }
 #endif
 
+
+static void set_timefmt(request_rec *r, char *value)
+{
+    table *e = r->subprocess_env;
+
+    ap_table_setn(e, INCLUDE_TIME_FORMAT, ap_pstrdup(r->pool, value));
+    ap_table_unset(e, "DATE_LOCAL");
+    ap_table_unset(e, "DATE_GMT");
+    ap_table_unset(e, "LAST_MODIFIED");
+}
+
+
 /* error and tf must point to a string with room for at 
  * least MAX_STRING_LEN characters 
  */
-static int handle_config(FILE *in, request_rec *r, char *error, char *tf,
-                         int *sizefmt)
+static int handle_config(FILE *in, request_rec *r, char *error, int *sizefmt)
 {
     char tag[MAX_STRING_LEN];
     char *tag_val;
     char parsed_string[MAX_STRING_LEN];
-    table *env = r->subprocess_env;
 
     while (1) {
         if (!(tag_val = get_tag(r->pool, in, tag, sizeof(tag), 0))) {
@@ -970,13 +1009,8 @@
             parse_string(r, tag_val, error, MAX_STRING_LEN, 0);
         }
         else if (!strcmp(tag, "timefmt")) {
-            time_t date = r->request_time;
-
-            parse_string(r, tag_val, tf, MAX_STRING_LEN, 0);
-            ap_table_setn(env, "DATE_LOCAL", ap_ht_time(r->pool, date, tf, 0));
-            ap_table_setn(env, "DATE_GMT", ap_ht_time(r->pool, date, tf, 1));
-            ap_table_setn(env, "LAST_MODIFIED",
-                      ap_ht_time(r->pool, r->finfo.st_mtime, tf, 0));
+            parse_string(r, tag_val, parsed_string, MAX_STRING_LEN, 0);
+	    set_timefmt(r, parsed_string);
         }
         else if (!strcmp(tag, "sizefmt")) {
             parse_string(r, tag_val, parsed_string, sizeof(parsed_string), 0);
@@ -1106,7 +1140,7 @@
     }
 }
 
-static int handle_flastmod(FILE *in, request_rec *r, const char *error, const char *tf)
+static int handle_flastmod(FILE *in, request_rec *r, const char *error)
 {
     char tag[MAX_STRING_LEN];
     char *tag_val;
@@ -1123,7 +1157,8 @@
         else {
             parse_string(r, tag_val, parsed_string, sizeof(parsed_string), 0);
             if (!find_file(r, "flastmod", tag, parsed_string, &finfo, error)) {
-                ap_rputs(ap_ht_time(r->pool, finfo.st_mtime, tf, 0), r);
+                ap_rputs(ap_ht_time(r->pool, finfo.st_mtime,
+		    ap_table_get(r->subprocess_env, INCLUDE_TIME_FORMAT), 0), r);
             }
         }
     }
@@ -2052,7 +2087,12 @@
                 return -1;
             }
             parse_string(r, tag_val, parsed_string, sizeof(parsed_string), 0);
-            ap_table_setn(r->subprocess_env, var, ap_pstrdup(r->pool, parsed_string));
+	    if (strcmp(var, INCLUDE_TIME_FORMAT)) {
+		ap_table_setn(r->subprocess_env, var, ap_pstrdup(r->pool, parsed_string));
+	    }
+	    else {
+		set_timefmt(r, parsed_string);
+	    }
         }
         else {
             ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
@@ -2067,14 +2107,21 @@
 {
     char tag[MAX_STRING_LEN];
     char *tag_val;
-    array_header *arr = ap_table_elts(r->subprocess_env);
-    table_entry *elts = (table_entry *) arr->elts;
+    array_header *arr;
+    table_entry *elts;
     int i;
 
     if (!(tag_val = get_tag(r->pool, in, tag, sizeof(tag), 1))) {
         return 1;
     }
     else if (!strcmp(tag, "done")) {
+	/* force these to be defined */
+	get_envvar(r, "DATE_LOCAL");
+	get_envvar(r, "DATE_GMT");
+	get_envvar(r, "LAST_MODIFIED");
+	get_envvar(r, "USER_NAME");
+	arr = ap_table_elts(r->subprocess_env);
+	elts = (table_entry *) arr->elts;
         for (i = 0; i < arr->nelts; ++i) {
             ap_rvputs(r, elts[i].key, "=", elts[i].val, "\n", NULL);
         }
@@ -2098,7 +2145,6 @@
 static void send_parsed_content(FILE *f, request_rec *r)
 {
     char directive[MAX_STRING_LEN], error[MAX_STRING_LEN];
-    char timefmt[MAX_STRING_LEN];
     int noexec = ap_allow_options(r) & OPT_INCNOEXEC;
     int ret, sizefmt;
     int if_nesting;
@@ -2106,7 +2152,6 @@
     int conditional_status;
 
     ap_cpystrn(error, DEFAULT_ERROR_MSG, sizeof(error));
-    ap_cpystrn(timefmt, DEFAULT_TIME_FORMAT, sizeof(timefmt));
     sizefmt = SIZEFMT_KMG;
 
 /*  Turn printing on */
@@ -2187,7 +2232,7 @@
                 }
             }
             else if (!strcmp(directive, "config")) {
-                ret = handle_config(f, r, error, timefmt, &sizefmt);
+                ret = handle_config(f, r, error, &sizefmt);
             }
             else if (!strcmp(directive, "set")) {
                 ret = handle_set(f, r, error);
@@ -2202,7 +2247,7 @@
                 ret = handle_fsize(f, r, error, sizefmt);
             }
             else if (!strcmp(directive, "flastmod")) {
-                ret = handle_flastmod(f, r, error, timefmt);
+                ret = handle_flastmod(f, r, error);
             }
             else if (!strcmp(directive, "printenv")) {
                 ret = handle_printenv(f, r, error);
@@ -2347,7 +2392,7 @@
 	 * environment */
         ap_add_common_vars(r);
         ap_add_cgi_vars(r);
-        add_include_vars(r, DEFAULT_TIME_FORMAT);
+        add_include_vars(r);
     }
     /* XXX: this is bogus, at some point we're going to do a subrequest,
      * and when we do it we're going to be subjecting code that doesn't
Index: modules/standard/mod_rewrite.c
===================================================================
RCS file: /export/home/cvs/apache-1.3/src/modules/standard/mod_rewrite.c,v
retrieving revision 1.129
diff -u -r1.129 mod_rewrite.c
--- mod_rewrite.c	1998/08/13 01:55:15	1.129
+++ mod_rewrite.c	1998/08/26 23:32:14
@@ -1332,7 +1332,7 @@
      *  only do something under runtime if the engine is really enabled,
      *  for this directory, else return immediately!
      */
-    if (!(ap_allow_options(r) & (OPT_SYM_LINKS | OPT_SYM_OWNER))) {
+    if (!(ap_allow_options(r) & (OPT_SYM_LINKS | OPT_SYM_OWNER | OPT_SYM_GROUP))) {
         /* FollowSymLinks is mandatory! */
         ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
                      "Options FollowSymLinks or SymLinksIfOwnerMatch is off "
Index: support/.cvsignore
===================================================================
RCS file: /export/home/cvs/apache-1.3/src/support/.cvsignore,v
retrieving revision 1.6
diff -u -r1.6 .cvsignore
--- .cvsignore	1998/03/31 15:59:56	1.6
+++ .cvsignore	1998/08/26 23:32:19
@@ -1,3 +1,4 @@
+listenwrap
 Makefile
 rotatelogs
 htpasswd
Index: support/Makefile.tmpl
===================================================================
RCS file: /export/home/cvs/apache-1.3/src/support/Makefile.tmpl,v
retrieving revision 1.25
diff -u -r1.25 Makefile.tmpl
--- Makefile.tmpl	1998/08/03 08:44:08	1.25
+++ Makefile.tmpl	1998/08/26 23:32:19
@@ -25,6 +25,9 @@
 logresolve: logresolve.o
 	$(CC) $(CFLAGS) logresolve.o -o logresolve $(LDFLAGS) $(LIBS)
 
+listenwrap: listenwrap.o
+	$(CC) $(INCLUDES) $(CFLAGS) listenwrap.o -o listenwrap $(LDFLAGS) $(LIBS)
+
 ab: ab.o
 	$(CC) $(CFLAGS) ab.o -o ab $(LDFLAGS) $(LIBS)
 
Index: support/listenwrap.c
===================================================================
RCS file: listenwrap.c
diff -N listenwrap.c
--- /dev/null	Wed Aug 26 16:31:53 1998
+++ listenwrap.c	Wed Aug 26 16:32:19 1998
@@ -0,0 +1,148 @@
+#include "httpd.h"
+
+#define PORT			80
+#define SEND_BUFFER_SIZE	16384
+#define LISTEN_BACKLOG		511
+#define HTTP_USER		511
+#define HTTP_GROUP		511
+#define HTTPD_PATH		"/home/www/bin/httpd"
+
+/* stolen from http_main.c ... should be turned into a lib function I guess */
+
+#if defined(TCP_NODELAY) && !defined(MPE)
+static void sock_disable_nagle(int s)
+{
+    /* The Nagle algorithm says that we should delay sending partial
+     * packets in hopes of getting more data.  We don't want to do
+     * this; we are not telnet.  There are bad interactions between
+     * persistent connections and Nagle's algorithm that have very severe
+     * performance penalties.  (Failing to disable Nagle is not much of a
+     * problem with simple HTTP.)
+     *
+     * In spite of these problems, failure here is not a shooting offense.
+     */
+    int just_say_no = 1;
+
+    if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char *) &just_say_no,
+		   sizeof(int)) < 0) {
+	perror("setsockopt(TCP_NODELAY)");
+    }
+}
+
+#else
+#define sock_disable_nagle(s)	/* NOOP */
+#endif
+
+#ifndef MAX_SECS_TO_LINGER
+#define MAX_SECS_TO_LINGER 30
+#endif
+
+#ifdef USE_SO_LINGER
+#define NO_LINGCLOSE		/* The two lingering options are exclusive */
+
+static void sock_enable_linger(int s)
+{
+    struct linger li;
+
+    li.l_onoff = 1;
+    li.l_linger = MAX_SECS_TO_LINGER;
+
+    if (setsockopt(s, SOL_SOCKET, SO_LINGER,
+		   (char *) &li, sizeof(struct linger)) < 0) {
+	perror("setsockopt(SO_LINGER)");
+	/* not a fatal error */
+    }
+}
+
+#else
+#define sock_enable_linger(s)	/* NOOP */
+#endif /* USE_SO_LINGER */
+
+static int make_sock(const struct sockaddr_in *local_addr)
+{
+    int s;
+    int one = 1;
+
+    if ((s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
+	perror("socket");
+	exit(1);
+    }
+
+    if (bind(s, (struct sockaddr *) local_addr,
+	sizeof(struct sockaddr_in)) == -1) {
+	perror("bind");
+	exit(1);
+    }
+
+    if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &one,
+	sizeof(int)) < 0) {
+	perror("setsockopt(SO_REUSEADDR)");
+	exit(1);
+    }
+    one = 1;
+    if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char *) &one,
+	sizeof(int)) < 0) {
+	perror("setsockopt(SO_KEEPALIVE");
+	exit(1);
+    }
+
+    sock_disable_nagle(s);
+    sock_enable_linger(s);
+
+    one = SEND_BUFFER_SIZE;
+    if (setsockopt(s, SOL_SOCKET, SO_SNDBUF,
+	    (char *) &one, sizeof(int)) < 0) {
+	perror("setsockopt(SO_SNDBUF)");
+	/* not a fatal error */
+    }
+
+    if (listen(s, LISTEN_BACKLOG) == -1) {
+	perror("listen");
+	exit(1);
+    }
+
+    return s;
+}
+
+void main(int argc, char **argv)
+{
+    struct sockaddr_in local_addr;
+    int s;
+    char **new_argv;
+    char *new_env[] = {
+	"SHELL=/bin/sh",
+	"PATH=/usr/local/bin:/usr/bin:/bin",
+	NULL
+    };
+    char buf[512];
+
+    local_addr.sin_family = AF_INET;
+    local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+    local_addr.sin_port = htons(PORT);
+
+    s = make_sock(&local_addr);
+
+    new_argv = malloc(sizeof(char *) * (argc + 3));
+    new_argv[0] = HTTPD_PATH;
+    new_argv[1] = "-p";
+    sprintf(buf, "%d", s);
+    new_argv[2] = buf;
+    memcpy(new_argv + 3, argv + 1, sizeof(char *) * (argc - 1));
+    new_argv[argc+2] = NULL;
+
+    if (setgroups(0, NULL) == -1) {
+	perror("setgroups");
+	exit(1);
+    }
+    if (setgid(HTTP_GROUP) == -1) {
+	perror("setgid");
+	exit(1);
+    }
+    if (setuid(HTTP_USER) == -1) {
+	perror("setuid");
+	exit(1);
+    }
+    execve(HTTPD_PATH, new_argv, new_env);
+    perror("execve");
+    exit(1);
+}
