You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by Dean Gaudet <dg...@arctic.org> on 1998/03/26 06:50:29 UTC
arctic.patch
Hey I keep saying I'm always running HEAD... but the truth is I've always
got a few mods. Is there anything here that folks think I should clean up
and commit? This contains:
- the -p command line switch so that you can pass pre-opened sockets to
the server (so it doesn't need to run as root at all)
- listenwrap, which can be setuid root and spawn the server with a -p
option
- SymLinksIfGroupMatch, which I find absolutely necessary for systems that
have groups maintaining a web site... although I've stopped using it in
favour of mod_allowdev.
- gif89-expires-hack
- some extra debugging log messages
- the piped log child is spawned in its own process group, chdir()d to
server_root... this is so that you can use server_root relative paths in
the piped log command
- USE_MMAP_FILES is disabled. I did this last week for a very specific
reason... I'll post more later.
Dean
Index: include/http_core.h
===================================================================
RCS file: /export/home/cvs/apache-1.3/src/include/http_core.h,v
retrieving revision 1.39
diff -u -r1.39 http_core.h
--- http_core.h 1998/03/17 19:38:40 1.39
+++ http_core.h 1998/03/26 05:30:41
@@ -75,6 +75,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() */
@@ -136,7 +137,7 @@
/* Per-directory configuration */
-typedef unsigned char allow_options_t;
+typedef unsigned short allow_options_t;
typedef unsigned char overrides_t;
typedef struct {
Index: main/buff.c
===================================================================
RCS file: /export/home/cvs/apache-1.3/src/main/buff.c,v
retrieving revision 1.66
diff -u -r1.66 buff.c
--- buff.c 1998/03/25 02:57:22 1.66
+++ buff.c 1998/03/26 05:30:41
@@ -926,7 +926,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.
*/
@@ -944,6 +946,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;
@@ -1034,7 +1049,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.175
diff -u -r1.175 http_core.c
--- http_core.c 1998/03/17 19:38:42 1.175
+++ http_core.c 1998/03/26 05:30:41
@@ -66,6 +66,8 @@
#include "scoreboard.h"
#include "fnmatch.h"
+#undef USE_MMAP_FILES
+
#ifdef USE_MMAP_FILES
#include <sys/mman.h>
@@ -820,6 +822,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"))
@@ -1995,7 +1999,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;
}
@@ -2115,6 +2121,31 @@
if (d->content_md5 & 1) {
table_setn(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
@@ -2159,6 +2190,15 @@
MD5Update(&context, (void *)mm, r->finfo.st_size);
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 = 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.49
diff -u -r1.49 http_log.c
--- http_log.c 1998/03/17 07:54:19 1.49
+++ http_log.c 1998/03/26 05:30:42
@@ -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: main/http_main.c
===================================================================
RCS file: /export/home/cvs/apache-1.3/src/main/http_main.c,v
retrieving revision 1.311
diff -u -r1.311 http_main.c
--- http_main.c 1998/03/25 10:07:50 1.311
+++ http_main.c 1998/03/26 05:30:42
@@ -258,6 +258,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];
@@ -2753,6 +2754,9 @@
{
listen_rec *lr;
+ if (permanent_listeners) {
+ return;
+ }
ap_assert(old_listeners == NULL);
if (listeners == NULL) {
return;
@@ -2808,6 +2812,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;
@@ -3635,6 +3653,9 @@
* shut down gracefully, in case it happened to pick up a request
* while we were counting
*/
+ aplog_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, server_conf,
+ "server has %d children, %d are idle, killing one",
+ total_non_dead, idle_count);
kill(scoreboard_image->parent[to_kill].pid, SIGUSR1);
idle_spawn_rate = 1;
}
@@ -3906,6 +3927,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;
@@ -3924,9 +3997,9 @@
setup_prelinked_modules();
#ifdef DEBUG_SIGSTOP
- while ((c = getopt(argc, argv, "C:c:Xd:f:vVhlZ:")) != -1) {
+ while ((c = getopt(argc, argv, "C:c:Xd:f:vVhlZ:p:")) != -1) {
#else
- while ((c = getopt(argc, argv, "C:c:Xd:f:vVhl")) != -1) {
+ while ((c = getopt(argc, argv, "C:c:Xd:f:vVhlp:")) != -1) {
#endif
char **new;
switch (c) {
@@ -3957,6 +4030,9 @@
case 'l':
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.113
diff -u -r1.113 http_request.c
--- http_request.c 1998/03/17 07:54:22 1.113
+++ http_request.c 1998/03/26 05:30:43
@@ -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: modules/standard/mod_rewrite.c
===================================================================
RCS file: /export/home/cvs/apache-1.3/src/modules/standard/mod_rewrite.c,v
retrieving revision 1.93
diff -u -r1.93 mod_rewrite.c
--- mod_rewrite.c 1998/03/13 19:20:42 1.93
+++ mod_rewrite.c 1998/03/26 05:30:45
@@ -1247,7 +1247,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: support/.cvsignore
===================================================================
RCS file: /export/home/cvs/apache-1.3/src/support/.cvsignore,v
retrieving revision 1.5
diff -u -r1.5 .cvsignore
--- .cvsignore 1998/03/17 13:59:01 1.5
+++ .cvsignore 1998/03/26 05:30:47
@@ -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.12
diff -u -r1.12 Makefile.tmpl
--- Makefile.tmpl 1998/03/17 15:42:42 1.12
+++ Makefile.tmpl 1998/03/26 05:30:47
@@ -25,6 +25,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)
+
ab: ab.o
$(CC) $(INCLUDES) $(CFLAGS) ab.o -o ab $(LDFLAGS) $(LIBS)
Index: support/listenwrap.c
===================================================================
RCS file: listenwrap.c
diff -N listenwrap.c
--- /dev/null Wed Mar 25 21:30:00 1998
+++ listenwrap.c Wed Mar 25 21:30:47 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);
+}