-ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
+ScriptAlias /cgi-bin/ /home/httpd/cgi-bin/
-diff -bruN boa-0.94.8.2/request.c boa-0.94.8.2.pld/request.c
---- boa-0.94.8.2/request.c Thu Jan 1 01:00:00 1970
-+++ boa-0.94.8.2.pld/request.c Sun Sep 10 04:58:44 2000
-@@ -0,0 +1,660 @@
-+/*
-+ * Boa, an http server
-+ * Copyright (C) 1995 Paul Phillips <psp@well.com>
-+ * Some changes Copyright (C) 1996,97 Larry Doolittle <ldoolitt@jlab.org>
-+ * Some changes Copyright (C) 1996-99 Jon Nelson <jnelson@boa.org>
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 1, or (at your option)
-+ * any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ *
-+ */
-+
-+/* $Id$*/
-+
-+#include "boa.h"
-+#include <netinet/tcp.h>
-+#include <arpa/inet.h> /* inet_ntoa */
-+#include <stddef.h>
-+
-+int sockbufsize = SOCKETBUF_SIZE;
-+int total_connections;
-+
-+/*
-+ * Name: new_request
-+ * Description: Obtains a request struct off the free list, or if the
-+ * free list is empty, allocates memory
-+ *
-+ * Return value: pointer to initialized request
-+ */
-+
-+request *new_request(void)
-+{
-+ request *req;
-+
-+ if (request_free) {
-+ req = request_free; /* first on free list */
-+ dequeue(&request_free, request_free); /* dequeue the head */
-+ } else {
-+ req = (request *) malloc(sizeof (request));
-+ if (!req) {
-+ log_error_mesg(__FILE__, __LINE__,
-+ "out of memory allocating for new request structure");
-+ exit(errno);
-+ }
-+ }
-+
-+ memset(req, 0, offsetof(request, buffer) + 1);
-+
-+ return req;
-+}
-+
-+
-+/*
-+ * Name: get_request
-+ *
-+ * Description: Polls the server socket for a request. If one exists,
-+ * does some basic initialization and adds it to the ready queue;.
-+ */
-+
-+void get_request(int server_s)
-+{
-+ int fd; /* socket */
-+ struct SOCKADDR remote_addr; /* address */
-+ int remote_addrlen = sizeof (struct sockaddr_in);
-+ request *conn; /* connection */
-+ int len;
-+ static int system_bufsize = 0; /* Default size of SNDBUF given by system */
-+
-+ remote_addr.S_FAMILY = 0xdead;
-+ fd = accept(server_s, (struct sockaddr *) &remote_addr,
-+ &remote_addrlen);
-+
-+ if (fd == -1) {
-+ if (errno != EAGAIN && errno != EWOULDBLOCK) /* no requests */
-+ log_error_mesg(__FILE__, __LINE__, "accept");
-+ return;
-+ }
-+#ifdef DEBUGNONINET
-+ /* This shows up due to race conditions in some Linux kernels
-+ when the client closes the socket sometime between
-+ the select() and accept() syscalls.
-+ Code and description by Larry Doolittle <ldoolitt@boa.org>
-+ */
-+#define HEX(x) (((x)>9)?(('a'-10)+(x)):('0'+(x)))
-+ if (remote_addr.sin_family != AF_INET) {
-+ struct sockaddr *bogus = (struct sockaddr *) &remote_addr;
-+ char *ap, ablock[44];
-+ int i;
-+ close(fd);
-+ log_error_time();
-+ for (ap = ablock, i = 0; i < remote_addrlen && i < 14; i++) {
-+ *ap++ = ' ';
-+ *ap++ = HEX((bogus->sa_data[i] >> 4) & 0x0f);
-+ *ap++ = HEX(bogus->sa_data[i] & 0x0f);
-+ }
-+ *ap = '\0';
-+ fprintf(stderr, "non-INET connection attempt: socket %d, "
-+ "sa_family = %hu, sa_data[%d] = %s\n",
-+ fd, bogus->sa_family, remote_addrlen, ablock);
-+ return;
-+ }
-+#endif
-+
-+/* XXX Either delete this, or document why it's needed */
-+/* Pointed out 3-Oct-1999 by Paul Saab <paul@mu.org> */
-+#ifdef REUSE_EACH_CLIENT_CONNECTION_SOCKET
-+ if ((setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *) &sock_opt,
-+ sizeof (sock_opt))) == -1) {
-+ log_error_mesg(__FILE__, __LINE__,
-+ "setsockopt: unable to set SO_REUSEADDR");
-+ exit(errno);
-+ }
-+#endif
-+
-+ conn = new_request();
-+ conn->fd = fd;
-+ conn->status = READ_HEADER;
-+ conn->header_line = conn->client_stream;
-+ conn->time_last = current_time;
-+ conn->kacount = ka_max;
-+
-+ /* fill in local_ip_addr if relevant */
-+ if (virtualhost) {
-+ struct SOCKADDR salocal;
-+ int dummy = sizeof (salocal);
-+ if (getsockname(conn->fd, (struct sockaddr *) &salocal, &dummy) ==
-+ -1) {
-+ log_error_mesg(__FILE__, __LINE__, "getsockname");
-+ exit(errno);
-+ }
-+ ascii_sockaddr(&salocal, conn->local_ip_addr, NI_MAXHOST);
-+ }
-+
-+ /* nonblocking socket */
-+ if (fcntl(conn->fd, F_SETFL, NOBLOCK) == -1)
-+ log_error_mesg(__FILE__, __LINE__,
-+ "fcntl: unable to set new socket to non-block");
-+
-+ /* set close on exec to true */
-+ if (fcntl(conn->fd, F_SETFD, 1) == -1)
-+ log_error_mesg(__FILE__, __LINE__,
-+ "fctnl: unable to set close-on-exec for new socket");
-+
-+ /* Increase buffer size if we have to.
-+ * Only ask the system the buffer size on the first request,
-+ * and assume all subsequent sockets have the same size.
-+ */
-+ if (system_bufsize == 0) {
-+ len = sizeof (system_bufsize);
-+ if (getsockopt
-+ (conn->fd, SOL_SOCKET, SO_SNDBUF, &system_bufsize, &len) == 0
-+ && len == sizeof (system_bufsize)) {
-+ /*
-+ fprintf(stderr, "%sgetsockopt reports SNDBUF %d\n",
-+ get_commonlog_time(), system_bufsize);
-+ */
-+ ;
-+ } else {
-+ log_error_mesg(__FILE__, __LINE__, "getsockopt(SNDBUF)");
-+ system_bufsize = 1;
-+ }
-+ }
-+ if (system_bufsize < sockbufsize) {
-+ if (setsockopt
-+ (conn->fd, SOL_SOCKET, SO_SNDBUF, (void *) &sockbufsize,
-+ sizeof (sockbufsize)) == -1) {
-+ log_error_mesg(__FILE__, __LINE__,
-+ "setsockopt: unable to set socket buffer size");
-+#ifdef DIE_ON_ERROR_TUNING_SNDBUF
-+ exit(errno);
-+#endif
-+ }
-+ }
-+
-+ /* for log file and possible use by CGI programs */
-+ ascii_sockaddr(&remote_addr, conn->remote_ip_addr, NI_MAXHOST);
-+
-+ /* for possible use by CGI programs */
-+ /* the structure doesn't contain port
-+ conn->remote_port = ntohs(remote_addr.sin_port);
-+ */
-+ conn->remote_port = 0;
-+
-+ status.requests++;
-+
-+#ifdef USE_TCPNODELAY
-+ /* Thanks to Jef Poskanzer <jef@acme.com> for this tweak */
-+ {
-+ int one = 1;
-+ if (setsockopt(conn->fd, IPPROTO_TCP, TCP_NODELAY,
-+ (void *) &one, sizeof (one)) == -1) {
-+ log_error_mesg(__FILE__, __LINE__,
-+ "setsockopt: unable to set TCP_NODELAY");
-+ exit(errno);
-+ }
-+
-+ }
-+#endif
-+
-+ total_connections++;
-+ enqueue(&request_ready, conn);
-+}
-+
-+
-+/*
-+ * Name: free_request
-+ *
-+ * Description: Deallocates memory for a finished request and closes
-+ * down socket.
-+ */
-+
-+static void free_request(request ** list_head_addr, request * req)
-+{
-+ /* free_request should *never* get called by anything but
-+ process_requests */
-+
-+ if (req->buffer_end && req->status != DEAD) {
-+ req->status = DONE;
-+ return;
-+ }
-+ /* put request on the free list */
-+ dequeue(list_head_addr, req); /* dequeue from ready or block list */
-+
-+ FD_CLR(req->fd, &block_read_fdset);
-+ FD_CLR(req->fd, &block_write_fdset);
-+ FD_CLR(req->data_fd, &block_read_fdset);
-+ FD_CLR(req->post_data_fd, &block_write_fdset);
-+
-+ if (req->logline) /* access log */
-+ log_access(req);
-+
-+ if (req->mmap_entry_var)
-+ release_mmap(req->mmap_entry_var);
-+ else if (req->data_mem)
-+ munmap(req->data_mem, req->filesize);
-+
-+ if (req->data_fd)
-+ close(req->data_fd);
-+
-+ if (req->response_status >= 400)
-+ status.errors++;
-+
-+ if (req->cgi_env) {
-+ int i;
-+ for (i = COMMON_CGI_COUNT; i < req->cgi_env_index; ++i)
-+ if (req->cgi_env[i])
-+ free(req->cgi_env[i]);
-+ free(req->cgi_env);
-+ }
-+ if (req->pathname)
-+ free(req->pathname);
-+ if (req->path_info)
-+ free(req->path_info);
-+ if (req->path_translated)
-+ free(req->path_translated);
-+ if (req->script_name)
-+ free(req->script_name);
-+ if (req->query_string)
-+ free(req->query_string);
-+
-+ if ((req->keepalive == KA_ACTIVE) &&
-+ (req->response_status < 500) && req->kacount > 0) {
-+
-+ request *conn = new_request();
-+ conn->fd = req->fd;
-+ conn->status = READ_HEADER;
-+ conn->header_line = conn->client_stream;
-+ conn->kacount = req->kacount - 1;
-+
-+ /* close enough and we avoid a call to time(NULL) */
-+ conn->time_last = req->time_last;
-+
-+ /* for log file and possible use by CGI programs */
-+ memcpy(conn->remote_ip_addr, req->remote_ip_addr, NI_MAXHOST);
-+
-+ /* for possible use by CGI programs */
-+ conn->remote_port = req->remote_port;
-+
-+ status.requests++;
-+
-+ {
-+ int bytes_to_move;
-+
-+ /* we haven't parsed beyond req->parse_pos, so... */
-+ bytes_to_move = req->client_stream_pos - req->parse_pos;
-+
-+ if (bytes_to_move) {
-+ memcpy(conn->client_stream,
-+ req->client_stream + req->parse_pos, bytes_to_move);
-+ conn->client_stream_pos = bytes_to_move;
-+ FD_CLR(conn->fd, &block_read_fdset);
-+ enqueue(&request_ready, conn);
-+ } else {
-+ FD_SET(conn->fd, &block_read_fdset);
-+ enqueue(&request_block, conn);
-+ }
-+ }
-+ } else {
-+ close(req->fd);
-+ total_connections--;
-+ }
-+
-+ enqueue(&request_free, req);
-+
-+ return;
-+}
-+
-+/*
-+ * Name: process_requests
-+ *
-+ * Description: Iterates through the ready queue, passing each request
-+ * to the appropriate handler for processing. It monitors the
-+ * return value from handler functions, all of which return -1
-+ * to indicate a block, 0 on completion and 1 to remain on the
-+ * ready list for more procesing.
-+ */
-+
-+void process_requests(void)
-+{
-+ int retval = 0;
-+ request *current, *trailer;
-+
-+ current = request_ready;
-+
-+ while (current) {
-+ time(¤t_time);
-+ if (current->buffer_end && /* there is data in the buffer */
-+ current->status != DEAD && current->status != DONE) {
-+ retval = req_flush(current);
-+ /*
-+ * retval can be -2=error, -1=blocked, or bytes left
-+ */
-+ if (retval == -2) { /* error */
-+ current->status = DEAD;
-+ retval = 0;
-+ } else if (retval >= 0) {
-+ /* notice the >= which is different from below?
-+ Here, we may just be flushing headers.
-+ We don't want to return 0 because we are not DONE
-+ or DEAD */
-+
-+ retval = 1;
-+ }
-+ } else {
-+ switch (current->status) {
-+ case READ_HEADER:
-+ case ONE_CR:
-+ case ONE_LF:
-+ case TWO_CR:
-+ retval = read_header(current);
-+ break;
-+ case BODY_READ:
-+ retval = read_body(current);
-+ break;
-+ case BODY_WRITE:
-+ retval = write_body(current);
-+ break;
-+ case WRITE:
-+ retval = process_get(current);
-+ break;
-+ case PIPE_READ:
-+ retval = read_from_pipe(current);
-+ break;
-+ case PIPE_WRITE:
-+ retval = write_from_pipe(current);
-+ break;
-+ case DONE:
-+ /* a non-status that will terminate the request */
-+ retval = req_flush(current);
-+ /*
-+ * retval can be -2=error, -1=blocked, or bytes left
-+ */
-+ if (retval == -2) { /* error */
-+ current->status = DEAD;
-+ retval = 0;
-+ } else if (retval > 0) {
-+ retval = 1;
-+ }
-+ break;
-+ case DEAD:
-+ retval = 0;
-+ current->buffer_end = 0;
-+ SQUASH_KA(current);
-+ break;
-+ default:
-+ retval = 0;
-+ fprintf(stderr, "Unknown status (%d), "
-+ "closing!\n", current->status);
-+ current->status = DEAD;
-+ break;
-+ }
-+
-+ }
-+
-+ if (lame_duck_mode)
-+ SQUASH_KA(current);
-+
-+ switch (retval) {
-+ case -1: /* request blocked */
-+ trailer = current;
-+ current = current->next;
-+ block_request(trailer);
-+ break;
-+ case 0: /* request complete */
-+ current->time_last = current_time;
-+ trailer = current;
-+ current = current->next;
-+ free_request(&request_ready, trailer);
-+ break;
-+ case 1: /* more to do */
-+ current->time_last = current_time;
-+ current = current->next;
-+ break;
-+ default:
-+ log_error_time();
-+ fprintf(stderr, "Unknown retval in process.c - "
-+ "Status: %d, retval: %d\n", current->status, retval);
-+ current = current->next;
-+ break;
-+ }
-+ }
-+}
-+
-+/*
-+ * Name: process_logline
-+ *
-+ * Description: This is called with the first req->header_line received
-+ * by a request, called "logline" because it is logged to a file.
-+ * It is parsed to determine request type and method, then passed to
-+ * translate_uri for further parsing. Also sets up CGI environment if
-+ * needed.
-+ */
-+
-+int process_logline(request * req)
-+{
-+ char *stop, *stop2;
-+ static char *SIMPLE_HTTP_VERSION = "HTTP/0.9";
-+
-+ req->logline = req->client_stream;
-+ if (!memcmp(req->logline, "GET ", 4))
-+ req->method = M_GET;
-+ else if (!memcmp(req->logline, "HEAD ", 5))
-+ /* head is just get w/no body */
-+ req->method = M_HEAD;
-+ else if (!memcmp(req->logline, "POST ", 5))
-+ req->method = M_POST;
-+ else {
-+ log_error_time();
-+ fprintf(stderr, "malformed request: \"%s\"\n", req->logline);
-+ send_r_bad_request(req);
-+ return 0;
-+ }
-+
-+ /* Guaranteed to find ' ' since we matched a method above */
-+ stop = req->logline + 3;
-+ if (*stop != ' ')
-+ ++stop;
-+
-+ /* scan to start of non-whitespace */
-+ while (*(++stop) == ' ');
-+
-+ stop2 = stop;
-+
-+ /* scan to end of non-whitespace */
-+ while (*stop2 != '\0' && *stop2 != ' ')
-+ ++stop2;
-+
-+ if (stop2 - stop > MAX_HEADER_LENGTH) {
-+ log_error_time();
-+ fprintf(stderr, "URI too long %d: \"%s\"\n", MAX_HEADER_LENGTH,
-+ req->logline);
-+ send_r_bad_request(req);
-+ return 0;
-+ }
-+ memcpy(req->request_uri, stop, stop2 - stop);
-+ req->request_uri[stop2 - stop] = '\0';
-+
-+ if (*stop2 == ' ') {
-+ /* if found, we should get an HTTP/x.x */
-+ int p1, p2;
-+
-+ if (sscanf(++stop2, "HTTP/%d.%d", &p1, &p2) == 2 && p1 >= 1) {
-+ req->http_version = stop2;
-+ req->simple = 0;
-+ } else {
-+ log_error_time();
-+ fprintf(stderr, "bogus HTTP version: \"%s\"\n", stop2);
-+ send_r_bad_request(req);
-+ return 0;
-+ }
-+
-+ } else {
-+ req->http_version = SIMPLE_HTTP_VERSION;
-+ req->simple = 1;
-+ }
-+
-+ if (req->method == M_HEAD && req->simple) {
-+ send_r_bad_request(req);
-+ return 0;
-+ }
-+ if (translate_uri(req) == 0) { /* unescape, parse uri */
-+ SQUASH_KA(req);
-+ return 0; /* failure, close down */
-+ }
-+ if (req->is_cgi)
-+ create_env(req);
-+ return 1;
-+}
-+
-+/*
-+ * Name: process_header_end
-+ *
-+ * Description: takes a request and performs some final checking before
-+ * init_cgi or init_get
-+ * Returns 0 for error or NPH, or 1 for success
-+ */
-+
-+int process_header_end(request * req)
-+{
-+ if (!req->logline) {
-+ send_r_error(req);
-+ return 0;
-+ }
-+ if (req->method == M_POST) {
-+ char *tmpfilep = tmpnam(NULL);
-+
-+ if (!tmpfilep) {
-+ boa_perror(req, "tmpnam");
-+ return 0;
-+ }
-+ /* open temp file for post data */
-+ if ((req->post_data_fd = open(tmpfilep, O_RDWR | O_CREAT /* read-write, create */
-+ | O_EXCL, S_IRUSR /* don't overwrite, u+r */
-+ & ~S_IWUSR & ~S_IEXEC /* u-wx */
-+ & ~S_IRWXG /* g-rwx */
-+ & ~S_IRWXO)) == -1) { /* o-rwx */
-+ boa_perror(req, "tmpfile open");
-+ return 0;
-+ }
-+#ifndef REALLY_FASCIST_LOGGING
-+ unlink(tmpfilep);
-+#endif
-+ return 1;
-+ }
-+ if (req->is_cgi) {
-+ return init_cgi(req);
-+ }
-+ req->status = WRITE;
-+ return init_get(req); /* get and head */
-+}
-+
-+/*
-+ * Name: process_option_line
-+ *
-+ * Description: Parses the contents of req->header_line and takes
-+ * appropriate action.
-+ */
-+
-+void process_option_line(request * req)
-+{
-+ char c, *value, *line = req->header_line;
-+
-+ /* Start by aggressively hacking the in-place copy of the header line */
-+
-+#ifdef FASCIST_LOGGING
-+ log_error_time();
-+ fprintf(stderr, "%s:%d - Parsing \"%s\"\n", __FILE__, __LINE__, line);
-+#endif
-+
-+ value = strchr(line, ':');
-+ if (value == NULL)
-+ return;
-+ *value++ = '\0'; /* overwrite the : */
-+ to_upper(line); /* header types are case-insensitive */
-+ while ((c = *value) && (c == ' ' || c == '\t'))
-+ value++;
-+
-+ if (!memcmp(line, "IF_MODIFIED_SINCE", 18) && !req->if_modified_since)
-+ req->if_modified_since = value;
-+
-+ else if (!memcmp(line, "CONTENT_TYPE", 13) && !req->content_type)
-+ req->content_type = value;
-+
-+ else if (!memcmp(line, "CONTENT_LENGTH", 15) && !req->content_length)
-+ req->content_length = value;
-+
-+ else if (!memcmp(line, "CONNECTION", 11) &&
-+ ka_max && req->keepalive != KA_STOPPED) {
-+ req->keepalive = (!strncasecmp(value, "Keep-Alive", 10) ?
-+ KA_ACTIVE : KA_STOPPED);
-+ }
-+ /* #ifdef ACCEPT_ON */
-+ else if (!memcmp(line, "ACCEPT", 7))
-+ add_accept_header(req, value);
-+ /* #endif */
-+
-+ /* Need agent and referer for logs */
-+ else if (!memcmp(line, "REFERER", 8))
-+ req->header_referer = value;
-+ else if (!memcmp(line, "USER_AGENT", 11))
-+ req->header_user_agent = value;
-+
-+ /* Silently ignore unknown header lines unless is_cgi */
-+ else if (req->is_cgi)
-+ add_cgi_env(req, line, value);
-+ return;
-+}
-+
-+/*
-+ * Name: add_accept_header
-+ * Description: Adds a mime_type to a requests accept char buffer
-+ * silently ignore any that don't fit -
-+ * shouldn't happen because of relative buffer sizes
-+ */
-+
-+void add_accept_header(request * req, char *mime_type)
-+{
-+#ifdef ACCEPT_ON
-+ int l = strlen(req->accept);
-+ int l2 = strlen(mime_type);
-+
-+ if ((l + l2 + 2) >= MAX_HEADER_LENGTH)
-+ return;
-+
-+ if (req->accept[0] == '\0')
-+ strcpy(req->accept, mime_type);
-+ else {
-+ req->accept[l] = ',';
-+ req->accept[l + 1] = ' ';
-+ memcpy(req->accept + l + 2, mime_type, l2 + 1);
-+ /* the +1 is for the '\0' */
-+ /*
-+ sprintf(req->accept + l, ", %s", mime_type);
-+ */
-+ }
-+#endif
-+}
-+
-+void free_requests(void)
-+{
-+ request *ptr, *next;
-+
-+ ptr = request_free;
-+ while (ptr != NULL) {
-+ next = ptr->next;
-+ free(ptr);
-+ ptr = next;
-+ }
-+ request_free = NULL;
-+}
diff -bruN boa-0.94.8.2/src/Makefile.in boa-0.94.8.2.pld/src/Makefile.in
--- boa-0.94.8.2/src/Makefile.in Sat Feb 12 22:52:45 2000
+++ boa-0.94.8.2.pld/src/Makefile.in Sun Sep 10 04:37:16 2000
}
#ifdef WHEN_DOES_THIS_APPLY
if ((s->__ss_family == AF_INET6) &&
+diff -bruN boa-0.94.8.2/src/request.c boa-0.94.8.2.pld/src/request.c
+--- boa-0.94.8.2/src/request.c Fri May 26 04:46:03 2000
++++ boa-0.94.8.2.pld/src/request.c Sun Sep 10 04:58:44 2000
+@@ -186,7 +186,10 @@
+ ascii_sockaddr(&remote_addr, conn->remote_ip_addr, NI_MAXHOST);
+
+ /* for possible use by CGI programs */
++ /* the structure doesn't contain port
+ conn->remote_port = ntohs(remote_addr.sin_port);
++ */
++ conn->remote_port = 0;
+
+ status.requests++;
+