Works for "GET / HTTP/1.0"

This commit is contained in:
Neale Pickett 2012-02-13 22:49:10 -07:00
parent 45a5cd8fae
commit ef5f424643
3 changed files with 200 additions and 211 deletions

View File

@ -1,14 +1,16 @@
VERSION := $(shell head -n 1 CHANGES | tr -d :) VERSION := $(shell head -n 1 CHANGES | tr -d :)
CFLAGS = -DFNORD='fnord/$(VERSION)' CFLAGS = -DFNORD='"fnord/$(VERSION)"'
all: fnord fnord-cgi fnord-idx all: fnord fnord-cgi fnord-idx
fnord-cgi: httpd.c
fnord-cgi: CFLAGS += -DCGI fnord-cgi: CFLAGS += -DCGI
fnord-cgi: fnord.c
$(CC) $(CFLAGS) -o $@ $(LDFLAGS) $<
fnord-idx: httpd.c
fnord-idx: CFLAGS += -DDIR_LIST fnord-idx: CFLAGS += -DDIR_LIST
fnord-idx: fnord.c
$(CC) $(CFLAGS) -o $@ $(LDFLAGS) $<
clean: clean:
rm -f *.[oa] fnord fnord-cgi fnord-idx rm -f *.[oa] fnord fnord-cgi fnord-idx

377
fnord.c
View File

