1 diff -bruN boa-0.94.8.2/boa.conf boa-0.94.8.2.pld/boa.conf
2 --- boa-0.94.8.2/boa.conf Sun Jan 30 02:39:48 2000
3 +++ boa-0.94.8.2.pld/boa.conf Sun Sep 10 04:35:38 2000
5 # User: The name or UID the server should run as.
6 # Group: The group name or GID the server should run as.
13 # ServerAdmin: The email address where server problems should be sent.
14 # Note: this is not currently used, except as an environment variable
16 # Set to /dev/null if you don't want errors logged.
17 # If unset, defaults to /dev/stderr
19 -ErrorLog /var/log/boa/error_log
20 +ErrorLog /var/log/httpd/error_log
21 # Please NOTE: Sending the logs to a pipe ('|'), as shown below,
22 # is somewhat experimental and might fail under heavy load.
23 # "Usual libc implementations of printf will stall the whole
25 # Comment out or set to /dev/null (less effective) to disable
28 -AccessLog /var/log/boa/access_log
29 +AccessLog /var/log/httpd/access_log
30 # Please NOTE: Sending the logs to a pipe ('|'), as shown below,
31 # is somewhat experimental and might fail under heavy load.
32 # "Usual libc implementations of printf will stall the whole
34 # DocumentRoot: The root directory of the HTML documents.
35 # Comment out to disable server non user files.
37 -DocumentRoot /var/www
38 +DocumentRoot /home/httpd/html
40 # UserDir: The name of the directory which is appended onto a user's home
41 # directory if a ~user request is recieved.
43 # DirectoryIndex are commented out, accessing a directory will give
44 # an error (though accessing files in the directory are still ok).
46 -DirectoryMaker /usr/lib/boa/boa_indexer
47 +DirectoryMaker /usr/sbin/boa/boa_indexer
49 # DirectoryCache: If DirectoryIndex doesn't exist, and DirectoryMaker
50 # has been commented out, the the on-the-fly indexing of Boa can be used
52 # ScriptAlias: Maps a virtual path to a directory for serving scripts
53 # Example: ScriptAlias /htbin/ /www/htbin/
55 -ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
56 +ScriptAlias /cgi-bin/ /home/httpd/cgi-bin/
58 diff -bruN boa-0.94.8.2/request.c boa-0.94.8.2.pld/request.c
59 --- boa-0.94.8.2/request.c Thu Jan 1 01:00:00 1970
60 +++ boa-0.94.8.2.pld/request.c Sun Sep 10 04:58:44 2000
63 + * Boa, an http server
64 + * Copyright (C) 1995 Paul Phillips <psp@well.com>
65 + * Some changes Copyright (C) 1996,97 Larry Doolittle <ldoolitt@jlab.org>
66 + * Some changes Copyright (C) 1996-99 Jon Nelson <jnelson@boa.org>
68 + * This program is free software; you can redistribute it and/or modify
69 + * it under the terms of the GNU General Public License as published by
70 + * the Free Software Foundation; either version 1, or (at your option)
71 + * any later version.
73 + * This program is distributed in the hope that it will be useful,
74 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
75 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
76 + * GNU General Public License for more details.
78 + * You should have received a copy of the GNU General Public License
79 + * along with this program; if not, write to the Free Software
80 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
87 +#include <netinet/tcp.h>
88 +#include <arpa/inet.h> /* inet_ntoa */
91 +int sockbufsize = SOCKETBUF_SIZE;
92 +int total_connections;
96 + * Description: Obtains a request struct off the free list, or if the
97 + * free list is empty, allocates memory
99 + * Return value: pointer to initialized request
102 +request *new_request(void)
106 + if (request_free) {
107 + req = request_free; /* first on free list */
108 + dequeue(&request_free, request_free); /* dequeue the head */
110 + req = (request *) malloc(sizeof (request));
112 + log_error_mesg(__FILE__, __LINE__,
113 + "out of memory allocating for new request structure");
118 + memset(req, 0, offsetof(request, buffer) + 1);
125 + * Name: get_request
127 + * Description: Polls the server socket for a request. If one exists,
128 + * does some basic initialization and adds it to the ready queue;.
131 +void get_request(int server_s)
133 + int fd; /* socket */
134 + struct SOCKADDR remote_addr; /* address */
135 + int remote_addrlen = sizeof (struct sockaddr_in);
136 + request *conn; /* connection */
138 + static int system_bufsize = 0; /* Default size of SNDBUF given by system */
140 + remote_addr.S_FAMILY = 0xdead;
141 + fd = accept(server_s, (struct sockaddr *) &remote_addr,
145 + if (errno != EAGAIN && errno != EWOULDBLOCK) /* no requests */
146 + log_error_mesg(__FILE__, __LINE__, "accept");
150 + /* This shows up due to race conditions in some Linux kernels
151 + when the client closes the socket sometime between
152 + the select() and accept() syscalls.
153 + Code and description by Larry Doolittle <ldoolitt@boa.org>
155 +#define HEX(x) (((x)>9)?(('a'-10)+(x)):('0'+(x)))
156 + if (remote_addr.sin_family != AF_INET) {
157 + struct sockaddr *bogus = (struct sockaddr *) &remote_addr;
158 + char *ap, ablock[44];
162 + for (ap = ablock, i = 0; i < remote_addrlen && i < 14; i++) {
164 + *ap++ = HEX((bogus->sa_data[i] >> 4) & 0x0f);
165 + *ap++ = HEX(bogus->sa_data[i] & 0x0f);
168 + fprintf(stderr, "non-INET connection attempt: socket %d, "
169 + "sa_family = %hu, sa_data[%d] = %s\n",
170 + fd, bogus->sa_family, remote_addrlen, ablock);
175 +/* XXX Either delete this, or document why it's needed */
176 +/* Pointed out 3-Oct-1999 by Paul Saab <paul@mu.org> */
177 +#ifdef REUSE_EACH_CLIENT_CONNECTION_SOCKET
178 + if ((setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *) &sock_opt,
179 + sizeof (sock_opt))) == -1) {
180 + log_error_mesg(__FILE__, __LINE__,
181 + "setsockopt: unable to set SO_REUSEADDR");
186 + conn = new_request();
188 + conn->status = READ_HEADER;
189 + conn->header_line = conn->client_stream;
190 + conn->time_last = current_time;
191 + conn->kacount = ka_max;
193 + /* fill in local_ip_addr if relevant */
195 + struct SOCKADDR salocal;
196 + int dummy = sizeof (salocal);
197 + if (getsockname(conn->fd, (struct sockaddr *) &salocal, &dummy) ==
199 + log_error_mesg(__FILE__, __LINE__, "getsockname");
202 + ascii_sockaddr(&salocal, conn->local_ip_addr, NI_MAXHOST);
205 + /* nonblocking socket */
206 + if (fcntl(conn->fd, F_SETFL, NOBLOCK) == -1)
207 + log_error_mesg(__FILE__, __LINE__,
208 + "fcntl: unable to set new socket to non-block");
210 + /* set close on exec to true */
211 + if (fcntl(conn->fd, F_SETFD, 1) == -1)
212 + log_error_mesg(__FILE__, __LINE__,
213 + "fctnl: unable to set close-on-exec for new socket");
215 + /* Increase buffer size if we have to.
216 + * Only ask the system the buffer size on the first request,
217 + * and assume all subsequent sockets have the same size.
219 + if (system_bufsize == 0) {
220 + len = sizeof (system_bufsize);
222 + (conn->fd, SOL_SOCKET, SO_SNDBUF, &system_bufsize, &len) == 0
223 + && len == sizeof (system_bufsize)) {
225 + fprintf(stderr, "%sgetsockopt reports SNDBUF %d\n",
226 + get_commonlog_time(), system_bufsize);
230 + log_error_mesg(__FILE__, __LINE__, "getsockopt(SNDBUF)");
231 + system_bufsize = 1;
234 + if (system_bufsize < sockbufsize) {
236 + (conn->fd, SOL_SOCKET, SO_SNDBUF, (void *) &sockbufsize,
237 + sizeof (sockbufsize)) == -1) {
238 + log_error_mesg(__FILE__, __LINE__,
239 + "setsockopt: unable to set socket buffer size");
240 +#ifdef DIE_ON_ERROR_TUNING_SNDBUF
246 + /* for log file and possible use by CGI programs */
247 + ascii_sockaddr(&remote_addr, conn->remote_ip_addr, NI_MAXHOST);
249 + /* for possible use by CGI programs */
250 + /* the structure doesn't contain port
251 + conn->remote_port = ntohs(remote_addr.sin_port);
253 + conn->remote_port = 0;
257 +#ifdef USE_TCPNODELAY
258 + /* Thanks to Jef Poskanzer <jef@acme.com> for this tweak */
261 + if (setsockopt(conn->fd, IPPROTO_TCP, TCP_NODELAY,
262 + (void *) &one, sizeof (one)) == -1) {
263 + log_error_mesg(__FILE__, __LINE__,
264 + "setsockopt: unable to set TCP_NODELAY");
271 + total_connections++;
272 + enqueue(&request_ready, conn);
277 + * Name: free_request
279 + * Description: Deallocates memory for a finished request and closes
283 +static void free_request(request ** list_head_addr, request * req)
285 + /* free_request should *never* get called by anything but
286 + process_requests */
288 + if (req->buffer_end && req->status != DEAD) {
289 + req->status = DONE;
292 + /* put request on the free list */
293 + dequeue(list_head_addr, req); /* dequeue from ready or block list */
295 + FD_CLR(req->fd, &block_read_fdset);
296 + FD_CLR(req->fd, &block_write_fdset);
297 + FD_CLR(req->data_fd, &block_read_fdset);
298 + FD_CLR(req->post_data_fd, &block_write_fdset);
300 + if (req->logline) /* access log */
303 + if (req->mmap_entry_var)
304 + release_mmap(req->mmap_entry_var);
305 + else if (req->data_mem)
306 + munmap(req->data_mem, req->filesize);
309 + close(req->data_fd);
311 + if (req->response_status >= 400)
314 + if (req->cgi_env) {
316 + for (i = COMMON_CGI_COUNT; i < req->cgi_env_index; ++i)
317 + if (req->cgi_env[i])
318 + free(req->cgi_env[i]);
319 + free(req->cgi_env);
322 + free(req->pathname);
323 + if (req->path_info)
324 + free(req->path_info);
325 + if (req->path_translated)
326 + free(req->path_translated);
327 + if (req->script_name)
328 + free(req->script_name);
329 + if (req->query_string)
330 + free(req->query_string);
332 + if ((req->keepalive == KA_ACTIVE) &&
333 + (req->response_status < 500) && req->kacount > 0) {
335 + request *conn = new_request();
336 + conn->fd = req->fd;
337 + conn->status = READ_HEADER;
338 + conn->header_line = conn->client_stream;
339 + conn->kacount = req->kacount - 1;
341 + /* close enough and we avoid a call to time(NULL) */
342 + conn->time_last = req->time_last;
344 + /* for log file and possible use by CGI programs */
345 + memcpy(conn->remote_ip_addr, req->remote_ip_addr, NI_MAXHOST);
347 + /* for possible use by CGI programs */
348 + conn->remote_port = req->remote_port;
355 + /* we haven't parsed beyond req->parse_pos, so... */
356 + bytes_to_move = req->client_stream_pos - req->parse_pos;
358 + if (bytes_to_move) {
359 + memcpy(conn->client_stream,
360 + req->client_stream + req->parse_pos, bytes_to_move);
361 + conn->client_stream_pos = bytes_to_move;
362 + FD_CLR(conn->fd, &block_read_fdset);
363 + enqueue(&request_ready, conn);
365 + FD_SET(conn->fd, &block_read_fdset);
366 + enqueue(&request_block, conn);
371 + total_connections--;
374 + enqueue(&request_free, req);
380 + * Name: process_requests
382 + * Description: Iterates through the ready queue, passing each request
383 + * to the appropriate handler for processing. It monitors the
384 + * return value from handler functions, all of which return -1
385 + * to indicate a block, 0 on completion and 1 to remain on the
386 + * ready list for more procesing.
389 +void process_requests(void)
392 + request *current, *trailer;
394 + current = request_ready;
397 + time(¤t_time);
398 + if (current->buffer_end && /* there is data in the buffer */
399 + current->status != DEAD && current->status != DONE) {
400 + retval = req_flush(current);
402 + * retval can be -2=error, -1=blocked, or bytes left
404 + if (retval == -2) { /* error */
405 + current->status = DEAD;
407 + } else if (retval >= 0) {
408 + /* notice the >= which is different from below?
409 + Here, we may just be flushing headers.
410 + We don't want to return 0 because we are not DONE
416 + switch (current->status) {
421 + retval = read_header(current);
424 + retval = read_body(current);
427 + retval = write_body(current);
430 + retval = process_get(current);
433 + retval = read_from_pipe(current);
436 + retval = write_from_pipe(current);
439 + /* a non-status that will terminate the request */
440 + retval = req_flush(current);
442 + * retval can be -2=error, -1=blocked, or bytes left
444 + if (retval == -2) { /* error */
445 + current->status = DEAD;
447 + } else if (retval > 0) {
453 + current->buffer_end = 0;
454 + SQUASH_KA(current);
458 + fprintf(stderr, "Unknown status (%d), "
459 + "closing!\n", current->status);
460 + current->status = DEAD;
466 + if (lame_duck_mode)
467 + SQUASH_KA(current);
470 + case -1: /* request blocked */
472 + current = current->next;
473 + block_request(trailer);
475 + case 0: /* request complete */
476 + current->time_last = current_time;
478 + current = current->next;
479 + free_request(&request_ready, trailer);
481 + case 1: /* more to do */
482 + current->time_last = current_time;
483 + current = current->next;
487 + fprintf(stderr, "Unknown retval in process.c - "
488 + "Status: %d, retval: %d\n", current->status, retval);
489 + current = current->next;
496 + * Name: process_logline
498 + * Description: This is called with the first req->header_line received
499 + * by a request, called "logline" because it is logged to a file.
500 + * It is parsed to determine request type and method, then passed to
501 + * translate_uri for further parsing. Also sets up CGI environment if
505 +int process_logline(request * req)
507 + char *stop, *stop2;
508 + static char *SIMPLE_HTTP_VERSION = "HTTP/0.9";
510 + req->logline = req->client_stream;
511 + if (!memcmp(req->logline, "GET ", 4))
512 + req->method = M_GET;
513 + else if (!memcmp(req->logline, "HEAD ", 5))
514 + /* head is just get w/no body */
515 + req->method = M_HEAD;
516 + else if (!memcmp(req->logline, "POST ", 5))
517 + req->method = M_POST;
520 + fprintf(stderr, "malformed request: \"%s\"\n", req->logline);
521 + send_r_bad_request(req);
525 + /* Guaranteed to find ' ' since we matched a method above */
526 + stop = req->logline + 3;
530 + /* scan to start of non-whitespace */
531 + while (*(++stop) == ' ');
535 + /* scan to end of non-whitespace */
536 + while (*stop2 != '\0' && *stop2 != ' ')
539 + if (stop2 - stop > MAX_HEADER_LENGTH) {
541 + fprintf(stderr, "URI too long %d: \"%s\"\n", MAX_HEADER_LENGTH,
543 + send_r_bad_request(req);
546 + memcpy(req->request_uri, stop, stop2 - stop);
547 + req->request_uri[stop2 - stop] = '\0';
549 + if (*stop2 == ' ') {
550 + /* if found, we should get an HTTP/x.x */
553 + if (sscanf(++stop2, "HTTP/%d.%d", &p1, &p2) == 2 && p1 >= 1) {
554 + req->http_version = stop2;
558 + fprintf(stderr, "bogus HTTP version: \"%s\"\n", stop2);
559 + send_r_bad_request(req);
564 + req->http_version = SIMPLE_HTTP_VERSION;
568 + if (req->method == M_HEAD && req->simple) {
569 + send_r_bad_request(req);
572 + if (translate_uri(req) == 0) { /* unescape, parse uri */
574 + return 0; /* failure, close down */
582 + * Name: process_header_end
584 + * Description: takes a request and performs some final checking before
585 + * init_cgi or init_get
586 + * Returns 0 for error or NPH, or 1 for success
589 +int process_header_end(request * req)
591 + if (!req->logline) {
595 + if (req->method == M_POST) {
596 + char *tmpfilep = tmpnam(NULL);
599 + boa_perror(req, "tmpnam");
602 + /* open temp file for post data */
603 + if ((req->post_data_fd = open(tmpfilep, O_RDWR | O_CREAT /* read-write, create */
604 + | O_EXCL, S_IRUSR /* don't overwrite, u+r */
605 + & ~S_IWUSR & ~S_IEXEC /* u-wx */
606 + & ~S_IRWXG /* g-rwx */
607 + & ~S_IRWXO)) == -1) { /* o-rwx */
608 + boa_perror(req, "tmpfile open");
611 +#ifndef REALLY_FASCIST_LOGGING
617 + return init_cgi(req);
619 + req->status = WRITE;
620 + return init_get(req); /* get and head */
624 + * Name: process_option_line
626 + * Description: Parses the contents of req->header_line and takes
627 + * appropriate action.
630 +void process_option_line(request * req)
632 + char c, *value, *line = req->header_line;
634 + /* Start by aggressively hacking the in-place copy of the header line */
636 +#ifdef FASCIST_LOGGING
638 + fprintf(stderr, "%s:%d - Parsing \"%s\"\n", __FILE__, __LINE__, line);
641 + value = strchr(line, ':');
644 + *value++ = '\0'; /* overwrite the : */
645 + to_upper(line); /* header types are case-insensitive */
646 + while ((c = *value) && (c == ' ' || c == '\t'))
649 + if (!memcmp(line, "IF_MODIFIED_SINCE", 18) && !req->if_modified_since)
650 + req->if_modified_since = value;
652 + else if (!memcmp(line, "CONTENT_TYPE", 13) && !req->content_type)
653 + req->content_type = value;
655 + else if (!memcmp(line, "CONTENT_LENGTH", 15) && !req->content_length)
656 + req->content_length = value;
658 + else if (!memcmp(line, "CONNECTION", 11) &&
659 + ka_max && req->keepalive != KA_STOPPED) {
660 + req->keepalive = (!strncasecmp(value, "Keep-Alive", 10) ?
661 + KA_ACTIVE : KA_STOPPED);
663 + /* #ifdef ACCEPT_ON */
664 + else if (!memcmp(line, "ACCEPT", 7))
665 + add_accept_header(req, value);
668 + /* Need agent and referer for logs */
669 + else if (!memcmp(line, "REFERER", 8))
670 + req->header_referer = value;
671 + else if (!memcmp(line, "USER_AGENT", 11))
672 + req->header_user_agent = value;
674 + /* Silently ignore unknown header lines unless is_cgi */
675 + else if (req->is_cgi)
676 + add_cgi_env(req, line, value);
681 + * Name: add_accept_header
682 + * Description: Adds a mime_type to a requests accept char buffer
683 + * silently ignore any that don't fit -
684 + * shouldn't happen because of relative buffer sizes
687 +void add_accept_header(request * req, char *mime_type)
690 + int l = strlen(req->accept);
691 + int l2 = strlen(mime_type);
693 + if ((l + l2 + 2) >= MAX_HEADER_LENGTH)
696 + if (req->accept[0] == '\0')
697 + strcpy(req->accept, mime_type);
699 + req->accept[l] = ',';
700 + req->accept[l + 1] = ' ';
701 + memcpy(req->accept + l + 2, mime_type, l2 + 1);
702 + /* the +1 is for the '\0' */
704 + sprintf(req->accept + l, ", %s", mime_type);
710 +void free_requests(void)
712 + request *ptr, *next;
714 + ptr = request_free;
715 + while (ptr != NULL) {
720 + request_free = NULL;
722 diff -bruN boa-0.94.8.2/src/Makefile.in boa-0.94.8.2.pld/src/Makefile.in
723 --- boa-0.94.8.2/src/Makefile.in Sat Feb 12 22:52:45 2000
724 +++ boa-0.94.8.2.pld/src/Makefile.in Sun Sep 10 04:37:16 2000
726 # Add -pg to CFLAGS and LDFLAGS to get profiling output with gcc/gprof
729 -CFLAGS = -O -Wall -g
730 +CFLAGS = $(RPM_OPT_FLAGS) -DINET6
732 # Change these if necessary
734 diff -bruN boa-0.94.8.2/src/defines.h boa-0.94.8.2.pld/src/defines.h
735 --- boa-0.94.8.2/src/defines.h Mon May 1 22:33:25 2000
736 +++ boa-0.94.8.2.pld/src/defines.h Sun Sep 10 04:38:02 2000
738 /***** Change this, or use -c on the command line to specify it *****/
741 -#define SERVER_ROOT "/etc/boa"
742 +#define SERVER_ROOT "/etc/httpd"
745 /***** Various stuff that you may want to tweak, but probably shouldn't *****/
746 diff -bruN boa-0.94.8.2/src/ip.c boa-0.94.8.2.pld/src/ip.c
747 --- boa-0.94.8.2/src/ip.c Sat Feb 12 22:52:45 2000
748 +++ boa-0.94.8.2.pld/src/ip.c Sun Sep 10 04:47:32 2000
750 dest, len, NULL, 0, NI_NUMERICHOST)) {
751 fprintf(stderr, "[IPv6] getnameinfo failed\n");
754 - conn->local_ip_addr = strdup(host);
756 #ifdef WHEN_DOES_THIS_APPLY
757 if ((s->__ss_family == AF_INET6) &&