version 1.56.2.8, 2017/02/12 22:07:17 |
version 1.56.2.8.2.3, 2019/06/15 15:56:21 |
|
|
/* $eterna: bozohttpd.c,v 1.178 2011/11/18 09:21:15 mrg Exp $ */ |
/* $eterna: bozohttpd.c,v 1.178 2011/11/18 09:21:15 mrg Exp $ */ |
|
|
/* |
/* |
* Copyright (c) 1997-2017 Matthew R. Green |
* Copyright (c) 1997-2019 Matthew R. Green |
* All rights reserved. |
* All rights reserved. |
* |
* |
* Redistribution and use in source and binary forms, with or without |
* Redistribution and use in source and binary forms, with or without |
|
|
#define INDEX_HTML "index.html" |
#define INDEX_HTML "index.html" |
#endif |
#endif |
#ifndef SERVER_SOFTWARE |
#ifndef SERVER_SOFTWARE |
#define SERVER_SOFTWARE "bozohttpd/20170201" |
#define SERVER_SOFTWARE "bozohttpd/20190228" |
#endif |
|
#ifndef DIRECT_ACCESS_FILE |
|
#define DIRECT_ACCESS_FILE ".bzdirect" |
|
#endif |
|
#ifndef REDIRECT_FILE |
|
#define REDIRECT_FILE ".bzredirect" |
|
#endif |
|
#ifndef ABSREDIRECT_FILE |
|
#define ABSREDIRECT_FILE ".bzabsredirect" |
|
#endif |
#endif |
#ifndef PUBLIC_HTML |
#ifndef PUBLIC_HTML |
#define PUBLIC_HTML "public_html" |
#define PUBLIC_HTML "public_html" |
|
|
#include <netdb.h> |
#include <netdb.h> |
#include <pwd.h> |
#include <pwd.h> |
#include <grp.h> |
#include <grp.h> |
#include <signal.h> |
|
#include <stdarg.h> |
#include <stdarg.h> |
#include <stdlib.h> |
#include <stdlib.h> |
|
#include <strings.h> |
#include <string.h> |
#include <string.h> |
#include <syslog.h> |
#include <syslog.h> |
#include <time.h> |
#include <time.h> |
|
|
|
|
#include "bozohttpd.h" |
#include "bozohttpd.h" |
|
|
#ifndef MAX_WAIT_TIME |
#ifndef SSL_TIMEOUT |
#define MAX_WAIT_TIME 60 /* hang around for 60 seconds max */ |
#define SSL_TIMEOUT "30" /* wait for 30 seconds for ssl handshake */ |
|
#endif |
|
#ifndef INITIAL_TIMEOUT |
|
#define INITIAL_TIMEOUT "30" /* wait for 30 seconds initially */ |
|
#endif |
|
#ifndef HEADER_WAIT_TIME |
|
#define HEADER_WAIT_TIME "10" /* need more headers every 10 seconds */ |
|
#endif |
|
#ifndef TOTAL_MAX_REQ_TIME |
|
#define TOTAL_MAX_REQ_TIME "600" /* must have total request in 600 */ |
|
#endif /* seconds */ |
|
|
|
/* if monotonic time is not available try real time. */ |
|
#ifndef CLOCK_MONOTONIC |
|
#define CLOCK_MONOTONIC CLOCK_REALTIME |
#endif |
#endif |
|
|
/* variables and functions */ |
/* variables and functions */ |
|
|
#define LOG_FTP LOG_DAEMON |
#define LOG_FTP LOG_DAEMON |
#endif |
#endif |
|
|
volatile sig_atomic_t alarmhit; |
/* |
|
* List of special file that we should never serve. |
|
*/ |
|
struct { |
|
const char *file; |
|
const char *name; |
|
} specials[] = { |
|
{ DIRECT_ACCESS_FILE, "rejected direct access request" }, |
|
{ REDIRECT_FILE, "rejected redirect request" }, |
|
{ ABSREDIRECT_FILE, "rejected absredirect request" }, |
|
{ REMAP_FILE, "rejected remap request" }, |
|
{ AUTH_FILE, "rejected authfile request" }, |
|
{ NULL, NULL }, |
|
}; |
|
|
|
volatile sig_atomic_t bozo_timeout_hit; |
|
|
/* |
/* |
* check there's enough space in the prefs and names arrays. |
* check there's enough space in the prefs and names arrays. |
*/ |
*/ |
static int |
static int |
size_arrays(bozoprefs_t *bozoprefs, size_t needed) |
size_arrays(bozohttpd_t *httpd, bozoprefs_t *bozoprefs, size_t needed) |
{ |
{ |
char **temp; |
size_t len = sizeof(char *) * needed; |
|
|
if (bozoprefs->size == 0) { |
if (bozoprefs->size == 0) { |
/* only get here first time around */ |
/* only get here first time around */ |
bozoprefs->name = calloc(sizeof(char *), needed); |
bozoprefs->name = bozomalloc(httpd, len); |
if (bozoprefs->name == NULL) |
bozoprefs->value = bozomalloc(httpd, len); |
return 0; |
|
bozoprefs->value = calloc(sizeof(char *), needed); |
|
if (bozoprefs->value == NULL) { |
|
free(bozoprefs->name); |
|
return 0; |
|
} |
|
bozoprefs->size = needed; |
|
} else if (bozoprefs->count == bozoprefs->size) { |
} else if (bozoprefs->count == bozoprefs->size) { |
/* only uses 'needed' when filled array */ |
/* only uses 'needed' when filled array */ |
temp = realloc(bozoprefs->name, sizeof(char *) * needed); |
bozoprefs->name = bozorealloc(httpd, bozoprefs->name, len); |
if (temp == NULL) |
bozoprefs->value = bozorealloc(httpd, bozoprefs->value, len); |
return 0; |
|
bozoprefs->name = temp; |
|
temp = realloc(bozoprefs->value, sizeof(char *) * needed); |
|
if (temp == NULL) |
|
return 0; |
|
bozoprefs->value = temp; |
|
bozoprefs->size += needed; |
|
} |
} |
|
|
|
bozoprefs->size = needed; |
return 1; |
return 1; |
} |
} |
|
|
Line 220 bozo_set_pref(bozohttpd_t *httpd, bozopr |
|
Line 228 bozo_set_pref(bozohttpd_t *httpd, bozopr |
|
|
|
if ((i = findvar(bozoprefs, name)) < 0) { |
if ((i = findvar(bozoprefs, name)) < 0) { |
/* add the element to the array */ |
/* add the element to the array */ |
if (!size_arrays(bozoprefs, bozoprefs->size + 15)) |
if (!size_arrays(httpd, bozoprefs, bozoprefs->size + 15)) |
return 0; |
return 0; |
i = bozoprefs->count++; |
i = bozoprefs->count++; |
bozoprefs->name[i] = bozostrdup(httpd, NULL, name); |
bozoprefs->name[i] = bozostrdup(httpd, NULL, name); |
} else { |
} else { |
/* replace the element in the array */ |
/* replace the element in the array */ |
if (bozoprefs->value[i]) { |
free(bozoprefs->value[i]); |
free(bozoprefs->value[i]); |
|
bozoprefs->value[i] = NULL; |
|
} |
|
} |
} |
bozoprefs->value[i] = bozostrdup(httpd, NULL, value); |
bozoprefs->value[i] = bozostrdup(httpd, NULL, value); |
return 1; |
return 1; |
Line 278 parse_request(bozohttpd_t *httpd, char * |
|
Line 283 parse_request(bozohttpd_t *httpd, char * |
|
|
|
len = (ssize_t)strlen(in); |
len = (ssize_t)strlen(in); |
val = bozostrnsep(&in, " \t\n\r", &len); |
val = bozostrnsep(&in, " \t\n\r", &len); |
if (len < 1 || val == NULL) |
if (len < 1 || val == NULL || in == NULL) |
return; |
return; |
*method = val; |
*method = val; |
|
|
Line 368 bozo_clean_request(bozo_httpreq_t *reque |
|
Line 373 bozo_clean_request(bozo_httpreq_t *reque |
|
static void |
static void |
alarmer(int sig) |
alarmer(int sig) |
{ |
{ |
alarmhit = 1; |
bozo_timeout_hit = 1; |
|
} |
|
|
|
|
|
/* |
|
* set a timeout for "ssl", "initial", "header", or "request". |
|
*/ |
|
int |
|
bozo_set_timeout(bozohttpd_t *httpd, bozoprefs_t *prefs, |
|
const char *target, const char *val) |
|
{ |
|
const char **cur, *timeouts[] = { |
|
"ssl timeout", |
|
"initial timeout", |
|
"header timeout", |
|
"request timeout", |
|
NULL, |
|
}; |
|
/* adjust minlen if more timeouts appear with conflicting names */ |
|
const size_t minlen = 1; |
|
size_t len = strlen(target); |
|
|
|
for (cur = timeouts; len >= minlen && *cur; cur++) { |
|
if (strncmp(target, *cur, len) == 0) { |
|
bozo_set_pref(httpd, prefs, *cur, val); |
|
return 0; |
|
} |
|
} |
|
return 1; |
} |
} |
|
|
/* |
/* |
Line 536 process_method(bozo_httpreq_t *request, |
|
Line 569 process_method(bozo_httpreq_t *request, |
|
return bozo_http_error(httpd, 404, request, "unknown method"); |
return bozo_http_error(httpd, 404, request, "unknown method"); |
} |
} |
|
|
|
/* check header byte count */ |
|
static int |
|
bozo_got_header_length(bozo_httpreq_t *request, size_t len) |
|
{ |
|
|
|
if (len > BOZO_HEADERS_MAX_SIZE - request->hr_header_bytes) |
|
return bozo_http_error(request->hr_httpd, 413, request, |
|
"too many headers"); |
|
|
|
request->hr_header_bytes += len; |
|
|
|
return 0; |
|
} |
|
|
/* |
/* |
* This function reads a http request from stdin, returning a pointer to a |
* This function reads a http request from stdin, returning a pointer to a |
* bozo_httpreq_t structure, describing the request. |
* bozo_httpreq_t structure, describing the request. |
Line 553 bozo_read_request(bozohttpd_t *httpd) |
|
Line 600 bozo_read_request(bozohttpd_t *httpd) |
|
int line = 0; |
int line = 0; |
socklen_t slen; |
socklen_t slen; |
bozo_httpreq_t *request; |
bozo_httpreq_t *request; |
|
struct timespec ots, ts; |
|
|
/* |
/* |
* if we're in daemon mode, bozo_daemon_fork() will return here twice |
* if we're in daemon mode, bozo_daemon_fork() will return here twice |
* for each call. once in the child, returning 0, and once in the |
* for each call. once in the child, returning 0, and once in the |
* parent, returning 1. for each child, then we can setup SSL, and |
* parent, returning 1 for each child. |
* the parent can signal the caller there was no request to process |
|
* and it will wait for another. |
|
*/ |
*/ |
if (bozo_daemon_fork(httpd)) |
if (bozo_daemon_fork(httpd)) |
return NULL; |
return NULL; |
if (bozo_ssl_accept(httpd)) |
|
return NULL; |
|
|
|
request = bozomalloc(httpd, sizeof(*request)); |
request = bozomalloc(httpd, sizeof(*request)); |
memset(request, 0, sizeof(*request)); |
memset(request, 0, sizeof(*request)); |
Line 635 bozo_read_request(bozohttpd_t *httpd) |
|
Line 679 bozo_read_request(bozohttpd_t *httpd) |
|
sa.sa_flags = 0; |
sa.sa_flags = 0; |
sigaction(SIGALRM, &sa, NULL); |
sigaction(SIGALRM, &sa, NULL); |
|
|
alarm(MAX_WAIT_TIME); |
if (clock_gettime(CLOCK_MONOTONIC, &ots) != 0) { |
|
bozo_http_error(httpd, 500, NULL, "clock_gettime failed"); |
|
goto cleanup; |
|
} |
|
|
|
/* |
|
* now to try to setup SSL, and upon failure parent can signal the |
|
* caller there was no request to process and it will wait for |
|
* another. |
|
*/ |
|
if (bozo_ssl_accept(httpd)) |
|
return NULL; |
|
|
|
alarm(httpd->initial_timeout); |
while ((str = bozodgetln(httpd, STDIN_FILENO, &len, bozo_read)) != NULL) { |
while ((str = bozodgetln(httpd, STDIN_FILENO, &len, bozo_read)) != NULL) { |
alarm(0); |
alarm(0); |
if (alarmhit) { |
|
(void)bozo_http_error(httpd, 408, NULL, |
if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) { |
"request timed out"); |
bozo_http_error(httpd, 500, NULL, "clock_gettime failed"); |
|
goto cleanup; |
|
} |
|
/* |
|
* don't timeout if old tv_sec is not more than current |
|
* tv_sec, or if current tv_sec is less than the request |
|
* timeout (these shouldn't happen, but the first could |
|
* if monotonic time is not available.) |
|
* |
|
* the other timeout and header size checks should ensure |
|
* that even if time it set backwards or forwards a very |
|
* long way, timeout will eventually happen, even if this |
|
* one fails. |
|
*/ |
|
if (ts.tv_sec > ots.tv_sec && |
|
ts.tv_sec > httpd->request_timeout && |
|
ts.tv_sec - httpd->request_timeout > ots.tv_sec) |
|
bozo_timeout_hit = 1; |
|
|
|
if (bozo_timeout_hit) { |
|
bozo_http_error(httpd, 408, NULL, "request timed out"); |
goto cleanup; |
goto cleanup; |
} |
} |
line++; |
line++; |
|
|
if (line == 1) { |
if (line == 1) { |
|
|
if (len < 1) { |
if (len < 1) { |
(void)bozo_http_error(httpd, 404, NULL, |
bozo_http_error(httpd, 404, NULL, "null method"); |
"null method"); |
|
goto cleanup; |
goto cleanup; |
} |
} |
bozowarn(httpd, |
bozowarn(httpd, |
Line 663 bozo_read_request(bozohttpd_t *httpd) |
|
Line 738 bozo_read_request(bozohttpd_t *httpd) |
|
request->hr_file = file; |
request->hr_file = file; |
request->hr_query = query; |
request->hr_query = query; |
if (method == NULL) { |
if (method == NULL) { |
(void)bozo_http_error(httpd, 404, NULL, |
bozo_http_error(httpd, 404, NULL, "null method"); |
"null method"); |
|
goto cleanup; |
goto cleanup; |
} |
} |
if (file == NULL) { |
if (file == NULL) { |
(void)bozo_http_error(httpd, 404, NULL, |
bozo_http_error(httpd, 404, NULL, "null file"); |
"null file"); |
|
goto cleanup; |
goto cleanup; |
} |
} |
|
|
Line 697 bozo_read_request(bozohttpd_t *httpd) |
|
Line 770 bozo_read_request(bozohttpd_t *httpd) |
|
break; |
break; |
|
|
val = bozostrnsep(&str, ":", &len); |
val = bozostrnsep(&str, ":", &len); |
debug((httpd, DEBUG_EXPLODING, |
debug((httpd, DEBUG_EXPLODING, "read_req2: after " |
"read_req2: after bozostrnsep: str ``%s'' val ``%s''", |
"bozostrnsep: str `%s' val `%s'", str, val)); |
str, val)); |
|
if (val == NULL || len == -1) { |
if (val == NULL || len == -1) { |
(void)bozo_http_error(httpd, 404, request, |
bozo_http_error(httpd, 404, request, "no header"); |
"no header"); |
|
goto cleanup; |
goto cleanup; |
} |
} |
while (*str == ' ' || *str == '\t') |
while (*str == ' ' || *str == '\t') |
Line 710 bozo_read_request(bozohttpd_t *httpd) |
|
Line 781 bozo_read_request(bozohttpd_t *httpd) |
|
while (*val == ' ' || *val == '\t') |
while (*val == ' ' || *val == '\t') |
val++; |
val++; |
|
|
|
if (bozo_got_header_length(request, len)) |
|
goto cleanup; |
|
|
if (bozo_auth_check_headers(request, val, str, len)) |
if (bozo_auth_check_headers(request, val, str, len)) |
goto next_header; |
goto next_header; |
|
|
Line 719 bozo_read_request(bozohttpd_t *httpd) |
|
Line 793 bozo_read_request(bozohttpd_t *httpd) |
|
request->hr_content_type = hdr->h_value; |
request->hr_content_type = hdr->h_value; |
else if (strcasecmp(hdr->h_header, "content-length") == 0) |
else if (strcasecmp(hdr->h_header, "content-length") == 0) |
request->hr_content_length = hdr->h_value; |
request->hr_content_length = hdr->h_value; |
else if (strcasecmp(hdr->h_header, "host") == 0) |
else if (strcasecmp(hdr->h_header, "host") == 0) { |
|
if (request->hr_host) { |
|
/* RFC 7230 (HTTP/1.1): 5.4 */ |
|
bozo_http_error(httpd, 400, request, |
|
"Only allow one Host: header"); |
|
goto cleanup; |
|
} |
request->hr_host = bozostrdup(httpd, request, |
request->hr_host = bozostrdup(httpd, request, |
hdr->h_value); |
hdr->h_value); |
|
} |
/* RFC 2616 (HTTP/1.1): 14.20 */ |
/* RFC 2616 (HTTP/1.1): 14.20 */ |
else if (strcasecmp(hdr->h_header, "expect") == 0) { |
else if (strcasecmp(hdr->h_header, "expect") == 0) { |
(void)bozo_http_error(httpd, 417, request, |
bozo_http_error(httpd, 417, request, |
"we don't support Expect:"); |
"we don't support Expect:"); |
goto cleanup; |
goto cleanup; |
} |
} |
Line 744 bozo_read_request(bozohttpd_t *httpd) |
|
Line 825 bozo_read_request(bozohttpd_t *httpd) |
|
hdr->h_header, hdr->h_value)); |
hdr->h_header, hdr->h_value)); |
} |
} |
next_header: |
next_header: |
alarm(MAX_WAIT_TIME); |
alarm(httpd->header_timeout); |
} |
} |
|
|
/* now, clear it all out */ |
/* now, clear it all out */ |
|
|
/* RFC1945, 8.3 */ |
/* RFC1945, 8.3 */ |
if (request->hr_method == HTTP_POST && |
if (request->hr_method == HTTP_POST && |
request->hr_content_length == NULL) { |
request->hr_content_length == NULL) { |
(void)bozo_http_error(httpd, 400, request, |
bozo_http_error(httpd, 400, request, "missing content length"); |
"missing content length"); |
|
goto cleanup; |
goto cleanup; |
} |
} |
|
|
|
|
if (request->hr_proto == httpd->consts.http_11 && |
if (request->hr_proto == httpd->consts.http_11 && |
/*(strncasecmp(request->hr_file, "http://", 7) != 0) &&*/ |
/*(strncasecmp(request->hr_file, "http://", 7) != 0) &&*/ |
request->hr_host == NULL) { |
request->hr_host == NULL) { |
(void)bozo_http_error(httpd, 400, request, |
bozo_http_error(httpd, 400, request, "missing Host header"); |
"missing Host header"); |
|
goto cleanup; |
goto cleanup; |
} |
} |
|
|
Line 908 bozo_escape_rfc3986(bozohttpd_t *httpd, |
|
Line 987 bozo_escape_rfc3986(bozohttpd_t *httpd, |
|
buf = bozorealloc(httpd, buf, buflen); |
buf = bozorealloc(httpd, buf, buflen); |
} |
} |
|
|
for (len = 0, s = url, d = buf; *s;) { |
for (s = url, d = buf; *s;) { |
if (*s & 0x80) |
if (*s & 0x80) |
goto encode_it; |
goto encode_it; |
switch (*s) { |
switch (*s) { |
Line 933 bozo_escape_rfc3986(bozohttpd_t *httpd, |
|
Line 1012 bozo_escape_rfc3986(bozohttpd_t *httpd, |
|
case '"': |
case '"': |
if (absolute) |
if (absolute) |
goto leave_it; |
goto leave_it; |
|
/*FALLTHROUGH*/ |
case '\n': |
case '\n': |
case '\r': |
case '\r': |
case ' ': |
case ' ': |
encode_it: |
encode_it: |
snprintf(d, 4, "%%%02X", *s++); |
snprintf(d, 4, "%%%02X", (unsigned char)*s++); |
d += 3; |
d += 3; |
len += 3; |
|
break; |
break; |
leave_it: |
|
default: |
default: |
|
leave_it: |
*d++ = *s++; |
*d++ = *s++; |
len++; |
|
break; |
break; |
} |
} |
} |
} |
buf[len] = 0; |
*d = 0; |
|
|
return buf; |
return buf; |
} |
} |
|
|
} |
} |
|
|
/* |
/* |
|
* Like strncmp(), but s_esc may contain characters escaped by \. |
|
* The len argument does not include the backslashes used for escaping, |
|
* that is: it gives the raw len, after unescaping the string. |
|
*/ |
|
static int |
|
esccmp(const char *s_plain, const char *s_esc, size_t len) |
|
{ |
|
bool esc = false; |
|
|
|
while (len) { |
|
if (!esc && *s_esc == '\\') { |
|
esc = true; |
|
s_esc++; |
|
continue; |
|
} |
|
esc = false; |
|
if (*s_plain == 0 || *s_esc == 0 || *s_plain != *s_esc) |
|
return *s_esc - *s_plain; |
|
s_esc++; |
|
s_plain++; |
|
len--; |
|
} |
|
return 0; |
|
} |
|
|
|
/* |
|
* Check if the request refers to a uri that is mapped via a .bzremap. |
|
* We have /requested/path:/re/mapped/to/this.html lines in there, |
|
* and the : separator may be use in the left hand side escaped with |
|
* \ to encode a path containig a : character. |
|
*/ |
|
static void |
|
check_remap(bozo_httpreq_t *request) |
|
{ |
|
bozohttpd_t *httpd = request->hr_httpd; |
|
char *file = request->hr_file, *newfile; |
|
void *fmap; |
|
const char *replace = NULL, *map_to = NULL, *p; |
|
struct stat st; |
|
int mapfile; |
|
size_t avail, len, rlen, reqlen, num_esc = 0; |
|
bool escaped = false; |
|
|
|
mapfile = open(REMAP_FILE, O_RDONLY, 0); |
|
if (mapfile == -1) |
|
return; |
|
debug((httpd, DEBUG_FAT, "remap file found")); |
|
if (fstat(mapfile, &st) == -1) { |
|
bozowarn(httpd, "could not stat " REMAP_FILE ", errno: %d", |
|
errno); |
|
goto out; |
|
} |
|
|
|
fmap = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, mapfile, 0); |
|
if (fmap == NULL) { |
|
bozowarn(httpd, "could not mmap " REMAP_FILE ", error %d", |
|
errno); |
|
goto out; |
|
} |
|
reqlen = strlen(file); |
|
for (p = fmap, avail = st.st_size; avail; ) { |
|
/* |
|
* We have lines like: |
|
* /this/url:/replacement/that/url |
|
* If we find a matching left hand side, replace will point |
|
* to it and len will be its length. map_to will point to |
|
* the right hand side and rlen wil be its length. |
|
* If we have no match, both pointers will be NULL. |
|
*/ |
|
|
|
/* skip empty lines */ |
|
while ((*p == '\r' || *p == '\n') && avail) { |
|
p++; |
|
avail--; |
|
} |
|
replace = p; |
|
escaped = false; |
|
while (avail) { |
|
if (*p == '\r' || *p == '\n') |
|
break; |
|
if (!escaped && *p == ':') |
|
break; |
|
if (escaped) { |
|
escaped = false; |
|
num_esc++; |
|
} else if (*p == '\\') { |
|
escaped = true; |
|
} |
|
p++; |
|
avail--; |
|
} |
|
if (!avail || *p != ':') { |
|
replace = NULL; |
|
map_to = NULL; |
|
break; |
|
} |
|
len = p - replace - num_esc; |
|
/* |
|
* reqlen < len: the left hand side is too long, can't be a |
|
* match |
|
* reqlen == len: full string has to match |
|
* reqlen > len: make sure there is a path separator at 'len' |
|
* avail < 2: we are at eof, missing right hand side |
|
*/ |
|
if (avail < 2 || reqlen < len || |
|
(reqlen == len && esccmp(file, replace, len) != 0) || |
|
(reqlen > len && (file[len] != '/' || |
|
esccmp(file, replace, len) != 0))) { |
|
|
|
/* non-match, skip to end of line and continue */ |
|
while (*p != '\r' && *p != '\n' && avail) { |
|
p++; |
|
avail--; |
|
} |
|
replace = NULL; |
|
map_to = NULL; |
|
continue; |
|
} |
|
p++; |
|
avail--; |
|
|
|
/* found a match, parse the target */ |
|
map_to = p; |
|
while (*p != '\r' && *p != '\n' && avail) { |
|
p++; |
|
avail--; |
|
} |
|
rlen = p - map_to; |
|
break; |
|
} |
|
|
|
if (replace && map_to) { |
|
newfile = bozomalloc(httpd, strlen(file) + rlen - len + 1); |
|
memcpy(newfile, map_to, rlen); |
|
strcpy(newfile+rlen, file + len); |
|
debug((httpd, DEBUG_NORMAL, "remapping found '%s'", |
|
newfile)); |
|
free(request->hr_file); |
|
request->hr_file = newfile; |
|
} |
|
|
|
munmap(fmap, st.st_size); |
|
out: |
|
close(mapfile); |
|
} |
|
|
|
/* |
* deal with virtual host names; we do this: |
* deal with virtual host names; we do this: |
* if we have a virtual path root (httpd->virtbase), and we are given a |
* if we have a virtual path root (httpd->virtbase), and we are given a |
* virtual host spec (Host: ho.st or http://ho.st/), see if this |
* virtual host spec (Host: ho.st or http://ho.st/), see if this |
Line 1085 check_virtual(bozo_httpreq_t *request) |
|
Line 1310 check_virtual(bozo_httpreq_t *request) |
|
/* |
/* |
* convert http://virtual.host/ to request->hr_host |
* convert http://virtual.host/ to request->hr_host |
*/ |
*/ |
debug((httpd, DEBUG_OBESE, "checking for http:// virtual host in ``%s''", |
debug((httpd, DEBUG_OBESE, |
file)); |
"checking for http:// virtual host in '%s'", file)); |
if (strncasecmp(file, "http://", 7) == 0) { |
if (strncasecmp(file, "http://", 7) == 0) { |
|
/* bozostrdup() might access it. */ |
|
char *old_file = request->hr_file; |
|
|
/* we would do virtual hosting here? */ |
/* we would do virtual hosting here? */ |
file += 7; |
file += 7; |
/* RFC 2616 (HTTP/1.1), 5.2: URI takes precedence over Host: */ |
/* RFC 2616 (HTTP/1.1), 5.2: URI takes precedence over Host: */ |
Line 1096 check_virtual(bozo_httpreq_t *request) |
|
Line 1324 check_virtual(bozo_httpreq_t *request) |
|
if ((s = strchr(request->hr_host, '/')) != NULL) |
if ((s = strchr(request->hr_host, '/')) != NULL) |
*s = '\0'; |
*s = '\0'; |
s = strchr(file, '/'); |
s = strchr(file, '/'); |
free(request->hr_file); |
|
request->hr_file = bozostrdup(httpd, request, s ? s : "/"); |
request->hr_file = bozostrdup(httpd, request, s ? s : "/"); |
debug((httpd, DEBUG_OBESE, "got host ``%s'' file is now ``%s''", |
free(old_file); |
|
debug((httpd, DEBUG_OBESE, "got host '%s' file is now '%s'", |
request->hr_host, request->hr_file)); |
request->hr_host, request->hr_file)); |
} else if (!request->hr_host) |
} else if (!request->hr_host) |
goto use_slashdir; |
goto use_slashdir; |
Line 1113 check_virtual(bozo_httpreq_t *request) |
|
Line 1341 check_virtual(bozo_httpreq_t *request) |
|
} |
} |
|
|
if (!httpd->virtbase) { |
if (!httpd->virtbase) { |
|
|
/* |
/* |
* if we don't use vhost support, then set virthostname if |
* if we don't use vhost support, then set virthostname if |
* user supplied Host header. It will be used for possible |
* user supplied Host header. It will be used for possible |
* redirections |
* redirections |
*/ |
*/ |
|
|
if (request->hr_host) { |
if (request->hr_host) { |
s = strrchr(request->hr_host, ':'); |
s = strrchr(request->hr_host, ':'); |
if (s != NULL) |
if (s != NULL) |
/* truncate Host: as we want to copy it without port part */ |
/* |
|
* truncate Host: as we want to copy it |
|
* without port part |
|
*/ |
*s = '\0'; |
*s = '\0'; |
request->hr_virthostname = bozostrdup(httpd, request, |
request->hr_virthostname = bozostrdup(httpd, request, |
request->hr_host); |
request->hr_host); |
Line 1131 check_virtual(bozo_httpreq_t *request) |
|
Line 1360 check_virtual(bozo_httpreq_t *request) |
|
/* fix Host: again, if we truncated it */ |
/* fix Host: again, if we truncated it */ |
*s = ':'; |
*s = ':'; |
} |
} |
|
|
goto use_slashdir; |
goto use_slashdir; |
} |
} |
|
|
Line 1146 check_virtual(bozo_httpreq_t *request) |
|
Line 1374 check_virtual(bozo_httpreq_t *request) |
|
"for file `%s'", |
"for file `%s'", |
request->hr_host, httpd->virtbase, request->hr_file)); |
request->hr_host, httpd->virtbase, request->hr_file)); |
if (strncasecmp(httpd->virthostname, request->hr_host, len) != 0) { |
if (strncasecmp(httpd->virthostname, request->hr_host, len) != 0) { |
s = 0; |
s = NULL; |
DIR *dirp; |
DIR *dirp; |
struct dirent *d; |
struct dirent *d; |
|
|
Line 1156 check_virtual(bozo_httpreq_t *request) |
|
Line 1384 check_virtual(bozo_httpreq_t *request) |
|
strcmp(d->d_name, "..") == 0) { |
strcmp(d->d_name, "..") == 0) { |
continue; |
continue; |
} |
} |
debug((httpd, DEBUG_OBESE, "looking at dir``%s''", |
debug((httpd, DEBUG_OBESE, "looking at dir '%s'", |
d->d_name)); |
d->d_name)); |
if (strcmp(d->d_name, request->hr_host) == 0) { |
if (strcmp(d->d_name, request->hr_host) == 0) { |
/* found it, punch it */ |
/* found it, punch it */ |
|
|
if (chdir(s) < 0) |
if (chdir(s) < 0) |
return bozo_http_error(httpd, 404, request, |
return bozo_http_error(httpd, 404, request, |
"can't chdir to slashdir"); |
"can't chdir to slashdir"); |
|
|
|
/* |
|
* is there a mapping for this request? |
|
*/ |
|
check_remap(request); |
|
|
return 0; |
return 0; |
} |
} |
|
|
Line 1205 check_bzredirect(bozo_httpreq_t *request |
|
Line 1439 check_bzredirect(bozo_httpreq_t *request |
|
bozohttpd_t *httpd = request->hr_httpd; |
bozohttpd_t *httpd = request->hr_httpd; |
struct stat sb; |
struct stat sb; |
char dir[MAXPATHLEN], redir[MAXPATHLEN], redirpath[MAXPATHLEN + 1], |
char dir[MAXPATHLEN], redir[MAXPATHLEN], redirpath[MAXPATHLEN + 1], |
path[MAXPATHLEN]; |
path[MAXPATHLEN + 1]; |
char *basename, *finalredir; |
char *basename, *finalredir; |
int rv, absolute; |
int rv, absolute; |
|
|
Line 1213 check_bzredirect(bozo_httpreq_t *request |
|
Line 1447 check_bzredirect(bozo_httpreq_t *request |
|
* if this pathname is really a directory, but doesn't end in /, |
* if this pathname is really a directory, but doesn't end in /, |
* use it as the directory to look for the redir file. |
* use it as the directory to look for the redir file. |
*/ |
*/ |
if((size_t)snprintf(dir, sizeof(dir), "%s", request->hr_file + 1) >= |
if ((size_t)snprintf(dir, sizeof(dir), "%s", request->hr_file + 1) >= |
sizeof(dir)) { |
sizeof(dir)) { |
bozo_http_error(httpd, 404, request, |
bozo_http_error(httpd, 404, request, "file path too long"); |
"file path too long"); |
|
return -1; |
return -1; |
} |
} |
debug((httpd, DEBUG_FAT, "check_bzredirect: dir %s", dir)); |
debug((httpd, DEBUG_FAT, "check_bzredirect: dir %s", dir)); |
Line 1225 check_bzredirect(bozo_httpreq_t *request |
|
Line 1458 check_bzredirect(bozo_httpreq_t *request |
|
if ((!basename || basename[1] != '\0') && |
if ((!basename || basename[1] != '\0') && |
lstat(dir, &sb) == 0 && S_ISDIR(sb.st_mode)) { |
lstat(dir, &sb) == 0 && S_ISDIR(sb.st_mode)) { |
strcpy(path, dir); |
strcpy(path, dir); |
|
basename = dir; |
} else if (basename == NULL) { |
} else if (basename == NULL) { |
strcpy(path, "."); |
strcpy(path, "."); |
strcpy(dir, ""); |
strcpy(dir, ""); |
|
basename = request->hr_file + 1; |
} else { |
} else { |
*basename++ = '\0'; |
*basename++ = '\0'; |
bozo_check_special_files(request, basename); |
|
strcpy(path, dir); |
strcpy(path, dir); |
} |
} |
|
if (bozo_check_special_files(request, basename, true)) |
|
return -1; |
|
|
debug((httpd, DEBUG_FAT, "check_bzredirect: path %s", path)); |
debug((httpd, DEBUG_FAT, "check_bzredirect: path %s", path)); |
|
|
if ((size_t)snprintf(redir, sizeof(redir), "%s/%s", path, |
if ((size_t)snprintf(redir, sizeof(redir), "%s/%s", path, |
REDIRECT_FILE) >= sizeof(redir)) { |
REDIRECT_FILE) >= sizeof(redir)) { |
bozo_http_error(httpd, 404, request, |
return bozo_http_error(httpd, 404, request, |
"redirectfile path too long"); |
"redirectfile path too long"); |
return -1; |
|
} |
} |
if (lstat(redir, &sb) == 0) { |
if (lstat(redir, &sb) == 0) { |
if (!S_ISLNK(sb.st_mode)) |
if (!S_ISLNK(sb.st_mode)) |
return 0; |
return 0; |
absolute = 0; |
absolute = 0; |
} else { |
} else { |
if((size_t)snprintf(redir, sizeof(redir), "%s/%s", path, |
if ((size_t)snprintf(redir, sizeof(redir), "%s/%s", path, |
ABSREDIRECT_FILE) >= sizeof(redir)) { |
ABSREDIRECT_FILE) >= sizeof(redir)) { |
bozo_http_error(httpd, 404, request, |
bozo_http_error(httpd, 404, request, |
"redirectfile path too long"); |
"redirectfile path too long"); |
return -1; |
return -1; |
} |
} |
if (lstat(redir, &sb) < 0 || !S_ISLNK(sb.st_mode)) |
if (lstat(redir, &sb) < 0 || !S_ISLNK(sb.st_mode)) |
Line 1276 check_bzredirect(bozo_httpreq_t *request |
|
Line 1511 check_bzredirect(bozo_httpreq_t *request |
|
if ((size_t)snprintf(finalredir = redir, sizeof(redir), "%s%s/%s", |
if ((size_t)snprintf(finalredir = redir, sizeof(redir), "%s%s/%s", |
(strlen(dir) > 0 ? "/" : ""), dir, redirpath) >= sizeof(redir)) { |
(strlen(dir) > 0 ? "/" : ""), dir, redirpath) >= sizeof(redir)) { |
bozo_http_error(httpd, 404, request, |
bozo_http_error(httpd, 404, request, |
"redirect path too long"); |
"redirect path too long"); |
return -1; |
return -1; |
} |
} |
} else |
} else |
Line 1313 bozo_decode_url_percent(bozo_httpreq_t * |
|
Line 1548 bozo_decode_url_percent(bozo_httpreq_t * |
|
debug((httpd, DEBUG_EXPLODING, |
debug((httpd, DEBUG_EXPLODING, |
"fu_%%: got s == %%, s[1]s[2] == %c%c", |
"fu_%%: got s == %%, s[1]s[2] == %c%c", |
s[1], s[2])); |
s[1], s[2])); |
if (s[1] == '\0' || s[2] == '\0') { |
if (s[1] == '\0' || s[2] == '\0') |
(void)bozo_http_error(httpd, 400, request, |
return bozo_http_error(httpd, 400, request, |
"percent hack missing two chars afterwards"); |
"percent hack missing two chars afterwards"); |
return 1; |
if (s[1] == '0' && s[2] == '0') |
} |
return bozo_http_error(httpd, 404, request, |
if (s[1] == '0' && s[2] == '0') { |
"percent hack was %00"); |
(void)bozo_http_error(httpd, 404, request, |
if (s[1] == '2' && s[2] == 'f') |
"percent hack was %00"); |
return bozo_http_error(httpd, 404, request, |
return 1; |
"percent hack was %2f (/)"); |
} |
|
if (s[1] == '2' && s[2] == 'f') { |
|
(void)bozo_http_error(httpd, 404, request, |
|
"percent hack was %2f (/)"); |
|
return 1; |
|
} |
|
|
|
buf[0] = *++s; |
buf[0] = *++s; |
buf[1] = *++s; |
buf[1] = *++s; |
Line 1336 bozo_decode_url_percent(bozo_httpreq_t * |
|
Line 1565 bozo_decode_url_percent(bozo_httpreq_t * |
|
*t = (char)strtol(buf, NULL, 16); |
*t = (char)strtol(buf, NULL, 16); |
debug((httpd, DEBUG_EXPLODING, |
debug((httpd, DEBUG_EXPLODING, |
"fu_%%: strtol put '%02x' into *t", *t)); |
"fu_%%: strtol put '%02x' into *t", *t)); |
if (*t++ == '\0') { |
if (*t++ == '\0') |
(void)bozo_http_error(httpd, 400, request, |
return bozo_http_error(httpd, 400, request, |
"percent hack got a 0 back"); |
"percent hack got a 0 back"); |
return 1; |
|
} |
|
|
|
while (*s && *s != '%') { |
while (*s && *s != '%') { |
if (end && s >= end) |
if (end && s >= end) |
Line 1381 transform_request(bozo_httpreq_t *reques |
|
Line 1608 transform_request(bozo_httpreq_t *reques |
|
file = NULL; |
file = NULL; |
*isindex = 0; |
*isindex = 0; |
debug((httpd, DEBUG_FAT, "tf_req: file %s", request->hr_file)); |
debug((httpd, DEBUG_FAT, "tf_req: file %s", request->hr_file)); |
if (bozo_decode_url_percent(request, request->hr_file)) { |
|
goto bad_done; |
if (bozo_decode_url_percent(request, request->hr_file) || |
} |
check_virtual(request)) |
if (check_virtual(request)) { |
|
goto bad_done; |
goto bad_done; |
} |
|
file = request->hr_file; |
file = request->hr_file; |
|
|
if (file[0] != '/') { |
if (file[0] != '/') { |
(void)bozo_http_error(httpd, 404, request, "unknown URL"); |
bozo_http_error(httpd, 404, request, "unknown URL"); |
goto bad_done; |
goto bad_done; |
} |
} |
|
|
Line 1407 transform_request(bozo_httpreq_t *reques |
|
Line 1633 transform_request(bozo_httpreq_t *reques |
|
/* first of all expand user path */ |
/* first of all expand user path */ |
if (len > 1 && httpd->enable_users && file[1] == '~') { |
if (len > 1 && httpd->enable_users && file[1] == '~') { |
if (file[2] == '\0') { |
if (file[2] == '\0') { |
(void)bozo_http_error(httpd, 404, request, |
bozo_http_error(httpd, 404, request, |
"missing username"); |
"missing username"); |
goto bad_done; |
goto bad_done; |
} |
} |
if (strchr(file + 2, '/') == NULL) { |
if (strchr(file + 2, '/') == NULL) { |
char *userredirecturl; |
char *userredirecturl; |
|
|
bozoasprintf(httpd, &userredirecturl, "%s/", file); |
bozoasprintf(httpd, &userredirecturl, "%s/", file); |
handle_redirect(request, userredirecturl, 0); |
handle_redirect(request, userredirecturl, 0); |
free(userredirecturl); |
free(userredirecturl); |
Line 1432 transform_request(bozo_httpreq_t *reques |
|
Line 1659 transform_request(bozo_httpreq_t *reques |
|
switch (check_bzredirect(request)) { |
switch (check_bzredirect(request)) { |
case -1: |
case -1: |
goto bad_done; |
goto bad_done; |
case 1: |
case 0: |
|
break; |
|
default: |
return 0; |
return 0; |
} |
} |
|
|
Line 1452 transform_request(bozo_httpreq_t *reques |
|
Line 1681 transform_request(bozo_httpreq_t *reques |
|
newfile = bozostrdup(httpd, request, httpd->index_html); |
newfile = bozostrdup(httpd, request, httpd->index_html); |
*isindex = 1; |
*isindex = 1; |
} else { /* len == 0 ? */ |
} else { /* len == 0 ? */ |
(void)bozo_http_error(httpd, 500, request, |
bozo_http_error(httpd, 500, request, "request->hr_file is nul"); |
"request->hr_file is nul?"); |
|
goto bad_done; |
goto bad_done; |
} |
} |
|
|
if (newfile == NULL) { |
if (newfile == NULL) { |
(void)bozo_http_error(httpd, 500, request, "internal failure"); |
bozo_http_error(httpd, 500, request, "internal failure"); |
goto bad_done; |
goto bad_done; |
} |
} |
|
|
Line 1473 transform_request(bozo_httpreq_t *reques |
|
Line 1701 transform_request(bozo_httpreq_t *reques |
|
|
|
if (*newfile == '/' || strcmp(newfile, "..") == 0 || |
if (*newfile == '/' || strcmp(newfile, "..") == 0 || |
strstr(newfile, "/..") || strstr(newfile, "../")) { |
strstr(newfile, "/..") || strstr(newfile, "../")) { |
(void)bozo_http_error(httpd, 403, request, "illegal request"); |
bozo_http_error(httpd, 403, request, "illegal request"); |
goto bad_done; |
goto bad_done; |
} |
} |
|
|
Line 1485 transform_request(bozo_httpreq_t *reques |
|
Line 1713 transform_request(bozo_httpreq_t *reques |
|
request->hr_file = newfile; |
request->hr_file = newfile; |
} |
} |
|
|
if (bozo_process_cgi(request)) |
if (bozo_process_cgi(request) || |
return 0; |
bozo_process_lua(request)) |
|
|
if (bozo_process_lua(request)) |
|
return 0; |
return 0; |
|
|
debug((httpd, DEBUG_FAT, "transform_request set: %s", newfile)); |
debug((httpd, DEBUG_FAT, "transform_request set: %s", newfile)); |
return 1; |
return 1; |
|
|
bad_done: |
bad_done: |
debug((httpd, DEBUG_FAT, "transform_request returning: 0")); |
debug((httpd, DEBUG_FAT, "transform_request returning: 0")); |
free(newfile); |
free(newfile); |
Line 1591 bozo_process_request(bozo_httpreq_t *req |
|
Line 1818 bozo_process_request(bozo_httpreq_t *req |
|
switch (errno) { |
switch (errno) { |
case EPERM: |
case EPERM: |
case EACCES: |
case EACCES: |
(void)bozo_http_error(httpd, 403, request, |
bozo_http_error(httpd, 403, request, |
"no permission to open file"); |
"no permission to open file"); |
break; |
break; |
case ENAMETOOLONG: |
case ENAMETOOLONG: |
/*FALLTHROUGH*/ |
/*FALLTHROUGH*/ |
case ENOENT: |
case ENOENT: |
if (!bozo_dir_index(request, file, isindex)) |
if (!bozo_dir_index(request, file, isindex)) |
(void)bozo_http_error(httpd, 404, request, |
bozo_http_error(httpd, 404, request, "no file"); |
"no file"); |
|
break; |
break; |
default: |
default: |
(void)bozo_http_error(httpd, 500, request, "open file"); |
bozo_http_error(httpd, 500, request, "open file"); |
} |
} |
goto cleanup_nofd; |
goto cleanup_nofd; |
} |
} |
if (fstat(fd, &sb) < 0) { |
if (fstat(fd, &sb) < 0) { |
(void)bozo_http_error(httpd, 500, request, "can't fstat"); |
bozo_http_error(httpd, 500, request, "can't fstat"); |
goto cleanup; |
goto cleanup; |
} |
} |
if (S_ISDIR(sb.st_mode)) { |
if (S_ISDIR(sb.st_mode)) { |
Line 1693 bozo_process_request(bozo_httpreq_t *req |
|
Line 1919 bozo_process_request(bozo_httpreq_t *req |
|
|
|
/* make sure we're not trying to access special files */ |
/* make sure we're not trying to access special files */ |
int |
int |
bozo_check_special_files(bozo_httpreq_t *request, const char *name) |
bozo_check_special_files(bozo_httpreq_t *request, const char *name, bool doerror) |
{ |
{ |
bozohttpd_t *httpd = request->hr_httpd; |
bozohttpd_t *httpd = request->hr_httpd; |
|
size_t i; |
|
int error = 0; |
|
|
|
for (i = 0; specials[i].file; i++) { |
|
if (strcmp(name, specials[i].file) == 0) { |
|
if (doerror) { |
|
error = bozo_http_error(httpd, 403, request, |
|
specials[i].name); |
|
} else { |
|
error = -1; |
|
} |
|
} |
|
} |
|
|
/* ensure basename(name) != special files */ |
return error; |
if (strcmp(name, DIRECT_ACCESS_FILE) == 0) |
|
return bozo_http_error(httpd, 403, request, |
|
"no permission to open direct access file"); |
|
if (strcmp(name, REDIRECT_FILE) == 0) |
|
return bozo_http_error(httpd, 403, request, |
|
"no permission to open redirect file"); |
|
if (strcmp(name, ABSREDIRECT_FILE) == 0) |
|
return bozo_http_error(httpd, 403, request, |
|
"no permission to open redirect file"); |
|
return bozo_auth_check_special_files(request, name); |
|
} |
} |
|
|
/* generic header printing routine */ |
/* generic header printing routine */ |
Line 1852 bozo_escape_html(bozohttpd_t *httpd, con |
|
Line 2081 bozo_escape_html(bozohttpd_t *httpd, con |
|
case '&': |
case '&': |
j += 5; |
j += 5; |
break; |
break; |
|
case '"': |
|
j += 6; |
|
break; |
} |
} |
} |
} |
|
|
Line 1882 bozo_escape_html(bozohttpd_t *httpd, con |
|
Line 2114 bozo_escape_html(bozohttpd_t *httpd, con |
|
memcpy(tmp + j, "&", 5); |
memcpy(tmp + j, "&", 5); |
j += 5; |
j += 5; |
break; |
break; |
|
case '"': |
|
memcpy(tmp + j, """, 6); |
|
j += 6; |
|
break; |
default: |
default: |
tmp[j++] = url[i]; |
tmp[j++] = url[i]; |
} |
} |
Line 1902 static struct errors_map { |
|
Line 2138 static struct errors_map { |
|
{ 403, "403 Forbidden", "Access to this item has been denied",}, |
{ 403, "403 Forbidden", "Access to this item has been denied",}, |
{ 404, "404 Not Found", "This item has not been found", }, |
{ 404, "404 Not Found", "This item has not been found", }, |
{ 408, "408 Request Timeout", "This request took too long", }, |
{ 408, "408 Request Timeout", "This request took too long", }, |
|
{ 413, "413 Payload Too Large", "Use smaller requests", }, |
{ 417, "417 Expectation Failed","Expectations not available", }, |
{ 417, "417 Expectation Failed","Expectations not available", }, |
{ 420, "420 Enhance Your Calm","Chill, Winston", }, |
{ 420, "420 Enhance Your Calm","Chill, Winston", }, |
{ 500, "500 Internal Error", "An error occured on the server", }, |
{ 500, "500 Internal Error", "An error occured on the server", }, |
Line 1963 bozo_http_error(bozohttpd_t *httpd, int |
|
Line 2200 bozo_http_error(bozohttpd_t *httpd, int |
|
portbuf[0] = '\0'; |
portbuf[0] = '\0'; |
|
|
if (request && request->hr_file) { |
if (request && request->hr_file) { |
char *file = NULL, *user = NULL, *user_escaped = NULL; |
char *file = NULL, *user = NULL; |
int file_alloc = 0; |
int file_alloc = 0; |
const char *hostname = BOZOHOST(httpd, request); |
const char *hostname = BOZOHOST(httpd, request); |
|
|
Line 1976 bozo_http_error(bozohttpd_t *httpd, int |
|
Line 2213 bozo_http_error(bozohttpd_t *httpd, int |
|
|
|
#ifndef NO_USER_SUPPORT |
#ifndef NO_USER_SUPPORT |
if (request->hr_user != NULL) { |
if (request->hr_user != NULL) { |
|
char *user_escaped; |
|
|
user_escaped = bozo_escape_html(NULL, request->hr_user); |
user_escaped = bozo_escape_html(NULL, request->hr_user); |
if (user_escaped == NULL) |
if (user_escaped == NULL) |
user_escaped = request->hr_user; |
user_escaped = request->hr_user; |
Line 1990 bozo_http_error(bozohttpd_t *httpd, int |
|
Line 2229 bozo_http_error(bozohttpd_t *httpd, int |
|
"<html><head><title>%s</title></head>\n" |
"<html><head><title>%s</title></head>\n" |
"<body><h1>%s</h1>\n" |
"<body><h1>%s</h1>\n" |
"%s%s: <pre>%s</pre>\n" |
"%s%s: <pre>%s</pre>\n" |
"<hr><address><a href=\"http://%s%s/\">%s%s</a></address>\n" |
"<hr><address><a href=\"//%s%s/\">%s%s</a></address>\n" |
"</body></html>\n", |
"</body></html>\n", |
header, header, |
header, header, |
user ? user : "", file, |
user ? user : "", file, |
Line 2022 bozo_http_error(bozohttpd_t *httpd, int |
|
Line 2261 bozo_http_error(bozohttpd_t *httpd, int |
|
bozo_printf(httpd, "Server: %s\r\n", httpd->server_software); |
bozo_printf(httpd, "Server: %s\r\n", httpd->server_software); |
if (request && request->hr_allow) |
if (request && request->hr_allow) |
bozo_printf(httpd, "Allow: %s\r\n", request->hr_allow); |
bozo_printf(httpd, "Allow: %s\r\n", request->hr_allow); |
|
/* RFC 7231 (HTTP/1.1) 6.5.7 */ |
|
if (code == 408 && request && |
|
request->hr_proto == httpd->consts.http_11) |
|
bozo_printf(httpd, "Connection: close\r\n"); |
bozo_printf(httpd, "\r\n"); |
bozo_printf(httpd, "\r\n"); |
/* According to the RFC 2616 sec. 9.4 HEAD method MUST NOT return a |
/* According to the RFC 2616 sec. 9.4 HEAD method MUST NOT return a |
* message-body in the response */ |
* message-body in the response */ |
Line 2136 bozodgetln(bozohttpd_t *httpd, int fd, s |
|
Line 2379 bozodgetln(bozohttpd_t *httpd, int fd, s |
|
|
|
} |
} |
httpd->getln_buffer[len] = '\0'; |
httpd->getln_buffer[len] = '\0'; |
debug((httpd, DEBUG_OBESE, "bozodgetln returns: ``%s'' with len %zd", |
debug((httpd, DEBUG_OBESE, "bozodgetln returns: '%s' with len %zd", |
httpd->getln_buffer, len)); |
httpd->getln_buffer, len)); |
*lenp = len; |
*lenp = len; |
return httpd->getln_buffer; |
return httpd->getln_buffer; |
Line 2151 bozorealloc(bozohttpd_t *httpd, void *pt |
|
Line 2394 bozorealloc(bozohttpd_t *httpd, void *pt |
|
if (p) |
if (p) |
return p; |
return p; |
|
|
(void)bozo_http_error(httpd, 500, NULL, "memory allocation failure"); |
bozo_http_error(httpd, 500, NULL, "memory allocation failure"); |
exit(EXIT_FAILURE); |
exit(EXIT_FAILURE); |
} |
} |
|
|
Line 2164 bozomalloc(bozohttpd_t *httpd, size_t si |
|
Line 2407 bozomalloc(bozohttpd_t *httpd, size_t si |
|
if (p) |
if (p) |
return p; |
return p; |
|
|
(void)bozo_http_error(httpd, 500, NULL, "memory allocation failure"); |
bozo_http_error(httpd, 500, NULL, "memory allocation failure"); |
exit(EXIT_FAILURE); |
exit(EXIT_FAILURE); |
} |
} |
|
|
Line 2180 bozostrdup(bozohttpd_t *httpd, bozo_http |
|
Line 2423 bozostrdup(bozohttpd_t *httpd, bozo_http |
|
if (!request) |
if (!request) |
bozoerr(httpd, EXIT_FAILURE, "strdup"); |
bozoerr(httpd, EXIT_FAILURE, "strdup"); |
|
|
(void)bozo_http_error(httpd, 500, request, "memory allocation failure"); |
bozo_http_error(httpd, 500, request, "memory allocation failure"); |
exit(EXIT_FAILURE); |
exit(EXIT_FAILURE); |
} |
} |
|
|
Line 2202 bozo_init_httpd(bozohttpd_t *httpd) |
|
Line 2445 bozo_init_httpd(bozohttpd_t *httpd) |
|
|
|
/* error buffer for bozo_http_error() */ |
/* error buffer for bozo_http_error() */ |
if ((httpd->errorbuf = malloc(BUFSIZ)) == NULL) { |
if ((httpd->errorbuf = malloc(BUFSIZ)) == NULL) { |
(void) fprintf(stderr, |
fprintf(stderr, |
"bozohttpd: memory_allocation failure\n"); |
"bozohttpd: memory_allocation failure\n"); |
return 0; |
return 0; |
} |
} |
Line 2216 bozo_init_httpd(bozohttpd_t *httpd) |
|
Line 2459 bozo_init_httpd(bozohttpd_t *httpd) |
|
int |
int |
bozo_init_prefs(bozohttpd_t *httpd, bozoprefs_t *prefs) |
bozo_init_prefs(bozohttpd_t *httpd, bozoprefs_t *prefs) |
{ |
{ |
|
int rv = 0; |
|
|
/* make sure everything is clean */ |
/* make sure everything is clean */ |
(void) memset(prefs, 0x0, sizeof(*prefs)); |
(void) memset(prefs, 0x0, sizeof(*prefs)); |
|
|
/* set up default values */ |
/* set up default values */ |
if (!bozo_set_pref(httpd, prefs, "server software", SERVER_SOFTWARE) || |
if (!bozo_set_pref(httpd, prefs, "server software", SERVER_SOFTWARE)) |
!bozo_set_pref(httpd, prefs, "index.html", INDEX_HTML) || |
rv = 1; |
!bozo_set_pref(httpd, prefs, "public_html", PUBLIC_HTML)) |
if (!bozo_set_pref(httpd, prefs, "index.html", INDEX_HTML)) |
return 0; |
rv = 1; |
|
if (!bozo_set_pref(httpd, prefs, "public_html", PUBLIC_HTML)) |
|
rv = 1; |
|
if (!bozo_set_pref(httpd, prefs, "ssl timeout", SSL_TIMEOUT)) |
|
rv = 1; |
|
if (!bozo_set_pref(httpd, prefs, "initial timeout", INITIAL_TIMEOUT)) |
|
rv = 1; |
|
if (!bozo_set_pref(httpd, prefs, "header timeout", HEADER_WAIT_TIME)) |
|
rv = 1; |
|
if (!bozo_set_pref(httpd, prefs, "request timeout", TOTAL_MAX_REQ_TIME)) |
|
rv = 1; |
|
|
return 1; |
return rv; |
} |
} |
|
|
/* set default values */ |
/* set default values */ |
Line 2318 bozo_setup(bozohttpd_t *httpd, bozoprefs |
|
Line 2573 bozo_setup(bozohttpd_t *httpd, bozoprefs |
|
if ((cp = bozo_get_pref(prefs, "public_html")) != NULL) { |
if ((cp = bozo_get_pref(prefs, "public_html")) != NULL) { |
httpd->public_html = bozostrdup(httpd, NULL, cp); |
httpd->public_html = bozostrdup(httpd, NULL, cp); |
} |
} |
|
if ((cp = bozo_get_pref(prefs, "ssl timeout")) != NULL) { |
|
httpd->ssl_timeout = atoi(cp); |
|
} |
|
if ((cp = bozo_get_pref(prefs, "initial timeout")) != NULL) { |
|
httpd->initial_timeout = atoi(cp); |
|
} |
|
if ((cp = bozo_get_pref(prefs, "header timeout")) != NULL) { |
|
httpd->header_timeout = atoi(cp); |
|
} |
|
if ((cp = bozo_get_pref(prefs, "request timeout")) != NULL) { |
|
httpd->request_timeout = atoi(cp); |
|
} |
httpd->server_software = |
httpd->server_software = |
bozostrdup(httpd, NULL, bozo_get_pref(prefs, "server software")); |
bozostrdup(httpd, NULL, bozo_get_pref(prefs, "server software")); |
httpd->index_html = |
httpd->index_html = |