This is based on apache 1.3b4-dev ... which you can pick up at
dev.apache.org:/httpd/from-cvs/

There's more comments about it at
<http://www.arctic.org/~dgaudet/patches/apache-1.3-listenwrap.patch>,
and in the oct/nov 97 new-httpd maillogs at
dev.apache.org:/httpd/mail/

Dean

Index: src/main/buff.c
===================================================================
RCS file: /export/home/cvs/apachen/src/main/buff.c,v
retrieving revision 1.56
diff -u -r1.56 buff.c
--- buff.c	1998/01/13 23:11:07	1.56
+++ buff.c	1998/01/14 01:50:21
@@ -881,7 +881,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.
  */
@@ -899,6 +901,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;
@@ -989,7 +1004,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: src/main/http_core.c
===================================================================
RCS file: /export/home/cvs/apachen/src/main/http_core.c,v
retrieving revision 1.146
diff -u -r1.146 http_core.c
--- http_core.c	1998/01/13 23:11:10	1.146
+++ http_core.c	1998/01/14 01:50:21
@@ -724,6 +724,8 @@
 	    opt = OPT_SYM_LINKS;
 	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;
 	else if (!strcasecmp(w,"MultiViews"))
@@ -1773,7 +1775,9 @@
     if (r->proxyreq) return HTTP_FORBIDDEN;
     if ((r->uri[0] != '/') && strcmp(r->uri, "*")) {
 	aplog_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r->server,
-		    "Invalid URI in request %s", r->the_request);
+		    "(%s) Invalid URI in request %s",
+		    get_remote_host(r->connection, NULL, REMOTE_NOLOOKUP),
+		    r->the_request);
 	return BAD_REQUEST;
     }
     
@@ -1896,6 +1900,31 @@
 	if (d->content_md5 & 1) {
 	    table_set (r->headers_out, "Content-MD5", 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
+	    && 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) {
+		table_unset (r->headers_out, "Expires");
+		table_unset (r->headers_out, "Cache-Control");
+	    }
+	    fseek (f, 0L, SEEK_SET);
+#undef GIF_HEADER_LEN
+	}
 
 	rangestatus = set_byterange(r);
 #ifdef CHARSET_EBCDIC
