mirror of https://github.com/nealey/eris.git
2nd pass at stunnel vars
This commit is contained in:
parent
bdb9f0ac05
commit
c3ddfae1ff
290
eris.c
290
eris.c
|
@ -28,9 +28,9 @@
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
# include <sys/sendfile.h>
|
#include <sys/sendfile.h>
|
||||||
#else
|
#else
|
||||||
# define sendfile(a, b, c, d) -1
|
#define sendfile(a, b, c, d) -1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef min
|
#ifndef min
|
||||||
|
@ -50,28 +50,44 @@
|
||||||
#define DUMP_p(v) DUMPf("%s = %p", #v, v)
|
#define DUMP_p(v) DUMPf("%s = %p", #v, v)
|
||||||
#define DUMP_buf(v, l) DUMPf("%s = %.*s", #v, (int)(l), v)
|
#define DUMP_buf(v, l) DUMPf("%s = %.*s", #v, (int)(l), v)
|
||||||
|
|
||||||
/* Wait this long (seconds) for a valid HTTP request */
|
/*
|
||||||
|
* Wait this long (seconds) for a valid HTTP request
|
||||||
|
*/
|
||||||
#define READTIMEOUT 2
|
#define READTIMEOUT 2
|
||||||
|
|
||||||
/* Wait this long (seconds) for a non-file send to complete */
|
/*
|
||||||
|
* Wait this long (seconds) for a non-file send to complete
|
||||||
|
*/
|
||||||
#define WRITETIMEOUT 10
|
#define WRITETIMEOUT 10
|
||||||
|
|
||||||
/* Quit if we can't write at least this many bytes per second */
|
/*
|
||||||
|
* Quit if we can't write at least this many bytes per second
|
||||||
|
*/
|
||||||
#define MIN_WRITE_RATE 2560
|
#define MIN_WRITE_RATE 2560
|
||||||
|
|
||||||
/* Wait this long for CGI to complete */
|
/*
|
||||||
|
* Wait this long for CGI to complete
|
||||||
|
*/
|
||||||
#define CGI_TIMEOUT (5*60)
|
#define CGI_TIMEOUT (5*60)
|
||||||
|
|
||||||
/* How long each sendfile call can take */
|
/*
|
||||||
|
* How long each sendfile call can take
|
||||||
|
*/
|
||||||
#define SENDFILE_TIMEOUT ((int)(SIZE_MAX / MIN_WRITE_RATE))
|
#define SENDFILE_TIMEOUT ((int)(SIZE_MAX / MIN_WRITE_RATE))
|
||||||
|
|
||||||
/* Maximum size of a request header (the whole block) */
|
/*
|
||||||
|
* Maximum size of a request header (the whole block)
|
||||||
|
*/
|
||||||
#define MAXHEADERLEN 8192
|
#define MAXHEADERLEN 8192
|
||||||
|
|
||||||
/* Maximum size of a request line */
|
/*
|
||||||
|
* Maximum size of a request line
|
||||||
|
*/
|
||||||
#define MAXREQUESTLEN 2048
|
#define MAXREQUESTLEN 2048
|
||||||
|
|
||||||
/* Maximum number of header fields */
|
/*
|
||||||
|
* Maximum number of header fields
|
||||||
|
*/
|
||||||
#define MAXHEADERFIELDS 60
|
#define MAXHEADERFIELDS 60
|
||||||
|
|
||||||
#define BUFFER_SIZE 8192
|
#define BUFFER_SIZE 8192
|
||||||
|
@ -88,7 +104,9 @@ int portappend = 0;
|
||||||
char *connector = NULL;
|
char *connector = NULL;
|
||||||
|
|
||||||
|
|
||||||
/* Variables that persist between requests */
|
/*
|
||||||
|
* Variables that persist between requests
|
||||||
|
*/
|
||||||
int cwd;
|
int cwd;
|
||||||
int keepalive = 0;
|
int keepalive = 0;
|
||||||
char *remote_addr = NULL;
|
char *remote_addr = NULL;
|
||||||
|
@ -122,8 +140,7 @@ dolog(int code, off_t len)
|
||||||
sanitize(user_agent);
|
sanitize(user_agent);
|
||||||
sanitize(refer);
|
sanitize(refer);
|
||||||
|
|
||||||
fprintf(stderr, "%s %d %lu %s %s %s %s\n",
|
fprintf(stderr, "%s %d %lu %s %s %s %s\n", remote_addr, code, (unsigned long) len, host, user_agent, refer, path);
|
||||||
remote_addr, code, (unsigned long) len, host, user_agent, refer, path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -131,7 +148,7 @@ header(unsigned int code, const char *httpcomment)
|
||||||
{
|
{
|
||||||
printf("HTTP/1.%d %u %s\r\n", http_version, code, httpcomment);
|
printf("HTTP/1.%d %u %s\r\n", http_version, code, httpcomment);
|
||||||
printf("Server: %s\r\n", FNORD);
|
printf("Server: %s\r\n", FNORD);
|
||||||
printf("Connection: %s\r\n", keepalive?"keep-alive":"close");
|
printf("Connection: %s\r\n", keepalive ? "keep-alive" : "close");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,8 +171,7 @@ badrequest(long code, const char *httpcomment, const char *message)
|
||||||
if (message) {
|
if (message) {
|
||||||
msglen = (strlen(message) * 2) + 15;
|
msglen = (strlen(message) * 2) + 15;
|
||||||
|
|
||||||
printf("Content-Length: %lu\r\nContent-Type: text/html\r\n\r\n",
|
printf("Content-Length: %lu\r\nContent-Type: text/html\r\n\r\n", (unsigned long) msglen);
|
||||||
(unsigned long) msglen);
|
|
||||||
printf("<title>%s</title>%s", message, message);
|
printf("<title>%s</title>%s", message, message);
|
||||||
}
|
}
|
||||||
printf("\r\n");
|
printf("\r\n");
|
||||||
|
@ -201,18 +217,28 @@ void
|
||||||
get_ucspi_env()
|
get_ucspi_env()
|
||||||
{
|
{
|
||||||
char *ucspi = getenv("PROTO");
|
char *ucspi = getenv("PROTO");
|
||||||
|
char *ip = NULL;
|
||||||
|
char *port = NULL;
|
||||||
|
|
||||||
if (ucspi) {
|
if (ucspi) {
|
||||||
char *p;
|
char *p;
|
||||||
|
|
||||||
/* Busybox, as usual, has the right idea */
|
/*
|
||||||
|
* Busybox, as usual, has the right idea
|
||||||
|
*/
|
||||||
if ((p = proto_getenv(ucspi, "REMOTEADDR"))) {
|
if ((p = proto_getenv(ucspi, "REMOTEADDR"))) {
|
||||||
remote_addr = strdup(p);
|
remote_addr = strdup(p);
|
||||||
} else {
|
} else {
|
||||||
char *ip = proto_getenv(ucspi, "REMOTEIP");
|
ip = proto_getenv(ucspi, "REMOTEIP");
|
||||||
char *port = proto_getenv(ucspi, "REMOTEPORT");
|
port = proto_getenv(ucspi, "REMOTEPORT");
|
||||||
|
}
|
||||||
|
|
||||||
if (! ip) {
|
if ((p = proto_getenv(ucspi, "REMOTEINFO"))) {
|
||||||
|
remote_ident = strdup(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ip) {
|
||||||
// stunnel
|
// stunnel
|
||||||
ip = getenv("REMOTE_HOST");
|
ip = getenv("REMOTE_HOST");
|
||||||
port = getenv("REMOTE_PORT");
|
port = getenv("REMOTE_PORT");
|
||||||
|
@ -224,12 +250,6 @@ get_ucspi_env()
|
||||||
snprintf(buf, sizeof buf, "%s:%s", ip, port);
|
snprintf(buf, sizeof buf, "%s:%s", ip, port);
|
||||||
remote_addr = strdup(buf);
|
remote_addr = strdup(buf);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if ((p = proto_getenv(ucspi, "REMOTEINFO"))) {
|
|
||||||
remote_ident = strdup(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -265,8 +285,7 @@ parse_options(int argc, char *argv[])
|
||||||
exit(0);
|
exit(0);
|
||||||
case 'h':
|
case 'h':
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "Usage: %s [OPTIONS]\n",
|
fprintf(stderr, "Usage: %s [OPTIONS]\n", argv[0]);
|
||||||
argv[0]);
|
|
||||||
fprintf(stderr, "\n");
|
fprintf(stderr, "\n");
|
||||||
fprintf(stderr, "-a Enable authentication\n");
|
fprintf(stderr, "-a Enable authentication\n");
|
||||||
fprintf(stderr, "-c Enable CGI\n");
|
fprintf(stderr, "-c Enable CGI\n");
|
||||||
|
@ -293,8 +312,9 @@ sigchld(int sig)
|
||||||
static void
|
static void
|
||||||
sigalarm_cgi(int sig)
|
sigalarm_cgi(int sig)
|
||||||
{
|
{
|
||||||
/* send this out regardless of whether we've already sent a header,
|
/*
|
||||||
* to maybe help with debugging */
|
* send this out regardless of whether we've already sent a header, to maybe help with debugging
|
||||||
|
*/
|
||||||
badrequest(504, "Gateway Timeout", "The CGI is being too slow.");
|
badrequest(504, "Gateway Timeout", "The CGI is being too slow.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -316,7 +336,9 @@ cgi_child(const char *relpath)
|
||||||
env("CONTENT_TYPE", content_type);
|
env("CONTENT_TYPE", content_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Try to change to CGI's directory */
|
/*
|
||||||
|
* Try to change to CGI's directory
|
||||||
|
*/
|
||||||
{
|
{
|
||||||
char *delim = strrchr(relpath, '/');
|
char *delim = strrchr(relpath, '/');
|
||||||
|
|
||||||
|
@ -357,7 +379,9 @@ cgi_parent(int cin, int cout, int passthru)
|
||||||
nfds = cin;
|
nfds = cin;
|
||||||
|
|
||||||
if (content_length) {
|
if (content_length) {
|
||||||
/* have post data */
|
/*
|
||||||
|
* have post data
|
||||||
|
*/
|
||||||
FD_SET(cout, &wfds);
|
FD_SET(cout, &wfds);
|
||||||
if (cout > nfds) {
|
if (cout > nfds) {
|
||||||
nfds = cout;
|
nfds = cout;
|
||||||
|
@ -368,58 +392,74 @@ cgi_parent(int cin, int cout, int passthru)
|
||||||
}
|
}
|
||||||
|
|
||||||
alarm(CGI_TIMEOUT);
|
alarm(CGI_TIMEOUT);
|
||||||
if (-1 == select(nfds+1, &rfds, &wfds, NULL, NULL)) {
|
if (-1 == select(nfds + 1, &rfds, &wfds, NULL, NULL)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FD_ISSET(cin, &rfds)) {
|
if (FD_ISSET(cin, &rfds)) {
|
||||||
if (passthru) {
|
if (passthru) {
|
||||||
/* Pass everything through verbatim */
|
/*
|
||||||
|
* Pass everything through verbatim
|
||||||
|
*/
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
||||||
/* Re-use this big buffer */
|
/*
|
||||||
|
* Re-use this big buffer
|
||||||
|
*/
|
||||||
len = fread(cgiheader, 1, sizeof cgiheader, cinf);
|
len = fread(cgiheader, 1, sizeof cgiheader, cinf);
|
||||||
if (0 == len) {
|
if (0 == len) {
|
||||||
/* CGI is done */
|
/*
|
||||||
|
* CGI is done
|
||||||
|
*/
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
fwrite(cgiheader, 1, len, stdout);
|
fwrite(cgiheader, 1, len, stdout);
|
||||||
|
|
||||||
/* Naively assume the CGI knows best about sending stuff */
|
/*
|
||||||
|
* Naively assume the CGI knows best about sending stuff
|
||||||
|
*/
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
size += len;
|
size += len;
|
||||||
} else {
|
} else {
|
||||||
/* Interpret header fields */
|
/*
|
||||||
|
* Interpret header fields
|
||||||
|
*/
|
||||||
size_t readlen = (sizeof cgiheader) - cgiheaderlen;
|
size_t readlen = (sizeof cgiheader) - cgiheaderlen;
|
||||||
|
|
||||||
if (NULL == fgets(cgiheader + cgiheaderlen, readlen, cinf)) {
|
if (NULL == fgets(cgiheader + cgiheaderlen, readlen, cinf)) {
|
||||||
/* EOF or error */
|
/*
|
||||||
|
* EOF or error
|
||||||
|
*/
|
||||||
badrequest(500, "CGI Error", "CGI output too weird");
|
badrequest(500, "CGI Error", "CGI output too weird");
|
||||||
}
|
}
|
||||||
cgiheaderlen = strlen(cgiheader);
|
cgiheaderlen = strlen(cgiheader);
|
||||||
|
|
||||||
if ('\n' == cgiheader[cgiheaderlen - 1]) {
|
if ('\n' == cgiheader[cgiheaderlen - 1]) {
|
||||||
/* We read a whole line */
|
/*
|
||||||
|
* We read a whole line
|
||||||
|
*/
|
||||||
size_t len;
|
size_t len;
|
||||||
char *val;
|
char *val;
|
||||||
|
|
||||||
len = extract_header_field(cgiheader, &val, 0);
|
len = extract_header_field(cgiheader, &val, 0);
|
||||||
if (! len) {
|
if (!len) {
|
||||||
/* We've read the entire header block */
|
/*
|
||||||
|
* We've read the entire header block
|
||||||
|
*/
|
||||||
passthru = 1;
|
passthru = 1;
|
||||||
eoh();
|
eoh();
|
||||||
} else {
|
} else {
|
||||||
if (! header_sent) {
|
if (!header_sent) {
|
||||||
if (! strcasecmp(cgiheader, "Location")) {
|
if (!strcasecmp(cgiheader, "Location")) {
|
||||||
header(302, "CGI Redirect");
|
header(302, "CGI Redirect");
|
||||||
printf("%s: %s\r\n\r\n", cgiheader, val);
|
printf("%s: %s\r\n\r\n", cgiheader, val);
|
||||||
dolog(302, 0);
|
dolog(302, 0);
|
||||||
exit(0);
|
exit(0);
|
||||||
} else if (! strcasecmp(cgiheader, "Status")) {
|
} else if (!strcasecmp(cgiheader, "Status")) {
|
||||||
char *txt;
|
char *txt;
|
||||||
|
|
||||||
if (val) {
|
if (val) {
|
||||||
code = (int)strtol(val, &txt, 10);
|
code = (int) strtol(val, &txt, 10);
|
||||||
} else {
|
} else {
|
||||||
code = 0;
|
code = 0;
|
||||||
}
|
}
|
||||||
|
@ -496,7 +536,9 @@ serve_cgi(char *relpath)
|
||||||
close(cin[1]);
|
close(cin[1]);
|
||||||
close(cout[0]);
|
close(cout[0]);
|
||||||
|
|
||||||
/* Eris is not this smart yet */
|
/*
|
||||||
|
* Eris is not this smart yet
|
||||||
|
*/
|
||||||
keepalive = 0;
|
keepalive = 0;
|
||||||
|
|
||||||
cgi_parent(cin[0], cout[1], 0);
|
cgi_parent(cin[0], cout[1], 0);
|
||||||
|
@ -522,20 +564,26 @@ serve_cgi(char *relpath)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ssize_t
|
ssize_t
|
||||||
fake_sendfile(int out_fd, int in_fd, off_t *offset, size_t count)
|
fake_sendfile(int out_fd, int in_fd, off_t * offset, size_t count)
|
||||||
{
|
{
|
||||||
char buf[BUFFER_SIZE];
|
char buf[BUFFER_SIZE];
|
||||||
ssize_t l, m;
|
ssize_t l, m;
|
||||||
|
|
||||||
/* is mmap quicker? does it matter? */
|
/*
|
||||||
|
* is mmap quicker? does it matter?
|
||||||
|
*/
|
||||||
if (-1 == lseek(in_fd, *offset, SEEK_SET)) {
|
if (-1 == lseek(in_fd, *offset, SEEK_SET)) {
|
||||||
/* We're screwed. The most helpful thing we can do now is die. */
|
/*
|
||||||
|
* We're screwed. The most helpful thing we can do now is die.
|
||||||
|
*/
|
||||||
fprintf(stderr, "Unable to seek. Dying.\n");
|
fprintf(stderr, "Unable to seek. Dying.\n");
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
l = read(in_fd, buf, min(count, sizeof buf));
|
l = read(in_fd, buf, min(count, sizeof buf));
|
||||||
if (-1 == l) {
|
if (-1 == l) {
|
||||||
/* Also screwed. */
|
/*
|
||||||
|
* Also screwed.
|
||||||
|
*/
|
||||||
fprintf(stderr, "Unable to read an open file. Dying.\n");
|
fprintf(stderr, "Unable to read an open file. Dying.\n");
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
@ -544,7 +592,9 @@ fake_sendfile(int out_fd, int in_fd, off_t *offset, size_t count)
|
||||||
while (l) {
|
while (l) {
|
||||||
m = write(out_fd, buf, l);
|
m = write(out_fd, buf, l);
|
||||||
if (-1 == m) {
|
if (-1 == m) {
|
||||||
/* ALSO screwed. */
|
/*
|
||||||
|
* ALSO screwed.
|
||||||
|
*/
|
||||||
fprintf(stderr, "Unable to write to client: %m (req %s). Dying.\n", path);
|
fprintf(stderr, "Unable to write to client: %m (req %s). Dying.\n", path);
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
@ -596,7 +646,7 @@ serve_file(int fd, char *filename, struct stat *st)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (remain = len; remain; ) {
|
for (remain = len; remain;) {
|
||||||
size_t count = min(remain, SIZE_MAX);
|
size_t count = min(remain, SIZE_MAX);
|
||||||
ssize_t sent;
|
ssize_t sent;
|
||||||
|
|
||||||
|
@ -658,7 +708,7 @@ serve_idx(int fd, char *path)
|
||||||
name = symlink;
|
name = symlink;
|
||||||
printf("[LNK] "); /* symlink */
|
printf("[LNK] "); /* symlink */
|
||||||
} else if (S_ISREG(st.st_mode)) {
|
} else if (S_ISREG(st.st_mode)) {
|
||||||
printf("%10llu", (unsigned long long)st.st_size);
|
printf("%10llu", (unsigned long long) st.st_size);
|
||||||
} else {
|
} else {
|
||||||
continue; /* not a file we can provide -> skip */
|
continue; /* not a file we can provide -> skip */
|
||||||
}
|
}
|
||||||
|
@ -686,26 +736,36 @@ find_serve_file(char *relpath)
|
||||||
int fd;
|
int fd;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
/* Open fspath. If that worked, */
|
/*
|
||||||
|
* Open fspath. If that worked,
|
||||||
|
*/
|
||||||
if ((fd = open(relpath, O_RDONLY)) > -1) {
|
if ((fd = open(relpath, O_RDONLY)) > -1) {
|
||||||
fstat(fd, &st);
|
fstat(fd, &st);
|
||||||
/* If it is a directory, */
|
/*
|
||||||
|
* If it is a directory,
|
||||||
|
*/
|
||||||
if (S_ISDIR(st.st_mode)) {
|
if (S_ISDIR(st.st_mode)) {
|
||||||
char path2[PATH_MAX];
|
char path2[PATH_MAX];
|
||||||
int fd2;
|
int fd2;
|
||||||
|
|
||||||
/* Redirect if it doesn't end with / */
|
/*
|
||||||
if (! endswith(path, "/")) {
|
* Redirect if it doesn't end with /
|
||||||
|
*/
|
||||||
|
if (!endswith(path, "/")) {
|
||||||
header(301, "Redirect");
|
header(301, "Redirect");
|
||||||
printf("Location: %s/\r\n", path);
|
printf("Location: %s/\r\n", path);
|
||||||
eoh();
|
eoh();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Open relpath + "index.html". If that worked,*/
|
/*
|
||||||
|
* Open relpath + "index.html". If that worked,
|
||||||
|
*/
|
||||||
snprintf(path2, sizeof path2, "%sindex.html", relpath);
|
snprintf(path2, sizeof path2, "%sindex.html", relpath);
|
||||||
if ((fd2 = open(path2, O_RDONLY)) > -1) {
|
if ((fd2 = open(path2, O_RDONLY)) > -1) {
|
||||||
/* serve that file and return. */
|
/*
|
||||||
|
* serve that file and return.
|
||||||
|
*/
|
||||||
fstat(fd2, &st);
|
fstat(fd2, &st);
|
||||||
serve_file(fd2, path2, &st);
|
serve_file(fd2, path2, &st);
|
||||||
close(fd2);
|
close(fd2);
|
||||||
|
@ -714,7 +774,7 @@ find_serve_file(char *relpath)
|
||||||
} else {
|
} else {
|
||||||
if (docgi) {
|
if (docgi) {
|
||||||
snprintf(path2, sizeof path2, "%sindex.cgi", relpath);
|
snprintf(path2, sizeof path2, "%sindex.cgi", relpath);
|
||||||
if (! stat(path2, &st)) {
|
if (!stat(path2, &st)) {
|
||||||
return serve_cgi(path2);
|
return serve_cgi(path2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -740,7 +800,7 @@ find_serve_file(char *relpath)
|
||||||
p += 4;
|
p += 4;
|
||||||
env("PATH_INFO", p);
|
env("PATH_INFO", p);
|
||||||
*p = 0;
|
*p = 0;
|
||||||
if (! stat(relpath, &st)) {
|
if (!stat(relpath, &st)) {
|
||||||
close(fd);
|
close(fd);
|
||||||
return serve_cgi(relpath);
|
return serve_cgi(relpath);
|
||||||
}
|
}
|
||||||
|
@ -758,7 +818,9 @@ handle_request()
|
||||||
char buf[MAXHEADERLEN];
|
char buf[MAXHEADERLEN];
|
||||||
char *p;
|
char *p;
|
||||||
|
|
||||||
/* Initialize globals */
|
/*
|
||||||
|
* Initialize globals
|
||||||
|
*/
|
||||||
host = NULL;
|
host = NULL;
|
||||||
user_agent = NULL;
|
user_agent = NULL;
|
||||||
refer = NULL;
|
refer = NULL;
|
||||||
|
@ -771,10 +833,14 @@ handle_request()
|
||||||
|
|
||||||
alarm(READTIMEOUT);
|
alarm(READTIMEOUT);
|
||||||
|
|
||||||
/* Read request line first */
|
/*
|
||||||
|
* Read request line first
|
||||||
|
*/
|
||||||
request[0] = 0;
|
request[0] = 0;
|
||||||
if (NULL == fgets(request, sizeof request, stdin)) {
|
if (NULL == fgets(request, sizeof request, stdin)) {
|
||||||
/* They must have hung up! */
|
/*
|
||||||
|
* They must have hung up!
|
||||||
|
*/
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
if (!strncmp(request, "GET /", 5)) {
|
if (!strncmp(request, "GET /", 5)) {
|
||||||
|
@ -790,7 +856,9 @@ handle_request()
|
||||||
method = CONNECT;
|
method = CONNECT;
|
||||||
p = request + 8;
|
p = request + 8;
|
||||||
} else {
|
} else {
|
||||||
/* This also handles the case where fgets does nothing */
|
/*
|
||||||
|
* This also handles the case where fgets does nothing
|
||||||
|
*/
|
||||||
badrequest(405, "Method Not Allowed", "Unsupported HTTP method.");
|
badrequest(405, "Method Not Allowed", "Unsupported HTTP method.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -799,7 +867,9 @@ handle_request()
|
||||||
env("REQUEST_METHOD", request);
|
env("REQUEST_METHOD", request);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Interpret path into fspath. */
|
/*
|
||||||
|
* Interpret path into fspath.
|
||||||
|
*/
|
||||||
path = p;
|
path = p;
|
||||||
{
|
{
|
||||||
char *fsp = fspath;
|
char *fsp = fspath;
|
||||||
|
@ -818,7 +888,7 @@ handle_request()
|
||||||
query_string = p + 1;
|
query_string = p + 1;
|
||||||
break;
|
break;
|
||||||
case '%':
|
case '%':
|
||||||
if ((! query_string) && p[1] && p[2]) {
|
if ((!query_string) && p[1] && p[2]) {
|
||||||
int a = fromhex(p[1]);
|
int a = fromhex(p[1]);
|
||||||
int b = fromhex(p[2]);
|
int b = fromhex(p[2]);
|
||||||
|
|
||||||
|
@ -830,15 +900,17 @@ handle_request()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((! query_string) && (fsp - fspath + 1 < sizeof fspath)) {
|
if ((!query_string) && (fsp - fspath + 1 < sizeof fspath)) {
|
||||||
*(fsp++) = c;
|
*(fsp++) = c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*fsp = 0;
|
*fsp = 0;
|
||||||
|
|
||||||
/* Change "/." to "/:" to keep "hidden" files such and prevent directory traversal */
|
/*
|
||||||
|
* Change "/." to "/:" to keep "hidden" files such and prevent directory traversal
|
||||||
|
*/
|
||||||
while ((fsp = strstr(fspath, "/."))) {
|
while ((fsp = strstr(fspath, "/."))) {
|
||||||
*(fsp+1) = ':';
|
*(fsp + 1) = ':';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -850,10 +922,10 @@ handle_request()
|
||||||
}
|
}
|
||||||
|
|
||||||
http_version = -1;
|
http_version = -1;
|
||||||
if (! strncmp(p, "HTTP/1.", 7) && p[8] && ((p[8] == '\r') || (p[8] == '\n'))) {
|
if (!strncmp(p, "HTTP/1.", 7) && p[8] && ((p[8] == '\r') || (p[8] == '\n'))) {
|
||||||
http_version = p[7] - '0';
|
http_version = p[7] - '0';
|
||||||
}
|
}
|
||||||
if (! ((http_version == 0) || (http_version == 1))) {
|
if (!((http_version == 0) || (http_version == 1))) {
|
||||||
http_version = 0;
|
http_version = 0;
|
||||||
badrequest(505, "Version Not Supported", "HTTP version not supported");
|
badrequest(505, "Version Not Supported", "HTTP version not supported");
|
||||||
}
|
}
|
||||||
|
@ -867,7 +939,9 @@ handle_request()
|
||||||
env("SERVER_PROTOCOL", p);
|
env("SERVER_PROTOCOL", p);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read header fields */
|
/*
|
||||||
|
* Read header fields
|
||||||
|
*/
|
||||||
{
|
{
|
||||||
char *base = buf;
|
char *base = buf;
|
||||||
char *lastchar = base + (sizeof buf) - 2;
|
char *lastchar = base + (sizeof buf) - 2;
|
||||||
|
@ -881,7 +955,9 @@ handle_request()
|
||||||
char *name, *val;
|
char *name, *val;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
||||||
/* 40 is totally arbitrary here. */
|
/*
|
||||||
|
* 40 is totally arbitrary here.
|
||||||
|
*/
|
||||||
if (plen < 40) {
|
if (plen < 40) {
|
||||||
badrequest(431, "Request Header Too Large", "The HTTP header block was too large");
|
badrequest(431, "Request Header Too Large", "The HTTP header block was too large");
|
||||||
}
|
}
|
||||||
|
@ -900,55 +976,67 @@ handle_request()
|
||||||
}
|
}
|
||||||
|
|
||||||
len = extract_header_field(p, &val, 1);
|
len = extract_header_field(p, &val, 1);
|
||||||
if (! len) {
|
if (!len) {
|
||||||
/* blank line */
|
/*
|
||||||
|
* blank line
|
||||||
|
*/
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (! val) {
|
if (!val) {
|
||||||
badrequest(400, "Invalid header", "Unable to parse header block");
|
badrequest(400, "Invalid header", "Unable to parse header block");
|
||||||
}
|
}
|
||||||
|
|
||||||
name = p;
|
name = p;
|
||||||
|
|
||||||
/* Set up CGI environment variables */
|
/*
|
||||||
|
* Set up CGI environment variables
|
||||||
|
*/
|
||||||
if (docgi) {
|
if (docgi) {
|
||||||
env(cgi_name, val);
|
env(cgi_name, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* By default, re-use buffer space */
|
/*
|
||||||
|
* By default, re-use buffer space
|
||||||
|
*/
|
||||||
base = cgi_name;
|
base = cgi_name;
|
||||||
|
|
||||||
/* Handle special header fields */
|
/*
|
||||||
if (! strcmp(name, "HOST")) {
|
* Handle special header fields
|
||||||
|
*/
|
||||||
|
if (!strcmp(name, "HOST")) {
|
||||||
host = val;
|
host = val;
|
||||||
base = name + len + 1;
|
base = name + len + 1;
|
||||||
} else if (! strcmp(name, "USER_AGENT")) {
|
} else if (!strcmp(name, "USER_AGENT")) {
|
||||||
user_agent = val;
|
user_agent = val;
|
||||||
base = name + len + 1;
|
base = name + len + 1;
|
||||||
} else if (! strcmp(name, "REFERER")) {
|
} else if (!strcmp(name, "REFERER")) {
|
||||||
refer = val;
|
refer = val;
|
||||||
base = name + len + 1;
|
base = name + len + 1;
|
||||||
} else if (! strcmp(name, "CONTENT_TYPE")) {
|
} else if (!strcmp(name, "CONTENT_TYPE")) {
|
||||||
content_type = val;
|
content_type = val;
|
||||||
base = name + len + 1;
|
base = name + len + 1;
|
||||||
} else if (! strcmp(name, "CONTENT_LENGTH")) {
|
} else if (!strcmp(name, "CONTENT_LENGTH")) {
|
||||||
content_length = (size_t) strtoull(val, NULL, 10);
|
content_length = (size_t) strtoull(val, NULL, 10);
|
||||||
} else if (! strcmp(name, "CONNECTION")) {
|
} else if (!strcmp(name, "CONNECTION")) {
|
||||||
if (! strcasecmp(val, "keep-alive")) {
|
if (!strcasecmp(val, "keep-alive")) {
|
||||||
keepalive = 1;
|
keepalive = 1;
|
||||||
} else {
|
} else {
|
||||||
keepalive = 0;
|
keepalive = 0;
|
||||||
}
|
}
|
||||||
} else if (! strcmp(name, "IF_MODIFIED_SINCE")) {
|
} else if (!strcmp(name, "IF_MODIFIED_SINCE")) {
|
||||||
ims = timerfc(val);
|
ims = timerfc(val);
|
||||||
} else if (! strcmp(name, "RANGE")) {
|
} else if (!strcmp(name, "RANGE")) {
|
||||||
/* Range: bytes=17-23 */
|
/*
|
||||||
/* Range: bytes=23- */
|
* Range: bytes=17-23
|
||||||
if (! strncmp(val, "bytes=", 6)) {
|
*/
|
||||||
|
/*
|
||||||
|
* Range: bytes=23-
|
||||||
|
*/
|
||||||
|
if (!strncmp(val, "bytes=", 6)) {
|
||||||
p = val + 6;
|
p = val + 6;
|
||||||
range_start = (off_t) strtoull(p, &p, 10);
|
range_start = (off_t) strtoull(p, &p, 10);
|
||||||
if (*p == '-') {
|
if (*p == '-') {
|
||||||
range_end = (off_t) strtoull(p+1, NULL, 10);
|
range_end = (off_t) strtoull(p + 1, NULL, 10);
|
||||||
} else {
|
} else {
|
||||||
range_end = 0;
|
range_end = 0;
|
||||||
}
|
}
|
||||||
|
@ -957,8 +1045,10 @@ handle_request()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Try to change into the appropriate directory */
|
/*
|
||||||
if (! nochdir) {
|
* Try to change into the appropriate directory
|
||||||
|
*/
|
||||||
|
if (!nochdir) {
|
||||||
char fn[PATH_MAX];
|
char fn[PATH_MAX];
|
||||||
|
|
||||||
if (host) {
|
if (host) {
|
||||||
|
@ -977,7 +1067,7 @@ handle_request()
|
||||||
case ':':
|
case ':':
|
||||||
*p = 0;
|
*p = 0;
|
||||||
break;
|
break;
|
||||||
case 'A'...'Z':
|
case 'A' ... 'Z':
|
||||||
*p ^= ' ';
|
*p ^= ' ';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -993,7 +1083,9 @@ handle_request()
|
||||||
badrequest(500, "Unable to exec connector", strerror(errno));
|
badrequest(500, "Unable to exec connector", strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Serve the file */
|
/*
|
||||||
|
* Serve the file
|
||||||
|
*/
|
||||||
alarm(WRITETIMEOUT);
|
alarm(WRITETIMEOUT);
|
||||||
find_serve_file(fspath);
|
find_serve_file(fspath);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
|
@ -1013,7 +1105,7 @@ main(int argc, char *argv[], const char *const *envp)
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
handle_request();
|
handle_request();
|
||||||
if (! keepalive) {
|
if (!keepalive) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (-1 == fchdir(cwd)) {
|
if (-1 == fchdir(cwd)) {
|
||||||
|
|
Loading…
Reference in New Issue