httpd.c
资源名称:httpd.tar.gz [点击查看]
上传用户:lampled
上传日期:2007-01-07
资源大小:94k
文件大小:28k
源码类别:
Web服务器
开发平台:
Unix_Linux
- /* Copyright (C) 1995, 1996 by Sven Berkvens (sven@stack.nl) */
- #include "config.h"
- #include <sys/types.h>
- #ifdef HAVE_SYS_TIME_H
- #include <sys/time.h>
- #endif /* HAVE_SYS_TIME_H */
- #ifdef HAVE_SYS_RESOURCE_H
- #include <sys/resource.h>
- #endif /* HAVE_SYS_RESOURCE_H */
- #ifdef HAVE_SYS_MMAN_H
- #include <sys/mman.h>
- #endif /* HAVE_SYS_MMAN_H */
- #include <sys/socket.h>
- #ifdef HAVE_SYS_WAIT_H
- #include <sys/wait.h>
- #endif /* HAVE_SYS_WAIT_H */
- #include <sys/signal.h>
- #include <sys/stat.h>
- #ifdef HAVE_SYS_SELECT_H
- #include <sys/select.h>
- #endif /* HAVE_SYS_SELECT_H */
- #ifdef HAVE_SYS_PARAM_H
- #include <sys/param.h>
- #endif /* HAVE_SYS_PARAM_H */
- #ifdef HAVE_SYS_SYSLIMITS_H
- #include <sys/syslimits.h>
- #endif /* HAVE_SYS_SYSLIMITS_H */
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <fcntl.h>
- #include <string.h>
- #include <stdio.h>
- #include <errno.h>
- #include <netdb.h>
- #ifdef HAVE_TIME_H
- #ifdef SYS_TIME_WITH_TIME
- #include <time.h>
- #endif /* SYS_TIME_WITH_TIME */
- #endif /* HAVE_TIME_H */
- #include <stdlib.h>
- #ifndef NONEWSTYLE
- #include <stdarg.h>
- #else /* Not not NONEWSTYLE */
- #include <varargs.h>
- #endif /* NONEWSTYLE */
- #include <signal.h>
- #include <pwd.h>
- #include <grp.h>
- #include <unistd.h>
- #ifdef HAVE_ERR_H
- #include <err.h>
- #else /* Not HAVE_ERR_H */
- #include "err.h"
- #endif /* HAVE_ERR_H */
- #include <ctype.h>
- #ifdef HAVE_ALLOCA_H
- #include <alloca.h>
- #endif /* HAVE_ALLOCA_H */
- #ifdef HAVE_VFORK_H
- #include <vfork.h>
- #endif /* HAVE_VFORK_H */
- #ifdef HAVE_MEMORY_H
- #include <memory.h>
- #endif /* HAVE_MEMORY_H */
- #include "httpd.h"
- #include "methods.h"
- #include "local.h"
- #include "procname.h"
- #include "ssi.h"
- #include "extra.h"
- #include "cgi.h"
- #include "xscrypt.h"
- #include "path.h"
- #include "convert.h"
- #include "setenv.h"
- #include "getopt.h"
- #include "string.h"
- #ifdef __linux__
- extern char *tempnam(const char *, const char *);
- #endif /* __linux__ */
- /* This is for HP/UX */
- #ifdef HPUX
- #ifndef NOFORWARDS
- extern int setpriority PROTO((int, int, int));
- #endif /* NOFORWARDS */
- #endif /* HPUX */
- /* Global variables */
- int port, headers, localmode, netbufind, netbufsiz, readlinemode,
- headonly, postonly;
- static int sd, reqs, number, mainhttpd = 1;
- gid_t group_id, origegid;
- uid_t user_id, origeuid;
- char netbuf[MYBUFSIZ], remotehost[MAXHOSTNAMELEN], orig[MYBUFSIZ],
- currenttime[80], dateformat[MYBUFSIZ], real_path[XS_PATH_MAX],
- thishostname[MAXHOSTNAMELEN], version[16], error_path[XS_PATH_MAX],
- access_path[XS_PATH_MAX], refer_path[XS_PATH_MAX], rootdir[XS_PATH_MAX],
- total[XS_PATH_MAX], name[XS_PATH_MAX];
- static char browser[MYBUFSIZ], referer[MYBUFSIZ], outputbuffer[SENDBUFSIZE],
- thisdomain[MAXHOSTNAMELEN], message503[MYBUFSIZ],
- *startparams;
- FILE *access_log = NULL, *refer_log = NULL;
- time_t modtime;
- static struct in_addr thisaddress;
- /* Static arrays */
- static char six2pr[64] =
- {
- 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
- 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
- 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
- '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
- };
- /* Prototypes */
- #ifndef NOFORWARDS
- static VOID filedescrs PROTO((void));
- static VOID detach PROTO((void));
- static VOID child_handler PROTO((int));
- static VOID term_handler PROTO((int));
- static VOID open_logs PROTO((int));
- static VOID core_handler PROTO((int));
- static VOID set_signals PROTO((void));
- static int hexdigit PROTO((int));
- static int decode PROTO((char *));
- static VOID uudecode PROTO((char *));
- static VOID process_request PROTO((void));
- static VOID setup_environment PROTO((void));
- static VOID standalone_main PROTO((void));
- #endif /* NOFORWARDS */
- extern VOID
- stdheaders DECL3(int, lastmod, int, texthtml, int, endline)
- {
- setcurrenttime();
- printf("Date: %srnServer: %srn", currenttime, SERVER_IDENT);
- if (lastmod)
- printf("Last-modified: %srnExpires: %srn",
- currenttime, currenttime);
- if (texthtml)
- printf("Content-type: text/htmlrn");
- if (endline)
- printf("rn");
- }
- static VOID
- filedescrs DECL0
- {
- close(0); if (open(BITBUCKETNAME, O_RDONLY, 0) != 0)
- err(1, "Cannot open fd 0 (%s)", BITBUCKETNAME);
- if (dup2(0, 1) != 1)
- err(1, "Cannot dup2() fd 1");
- }
- static VOID
- detach DECL0
- {
- pid_t x;
- if (chdir("/"))
- err(1, "chdir(`/')");
- if ((x = fork()) > 0)
- exit(0);
- else if (x == -1)
- err(1, "fork()");
- #ifdef HAVE_SETSID
- if (setsid() == -1)
- err(1, "setsid() failed");
- #else /* Not HAVE_SETSID */
- if (setpgrp(getpid(), 0)) == -1)
- err(1, "setpgrp() failed");
- #endif /* HAVE_SETSID */
- }
- extern VOID
- setcurrenttime DECL0
- {
- time_t thetime;
- time(&thetime);
- strftime(currenttime, sizeof(currenttime),
- "%a, %d %b %Y %T GMT", gmtime(&thetime));
- }
- static VOID
- child_handler DECL1(int, sig)
- {
- #ifdef NeXT
- union wait status;
- #else /* Not NeXT */
- int status;
- #endif /* NeXT */
- while (wait3(&status, WNOHANG, NULL) > 0)
- /* NOTHING */;
- set_signals();
- }
- static VOID
- term_handler DECL1(int, sig)
- {
- if (mainhttpd)
- {
- setcurrenttime();
- fprintf(stderr, "[%s] Received signal %d, shutting down...n",
- currenttime, sig);
- fflush(stderr);
- mainhttpd = 0;
- killpg(0, SIGTERM);
- }
- exit(0);
- }
- static VOID
- open_logs DECL1(int, sig)
- {
- FILE *pidlog;
- char buffer[XS_PATH_MAX];
- uid_t savedeuid;
- gid_t savedegid;
- int tempfile;
- set_signals();
- savedeuid = savedegid = -1;
- if (!origeuid)
- {
- savedeuid = geteuid(); seteuid(origeuid);
- savedegid = getegid(); setegid(origegid);
- }
- if (mainhttpd)
- {
- sprintf(buffer, calcpath(PID_PATH));
- remove(buffer);
- if ((pidlog = fopen(buffer, "w")))
- {
- fprintf(pidlog, "%ldn", (long)getpid());
- fprintf(pidlog, "%sn", startparams);
- fclose(pidlog);
- }
- signal(SIGHUP, SIG_IGN); killpg(0, SIGHUP);
- }
- if (access_log)
- fclose(access_log);
- if (!(access_log = fopen(access_path, "a")))
- err(1, "fopen(`%s' [append])", access_path);
- #ifndef SETVBUF_REVERSED
- setvbuf(access_log, NULL, _IOLBF, 0);
- #else /* Not not SETVBUF_REVERSED */
- setvbuf(access_log, _IOLBF, NULL, 0);
- #endif /* SETVBUF_REVERSED */
- fflush(stderr);
- close(2);
- if ((tempfile = open(error_path, O_CREAT | O_APPEND | O_WRONLY,
- S_IWUSR | S_IRUSR | S_IROTH | S_IRGRP)) < 0)
- err(1, "open(`%s' [append])", error_path);
- if (tempfile != 2)
- {
- if (dup2(tempfile, 2) == -1)
- err(1, "dup2() failed");
- close(tempfile);
- }
- if (refer_log)
- fclose(refer_log);
- if (!(refer_log = fopen(refer_path, "a")))
- err(1, "fopen(`%s' [append])", refer_path);
- #ifndef SETVBUF_REVERSED
- setvbuf(refer_log, NULL, _IOLBF, 0);
- #else /* Not not SETVBUF_REVERSED */
- setvbuf(refer_log, _IOLBF, NULL, 0);
- #endif /* SETVBUF_REVERSED */
- if (mainhttpd)
- {
- setcurrenttime();
- fprintf(stderr, "[%s] httpd: Successful restartn",
- currenttime);
- }
- loadfiletypes();
- #ifdef HANDLE_COMPRESSED
- loadcompresstypes();
- #endif /* HANDLE_COMPRESSED */
- set_signals();
- if (!origeuid)
- {
- if (seteuid(savedeuid) == -1)
- err(1, "seteuid()");
- if (setegid(savedegid) == -1)
- err(1, "setegid()");
- }
- }
- extern VOID
- alarm_handler DECL1(int, sig)
- {
- alarm(0); setcurrenttime();
- fprintf(stderr, "[%s] httpd: Send timed out for `%s'n",
- currenttime, remotehost[0] ? remotehost : "(none)");
- exit(1);
- }
- static VOID
- core_handler DECL1(int, sig)
- {
- const char *env;
- alarm(0); setcurrenttime();
- env = getenv("DOCUMENT_ARGUMENTS");
- fprintf(stderr, "[%s] httpd(pid %ld): FATAL SIGNAL %d [from: `%s' req: `%s' params: `%s' referer: `%s']n",
- currenttime, (long)getpid(), sig,
- remotehost[0] ? remotehost : "(none)",
- orig[0] ? orig : "(none)", env ? env : "(none)",
- referer[0] ? referer : "(none)");
- exit(1);
- }
- static VOID
- set_signals DECL0
- {
- struct sigaction action;
- #ifdef HAVE_SIGEMPTYSET
- sigemptyset(&action.sa_mask);
- #else /* Not HAVE_SIGEMPTYSET */
- action.sa_mask = 0;
- #endif /* HAVE_SIGEMPTYSET */
- action.sa_handler = open_logs;
- #ifdef SA_RESTART
- action.sa_flags = SA_RESTART;
- #else /* Not SA_RESTART */
- action.sa_flags = 0;
- #endif /* SA_RESTART */
- sigaction(SIGHUP, &action, NULL);
- action.sa_handler = child_handler;
- action.sa_flags = 0;
- sigaction(SIGCHLD, &action, NULL);
- action.sa_handler = alarm_handler;
- action.sa_flags = 0;
- sigaction(SIGALRM, &action, NULL);
- action.sa_handler = term_handler;
- action.sa_flags = 0;
- sigaction(SIGTERM, &action, NULL);
- action.sa_handler = term_handler;
- action.sa_flags = 0;
- sigaction(SIGINT, &action, NULL);
- #ifdef SIGBUS
- action.sa_handler = core_handler;
- action.sa_flags = 0;
- sigaction(SIGBUS, &action, NULL);
- #endif /* SIGBUS */
- #ifdef SIGSEGV
- action.sa_handler = core_handler;
- action.sa_flags = 0;
- sigaction(SIGSEGV, &action, NULL);
- #endif /* SIGSEGV */
- }
- extern VOID
- error DECL1C(char *, message)
- {
- const char *env;
- alarm(180); setcurrenttime();
- env = getenv("DOCUMENT_ARGUMENTS");
- fprintf(stderr, "[%s] httpd(pid %ld): %s [from: `%s' req: `%s' params: `%s' referer: `%s']n",
- currenttime, (long)getpid(), message,
- remotehost[0] ? remotehost : "(none)",
- orig[0] ? orig : "(none)", env ? env : "(none)",
- referer[0] ? referer : "(none)");
- if (headers)
- {
- printf("%s %srn", version, message);
- stdheaders(1, 1, 1);
- }
- if (!headonly)
- {
- printf("rn<HTML><HEAD><TITLE>%s</TITLE></HEAD><BODY>n",
- message);
- printf("<H1>%s</H1></BODY></HTML>n", message);
- }
- fflush(stdout); fflush(stderr); alarm(0);
- }
- extern VOID
- redirect DECL2C_(char *, redir, int, permanent)
- {
- const char *env;
- env = getenv("DOCUMENT_ARGUMENTS");
- if (headers)
- {
- printf("%s %s movedrnLocation: %srn", version,
- permanent ? "301 Permanently" : "302 Temporarily",
- redir);
- stdheaders(1, 1, 1);
- }
- if (!headonly)
- {
- printf("rn<HTML><HEAD><TITLE>Document has moved</TITLE></HEAD>");
- printf("<BODY>n<H1>Document has moved</H1>This document has ");
- printf("%smoved to <A HREF="%s%s%s">%s</A>.</BODY></HTML>n",
- permanent ? "permanently " : "", redir,
- env ? "?" : "", env ? env : "", redir);
- }
- fflush(stdout);
- }
- static int
- hexdigit DECL1(int, ch)
- {
- const char *temp, *hexdigits = "0123456789ABCDEF";
- if ((temp = strchr(hexdigits, toupper(ch))))
- return(temp - hexdigits);
- else
- {
- error("500 Invalid `percent' parameters");
- return(-1);
- }
- }
- static int
- decode DECL1(char *, str)
- {
- char *posd, chr;
- const char *poss;
- int top, bottom;
- poss = posd = str;
- while ((chr = *poss))
- {
- if (chr != '%')
- {
- if (chr == '?')
- {
- bcopy(poss, posd, strlen(poss) + 1);
- return(ERR_NONE);
- }
- *(posd++) = chr;
- poss++;
- } else
- {
- if ((top = hexdigit((int)poss[1])) == -1)
- return(ERR_QUIT);
- if ((bottom = hexdigit((int)poss[2])) == -1)
- return(ERR_QUIT);
- *(posd++) = (top << 4) + bottom;
- poss += 3;
- }
- }
- *posd = 0;
- return(ERR_NONE);
- }
- static VOID
- uudecode DECL1(char *, buffer)
- {
- unsigned char pr2six[256], bufplain[32], *bufout = bufplain;
- int nbytesdecoded, j, nprbytes;
- char *bufin = buffer;
- for (j = 0; j < 256; j++)
- pr2six[j] = 64;
- for (j = 0; j < 64; j++)
- pr2six[(int)six2pr[j]] = (unsigned char)j;
- bufin = buffer;
- while (pr2six[(int)*(bufin++)] <= 63)
- /* NOTHING HERE */;
- nprbytes = bufin - buffer - 1;
- nbytesdecoded = ((nprbytes + 3) / 4) * 3;
- bufin = buffer;
- while (nprbytes > 0)
- {
- *(bufout++) = (unsigned char) ((pr2six[(int)*bufin] << 2) |
- (pr2six[(int)bufin[1]] >> 4));
- *(bufout++) = (unsigned char) ((pr2six[(int)bufin[1]] << 4) |
- (pr2six[(int)bufin[2]] >> 2));
- *(bufout++) = (unsigned char) ((pr2six[(int)bufin[2]] << 6) |
- (pr2six[(int)bufin[3]]));
- bufin += 4; nprbytes -= 4;
- }
- if (nprbytes & 3)
- {
- if (pr2six[(int)*(bufin - 2)] > 63)
- nbytesdecoded -= 2;
- else
- nbytesdecoded--;
- }
- if (nbytesdecoded)
- bcopy((char *)bufplain, buffer, nbytesdecoded);
- buffer[nbytesdecoded] = 0;
- }
- extern int
- check_auth DECL1(FILE *, authfile)
- {
- char *search, line[MYBUFSIZ], compare[MYBUFSIZ], *find;
- const char *env;
- if (!(env = getenv("AUTH_TYPE")))
- {
- if (headers)
- {
- printf("%s 401 Unauthorizedrn", version);
- printf("WWW-authenticate: basic realm="this page"rn");
- stdheaders(1, 1, 1);
- }
- printf("rn<HTML><HEAD><TITLE>Unauthorized</TITLE></HEAD>n");
- printf("<BODY><H1>Unauthorized</H1>nYour client does not ");
- printf("understand authentication.n</BODY></HTML>n");
- fclose(authfile); return(1);
- }
- strncpy(line, env, MYBUFSIZ - 1); line[MYBUFSIZ - 1] = 0;
- find = line + strlen(line);
- while ((find > line) && (*(find - 1) < ' '))
- *(--find) = 0;
- for (search = line; *search && (*search != ' ') &&
- (*search != 9); search++) ;
- while ((*search == 9) || (*search == ' '))
- search++;
- uudecode(search);
- if ((find = strchr(search, ':')))
- {
- *find = 0;
- setenv("REMOTE_USER", search, 1);
- *find = ':';
- setenv("REMOTE_PASSWORD", find + 1, 1);
- xs_encrypt(find + 1);
- }
- while (fgets(compare, MYBUFSIZ, authfile))
- {
- compare[strlen(compare) - 1] = 0;
- if (!strcmp(compare + 1, search))
- {
- fclose(authfile); return(0);
- }
- }
- fclose(authfile);
- server_error("401 Wrong user/password combination", "UNAUTHORIZED");
- return(1);
- }
- extern char *
- escape DECL1C(char *, what)
- {
- char *escapebuf, *w;
- if (!(w = escapebuf = (char *)malloc(BUFSIZ)))
- return(NULL);
- while (*what && ((w - escapebuf) < (BUFSIZ - 10)))
- {
- switch(*what)
- {
- case '<':
- strcpy(w, "<"); w += 4;
- break;
- case '>':
- strcpy(w, ">"); w += 4;
- break;
- case '&':
- strcpy(w, "&"); w += 5;
- break;
- case '"':
- strcpy(w, """); w += 6;
- break;
- default:
- *(w++) = *what;
- break;
- }
- what++;
- }
- *w = 0;
- return(escapebuf);
- }
- extern VOID
- server_error DECL2CC(char *, readable, char *, cgi)
- {
- struct stat statbuf;
- const struct passwd *userinfo;
- char *search, cgipath[XS_PATH_MAX], base[XS_PATH_MAX],
- *escaped;
- const char *env;
- if (headonly)
- {
- error(readable);
- return;
- }
- setenv("ERROR_CODE", cgi, 1);
- setenv("ERROR_READABLE", readable, 1);
- setenv("ERROR_URL", orig, 1);
- setenv("ERROR_URL_EXPANDED", convertpath(orig), 1);
- escaped = escape(orig);
- setenv("ERROR_URL_ESCAPED", escaped ? escaped : "", 1);
- if (escaped)
- free(escaped);
- env = getenv("DOCUMENT_ARGUMENTS");
- if (real_path[1] == '~')
- {
- if ((search = strchr(real_path + 2, '/')))
- *search = 0;
- if ((userinfo = getpwnam(real_path + 2)))
- {
- if (search)
- *search = '/';
- if (!transform_user_dir(base, userinfo, 0))
- {
- sprintf(cgipath, "%s/%s/error",
- base, HTTPD_SCRIPT_ROOT);
- if (!stat(cgipath, &statbuf))
- {
- sprintf(cgipath, "/~%s/%s/error",
- userinfo->pw_name,
- HTTPD_SCRIPT_ROOT);
- goto EXECUTE;
- }
- }
- }
- if (search)
- *search = '/';
- }
- strcpy(base, calcpath(HTTPD_SCRIPT_ROOT_P));
- sprintf(cgipath, "%s/error", base);
- if (stat(cgipath, &statbuf))
- error(readable);
- else
- {
- sprintf(cgipath, "/%s/error", HTTPD_SCRIPT_ROOT);
- EXECUTE:
- setcurrenttime();
- fprintf(stderr, "[%s] httpd(pid %ld): %s [from: `%s' req: `%s' params: `%s' referer: `%s']n",
- currenttime, (long)getpid(), readable,
- remotehost[0] ? remotehost : "(none)",
- orig[0] ? orig : "(none)", env ? env : "(none)",
- referer[0] ? referer : "(none)");
- do_script(cgipath, headers);
- }
- }
- extern int
- readline DECL2(int, sd, char *, buf)
- {
- char ch, *buf2;
- buf2 = buf; *buf2 = 0;
- do
- {
- if (netbufind >= netbufsiz)
- {
- TRYAGAIN:
- netbufsiz = read(sd, netbuf,
- readlinemode ? MYBUFSIZ : 1);
- if (netbufsiz == -1)
- {
- if ((errno == EAGAIN) || (errno == EINTR))
- {
- mysleep(1); goto TRYAGAIN;
- }
- fprintf(stderr, "[%s] httpd: readline(): %sn",
- currenttime, strerror(errno));
- if (sd == 0)
- error("503 Unexpected network error");
- return(ERR_QUIT);
- }
- if (netbufsiz == 0)
- {
- if (*buf)
- {
- *buf2 = 0;
- return(ERR_NONE);
- }
- if (sd == 0)
- error("503 You closed the connection!");
- return(ERR_QUIT);
- }
- netbufind = 0;
- }
- ch = *(buf2++) = netbuf[netbufind++];
- } while ((ch != 'n') && (buf2 < (buf + MYBUFSIZ - 64)));
- *buf2 = 0;
- return(ERR_NONE);
- }
- static VOID
- process_request DECL0
- {
- char line[MYBUFSIZ], extra[MYBUFSIZ], *temp,
- *params, *url, *ver;
- int index, readerror;
- size_t size;
- strcpy(version, "HTTP/0.9");
- strcpy(dateformat, "%a %b %e %H:%M:%S %Y");
- total[0] = orig[0] = name[0] = referer[0] = line[0] =
- real_path[0] = browser[0] = 0;
- netbufsiz = netbufind = headonly = postonly = headers = index = 0;
- unsetenv("CONTENT_LENGTH"); unsetenv("AUTH_TYPE");
- unsetenv("CONTENT_TYPE"); unsetenv("DOCUMENT_ARGUMENTS");
- unsetenv("ERROR_CODE"); unsetenv("ERROR_READABLE");
- unsetenv("ERROR_URL"); unsetenv("ERROR_URL_ESCAPED");
- unsetenv("ERROR_URL_EXPANDED"); unsetenv("REMOTE_USER");
- unsetenv("REMOTE_PASSWORD"); unsetenv("HTTP_REFERER");
- unsetenv("HTTP_COOKIE");
- alarm(180); errno = 0;
- readerror = read(0, line, 1);
- if (readerror == 1)
- readerror = read(0, line + 1, 1);
- if (readerror == 1)
- readerror = read(0, line + 2, 1);
- if (readerror == 1)
- readerror = read(0, line + 3, 1);
- if (readerror != 1)
- {
- if (readerror == -1)
- fprintf(stderr, "[%s] Request line: read() failed: %sn",
- currenttime, strerror(errno));
- else
- fprintf(stderr, "[%s] Request line: read() got no inputn",
- currenttime);
- error("400 Unable to read begin of request line");
- return;
- }
- readlinemode = strncasecmp("POST", line, 4);
- if (readline(0, line + 4) == ERR_QUIT)
- {
- error("400 Unable to read request line");
- return;
- }
- size = strlen(line);
- bzero(line + size, 16);
- temp = orig + strlen(orig);
- while ((temp > orig) && (*(temp - 1) <= ' '))
- *(--temp) = 0;
- url = line;
- while (*url && (*url > ' '))
- url++;
- *(url++) = 0;
- while (*url <= ' ')
- url++;
- ver = url;
- while (*ver && (*ver > ' '))
- ver++;
- *(ver++) = 0;
- while (*ver <= ' ')
- ver++;
- temp = ver;
- while (*temp && (*temp > ' '))
- temp++;
- *temp = 0;
- if (!strncasecmp(ver, "HTTP/", 5))
- {
- headers = 1; strcpy(version, "HTTP/1.0");
- setenv("SERVER_PROTOCOL", version, 1);
- while (1)
- {
- char *param;
- if (readline(0, extra) == ERR_QUIT)
- {
- error("400 Unable to read HTTP headers");
- return;
- }
- if (extra[0] <= ' ')
- break;
- if (!(param = strchr(extra, ':')))
- continue;
- *(param++) = 0;
- while ((*param == ' ') || (*param == 9))
- param++;
- if (!strcasecmp("Content-length", extra))
- setenv("CONTENT_LENGTH", param, 1);
- else if (!strcasecmp("Content-type", extra))
- setenv("CONTENT_TYPE", param, 1);
- else if (!strcasecmp("User-agent", extra))
- {
- strncpy(browser, param, MYBUFSIZ - 1);
- browser[MYBUFSIZ - 1] = 0;
- setenv("USER_AGENT", browser, 1);
- setenv("HTTP_USER_AGENT", browser, 1);
- strtok(browser, "/");
- for (temp = browser; *temp; temp++)
- *temp = tolower(*temp);
- *browser = toupper(*browser);
- setenv("USER_AGENT_SHORT", browser, 1);
- } else if (!strcasecmp("Referer", extra))
- {
- strncpy(referer, param, MYBUFSIZ-16);
- while (referer[0] &&
- referer[strlen(referer) - 1] <= ' ')
- referer[strlen(referer) - 1] = 0;
- setenv("HTTP_REFERER", referer, 1);
- } else if (!strcasecmp("Authorization", extra))
- setenv("AUTH_TYPE", param, 1);
- else if (!strcasecmp("Cookie", extra))
- setenv("HTTP_COOKIE", param, 1);
- }
- } else
- setenv("SERVER_PROTOCOL", version, 1);
- if (!getenv("CONTENT_LENGTH"))
- setenv("CONTENT_LENGTH", "0", 1);
- if (!browser[0])
- {
- setenv("USER_AGENT", "UNKNOWN", 1);
- setenv("HTTP_USER_AGENT", "UNKNOWN", 1);
- setenv("USER_AGENT_SHORT", "UNKNOWN", 1);
- }
- alarm(0);
- params = url;
- if (decode(params))
- return;
- size = strlen(params);
- bzero(params + size, 16);
- bcopy(params, orig, size + 16);
- if (referer[0] &&
- (!thisdomain[0] || !strcasestr(referer, thisdomain)))
- fprintf(refer_log, "%s -> %sn", referer, params);
- if (params[0] != '/')
- {
- server_error("400 Relative URL's are not supported",
- "NO_RELATIVE_URLS");
- return;
- }
- setenv("REQUEST_METHOD", line, 1);
- if (!strcmp("GET", line))
- do_get(params);
- else if (!strcmp("HEAD", line))
- do_head(params);
- else if (!strcmp("POST", line))
- do_post(params);
- else
- server_error("400 Unknown method", "UNKNOWN_METHOD");
- }
- static VOID
- standalone_main DECL0
- {
- int csd = 0, clen, count, temp;
- struct sockaddr_in sa_server, sa_client;
- const struct hostent *remote;
- pid_t *childs, pid;
- struct rlimit limit;
- /* Speed hack */
- gethostbyname("localhost");
- detach(); open_logs(0);
- setprocname("xs(MAIN): Initializing deamons...");
- if ((sd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)
- err(1, "socket()");
- temp = 1;
- if ((setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &temp, sizeof(temp))) == -1)
- err(1, "setsockopt(REUSEADDR)");
- temp = 1;
- if ((setsockopt(sd, SOL_SOCKET, SO_KEEPALIVE, &temp, sizeof(temp))) == -1)
- err(1, "setsockopt(KEEPALIVE)");
- memset(&sa_server, 0, sizeof(sa_server));
- sa_server.sin_family = AF_INET;
- sa_server.sin_addr = thisaddress;
- sa_server.sin_port = htons(port);
- if (bind(sd, (struct sockaddr *)&sa_server, sizeof(sa_server)) == -1)
- err(1, "bind()");
- if (listen(sd, MAXLISTEN))
- err(1, "listen()");
- #ifdef RLIMIT_NPROC
- limit.rlim_max = limit.rlim_cur = RLIM_INFINITY;
- setrlimit(RLIMIT_NPROC, &limit);
- #endif /* RLIMIT_NPROC */
- #ifdef RLIMIT_CPU
- limit.rlim_max = limit.rlim_cur = RLIM_INFINITY;
- setrlimit(RLIMIT_CPU, &limit);
- #endif /* RLIMIT_CPU */
- set_signals(); reqs = 0;
- if (!(childs = (pid_t *)malloc(sizeof(pid_t) * number)))
- errx(1, "malloc() failed");
- for (count = 0; count < number; count++)
- {
- switch(pid = fork())
- {
- case -1:
- warn("fork() failed");
- killpg(0, SIGTERM);
- exit(1);
- case 0:
- mainhttpd = 0;
- goto CHILD;
- default:
- childs[count] = pid;
- }
- }
- fflush(stdout);
- while (1)
- {
- setprocname("xs(MAIN): Waiting for dead children");
- while (mysleep(30))
- /* NOTHING HERE */;
- setprocname("xs(MAIN): Searching for dead children");
- for (count = 0; count < number; count++)
- {
- if (kill(childs[count], 0))
- {
- fflush(stdout);
- switch(pid = fork())
- {
- case -1:
- fprintf(stderr,
- "[%s] httpd: fork() failed: %sn",
- currenttime, strerror(errno));
- break;
- case 0:
- mainhttpd = 0;
- goto CHILD;
- default:
- childs[count] = pid;
- }
- }
- }
- }
- CHILD:
- #ifndef SETVBUF_REVERSED
- setvbuf(stdout, outputbuffer, _IOFBF, SENDBUFSIZE);
- #else /* Not not SETVBUF_REVERSED */
- setvbuf(stdout, _IOFBF, outputbuffer, SENDBUFSIZE);
- #endif /* SETVBUF_REVERSED */
- while (1)
- {
- struct linger sl;
- setprocname("xs(%d): [Reqs: %06d] Setting up myself to accept a connection",
- count + 1, reqs);
- if (!origeuid && (seteuid(origeuid) == -1))
- err(1, "seteuid(%ld) failed", (long)origeuid);
- if (!origeuid && (setegid(origegid) == -1))
- err(1, "setegid(%ld) failed", (long)origegid);
- filedescrs(); clen = sizeof(sa_client);
- setprocname("xs(%d): [Reqs: %06d] Waiting for a connection...",
- count + 1, reqs);
- csd = accept(sd, (struct sockaddr *)&sa_client, &clen);
- if (csd < 0)
- {
- if (errno == EINTR)
- child_handler(SIGCHLD);
- continue;
- }
- setprocname("xs(%d): [Reqs: %06d] accept() gave me a connection...",
- count + 1, reqs);
- if (fcntl(csd, F_SETFL, 0))
- warn("fcntl() in standalone_main");
- sl.l_onoff = 1; sl.l_linger = 600;
- setsockopt(csd, SOL_SOCKET, SO_LINGER, &sl, sizeof(sl));
- #ifdef SO_SNDBUF
- temp = SENDBUFSIZE + 64;
- setsockopt(csd, SOL_SOCKET, SO_SNDBUF, &temp, sizeof(temp));
- #endif /* SO_SNDBUF */
- #ifdef SO_RCVBUF
- temp = 512;
- setsockopt(csd, SOL_SOCKET, SO_RCVBUF, &temp, sizeof(temp));
- #endif /* SO_RCVBUF */
- dup2(csd, 0); dup2(csd, 1); close(csd);
- #ifndef SETVBUF_REVERSED
- setvbuf(stdin, NULL, _IONBF, 0);
- #else /* Not not SETVBUF_REVERSED */
- setvbuf(stdin, _IONBF, NULL, 0);
- #endif /* SETVBUF_REVERSED */
- if ((remote = gethostbyaddr((char *)&sa_client.sin_addr,
- sizeof(struct in_addr), sa_client.sin_family)))
- {
- strcpy(remotehost, remote->h_name);
- setenv("REMOTE_HOST", remotehost, 1);
- } else
- {
- strcpy(remotehost, inet_ntoa(sa_client.sin_addr));
- unsetenv("REMOTE_HOST");
- }
- setenv("REMOTE_ADDR", inet_ntoa(sa_client.sin_addr), 1);
- setprocname("xs(%d): Connect from `%s'", count + 1, remotehost);
- setcurrenttime();
- if (message503[0])
- {
- alarm(180);
- printf("HTTP/1.0 503 BusyrnContent-type: text/plainrnrn");
- printf("%sn", message503);
- } else
- process_request();
- alarm(0); reqs++;
- fflush(stdout); fflush(stdin); fflush(stderr);
- }
- /* NOTREACHED */
- }
- static VOID
- setup_environment DECL0
- {
- char buffer[16];
- setenv("SERVER_SOFTWARE", SERVER_IDENT, 1);
- setenv("SERVER_NAME", thishostname, 1);
- setenv("GATEWAY_INTERFACE", "CGI/1.1", 1);
- sprintf(buffer, "%d", port);
- setenv("SERVER_PORT", buffer, 1);
- sprintf(buffer, "%d", localmode);
- setenv("LOCALMODE", buffer, 1);
- setenv("HTTPD_ROOT", rootdir, 1);
- }
- int
- main DECL3(int, argc, char **, argv, char **, envp)
- {
- const struct passwd *userinfo;
- const struct group *groupinfo;
- int option, num;
- const struct hostent *hp;
- origeuid = geteuid(); origegid = getegid();
- #ifdef HAVE_SETPRIORITY
- if (setpriority(PRIO_PROCESS, (pid_t)0, PRIO_MAX))
- warn("setpriority");
- #endif /* HAVE_SETPRIORITY */
- for (num = option = 0; option < argc; option++)
- num += (1 + strlen(argv[option]));
- if (!(startparams = (char *)malloc(num)))
- errx(1, "Cannot malloc memory for startparams");
- *startparams = 0;
- for (option = 0; option < argc; option++)
- {
- strcat(startparams, argv[option]);
- if (option < argc - 1)
- strcat(startparams, " ");
- }
- port = 80; number = HTTPD_NUMBER; localmode = 1;
- strcpy(rootdir, HTTPD_ROOT); message503[0] = 0;
- #ifdef THISDOMAIN
- strcpy(thisdomain, THISDOMAIN);
- #else /* Not THISDOMAIN */
- thisdomain[0] = 0;
- #endif /* THISDOMAIN */
- thisaddress.s_addr = htonl(INADDR_ANY);
- if (gethostname(thishostname, MAXHOSTNAMELEN) == -1)
- errx(1, "gethostname() failed");
- if ((userinfo = getpwnam(HTTPD_USERID)))
- user_id = userinfo->pw_uid;
- else
- user_id = 32767;
- if ((groupinfo = getgrnam(HTTPD_GROUPID)))
- group_id = groupinfo->gr_gid;
- else
- group_id = 32766;
- if ((short)user_id == -1)
- err(1, "Check your password file: nobody may not have UID -1 or 65535.");
- if ((short)group_id == -1)
- err(1, "Check your group file: nogroup may not have GID -1 or 65535.");
- sprintf(access_path, "%s/access_log", calcpath(HTTPD_LOG_ROOT));
- sprintf(error_path, "%s/error_log", calcpath(HTTPD_LOG_ROOT));
- sprintf(refer_path, "%s/referer_log", calcpath(HTTPD_LOG_ROOT));
- while ((option = getopt(argc, argv, "a:d:g:l:m:n:p:r:u:A:R:E:")) != EOF)
- {
- switch(option)
- {
- case 'n':
- if ((number = atoi(optarg)) <= 0)
- errx(1, "Invalid number of processes");
- break;
- case 'p':
- if ((port = atoi(optarg)) <= 0)
- errx(1, "Invalid port number");
- break;
- case 'u':
- if ((user_id = atoi(optarg)) > 0)
- break;
- if (!(userinfo = getpwnam(optarg)))
- errx(1, "Invalid user ID");
- user_id = userinfo->pw_uid;
- break;
- case 'g':
- if ((group_id = atoi(optarg)) > 0)
- break;
- if (!(groupinfo = getgrnam(optarg)))
- errx(1, "Invalid group ID");
- group_id = groupinfo->gr_gid;
- break;
- case 'd':
- if (*optarg != '/')
- errx(1, "The -d directory must start with a /");
- strncpy(rootdir, optarg, XS_PATH_MAX-1);
- rootdir[XS_PATH_MAX-1] = 0;
- break;
- case 'a':
- if ((thisaddress.s_addr = inet_addr(optarg)) == -1)
- {
- if ((hp = gethostbyname(optarg)))
- memcpy((char *)&thisaddress,
- hp->h_addr, hp->h_length);
- else
- errx(1, "gethostbyname(`%s') failed",
- optarg);
- }
- strcpy(thishostname, optarg);
- break;
- case 'r':
- strcpy(thisdomain, optarg);
- break;
- case 'l':
- if ((localmode = atoi(optarg)) <= 0)
- errx(1, "Argument to -l is invalid");
- break;
- case 'm':
- strcpy(message503, optarg);
- break;
- case 'A':
- strcpy(access_path, optarg);
- break;
- case 'R':
- strcpy(refer_path, optarg);
- break;
- case 'E':
- strcpy(error_path, optarg);
- break;
- default:
- errx(1, "Usage: httpd [-u username] [-g group] [-p port] [-n number] [-d rootdir]n[-r refer-ignore-domain] [-l localmode] [-a address] [-m service-message]n[-A access-log-path] [-E error-log-path] [-R referer-log-path]");
- }
- }
- initsetprocname(argc, argv, envp);
- setup_environment();
- standalone_main();
- exit(0);
- }