@@ -1957,6 +1986,15 @@
 	    MD5Update(&context, (void *)mm, r->finfo.st_size);
 	    table_set (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 = set_byterange(r);
Index: src/main/http_core.h
===================================================================
RCS file: /export/home/cvs/apachen/src/main/http_core.h,v
retrieving revision 1.30
diff -u -r1.30 http_core.h
--- http_core.h	1998/01/07 16:46:04	1.30
+++ http_core.h	1998/01/14 01:50:21
@@ -72,6 +72,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() */
@@ -126,7 +127,7 @@
 
 /* Per-directory configuration */
 
-typedef unsigned char allow_options_t;
+typedef unsigned short allow_options_t;
 typedef unsigned char overrides_t;
 
 typedef struct {
Index: src/main/http_log.c
===================================================================
RCS file: /export/home/cvs/apachen/src/main/http_log.c,v
retrieving revision 1.48
diff -u -r1.48 http_log.c
--- http_log.c	1998/01/07 16:46:05	1.48
+++ http_log.c	1998/01/14 01:50:21
@@ -65,6 +65,7 @@
 #include "http_core.h"
 #include "http_log.h"
 #include "http_main.h"
+#include "http_conf_globals.h"
 
 #include <stdarg.h>
 
@@ -385,15 +386,15 @@
 }
     
 
-void log_pid (pool *p, char *pid_fname)
+void log_pid (pool *p, char *fname)
 {
     FILE *pid_file;
 
-    if (!pid_fname) return;
-    pid_fname = server_root_relative (p, pid_fname);
-    if(!(pid_file = fopen(pid_fname,"w"))) {
+    if (!fname) return;
+    fname = server_root_relative (p, fname);
+    if(!(pid_file = fopen(fname,"w"))) {
 	perror("fopen");
-        fprintf(stderr,"httpd: could not log pid to file %s\n", pid_fname);
+        fprintf(stderr,"httpd: could not log pid to file %s\n", fname);
         exit(1);
     }
     fprintf(pid_file,"%ld\n",(long)getpid());
@@ -452,6 +453,7 @@
 static int piped_log_spawn (piped_log *pl)
 {
     int pid;
+    int pgrp;
 
     block_alarms();
     pid = fork();
@@ -462,6 +464,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(server_root) == -1) {
+	    aplog_error(APLOG_MARK, APLOG_CRIT, NULL,
+		"logger: unable to chdir(%s)", server_root);
+	    exit (1);
+	}
+#ifndef NO_SETSID
+	if ((pgrp = setsid()) == -1) {
+	    aplog_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) {
+	    aplog_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) {
+	    aplog_error(APLOG_MARK, APLOG_CRIT, NULL, "logger: setpgrp failed");
+	    exit(1);
+	}
+#endif
 	close (STDIN_FILENO);
 	dup2 (pl->fds[0], STDIN_FILENO);
 
@@ -491,6 +523,9 @@
 {
     piped_log *pl = data;
 
+    aplog_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: src/main/http_main.c
===================================================================
RCS file: /export/home/cvs/apachen/src/main/http_main.c,v
retrieving revision 1.268
diff -u -r1.268 http_main.c
--- http_main.c	1998/01/13 23:11:11	1.268
+++ http_main.c	1998/01/14 01:50:22
@@ -226,6 +226,7 @@
  */
 listen_rec *listeners;
 static listen_rec *head_listener;
+static listen_rec *permanent_listeners;
 
 char server_root[MAX_STRING_LEN];
 char server_confname[MAX_STRING_LEN];
@@ -2606,6 +2607,9 @@
 {
     listen_rec *lr;
 
+    if (permanent_listeners) {
+	return;
+    }
     ap_assert(old_listeners == NULL);
     if (listeners == NULL) {
 	return;
@@ -2661,6 +2665,20 @@
     listen_rec *lr;
     int fd;
 
+    if (permanent_listeners) {
+	lr = permanent_listeners;
+	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 = listeners;
@@ -3011,15 +3029,24 @@
 		break;		/* We have a socket ready for reading */
 	    else {
 
-#if defined(EPROTO) && defined(ECONNABORTED)
-		if ((errno != EPROTO) && (errno != ECONNABORTED))
-#elif defined(EPROTO)
-		    if (errno != EPROTO)
-#elif defined(ECONNABORTED)
-			if (errno != ECONNABORTED)
+		switch (errno) {
+#ifdef EPROTO
+		case EPROTO:
 #endif
-			    aplog_error(APLOG_MARK, APLOG_ERR, server_conf,
-					"accept: (client socket)");
+#ifdef ECONNABORTED
+		case ECONNABORTED:
+#endif
+#ifdef ECONNRESET
+		case ECONNRESET:
+#endif
+#ifdef ETIMEDOUT
+		case ETIMEDOUT:
+#endif
+		    break;
+		default:
+		    aplog_error(APLOG_MARK, APLOG_ERR, server_conf,
+				"accept: (client socket)");
+		}
 	    }
 
 	    /* go around again, safe to die */
@@ -3601,6 +3628,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) {
+	aplog_error(APLOG_MARK, APLOG_ERR, NULL,
+	    "error parsing arg -p '%s', skipping", arg);
+	return;
+    }
+
+    if (local_addr.sin_family != AF_INET) {
+	aplog_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)) {
+	aplog_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) {
+	aplog_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;
 
@@ -3636,7 +3715,7 @@
 
     setup_prelinked_modules();
 
-    while ((c = getopt(argc, argv, "C:c:Xd:f:vVhlZ:")) != -1) {
+    while ((c = getopt(argc, argv, "C:c:Xd:f:vVhlZ:p:")) != -1) {
 	char **new;
 	switch (c) {
 	case 'c':
@@ -3666,6 +3745,9 @@
 	case 'l':
 	    show_modules();
 	    exit(0);
+	case 'p':
+	    pre_opened_socket(optarg);
+	    break;
 	case 'X':
 	    ++one_process;	/* Weird debugging mode. */
 	    break;
Index: src/main/http_request.c
===================================================================
RCS file: /export/home/cvs/apachen/src/main/http_request.c,v
retrieving revision 1.99
diff -u -r1.99 http_request.c
--- http_request.c	1998/01/11 20:55:18	1.99
+++ http_request.c	1998/01/14 01:50:22
@@ -153,13 +153,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: src/main/util.c
===================================================================
RCS file: /export/home/cvs/apachen/src/main/util.c,v
retrieving revision 1.84
diff -u -r1.84 util.c
--- util.c	1998/01/13 23:11:14	1.84
+++ util.c	1998/01/14 01:50:22
@@ -793,7 +793,7 @@
 		/* increase line number and return on LF */
 		++cfp->line_number;
 	    }
-	    if (c == EOF || c == 0x4 || c == LF || i == (bufsize - 1)) {
+	    if (c == EOF || c == 0x4 || c == LF || i >= (bufsize - 2)) {
 		/* blast trailing whitespace */
 		while (i > 0 && isspace(buf[i - 1]))
 		    --i;
Index: src/modules/proxy/mod_proxy.c
===================================================================
RCS file: /export/home/cvs/apachen/src/modules/proxy/mod_proxy.c,v
retrieving revision 1.30
diff -u -r1.30 mod_proxy.c
--- mod_proxy.c	1998/01/07 16:46:34	1.30
+++ mod_proxy.c	1998/01/14 01:50:25
@@ -82,10 +82,10 @@
 /* -------------------------------------------------------------- */
 /* Translate the URL into a 'filename' */
 
-static int alias_match(char *uri, char *alias_fakename)
+static int alias_match(const char *uri, const char *alias_fakename)
 {
-    char *end_fakename = alias_fakename + strlen(alias_fakename);
-    char *aliasp = alias_fakename, *urip = uri;
+    const char *end_fakename = alias_fakename + strlen(alias_fakename);
+    const char *aliasp = alias_fakename, *urip = uri;
 
     while (aliasp < end_fakename) {
 	if (*aliasp == '/') {
Index: src/modules/standard/mod_rewrite.c
===================================================================
RCS file: /export/home/cvs/apachen/src/modules/standard/mod_rewrite.c,v
retrieving revision 1.61
diff -u -r1.61 mod_rewrite.c
--- mod_rewrite.c	1998/01/13 23:11:26	1.61
+++ mod_rewrite.c	1998/01/14 01:50:27
@@ -1184,7 +1184,7 @@
      *  only do something under runtime if the engine is really enabled,
      *  for this directory, else return immediately!
      */
-    if (!(allow_options(r) & (OPT_SYM_LINKS | OPT_SYM_OWNER))) {
+    if (!(allow_options(r) & (OPT_SYM_LINKS | OPT_SYM_OWNER | OPT_SYM_GROUP))) {
         /* FollowSymLinks is mandatory! */
         aplog_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r->server,
                     "Options FollowSymLinks or SymLinksIfOwnerMatch is off "
Index: src/support/Makefile.tmpl
===================================================================
RCS file: /export/home/cvs/apachen/src/support/Makefile.tmpl,v
retrieving revision 1.8
diff -u -r1.8 Makefile.tmpl
--- Makefile.tmpl	1997/11/15 19:04:54	1.8
+++ Makefile.tmpl	1998/01/14 01:50:29
@@ -27,6 +27,9 @@
 logresolve: logresolve.o
 	$(CC) $(INCLUDES) $(CFLAGS) logresolve.o -o logresolve $(LDFLAGS) $(LIBS)
 
+listenwrap: listenwrap.o
+	$(CC) $(INCLUDES) $(CFLAGS) listenwrap.o -o listenwrap $(LDFLAGS) $(LIBS)
+
 clean:
 	rm -f $(TARGETS) *.o
 
Index: src/support/listenwrap.c
===================================================================
RCS file: listenwrap.c
diff -N listenwrap.c
--- /dev/null	Tue Jan 13 17:50:00 1998
+++ listenwrap.c	Tue Jan 13 17:50:29 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);
+}