@ -22,10 +22,14 @@
#include <sys/mman.h> #include <sys/mman.h>
#include <limits.h> #include <limits.h>
#include "str.c"
/* /*
* Some things I use for debugging * Some things I use for debugging
*/ */
#ifdef DUMP #define XXNODUMP
#ifndef NODUMP
#define DUMPf(fmt, args...) fprintf(stderr, "%s:%s:%d " fmt "\n", __FILE__, __FUNCTION__, __LINE__, ##args) #define DUMPf(fmt, args...) fprintf(stderr, "%s:%s:%d " fmt "\n", __FILE__, __FUNCTION__, __LINE__, ##args)
#else #else
#define DUMPf(fmt, args...) #define DUMPf(fmt, args...)
@ -157,7 +161,7 @@ static long retcode = 404; /* used for logging code */
char *host = "?"; /* Host: header */ char *host = "?"; /* Host: header */
char *port; /* also Host: header, :80 part */ char *port; /* also Host: header, :80 part */
char *args; /* URL behind ? (for CGIs) */ char *args; /* URL behind ? (for CGIs) */
char *url; /* string between GET and HTTP/1.0, char *url; /* string between GET and HTTP/1.0, *
* demangled */ * demangled */
char *ua = "?"; /* user-agent */ char *ua = "?"; /* user-agent */
char *refer; /* Referrer: header */ char *refer; /* Referrer: header */
@ -166,7 +170,7 @@ int httpversion; /* 0 == 1.0, 1 == 1.1 */
#ifdef KEEPALIVE #ifdef KEEPALIVE
int keepalive = 0; /* should we keep the connection alive? */ int keepalive = 0; /* should we keep the connection alive? */
int rootdir; /* fd of root directory, so we can fchdir int rootdir; /* fd of root directory, so we can fchdir
* back for keep-alive */ * * back for keep-alive */
#endif #endif
#ifdef CGI #ifdef CGI
char *cookie; /* Referrer: header */ char *cookie; /* Referrer: header */
@ -182,11 +186,11 @@ unsigned long post_len = 0;
#if _FILE_OFFSET_BITS == 64 #if _FILE_OFFSET_BITS == 64
static unsigned long long rangestart, static unsigned long long rangestart,
rangeend; /* for ranged queries */ rangeend; /* for ranged queries */
#define strtorange strtoull
#else #else
static unsigned long rangestart, static unsigned long rangestart,
rangeend; /* for ranged queries */ rangeend; /* for ranged queries */
#define scan_range scan_ulong #define strtorange strtoul
#define buffer_putrange buffer_putulong
#endif #endif
static const char days[] = "SunMonTueWedThuFriSat"; static const char days[] = "SunMonTueWedThuFriSat";
@ -202,9 +206,10 @@ char *remote_ident;
static void static void
sanitize(char *ua) sanitize(char *ua)
{ /* replace strings with underscores for { /* replace strings with underscores for *
* logging */ * logging */
int j; int j;
if (! ua) return;
for (j = 0; ua[j]; ++j) for (j = 0; ua[j]; ++j)
if (isspace(ua[j])) if (isspace(ua[j]))
ua[j] = '_'; ua[j] = '_';
@ -215,8 +220,7 @@ dolog(off_t len)
{ /* write a log line to stderr */ { /* write a log line to stderr */
sanitize(host); sanitize(host);
sanitize(ua); sanitize(ua);
if (refer) sanitize(refer);
sanitize(refer);
fprintf(stderr, "%s %d %d %s %s %s %s\n", fprintf(stderr, "%s %d %d %s %s %s %s\n",
remote_ip ? remote_ip : "0.0.0.0", remote_ip ? remote_ip : "0.0.0.0",
@ -229,22 +233,21 @@ dolog(off_t len)
static void static void
badrequest(long code, const char *httpcomment, const char *message) badrequest(long code, const char *httpcomment, const char *message)
{ {
DUMP();
retcode = code; retcode = code;
DUMP();
dolog(0); dolog(0);
buffer_puts(buffer_1, "HTTP/1.0 "); DUMP();
buffer_putulong(buffer_1, code); printf("HTTP/1.0 %d %s\r\nConnection: close\r\n", code, httpcomment);
buffer_putspace(buffer_1); if (message && message[0]) {
buffer_puts(buffer_1, httpcomment); printf("Content-Length: %d\r\nContent-Type: text/html\r\n\r\n",
buffer_puts(buffer_1, "\r\nConnection: close\r\n"); strlen(message));
if (message[0]) { fputs(message, stdout);
buffer_puts(buffer_1, "Content-Length: ");
buffer_putulong(buffer_1, strlen(message));
buffer_puts(buffer_1, "\r\nContent-Type: text/html\r\n\r\n");
buffer_puts(buffer_1, message);
} else { } else {
buffer_puts(buffer_1, "\r\n"); printf("\r\n", stdout);
} }
buffer_flush(buffer_1); DUMP();
fflush(stdout);
exit(0); exit(0);
} }
@ -436,8 +439,8 @@ do_cgi(const char *pathinfo, const char *const *envp)
cgi_env[++i] = tmp; cgi_env[++i] = tmp;
tmp += str_copy(tmp, "PATH_TRANSLATED="); tmp += str_copy(tmp, "PATH_TRANSLATED=");
tmp += tmp +=
realpath(pathinfo, tmp) ? str_len(tmp) : str_copy(tmp, realpath(pathinfo, tmp) ? strlen(tmp) : str_copy(tmp,
pathinfo); pathinfo);
++tmp; ++tmp;
} }
@ -452,7 +455,7 @@ do_cgi(const char *pathinfo, const char *const *envp)
/* /*
* argv * argv
*/ */
if (args && (args[str_chr(args, '=')] == 0)) { if (args && (strchr(args, '=') == 0)) {
int n = 3; int n = 3;
for (i = 0; args[i]; ++i) for (i = 0; args[i]; ++i)
if (args[i] == '+') if (args[i] == '+')
@ -519,10 +522,11 @@ cgi_send_correct_http(const char *s, unsigned int sl)
++i; ++i;
goto out_nl; goto out_nl;
} else { } else {
if (s[i] != '\n') if (s[i] != '\n') {
buffer_put(buffer_1, s + i, 1); putchar(s[i]);
else { } else {
out_nl:buffer_put(buffer_1, "\r\n", 2); out_nl:
printf("\r\n");
if (ch == '\n') { if (ch == '\n') {
++i; ++i;
break; break;
@ -531,7 +535,7 @@ cgi_send_correct_http(const char *s, unsigned int sl)
} }
ch = s[i]; ch = s[i];
} }
buffer_put(buffer_1, s + i, sl - i); printf("%.*s", sl - i, s + i);
} }
static void static void
@ -590,29 +594,26 @@ start_cgi(int nph, const char *pathinfo, const char *const *envp)
if (startup) { if (startup) {
startup = 0; startup = 0;
if (nph) { /* NPH-CGI */ if (nph) { /* NPH-CGI */
buffer_put(buffer_1, ibuf, n); printf("%.*s", n, ibuf);
scan_ulong(ibuf + 9, &retcode); /* only /*
* get * skip HTTP/x.x
* error */
* code / retcode = strtoul(ibuf + 9, NULL, 10);
* str_len("HTTP/x.x
* ")==9 */
} else { /* CGI */ } else { /* CGI */
if (byte_diff(ibuf, 10, "Location: ") == 0) { if (memcmp(ibuf, "Location: ", 10) == 0) {
retcode = 302; retcode = 302;
buffer_puts(buffer_1, printf
"HTTP/1.0 302 CGI-Redirect\r\nConnection: close\r\n"); ("HTTP/1.0 302 CGI-Redirect\r\nConnection: close\r\n");
signal(SIGCHLD, SIG_IGN); signal(SIGCHLD, SIG_IGN);
cgi_send_correct_http(ibuf, n); cgi_send_correct_http(ibuf, n);
buffer_flush(buffer_1); fflush(stdout);
dolog(0); dolog(0);
exit(0); exit(0);
} else { } else {
retcode = 200; retcode = 200;
buffer_puts(buffer_1, printf("HTTP/1.0 200 OK\r\nServer: "
"HTTP/1.0 200 OK\r\nServer: " FNORD
FNORD "\r\nPragma: no-cache\r\nConnection: close\r\n");
"\r\nPragma: no-cache\r\nConnection: close\r\n");
signal(SIGCHLD, SIG_IGN); signal(SIGCHLD, SIG_IGN);
cgi_send_correct_http(ibuf, n); cgi_send_correct_http(ibuf, n);
} }
@ -622,7 +623,7 @@ start_cgi(int nph, const char *pathinfo, const char *const *envp)
* non startup * non startup
*/ */
else { else {
buffer_put(buffer_1, ibuf, n); printf("%.*s", n, ibuf);
} }
size += n; size += n;
if (pfd[0].revents & POLLHUP) if (pfd[0].revents & POLLHUP)
@ -652,16 +653,13 @@ start_cgi(int nph, const char *pathinfo, const char *const *envp)
badrequest(500, "Internal Server Error", badrequest(500, "Internal Server Error",
"Looks like the CGI crashed."); "Looks like the CGI crashed.");
else { else {
buffer_puts(buffer_1, "\n\n"); printf("\n\nLooks like the CGI crashed.\n\n");
buffer_puts(buffer_1,
"Looks like the CGI crashed.");
buffer_puts(buffer_1, "\n\n");
break; break;
} }
} }
} }
buffer_flush(buffer_1); fflush(stdout);
dolog(size); dolog(size);
#ifdef TCP_CORK #ifdef TCP_CORK
{ {
@ -706,7 +704,7 @@ fromhex(int c)
static char * static char *
header(char *buf, int buflen, const char *hname) header(char *buf, int buflen, const char *hname)
{ {
int slen = str_len(hname); int slen = strlen(hname);
int i; int i;
char *c; char *c;
@ -793,14 +791,14 @@ getmimetype(char *url, int explicit)
{ {
char save; char save;
int ext; int ext;
ext = str_len(url); ext = strlen(url);
while (ext > 0 && url[ext] != '.' && url[ext] != '/') while (ext > 0 && url[ext] != '.' && url[ext] != '/')
--ext; --ext;
if (url[ext] == '.') { if (url[ext] == '.') {
++ext; ++ext;
if (str_equal(url + ext, "bz2")) if (!strcmp(url + ext, "bz2"))
goto octetstream; goto octetstream;
if (str_equal(url + ext, "gz")) { if (!strcmp(url + ext, "gz")) {
if (!encoding) { if (!encoding) {
if (explicit) if (explicit)
goto octetstream; goto octetstream;
@ -815,7 +813,7 @@ getmimetype(char *url, int explicit)
} else { } else {
int i; int i;
for (i = 0; mimetab[i].name; ++i) for (i = 0; mimetab[i].name; ++i)
if (str_equal(mimetab[i].name, url + ext)) { if (!strcmp(mimetab[i].name, url + ext)) {
mimetype = (char *) mimetab[i].type; mimetype = (char *) mimetab[i].type;
break; break;
} }
@ -833,8 +831,8 @@ matchcommalist(const char *needle, const char *haystack)
/* /*
* return nonzero if match was found * return nonzero if match was found
*/ */
int len = str_len(needle); int len = strlen(needle);
if (!byte_equal(needle, len, haystack)) if (strncmp(needle, haystack, len))
return 0; return 0;
switch (haystack[len]) { switch (haystack[len]) {
case ';': case ';':
@ -910,7 +908,7 @@ findincommalist(const char *needle, const char *haystack)
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE. * THE POSSIBILITY OF SUCH DAMAGE.
*/ */
static time_t static time_t
timerfc(const char *s) timerfc(const char *s)
{ {
static const int daytab[2][12] = { static const int daytab[2][12] = {
@ -1129,19 +1127,16 @@ doit(char *buf, int buflen, char *url, int explicit)
* format: "bytes=17-23", "bytes=23-" * format: "bytes=17-23", "bytes=23-"
*/ */
if (!strncmp(accept, "bytes=", 6)) { if (!strncmp(accept, "bytes=", 6)) {
int i;
accept += 6; accept += 6;
i = scan_range(accept, &rangestart); rangestart = strtorange(accept, &accept, 10);
if (i) { if (*accept == '-') {
accept += i; ++accept;
if (*accept == '-') { if (*accept) {
++accept; rangeend = strtorange(accept, &accept, 10);
if (*accept) { if (!*accept) {
i = scan_range(accept, &rangeend); rangeend = st.st_size;
if (!i) } else {
rangeend = st.st_size; ++rangeend;
else
++rangeend;
} }
} }
} }
@ -1162,8 +1157,8 @@ doit(char *buf, int buflen, char *url, int explicit)
static void static void
redirectboilerplate() redirectboilerplate()
{ {
buffer_puts(buffer_1, printf
"HTTP/1.0 301 Go Away\r\nConnection: close\r\nContent-Length: 0\r\nLocation: "); ("HTTP/1.0 301 Go Away\r\nConnection: close\r\nContent-Length: 0\r\nLocation: ");
} }
static void static void
@ -1181,27 +1176,27 @@ handleredirect(const char *url, const char *origurl)
* el-cheapo redirection * el-cheapo redirection
*/ */
redirectboilerplate(); redirectboilerplate();
buffer_put(buffer_1, symlink, len); printf("%.*s", len, symlink);
#ifdef OLD_STYLE_REDIRECT #ifdef OLD_STYLE_REDIRECT
fini: fini:
#endif #endif
retcode = 301; retcode = 301;
buffer_puts(buffer_1, "\r\n\r\n"); printf("\r\n\r\n");
dolog(0); dolog(0);
buffer_flush(buffer_1); fflush(stdout);
exit(0); exit(0);
} }
#ifdef OLD_STYLE_REDIRECT #ifdef OLD_STYLE_REDIRECT
if ((env = getenv("REDIRECT_HOST"))) { if ((env = getenv("REDIRECT_HOST"))) {
redirectboilerplate(); redirectboilerplate();
buffer_puts(buffer_1, env); fputs(env, stdout);
while (*origurl == '/') while (*origurl == '/')
++origurl; ++origurl;
buffer_puts(buffer_1, origurl); fputs(origurl, stdout);
goto fini; goto fini;
} else if ((env = getenv("REDIRECT_URI"))) { } else if ((env = getenv("REDIRECT_URI"))) {
redirectboilerplate(); redirectboilerplate();
buffer_puts(buffer_1, env); fputs(env, stdout);
goto fini; goto fini;
} }
#endif #endif
@ -1216,39 +1211,21 @@ hdl_encode_html(const char *s, unsigned int sl)
unsigned char ch = s[i]; unsigned char ch = s[i];
if (ch > 159) { if (ch > 159) {
encode_dec: encode_dec:
buffer_puts(buffer_1, "&#"); printf("&#%lu;", ch);
buffer_putulong(buffer_1, ch);
buffer_puts(buffer_1, ";");
} else if ((ch > 128) || (ch < 32)) { } else if ((ch > 128) || (ch < 32)) {
buffer_put(buffer_1, " ", 1); putchar('_');
} else if (ch == '"') } else if (ch == '"')
buffer_puts(buffer_1, "&quot;"); fputs("&quot;", stdout);
else if (ch == '&') else if (ch == '&')
buffer_puts(buffer_1, "&amp;"); fputs("&amp;", stdout);
else if (ch == '<') else if (ch == '<')
buffer_puts(buffer_1, "&lt;"); fputs("&lt;", stdout);
else if (ch == '>') else if (ch == '>')
buffer_puts(buffer_1, "&gt;"); fputs("&gt;", stdout);
else else
buffer_put(buffer_1, &ch, 1); putchar(ch);
} }
} }
static int
buffer_puthex(unsigned int i)
{
unsigned int t;
char x[4];
t = '0' | (i >> 4) & 0xf;
if (t > '9')
t += 39;
i = '0' | (i & 0xf);
if (i > '9')
i += 39;
x[0] = '%';
x[1] = t;
x[2] = i;
return buffer_put(buffer_1, x, 3);
}
static void static void
hdl_encode_uri(const char *s, unsigned int sl) hdl_encode_uri(const char *s, unsigned int sl)
{ {
@ -1256,23 +1233,23 @@ hdl_encode_uri(const char *s, unsigned int sl)
for (i = 0; i < sl; ++i) { for (i = 0; i < sl; ++i) {
unsigned char ch = s[i]; unsigned char ch = s[i];
if ((ch != '%') && (ch > 32) && (ch < 127)) if ((ch != '%') && (ch > 32) && (ch < 127))
buffer_put(buffer_1, &ch, 1); putchar(ch);
else else
buffer_puthex(ch); printf("%%%02x", ch);
} }
} }
static void static void
handledirlist(const char *origurl) handledirlist(const char *origurl)
{ {
DIR *dir; DIR *dir;
unsigned int nl = str_len(origurl); unsigned int nl = strlen(origurl);
const char *nurl = origurl; const char *nurl = origurl;
url = (char *) origurl; url = (char *) origurl;
while (nurl[0] == '/') while (nurl[0] == '/')
++nurl; ++nurl;
if (nurl <= origurl) if (nurl <= origurl)
return; return;
nl = str_len(nurl); nl = strlen(nurl);
if (nurl[nl - 1] != '/') if (nurl[nl - 1] != '/')
return; return;
if (!stat(nl ? nurl : ".", &st) && (S_ISDIR(st.st_mode)) if (!stat(nl ? nurl : ".", &st) && (S_ISDIR(st.st_mode))
@ -1283,38 +1260,37 @@ handledirlist(const char *origurl)
struct dirent *de; struct dirent *de;
unsigned int i, unsigned int i,
size = 32 + nl; size = 32 + nl;
buffer_puts(buffer_1, fputs("HTTP/1.0 200 OK\r\nServer: " FNORD
"HTTP/1.0 200 OK\r\nServer: " FNORD "\r\nConnection: close\r\n", stdout);
"\r\nConnection: close\r\n"); fputs("Content-Type: text/html\r\n", stdout);
buffer_puts(buffer_1, "Content-Type: text/html\r\n"); fputs("\r\n<h3>Directory Listing: /", stdout);
buffer_puts(buffer_1, "\r\n<h3>Directory Listing: /");
hdl_encode_html(nurl, nl); hdl_encode_html(nurl, nl);
buffer_puts(buffer_1, "</h3>\n<pre>\n"); fputs("</h3>\n<pre>\n", stdout);
if (nl != 0) { if (nl != 0) {
for (i = nl - 2; i > 0; --i) for (i = nl - 2; i > 0; --i)
if (nurl[i] == '/') if (nurl[i] == '/')
break; break;
buffer_puts(buffer_1, "<a href=\""); fputs("<a href=\"", stdout);
buffer_puts(buffer_1, "/"); fputs("/", stdout);
hdl_encode_uri(nurl, i); hdl_encode_uri(nurl, i);
if (i > 0) if (i > 0)
buffer_puts(buffer_1, "/"); fputs("/", stdout);
buffer_puts(buffer_1, "\">Parent directory"); fputs("\">Parent directory", stdout);
buffer_puts(buffer_1, "</a>\n"); fputs("</a>\n", stdout);
size += 40 + i; size += 40 + i;
} }
while (de = readdir(dir)) { while (de = readdir(dir)) {
char symlink[1024]; char symlink[1024];
char *p = de->d_name; char *p = de->d_name;
unsigned int pl, unsigned int pl,
dl = str_len(de->d_name); dl = strlen(de->d_name);
pl = dl; pl = dl;
if (de->d_name[0] == '.') if (de->d_name[0] == '.')
continue; /* hidden files -> skip */ continue; /* hidden files -> skip */
if (lstat(de->d_name, &st)) if (lstat(de->d_name, &st))
continue; /* can't stat -> skip */ continue; /* can't stat -> skip */
if (S_ISDIR(st.st_mode)) if (S_ISDIR(st.st_mode))
buffer_puts(buffer_1, "[DIR] "); fputs("[DIR] ", stdout);
else if (S_ISLNK(st.st_mode)) { else if (S_ISLNK(st.st_mode)) {
#ifdef SYSTEM_SYMLINK_DEREF #ifdef SYSTEM_SYMLINK_DEREF
if (stat(de->d_name, &st)) /* dangling symlink */ if (stat(de->d_name, &st)) /* dangling symlink */
@ -1324,29 +1300,29 @@ handledirlist(const char *origurl)
continue; continue;
p = symlink; p = symlink;
} }
buffer_puts(buffer_1, "[LNK] "); /* a symlink to fputs("[LNK] ", stdout); /* a symlink to *
* something ... */ * something ... */
} else if (S_ISREG(st.st_mode)) } else if (S_ISREG(st.st_mode))
buffer_puts(buffer_1, "[TXT] "); fputs("[TXT] ", stdout);
else else
continue; /* not a file we can provide -> skip */ continue; /* not a file we can provide -> skip */
/* /*
* write a href * write a href
*/ */
buffer_puts(buffer_1, "<a href=\""); fputs("<a href=\"", stdout);
hdl_encode_uri(p, pl); hdl_encode_uri(p, pl);
if (S_ISDIR(st.st_mode)) if (S_ISDIR(st.st_mode))
buffer_puts(buffer_1, "/"), ++size; fputs("/", stdout), ++size;
buffer_puts(buffer_1, "\">"); fputs("\">", stdout);
if (de->d_name[0] == ':') if (de->d_name[0] == ':')
de->d_name[0] = '.'; /* fnord special ... */ de->d_name[0] = '.'; /* fnord special ... */
hdl_encode_html(de->d_name, dl); hdl_encode_html(de->d_name, dl);
buffer_puts(buffer_1, "</a>\n"); fputs("</a>\n", stdout);
size += 22 + (dl << 1); size += 22 + (dl << 1);
} }
closedir(dir); closedir(dir);
buffer_puts(buffer_1, "</pre>\n"); fputs("</pre>\n", stdout);
buffer_flush(buffer_1); fflush(stdout);
retcode = 200; retcode = 200;
dolog(size); dolog(size);
exit(0); exit(0);
@ -1360,12 +1336,12 @@ static int
handleindexcgi(const char *testurl, const char *origurl, char *space) handleindexcgi(const char *testurl, const char *origurl, char *space)
{ {
unsigned int ul, unsigned int ul,
ol = str_len(origurl); ol = strlen(origurl);
char *test; char *test;
while (testurl[0] == '/') while (testurl[0] == '/')
++testurl, --ol; ++testurl, --ol;
ul = str_len(testurl); ul = strlen(testurl);
if (str_diff(testurl + ol, "index.html")) if (strcmp(testurl + ol, "index.html"))
return 0; /* no request for index.html */ return 0; /* no request for index.html */
test = space; test = space;
++test; ++test;
@ -1395,7 +1371,7 @@ get_ucspi_env(void)
{ {
char *ucspi = getenv("PROTO"); char *ucspi = getenv("PROTO");
if (ucspi) { if (ucspi) {
char *buf = alloca(str_len(ucspi) + 20); char *buf = alloca(strlen(ucspi) + 20);
unsigned int tmp = str_copy(buf, ucspi); unsigned int tmp = str_copy(buf, ucspi);
buf[tmp + str_copy(buf + tmp, "REMOTEIP")] = 0; buf[tmp + str_copy(buf + tmp, "REMOTEIP")] = 0;
remote_ip = getenv(buf); remote_ip = getenv(buf);
@ -1549,8 +1525,8 @@ serve_static_data(int fd)
read(fd, tmp, len); /* if read fails, we can't back down now. read(fd, tmp, len); /* if read fails, we can't back down now.
* We already committed on the * We already committed on the
* content-length */ * content-length */
buffer_put(buffer_1, tmp, len); fwrite(tmp, len, 1, stdout);
buffer_flush(buffer_1); fflush(stdout);
return 0; return 0;
} }
#ifdef USE_SENDFILE #ifdef USE_SENDFILE
@ -1563,7 +1539,7 @@ serve_static_data(int fd)
corked = 1; corked = 1;
} }
#endif #endif
buffer_flush(buffer_1); fflush(stdout);
{ {
off_t l = rangeend - rangestart; off_t l = rangeend - rangestart;
do { do {
@ -1581,7 +1557,7 @@ serve_static_data(int fd)
return 0; return 0;
} }
#else #else
buffer_flush(buffer_1); fflush(stdout);
#ifdef TCP_CORK #ifdef TCP_CORK
{ {
int one = 1; int one = 1;
@ -1625,7 +1601,10 @@ main(int argc, char *argv[], const char *const *envp)
goto error500; goto error500;
if ((tmp = getenv("GID"))) { if ((tmp = getenv("GID"))) {
long gid; long gid;
if (tmp[scan_ulong(tmp, &gid)] == 0) { char *endptr;
gid = strtoul(tmp, &endptr, 0);
if (*endptr == 0) {
gid_t gi = gid; gid_t gi = gid;
if (setgroups(1, &gi)) if (setgroups(1, &gi))
goto error500; goto error500;
@ -1634,7 +1613,10 @@ main(int argc, char *argv[], const char *const *envp)
} }
if ((tmp = getenv("UID"))) { if ((tmp = getenv("UID"))) {
long uid; long uid;
if (tmp[scan_ulong(tmp, &uid)] == 0) { char *endptr;
uid = strtoul(tmp, &endptr, 0);
if (*endptr == 0) {
if (setuid(uid)) if (setuid(uid))
goto error500; goto error500;
} else } else
@ -1711,16 +1693,16 @@ main(int argc, char *argv[], const char *const *envp)
origurl = url; origurl = url;
{ {
int nl = str_chr(buf, '\r'); char *nl = strchr(buf, '\r');
int space = str_chr(url, ' '); char *space = strchr(url, ' ');
if (space >= nl) if (space >= nl)
badrequest(400, "Bad Request", badrequest(400, "Bad Request",
"<title>Bad Request</title>HTTP/0.9 not supported"); "<title>Bad Request</title>HTTP/0.9 not supported");
if (str_diffn(url + space + 1, "HTTP/1.", 7)) if (strncmp(space + 1, "HTTP/1.", 7))
badrequest(400, "Bad Request", badrequest(400, "Bad Request",
"<title>Bad Request</title>Only HTTP 1.x supported"); "<title>Bad Request</title>Only HTTP 1.x supported");
url[space] = 0; *space = 0;
httpversion = url[space + 8] - '0'; httpversion = space[8] - '0';
#ifdef KEEPALIVE #ifdef KEEPALIVE
keepalive = 0; keepalive = 0;
#endif #endif
@ -1779,7 +1761,7 @@ main(int argc, char *argv[], const char *const *envp)
#ifdef KEEPALIVE #ifdef KEEPALIVE
if ((tmp = header(buf, len, "Connection"))) { /* see if it's if ((tmp = header(buf, len, "Connection"))) { /* see if it's
* "keep-alive" or * "keep-alive" or
* "close" */ * * "close" */
if (!strcasecmp(tmp, "keep-alive")) if (!strcasecmp(tmp, "keep-alive"))
keepalive = 1; keepalive = 1;
else if (!strcasecmp(tmp, "close")) else if (!strcasecmp(tmp, "close"))
@ -1813,13 +1795,13 @@ main(int argc, char *argv[], const char *const *envp)
if (!host) if (!host)
i = 100; i = 100;
else else
i = str_len(host) + 7; i = strlen(host) + 7;
Buf = alloca(i); Buf = alloca(i);
if (!host) { if (!host) {
char *ip = getenv("TCPLOCALIP"); char *ip = getenv("TCPLOCALIP");
if (!ip) if (!ip)
ip = "127.0.0.1"; ip = "127.0.0.1";
if (str_len(ip) + str_len(port) > 90) if (strlen(ip) + strlen(port) > 90)
exit(101); exit(101);
host = Buf; host = Buf;
i = str_copy(Buf, ip); i = str_copy(Buf, ip);
@ -1827,8 +1809,8 @@ main(int argc, char *argv[], const char *const *envp)
i += str_copy(Buf + i, port); i += str_copy(Buf + i, port);
#ifdef NORMALIZE_HOST #ifdef NORMALIZE_HOST
} else { } else {
int colon = str_chr(host, ':'); char *colon = strchr(host, ':');
if (host[colon] == 0) { if (*colon == 0) {
i = str_copy(Buf, host); i = str_copy(Buf, host);
i += str_copy(Buf + i, ":"); i += str_copy(Buf + i, ":");
i += str_copy(Buf + i, port); i += str_copy(Buf + i, port);
@ -1836,7 +1818,7 @@ main(int argc, char *argv[], const char *const *envp)
} }
#endif #endif
} }
for (i = str_len(host); i >= 0; --i) for (i = strlen(host); i >= 0; --i)
if ((host[i] = tolower(host[i])) == '/') if ((host[i] = tolower(host[i])) == '/')
hostb0rken: hostb0rken:
badrequest(400, "Bad Request", badrequest(400, "Bad Request",
@ -1860,17 +1842,17 @@ main(int argc, char *argv[], const char *const *envp)
*/ */
redirectboilerplate(); redirectboilerplate();
if (symlink[0] == '=') { if (symlink[0] == '=') {
buffer_put(buffer_1, symlink + 1, linklen - 1); fwrite(symlink + 1, linklen - 1, 1, stdout);
} else { } else {
buffer_put(buffer_1, symlink, linklen); fwrite(symlink, linklen, 1, stdout);
while (url[0] == '/') while (url[0] == '/')
++url; ++url;
buffer_puts(buffer_1, url); fputs(url, stdout);
} }
retcode = 301; retcode = 301;
buffer_puts(buffer_1, "\r\n\r\n"); fputs("\r\n\r\n", stdout);
dolog(0); dolog(0);
buffer_flush(buffer_1); fflush(stdout);
exit(0); exit(0);
} }
#endif #endif
@ -1913,26 +1895,25 @@ main(int argc, char *argv[], const char *const *envp)
if (!WIFEXITED(status) || WEXITSTATUS(status)) { if (!WIFEXITED(status) || WEXITSTATUS(status)) {
retcode = 401; retcode = 401;
dolog(0); dolog(0);
buffer_puts(buffer_1, fputs("HTTP/1.0 401 Authorization Required\r\n"
"HTTP/1.0 401 Authorization Required\r\n" "WWW-Authenticate: Basic realm=\"", stdout);
"WWW-Authenticate: Basic realm=\""); fputs(host, stdout);
buffer_puts(buffer_1, host); fputs("\"\r\nConnection: close\r\n\r\n"
buffer_puts(buffer_1, "\"\r\nConnection: close\r\n\r\n" "Access to this site is restricted.\r\n"
"Access to this site is restricted.\r\n" "Please provide credentials.\r\n", stdout);
"Please provide credentials.\r\n"); fflush(stdout);
buffer_flush(buffer_1);
exit(0); exit(0);
} }
} }
} }
} }
#endif /* AUTH */ #endif /* AUTH */
nurl = url + str_len(url); nurl = url + strlen(url);
if (nurl > url) if (nurl > url)
--nurl; --nurl;
if (*nurl == '/') { if (*nurl == '/') {
int i; int i;
nurl = alloca(str_len(url) + 12); nurl = alloca(strlen(url) + 12);
i = str_copy(nurl, url); i = str_copy(nurl, url);
i += str_copy(nurl + i, "index.html"); i += str_copy(nurl + i, "index.html");
nurl[i] = 0; nurl[i] = 0;
@ -1953,7 +1934,7 @@ main(int argc, char *argv[], const char *const *envp)
break; break;
} }
if (pathinfo) { if (pathinfo) {
int len = str_len(pathinfo) + 1; int len = strlen(pathinfo) + 1;
tmp = alloca(len); tmp = alloca(len);
memcpy(tmp, pathinfo, len); memcpy(tmp, pathinfo, len);
*pathinfo = 0; *pathinfo = 0;
@ -1992,14 +1973,14 @@ main(int argc, char *argv[], const char *const *envp)
/* /*
* look if file.gz is also there and acceptable * look if file.gz is also there and acceptable
*/ */
char *fnord = alloca(str_len(url) + 4); char *fnord = alloca(strlen(url) + 4);
int i, int i,
fd2, fd2,
trypng = 0; trypng = 0;
char *oldencoding = encoding; char *oldencoding = encoding;
char *oldmimetype = mimetype; char *oldmimetype = mimetype;
i = str_copy(fnord, url); i = str_copy(fnord, url);
if (i > 4 && str_equal(fnord + i - 4, ".gif")) { if (i > 4 && !strcmp(fnord + i - 4, ".gif")) {
trypng = 1; trypng = 1;
str_copy(fnord + i - 3, "png"); str_copy(fnord + i - 3, "png");
} else } else
@ -2017,65 +1998,45 @@ main(int argc, char *argv[], const char *const *envp)
retcode = 200; retcode = 200;
dolog(st.st_size); dolog(st.st_size);
if (rangestart || rangeend != st.st_size) if (rangestart || rangeend != st.st_size)
buffer_puts(buffer_1, fputs("HTTP/1.0 206 Partial Content\r\n", stdout);
"HTTP/1.0 206 Partial Content\r\nServer: "
FNORD "\r\nContent-Type: ");
else else
buffer_puts(buffer_1, fputs("HTTP/1.0 200 OK\r\n", stdout);
"HTTP/1.0 200 OK\r\nServer: " FNORD fputs("Server: " FNORD "\r\nContent-Type: ", stdout);
"\r\nContent-Type: "); fputs(mimetype, stdout);
buffer_puts(buffer_1, mimetype); fputs("\r\n", stdout);
buffer_puts(buffer_1, "\r\n");
#ifdef KEEPALIVE #ifdef KEEPALIVE
switch (keepalive) { switch (keepalive) {
case -1: case -1:
buffer_puts(buffer_1, "Connection: close\r\n"); fputs("Connection: close\r\n", stdout);
break; break;
case 1: case 1:
buffer_puts(buffer_1, "Connection: Keep-Alive\r\n"); fputs("Connection: Keep-Alive\r\n", stdout);
break; break;
} }
#endif #endif
if (encoding) { if (encoding) {
buffer_puts(buffer_1, "Content-Encoding: "); printf("Content-Encoding: %s\r\n");
buffer_puts(buffer_1, encoding);
buffer_puts(buffer_1, "\r\n");
} }
buffer_puts(buffer_1, "Content-Length: "); printf("Content-Length: %lu\r\n", rangeend - rangestart);
buffer_putrange(buffer_1, rangeend - rangestart); printf("Last-Modified: ");
buffer_puts(buffer_1, "\r\nLast-Modified: ");
{ {
struct tm *x = gmtime(&st.st_mtime); struct tm *x = gmtime(&st.st_mtime);
/* /*
* "Sun, 06 Nov 1994 08:49:37 GMT" * "Sun, 06 Nov 1994 08:49:37 GMT"
*/ */
buffer_put(buffer_1, days + 3 * x->tm_wday, 3); printf("%.3s, %02d %.3s %d %02d:%02d:%02d GMT\r\n",
buffer_puts(buffer_1, ", "); days + (3 * x->tm_wday),
buffer_put2digits(buffer_1, x->tm_mday); x->tm_mday,
buffer_puts(buffer_1, " "); months + (3 * x->tm_mon),
buffer_put(buffer_1, months + 3 * x->tm_mon, 3); x->tm_year + 1900,
buffer_puts(buffer_1, " "); x->tm_hour, x->tm_min, x->tm_sec);
buffer_put2digits(buffer_1, (x->tm_year + 1900) / 100);
buffer_put2digits(buffer_1, (x->tm_year + 1900) % 100);
buffer_puts(buffer_1, " ");
buffer_put2digits(buffer_1, x->tm_hour);
buffer_puts(buffer_1, ":");
buffer_put2digits(buffer_1, x->tm_min);
buffer_puts(buffer_1, ":");
buffer_put2digits(buffer_1, x->tm_sec);
buffer_puts(buffer_1, " GMT\r\n");
} }
if (rangestart || rangeend != st.st_size) { if (rangestart || rangeend != st.st_size) {
buffer_puts(buffer_1, printf
"Accept-Ranges: bytes\r\nContent-Range: bytes "); ("Accept-Ranges: bytes\r\nContent-Range: bytes %lu-%lu/%lu\r\n",
buffer_putrange(buffer_1, rangestart); rangestart, rangeend - 1, st.st_size);
buffer_puts(buffer_1, "-");
buffer_putrange(buffer_1, rangeend - 1);
buffer_puts(buffer_1, "/");
buffer_putrange(buffer_1, st.st_size);
buffer_puts(buffer_1, "\r\n");
} }
buffer_puts(buffer_1, "\r\n"); fputs("\r\n", stdout);
if (method == GET || method == POST) { if (method == GET || method == POST) {
switch (serve_static_data(fd)) { switch (serve_static_data(fd)) {
case 0: case 0:
@ -2104,7 +2065,7 @@ main(int argc, char *argv[], const char *const *envp)
error500: error500:
retcode = 500; retcode = 500;
} else } else
buffer_flush(buffer_1); fflush(stdout);
} }
} }
#ifdef CHROOT #ifdef CHROOT

26
str.c Normal file
View File

@ -0,0 +1,26 @@
unsigned int
str_copy(char *out, const char *in)
{
char *s = out;
const char *t = in;
while (1) {
if (!(*s=*t)) break;
s += 1;
t += 1;
}
return s - out;
}
int
str_start(const char *s, const char *t)
{
char x;
while (1) {
x = *t++;
if (!x) return 1;
if (x != *s++) return 0;
}
}