methods.c
资源名称:httpd.tar.gz [点击查看]
上传用户:lampled
上传日期:2007-01-07
资源大小:94k
文件大小:15k
源码类别:
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__ */
- /* Global structures */
- typedef struct ftypes
- {
- struct ftypes *next;
- char name[32], ext[16];
- } ftypes;
- #ifdef HANDLE_COMPRESSED
- typedef struct ctypes
- {
- struct ctypes *next;
- char prog[XS_PATH_MAX], ext[16];
- } ctypes;
- #endif /* HANDLE_COMPRESSED */
- static ftypes *ftype = NULL;
- #ifdef HANDLE_COMPRESSED
- static ctypes *ctype = NULL;
- #endif /* HANDLE_COMPRESSED */
- extern VOID
- senduncompressed DECL1(int, fd)
- {
- #ifdef WANT_SSI
- int errval, html;
- #endif /* WANT_SSI */
- #ifndef HAVE_MMAP
- size_t readtotal, writetotal;
- #endif /* HAVE_MMAP */
- size_t size, written;
- char modified[32];
- alarm(180);
- if ((size = lseek(fd, 0, SEEK_END)) == -1)
- {
- error("500 Cannot lseek() to end of file");
- return;
- }
- if (lseek(fd, 0, SEEK_SET))
- {
- error("500 Cannot lseek() to beginning of file");
- return;
- }
- if (headers)
- {
- printf("%s 200 OKrn", version);
- stdheaders(0, 0, 0);
- #ifndef WANT_SSI
- getfiletype(1);
- printf("Content-length: %ldrn", (long)size);
- #else /* Not WANT_SSI */
- html = getfiletype(1);
- if (!html)
- printf("Content-length: %ldrn", (long)size);
- #endif /* WANT_SSI */
- strftime(modified, sizeof(modified),
- "%a, %d %b %Y %T GMT", gmtime(&modtime));
- printf("Last-modified: %srnrn", modified);
- }
- #ifdef WANT_SSI
- else
- {
- html = getfiletype(0);
- if (html)
- printf("rn");
- }
- #endif /* WANT_SSI */
- if (headonly)
- goto DONE;
- UNPARSED:
- #ifdef WANT_SSI
- if (!html)
- #endif /* WANT_SSI */
- #ifdef HAVE_MMAP
- {
- char *buffer;
- if ((buffer = (char *)mmap((caddr_t)0, size, PROT_READ,
- MAP_SHARED, fd, 0)) == (char *)-1)
- {
- fprintf(stderr, "[%s] httpd: mmap() failed: %sn",
- currenttime, strerror(errno));
- exit(1);
- }
- alarm((size / MINBYTESPERSEC) + 20);
- fflush(stdout);
- if ((written = write(fileno(stdout), buffer, size)) != size)
- {
- if (written != -1)
- fprintf(stderr, "[%s] httpd: Aborted for `%s' (%ld of %ld bytes sent)n",
- currenttime,
- remotehost[0] ? remotehost : "(none)",
- (long)written, (long)size);
- else
- fprintf(stderr, "[%s] httpd: Aborted for `%s'n",
- currenttime,
- remotehost[0] ? remotehost : "(none)");
- }
- munmap(buffer, size); size = written;
- alarm(0);
- }
- #else /* Not HAVE_MMAP */
- {
- char buffer[SENDBUFSIZE];
- writetotal = 0;
- alarm((size / MINBYTESPERSEC) + 20);
- fflush(stdout);
- while ((readtotal = read(fd, buffer, SENDBUFSIZE)) > 0)
- {
- if ((written = write(fileno(stdout), buffer,
- readtotal)) != readtotal)
- {
- fprintf(stderr,
- "[%s] httpd: Aborted for `%s' (No mmap) (%ld of %ld bytes sent)n",
- currenttime,
- remotehost[0] ? remotehost : "(none)",
- writetotal + written, size);
- size = writetotal;
- alarm(0); goto DONE;
- }
- writetotal += written;
- }
- size = writetotal;
- alarm(0);
- }
- #endif /* HAVE_MMAP */
- #ifdef WANT_SSI
- else
- {
- size = 0;
- alarm((size / MINBYTESPERSEC) + 60);
- errval = sendwithdirectives(fd, &size);
- close(fd);
- switch(errval)
- {
- case ERR_QUIT:
- fprintf(stderr, "[%s] httpd: Aborted for `%s' (ERR_QUIT)n",
- currenttime,
- remotehost[0] ? remotehost : "(none)");
- break;
- case ERR_CONT:
- html = 0; goto UNPARSED;
- default:
- break;
- }
- }
- #endif /* WANT_SSI */
- DONE:
- {
- char buffer[80];
- time_t theclock;
- time(&theclock);
- strftime(buffer, 80, "%d/%b/%Y:%H:%M:%S", localtime(&theclock));
- fprintf(access_log, "%s - - [%s +0000] "%s %s %s" 200 %ldn",
- remotehost, buffer, headonly ? "HEAD" : "GET", real_path,
- version, size > 0 ? (long)size : (long)0);
- }
- close(fd);
- }
- #ifdef HANDLE_COMPRESSED
- extern VOID
- sendcompressed DECL2_C(int, fd, char *, method)
- {
- pid_t pid;
- int count, processed;
- char *tmp;
- #ifdef HAVE_TEMPNAM
- if (!(tmp = tempnam(TEMPORARYPATH, "xs-www")))
- #endif /* HAVE_TEMPNAM */
- {
- if (!(tmp = (char *)malloc(32 + strlen(TEMPORARYPATH))))
- {
- error("500 Out of memory in sendcompressed()");
- close(fd); return;
- }
- sprintf(tmp, "%s/.xs-www.%016ld",
- TEMPORARYPATH, (long)getpid());
- }
- remove(tmp);
- if ((processed = open(tmp, O_CREAT | O_TRUNC | O_RDWR | O_EXCL,
- S_IWUSR | S_IRUSR )) < 0)
- {
- fprintf(stderr, "[%s] httpd: Cannot open(`%s'): %sn",
- currenttime, tmp, strerror(errno));
- error("500 Unable to open temporary file");
- exit(1);
- }
- remove(tmp); free(tmp); fflush(stdout);
- switch(pid = fork())
- {
- case -1:
- fprintf(stderr, "[%s] httpd: Cannot fork(): %sn",
- currenttime, strerror(errno));
- error("500 Cannot fork() in sendcompressed()");
- close(fd); close(processed); return;
- case 0:
- #ifdef HAVE_SETSID
- if (setsid() == -1)
- {
- error("500 setsid() failed");
- exit(1);
- }
- #else /* Not HAVE_SETSID */
- if (setpgrp(getpid(), 0)) == -1)
- {
- error("500 setpgrp() failed");
- exit(1);
- }
- #endif /* HAVE_SETSID */
- dup2(fd, 0); dup2(processed, 1);
- for (count = 3; count < 64; count++)
- close(count);
- execl(method, method, NULL);
- fprintf(stderr, "[%s] httpd: Cannot execl(`%s'): %sn",
- currenttime, method, strerror(errno));
- error("500 Cannot start conversion program");
- exit(1);
- default:
- close(fd);
- if (!kill(pid, 0) && mysleep(180))
- {
- close(processed);
- killpg(pid, SIGTERM);
- mysleep(3);
- killpg(pid, SIGKILL);
- error("500 Conversion program timed out");
- return;
- }
- if (!kill(pid, 0))
- {
- close(processed);
- killpg(pid, SIGKILL);
- error("500 Interrupted during conversion");
- return;
- }
- }
- senduncompressed(processed);
- }
- #endif /* HANDLE_COMPRESSED */
- extern VOID
- do_get DECL1(char *, params)
- {
- char *temp, auth[XS_PATH_MAX], base[XS_PATH_MAX];
- const char *file, *question;
- int fd, wasdir;
- size_t size;
- struct stat statbuf;
- const struct passwd *userinfo;
- FILE *authfile;
- #ifdef HANDLE_COMPRESSED
- const ctypes *search = NULL;
- #endif /* HANDLE_COMPRESSED */
- alarm(240);
- question = strchr(params, '?');
- while ((temp = strstr(params, "//")))
- {
- if (!question || (temp < question))
- bcopy(temp + 1, temp, strlen(temp));
- else
- break;
- }
- strcpy(real_path, params);
- bzero(params + strlen(params), 16);
- setprocname("xs: Handling `%s' from `%s'", real_path, remotehost);
- userinfo = NULL;
- if (params[1] == '~')
- {
- if ((temp = strchr(params + 2, '/')))
- *temp = 0;
- if (!(userinfo = getpwnam(params + 2)))
- {
- server_error("404 User is unknown", "USER_UNKNOWN");
- return;
- }
- if (transform_user_dir(base, userinfo, 1))
- return;
- if (!origeuid)
- {
- setegid(userinfo->pw_gid);
- setgroups(1, (gid_t *)&userinfo->pw_gid);
- seteuid(userinfo->pw_uid);
- }
- if (!geteuid())
- {
- error("500 Effective UID is not valid");
- return;
- }
- if (temp)
- {
- *temp = '/';
- file = temp;
- } else
- file = params + strlen(params);
- } else
- {
- file = params;
- strcpy(base, calcpath(HTTPD_DOCUMENT_ROOT));
- strcat(base, "/");
- if (!origeuid)
- {
- setegid(group_id);
- setgroups(1, &group_id);
- seteuid(user_id);
- }
- if (!geteuid())
- {
- error("500 Effective UID is not valid");
- return;
- }
- }
- size = strlen(HTTPD_SCRIPT_ROOT);
- if (*file && (!strncmp(file + 1, HTTPD_SCRIPT_ROOT, size)) &&
- (file[size + 1] == '/'))
- {
- do_script(params, 1);
- return;
- }
- if (postonly)
- {
- server_error("403 Cannot use POST method on non-CGI",
- "POST_ON_NON_CGI");
- return;
- }
- if ((temp = strchr(file, '?')))
- {
- *temp = 0;
- setenv("DOCUMENT_ARGUMENTS", temp + 1, 1);
- if ((temp = strchr(real_path, '?')))
- *temp = 0;
- }
- if (*file)
- wasdir = (file[strlen(file) - 1] == '/');
- else
- wasdir = 0;
- if (strstr(file, "..") || strstr(file, "/.x"))
- {
- server_error("403 Invalid path specified", "INVALID_PATH");
- return;
- }
- /* if (*file == '/')
- file++; */
- if ((temp = strrchr(file, '/')))
- {
- *temp = 0;
- size = strlen(base);
- ((char *)file)[XS_PATH_MAX - (temp - file + 1 + size)] = 0;
- strcpy(base + size, file);
- strcat(base + size, "/");
- file = temp + 1;
- }
- if ((!*file) && (wasdir))
- strcat(real_path, file = INDEX_HTML);
- RETRY:
- sprintf(total, "%s/.xsuid", base);
- if (!stat(total, &statbuf))
- {
- if (!origeuid)
- {
- seteuid(origeuid);
- setegid(group_id);
- setgroups(1, &group_id);
- seteuid(user_id);
- }
- if (!geteuid())
- {
- error("500 Effective UID is not valid");
- return;
- }
- }
- sprintf(total, "%s%s.redir", base, file);
- if ((fd = open(total, O_RDONLY, 0)) >= 0)
- {
- if ((size = read(fd, total, MYBUFSIZ)) <= 0)
- {
- error("500 Redirection file error");
- close(fd); return;
- }
- total[size] = 0;
- strtok(total, "rn"); redirect(total, 0);
- close(fd); return;
- }
- sprintf(total, "%s/.redir", base);
- if ((fd = open(total, O_RDONLY, 0)) >= 0)
- {
- if ((size = read(fd, total, XS_PATH_MAX - strlen(file) - 16)) <= 0)
- {
- error("500 Directory redirection file error");
- close(fd); return;
- }
- close(fd);
- temp = total + size; *temp = 0;
- while ((temp > total) && (*(temp - 1) < ' '))
- *(--temp) = 0;
- strcat(total, file);
- strtok(total, "rn"); redirect(total, 0);
- return;
- }
- sprintf(total, "%s/.noxs", base);
- if (!stat(total, &statbuf))
- {
- server_error("403 Directory is not available", "DIR_NOT_AVAIL");
- return;
- }
- #ifdef HANDLE_COMPRESSED
- search = NULL;
- #endif /* HANDLE_COMPRESSED */
- sprintf(total, "%s%s", base, file);
- if (stat(total, &statbuf))
- #ifdef HANDLE_COMPRESSED
- {
- search = ctype;
- temp = total + strlen(total);
- while (search)
- {
- strcpy(temp, search->ext);
- if (!stat(total, &statbuf))
- break;
- search = search->next;
- }
- if (!search)
- goto NOTFOUND;
- }
- #else /* Not HANDLE_COMPRESSED */
- goto NOTFOUND;
- #endif /* HANDLE_COMPRESSED */
- if (!S_ISREG(statbuf.st_mode))
- {
- if (!S_ISDIR(statbuf.st_mode))
- {
- server_error("403 Not a regular file", "NOT_REGULAR");
- return;
- }
- if (!strcmp(file, INDEX_HTML) || !strcmp(file, INDEX_HTML_2))
- {
- error("403 The index may not be a directory");
- return;
- }
- if (wasdir)
- {
- wasdir = 0;
- strcat(real_path, file = INDEX_HTML);
- goto RETRY;
- } else
- {
- if (port != 80)
- sprintf(total, "http://%s:%d%s/",
- thishostname, port, orig);
- else
- sprintf(total, "http://%s%s/",
- thishostname, orig);
- redirect(total, 1);
- return;
- }
- }
- sprintf(auth, "%s/%s", base, AUTHFILE);
- if ((authfile = fopen(auth, "r")))
- {
- if (check_auth(authfile))
- return;
- }
- modtime = statbuf.st_mtime;
- if ((fd = open(total, O_RDONLY, 0)) < 0)
- {
- server_error("403 File permissions deny access", "PERMISSION");
- return;
- }
- strcpy(name, file);
- #ifdef HANDLE_COMPRESSED
- if (search)
- sendcompressed(fd, search->prog);
- else
- #endif /* HANDLE_COMPRESSED */
- senduncompressed(fd);
- return;
- NOTFOUND:
- if (!strcmp(file, INDEX_HTML) && strcmp(INDEX_HTML, INDEX_HTML_2))
- {
- strcpy(real_path + strlen(real_path) - strlen(INDEX_HTML),
- file = INDEX_HTML_2);
- wasdir = 0;
- goto RETRY;
- }
- server_error("404 Requested URL not found", "NOT_FOUND");
- }
- extern VOID
- do_post DECL1(char *, params)
- {
- postonly = 1;
- do_get(params);
- }
- extern VOID
- do_head DECL1(char *, params)
- {
- headonly = 1;
- do_get(params);
- }
- extern VOID
- loadfiletypes DECL0
- {
- char line[MYBUFSIZ], *end, *comment;
- const char *mimepath;
- FILE *mime;
- ftypes *prev, *new;
- while (ftype)
- {
- new = ftype->next;
- free(ftype); ftype = new;
- }
- mimepath = calcpath(MIMETYPESFILE);
- if (!(mime = fopen(mimepath, "r")))
- err(1, "fopen(`%s' [read])", mimepath);
- prev = NULL;
- while (fgets(line, MYBUFSIZ, mime))
- {
- if ((comment = strchr(line, '#')))
- *comment = 0;
- end = line + strlen(line);
- while ((end > line) && (*(end - 1) <= ' '))
- *(--end) = 0;
- if (end == line)
- continue;
- if (!(new = (ftypes *)malloc(sizeof(ftypes))))
- errx(1, "Out of memory in loadfiletypes()");
- if (prev)
- prev->next = new;
- else
- ftype = new;
- prev = new; new->next = NULL;
- if (sscanf(line, "%s %s", new->name, new->ext) != 2)
- errx(1, "Unable to parse line `%s' in `%s'",
- line, mimepath);
- }
- fclose(mime);
- }
- #ifdef HANDLE_COMPRESSED
- extern VOID
- loadcompresstypes DECL0
- {
- char line[MYBUFSIZ], *end, *comment;
- const char *path;
- FILE *methods;
- ctypes *prev, *new;
- while (ctype)
- {
- new = ctype->next;
- free(ctype); ctype = new;
- }
- path = calcpath(COMPRESS_METHODS);
- if (!(methods = fopen(path, "r")))
- err(1, "fopen(`%s' [read])", path);
- prev = NULL;
- while (fgets(line, MYBUFSIZ, methods))
- {
- if ((comment = strchr(line, '#')))
- *comment = 0;
- end = line + strlen(line);
- while ((end > line) && (*(end - 1) <= ' '))
- *(--end) = 0;
- if (line == end)
- continue;
- if (!(new = (ctypes *)malloc(sizeof(ctypes))))
- errx(1, "Out of memory in loadcompresstypes()");
- if (prev)
- prev->next = new;
- else
- ctype = new;
- prev = new; new->next = NULL;
- if (sscanf(line, "%s %s", new->prog, new->ext) != 2)
- errx(1, "Unable to parse `%s' in `%s'", line, path);
- }
- fclose(methods);
- }
- #endif /* HANDLE_COMPRESSED */
- extern int
- getfiletype DECL1(int, print)
- {
- const ftypes *search;
- const char *ext;
- char extension[20];
- int count;
- if (!(ext = strrchr(name, '.')) || !(*(++ext)))
- {
- if (print)
- printf("Content-type: text/plainrn");
- return(0);
- }
- for (count = 0; ext[count] && (count < 16); count++)
- extension[count] = tolower(ext[count]);
- extension[count] = 0;
- search = ftype;
- while (search)
- {
- if (!strcmp(extension, search->ext))
- {
- if (print)
- printf("Content-type: %srn", search->name);
- return(!strcmp(search->name, "text/html"));
- }
- search = search->next;
- }
- if (print)
- printf("Content-type: application/octet-streamrn");
- return(0);
- }