From feb0f9fb3a99999911b79f826fdc164c5763237a Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Thu, 8 Jul 2021 15:56:23 -0700 Subject: [PATCH] Make improvements to redbean - Fix Content-Type inference when file extension has number - Remove shoddy Class A granular IP classiifcation - Have setuid() and setgid() take effect w/o daemonization - Make GetParams() return empty table instead of nil - Change SetLogLevel(int) to only apply to one message - Make SetLogLevel(int) good enough to be access_log off - Introduce ProgramUid(int) which is same as -U INT - Introduce ProgramGid(int) which is same as -G INT - Introduce ProgramLogPath(str) which is same as -L PATH - Introduce ProgramDirectory(str) which is same as -D PATH - Introduce ProgramLogBodies(bool) which is same as -b - Introduce ProgramLogMessages(bool) which is same as -m --- net/http/findcontenttype.c | 146 +++++++++++++ net/http/http.h | 1 + test/net/http/findcontenttype_test.c | 26 +++ tool/net/counters.inc | 18 -- tool/net/redbean.c | 304 +++++++++------------------ 5 files changed, 271 insertions(+), 224 deletions(-) create mode 100644 net/http/findcontenttype.c create mode 100644 test/net/http/findcontenttype_test.c diff --git a/net/http/findcontenttype.c b/net/http/findcontenttype.c new file mode 100644 index 000000000..922f6ef6c --- /dev/null +++ b/net/http/findcontenttype.c @@ -0,0 +1,146 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2021 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/assert.h" +#include "libc/bits/bits.h" +#include "libc/bits/bswap.h" +#include "libc/macros.internal.h" +#include "libc/str/str.h" +#include "net/http/http.h" + +static const struct ContentTypeExtension { + unsigned char ext[8]; + const char *mime; +} kContentTypeExtension[] = { + {"7z", "application/x-7z-compressed"}, // + {"aac", "audio/aac"}, // + {"apng", "image/apng"}, // + {"atom", "application/atom+xml"}, // + {"avi", "video/x-msvideo"}, // + {"avif", "image/avif"}, // + {"azw", "application/vnd.amazon.ebook"}, // + {"bmp", "image/bmp"}, // + {"bz2", "application/x-bzip2"}, // + {"c", "text/plain"}, // + {"cc", "text/plain"}, // + {"css", "text/css"}, // + {"csv", "text/csv"}, // + {"doc", "application/msword"}, // + {"epub", "application/epub+zip"}, // + {"gif", "image/gif"}, // + {"gz", "application/gzip"}, // + {"h", "text/plain"}, // + {"htm", "text/html"}, // + {"html", "text/html"}, // + {"i", "text/plain"}, // + {"ico", "image/vnd.microsoft.icon"}, // + {"jar", "application/java-archive"}, // + {"jpeg", "image/jpeg"}, // + {"jpg", "image/jpeg"}, // + {"js", "text/javascript"}, // + {"json", "application/json"}, // + {"m4a", "audio/mpeg"}, // + {"markdown", "text/plain"}, // + {"md", "text/plain"}, // + {"mid", "audio/midi"}, // + {"midi", "audio/midi"}, // + {"mp2", "audio/mpeg"}, // + {"mp3", "audio/mpeg"}, // + {"mp4", "video/mp4"}, // + {"mpeg", "video/mpeg"}, // + {"mpg", "video/mpeg"}, // + {"oga", "audio/ogg"}, // + {"ogg", "application/ogg"}, // + {"ogv", "video/ogg"}, // + {"ogx", "application/ogg"}, // + {"otf", "font/otf"}, // + {"pdf", "application/pdf"}, // + {"png", "image/png"}, // + {"rar", "application/vnd.rar"}, // + {"rtf", "application/rtf"}, // + {"s", "text/plain"}, // + {"sh", "application/x-sh"}, // + {"sqlite", "application/vnd.sqlite3"}, // + {"sqlite3", "application/vnd.sqlite3"}, // + {"svg", "image/svg+xml"}, // + {"swf", "application/x-shockwave-flash"}, // + {"t38", "image/t38"}, // + {"tar", "application/x-tar"}, // + {"tiff", "image/tiff"}, // + {"ttf", "font/ttf"}, // + {"txt", "text/plain"}, // + {"ul", "audio/basic"}, // + {"ulaw", "audio/basic"}, // + {"wasm", "application/wasm"}, // + {"wav", "audio/x-wav"}, // + {"weba", "audio/webm"}, // + {"webm", "video/webm"}, // + {"webp", "image/webp"}, // + {"woff", "font/woff"}, // + {"woff2", "font/woff2"}, // + {"wsdl", "application/wsdl+xml"}, // + {"xhtml", "application/xhtml+xml"}, // + {"xls", "application/vnd.ms-excel"}, // + {"xml", "application/xml"}, // + {"xsl", "application/xslt+xml"}, // + {"xslt", "application/xslt+xml"}, // + {"xz", "application/x-xz"}, // + {"z", "application/zlib"}, // + {"zip", "application/zip"}, // + {"zst", "application/zstd"}, // +}; + +static inline int CompareInts(const uint64_t x, uint64_t y) { + return x > y ? 1 : x < y ? -1 : 0; +} + +static const char *BisectContentType(uint64_t ext) { + int c, m, l, r; + l = 0; + r = ARRAYLEN(kContentTypeExtension) - 1; + while (l <= r) { + m = (l + r) >> 1; + c = CompareInts(READ64BE(kContentTypeExtension[m].ext), ext); + if (c < 0) { + l = m + 1; + } else if (c > 0) { + r = m - 1; + } else { + return kContentTypeExtension[m].mime; + } + } + return 0; +} + +/** + * Returns Content-Type for file extension. + */ +const char *FindContentType(const char *p, size_t n) { + int c; + uint64_t w; + if (n == -1) n = p ? strlen(p) : 0; + for (w = 0; n--;) { + c = p[n] & 255; + if (c == '.') { + return BisectContentType(bswap_64(w)); + } + w <<= 8; + w |= kToLower[c]; + } + return 0; +} diff --git a/net/http/http.h b/net/http/http.h index 26c506d3b..6c1c6a7c0 100644 --- a/net/http/http.h +++ b/net/http/http.h @@ -206,6 +206,7 @@ int64_t ParseIp(const char *, size_t); int ParseForwarded(const char *, size_t, uint32_t *, uint16_t *); bool IsMimeType(const char *, size_t, const char *); ssize_t Unchunk(struct HttpUnchunker *, char *, size_t, size_t *); +const char *FindContentType(const char *, size_t); COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/test/net/http/findcontenttype_test.c b/test/net/http/findcontenttype_test.c new file mode 100644 index 000000000..baacbd52a --- /dev/null +++ b/test/net/http/findcontenttype_test.c @@ -0,0 +1,26 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2021 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/testlib/testlib.h" +#include "net/http/http.h" + +TEST(FindContentType, test) { + EXPECT_STREQ("video/mp4", FindContentType("/foo.mp4", -1)); + EXPECT_STREQ("video/mp4", FindContentType("/FOO.MP4", -1)); + EXPECT_STREQ("text/html", FindContentType("/foo.html", -1)); +} diff --git a/tool/net/counters.inc b/tool/net/counters.inc index 807bb301b..96b3579a0 100644 --- a/tool/net/counters.inc +++ b/tool/net/counters.inc @@ -42,24 +42,6 @@ C(maps) C(meltdowns) C(messageshandled) C(missinglengths) -C(netafrinic) -C(netanonymous) -C(netapnic) -C(netapple) -C(netarin) -C(netatt) -C(netcogent) -C(netcomcast) -C(netdod) -C(netford) -C(netlacnic) -C(netloopback) -C(netother) -C(netprivate) -C(netprudential) -C(netripe) -C(nettestnet) -C(netusps) C(notfounds) C(notmodifieds) C(openfails) diff --git a/tool/net/redbean.c b/tool/net/redbean.c index 5e2738c89..cfdef71e3 100644 --- a/tool/net/redbean.c +++ b/tool/net/redbean.c @@ -167,88 +167,6 @@ static const char *const kIndexPaths[] = { "index.html", }; -static const struct ContentTypeExtension { - unsigned char ext[8]; - const char *mime; -} kContentTypeExtension[] = { - {"7z", "application/x-7z-compressed"}, // - {"aac", "audio/aac"}, // - {"apng", "image/apng"}, // - {"atom", "application/atom+xml"}, // - {"avi", "video/x-msvideo"}, // - {"avif", "image/avif"}, // - {"azw", "application/vnd.amazon.ebook"}, // - {"bmp", "image/bmp"}, // - {"bz2", "application/x-bzip2"}, // - {"c", "text/plain"}, // - {"cc", "text/plain"}, // - {"css", "text/css"}, // - {"csv", "text/csv"}, // - {"doc", "application/msword"}, // - {"epub", "application/epub+zip"}, // - {"gif", "image/gif"}, // - {"gz", "application/gzip"}, // - {"h", "text/plain"}, // - {"htm", "text/html"}, // - {"html", "text/html"}, // - {"i", "text/plain"}, // - {"ico", "image/vnd.microsoft.icon"}, // - {"jar", "application/java-archive"}, // - {"jpeg", "image/jpeg"}, // - {"jpg", "image/jpeg"}, // - {"js", "text/javascript"}, // - {"json", "application/json"}, // - {"m4a", "audio/mpeg"}, // - {"markdown", "text/plain"}, // - {"md", "text/plain"}, // - {"mid", "audio/midi"}, // - {"midi", "audio/midi"}, // - {"mp2", "audio/mpeg"}, // - {"mp3", "audio/mpeg"}, // - {"mp4", "video/mp4"}, // - {"mpeg", "video/mpeg"}, // - {"mpg", "video/mpeg"}, // - {"oga", "audio/ogg"}, // - {"ogg", "application/ogg"}, // - {"ogv", "video/ogg"}, // - {"ogx", "application/ogg"}, // - {"otf", "font/otf"}, // - {"pdf", "application/pdf"}, // - {"png", "image/png"}, // - {"rar", "application/vnd.rar"}, // - {"rtf", "application/rtf"}, // - {"s", "text/plain"}, // - {"sh", "application/x-sh"}, // - {"sqlite", "application/vnd.sqlite3"}, // - {"sqlite3", "application/vnd.sqlite3"}, // - {"svg", "image/svg+xml"}, // - {"swf", "application/x-shockwave-flash"}, // - {"t38", "image/t38"}, // - {"tar", "application/x-tar"}, // - {"tiff", "image/tiff"}, // - {"ttf", "font/ttf"}, // - {"txt", "text/plain"}, // - {"ul", "audio/basic"}, // - {"ulaw", "audio/basic"}, // - {"wasm", "application/wasm"}, // - {"wav", "audio/x-wav"}, // - {"weba", "audio/webm"}, // - {"webm", "video/webm"}, // - {"webp", "image/webp"}, // - {"woff", "font/woff"}, // - {"woff2", "font/woff2"}, // - {"wsdl", "application/wsdl+xml"}, // - {"xhtml", "application/xhtml+xml"}, // - {"xls", "application/vnd.ms-excel"}, // - {"xml", "application/xml"}, // - {"xsl", "application/xslt+xml"}, // - {"xslt", "application/xslt+xml"}, // - {"xz", "application/x-xz"}, // - {"z", "application/zlib"}, // - {"zip", "application/zip"}, // - {"zst", "application/zstd"}, // -}; - static const char kRegCode[][8] = { "OK", "NOMATCH", "BADPAT", "COLLATE", "ECTYPE", "EESCAPE", "ESUBREG", "EBRACK", "EPAREN", "EBRACE", "BADBR", "ERANGE", "ESPACE", "BADRPT", @@ -390,9 +308,10 @@ static int zfd; static int frags; static int gmtoff; static int client; -static int daemonuid; -static int daemongid; +static int changeuid; +static int changegid; static int statuscode; +static int oldloglevel; static int maxpayloadsize; static int messageshandled; static uint32_t clientaddrsize; @@ -544,6 +463,7 @@ static void UnmapLater(int f, void *p, size_t n) { } static void CollectGarbage(void) { + __log_level = oldloglevel; DestroyHttpMessage(&msg); while (freelist.n) { free(freelist.p[--freelist.n]); @@ -935,10 +855,6 @@ static void DescribeAddress(char buf[32], uint32_t addr, uint16_t port) { p += uint64toarray_radix10((addr & 0x0000FF00) >> 010, p), *p++ = '.'; p += uint64toarray_radix10((addr & 0x000000FF) >> 000, p), *p++ = ':'; p += uint64toarray_radix10(port, p); - if ((s = GetIpCategoryName(CategorizeIp(addr)))) { - *p++ = ' '; - p = stpcpy(p, s); - } *p++ = '\0'; } @@ -992,6 +908,14 @@ static void ProgramBrand(const char *s) { free(p); } +static void ProgramUid(long x) { + changeuid = x; +} + +static void ProgramGid(long x) { + changegid = x; +} + static void ProgramTimeout(long ms) { ldiv_t d; if (ms < 0) { @@ -1041,8 +965,11 @@ static bool HasString(struct Strings *l, const char *s, size_t n) { return false; } -static void AddStagingDirectory(char *s) { - size_t n = strlen(s); +static void ProgramDirectory(const char *path) { + char *s; + size_t n; + s = strdup(path); + n = strlen(s); while (n && (s[n - 1] == '/' || s[n - 1] == '\\')) s[--n] = 0; if (!n || !isdirectory(s)) { fprintf(stderr, "error: not a directory: %`'s\n", s); @@ -1079,6 +1006,10 @@ static void ProgramHeader(const char *s) { } } +static void ProgramLogPath(const char *s) { + logpath = strdup(s); +} + static bool IsServerFd(int fd) { size_t i; for (i = 0; i < servers.n; ++i) { @@ -1089,6 +1020,11 @@ static bool IsServerFd(int fd) { return false; } +static void ChangeUser(void) { + if (changegid) LOGIFNEG1(setgid(changegid)); + if (changeuid) LOGIFNEG1(setuid(changeuid)); +} + static void Daemonize(void) { char ibuf[21]; int i, fd, pid; @@ -1110,8 +1046,7 @@ static void Daemonize(void) { open("/dev/null", O_RDONLY); open(logpath, O_APPEND | O_WRONLY | O_CREAT, 0640); dup2(1, 2); - LOGIFNEG1(setgid(daemongid)); - LOGIFNEG1(setuid(daemonuid)); + ChangeUser(); } static void ReportWorkerExit(int pid, int ws) { @@ -2253,7 +2188,7 @@ static void GetOpts(int argc, char *argv[]) { ProgramRedirectArg(0, optarg); break; case 'D': - AddStagingDirectory(optarg); + ProgramDirectory(optarg); break; case 'c': ProgramCache(strtol(optarg, NULL, 0)); @@ -2272,16 +2207,16 @@ static void GetOpts(int argc, char *argv[]) { ProgramHeader(optarg); break; case 'L': - logpath = optarg; + ProgramLogPath(optarg); break; case 'P': pidpath = optarg; break; case 'U': - daemonuid = atoi(optarg); + ProgramUid(atoi(optarg)); break; case 'G': - daemongid = atoi(optarg); + ProgramGid(atoi(optarg)); break; #ifndef UNSECURE case 'C': @@ -2297,9 +2232,6 @@ static void GetOpts(int argc, char *argv[]) { PrintUsage(stderr, EX_USAGE); } } - if (logpath) { - CHECK_NOTNULL(freopen(logpath, "a", stderr)); - } if (!!keypath ^ !!certpath) { fprintf(stderr, "error: the -C and -K flags need to be passed together\n"); exit(1); @@ -3447,6 +3379,7 @@ static int LuaPushHeaders(lua_State *L, struct HttpMessage *m, const char *b) { static void LogMessage(const char *d, const char *s, size_t n) { size_t n2, n3; char *s2, *s3; + if (!LOGGABLE(kLogInfo)) return; while (n && (s[n - 1] == '\r' || s[n - 1] == '\n')) --n; if ((s2 = DecodeLatin1(s, n, &n2))) { if ((s3 = IndentLines(s2, n2, &n3, 1))) { @@ -3461,6 +3394,7 @@ static void LogBody(const char *d, const char *s, size_t n) { char *s2, *s3; size_t n2, n3; if (!n) return; + if (!LOGGABLE(kLogInfo)) return; while (n && (s[n - 1] == '\r' || s[n - 1] == '\n')) --n; if ((s2 = VisualizeControlCodes(s, n, &n2))) { if ((s3 = IndentLines(s2, n2, &n3, 1))) { @@ -3618,7 +3552,9 @@ static int LuaFetch(lua_State *L) { luaL_error(L, "write failed: %s", strerror(errno)); unreachable; } - if (logmessages) LogMessage("sent", request, requestlen); + if (logmessages) { + LogMessage("sent", request, requestlen); + } /* * Handle response. @@ -3660,7 +3596,9 @@ static int LuaFetch(lua_State *L) { if (rc == -1) goto TransportError; if (rc) { hdrsize = rc; - if (logmessages) LogMessage("received", inbuf.p, hdrsize); + if (logmessages) { + LogMessage("received", inbuf.p, hdrsize); + } if (100 <= msg.status && msg.status <= 199) { if ((HasHeader(kHttpContentLength) && !HeaderEqualCase(kHttpContentLength, "0")) || @@ -4043,20 +3981,16 @@ static int LuaGetParam(lua_State *L) { static void LuaPushUrlParams(lua_State *L, struct UrlParams *h) { size_t i; - if (h->p) { + lua_newtable(L); + for (i = 0; i < h->n; ++i) { lua_newtable(L); - for (i = 0; i < h->n; ++i) { - lua_newtable(L); - lua_pushlstring(L, h->p[i].key.p, h->p[i].key.n); - lua_seti(L, -2, 1); - if (h->p[i].val.p) { - lua_pushlstring(L, h->p[i].val.p, h->p[i].val.n); - lua_seti(L, -2, 2); - } - lua_seti(L, -2, i + 1); + lua_pushlstring(L, h->p[i].key.p, h->p[i].key.n); + lua_seti(L, -2, 1); + if (h->p[i].val.p) { + lua_pushlstring(L, h->p[i].val.p, h->p[i].val.n); + lua_seti(L, -2, 2); } - } else { - lua_pushnil(L); + lua_seti(L, -2, i + 1); } } @@ -4468,11 +4402,6 @@ static noinline int LuaProgramInt(lua_State *L, void P(long)) { return 0; } -static int LuaProgramAddr(lua_State *L) { - ProgramAddr(luaL_checkstring(L, 1)); - return 0; -} - static int LuaProgramPort(lua_State *L) { return LuaProgramInt(L, ProgramPort); } @@ -4485,11 +4414,35 @@ static int LuaProgramTimeout(lua_State *L) { return LuaProgramInt(L, ProgramTimeout); } -static int LuaProgramBrand(lua_State *L) { - ProgramBrand(luaL_checkstring(L, 1)); +static int LuaProgramUid(lua_State *L) { + return LuaProgramInt(L, ProgramUid); +} + +static int LuaProgramGid(lua_State *L) { + return LuaProgramInt(L, ProgramGid); +} + +static noinline int LuaProgramString(lua_State *L, void P(const char *)) { + P(luaL_checkstring(L, 1)); return 0; } +static int LuaProgramAddr(lua_State *L) { + return LuaProgramString(L, ProgramAddr); +} + +static int LuaProgramBrand(lua_State *L) { + return LuaProgramString(L, ProgramBrand); +} + +static int LuaProgramDirectory(lua_State *L) { + return LuaProgramString(L, ProgramDirectory); +} + +static int LuaProgramLogPath(lua_State *L) { + return LuaProgramString(L, ProgramLogPath); +} + static int LuaProgramPrivateKey(lua_State *L) { #ifndef UNSECURE size_t n; @@ -4526,7 +4479,7 @@ static int LuaProgramRedirect(lua_State *L) { return 0; } -static int LuaProgramBool(lua_State *L, bool *b) { +static noinline int LuaProgramBool(lua_State *L, bool *b) { *b = lua_toboolean(L, 1); return 0; } @@ -4539,6 +4492,14 @@ static int LuaProgramSslFetchVerify(lua_State *L) { return LuaProgramBool(L, &sslfetchverify); } +static int LuaProgramLogMessages(lua_State *L) { + return LuaProgramBool(L, &logmessages); +} + +static int LuaProgramLogBodies(lua_State *L) { + return LuaProgramBool(L, &logbodies); +} + static int LuaGetLogLevel(lua_State *L) { lua_pushinteger(L, __log_level); return 1; @@ -4916,13 +4877,19 @@ static const luaL_Reg kLuaFuncs[] = { {"ProgramBrand", LuaProgramBrand}, // {"ProgramCache", LuaProgramCache}, // {"ProgramCertificate", LuaProgramCertificate}, // + {"ProgramDirectory", LuaProgramDirectory}, // + {"ProgramGid", LuaProgramGid}, // {"ProgramHeader", LuaProgramHeader}, // + {"ProgramLogBodies", LuaProgramLogBodies}, // + {"ProgramLogMessages", LuaProgramLogMessages}, // + {"ProgramLogPath", LuaProgramLogPath}, // {"ProgramPort", LuaProgramPort}, // {"ProgramPrivateKey", LuaProgramPrivateKey}, // {"ProgramRedirect", LuaProgramRedirect}, // {"ProgramSslClientVerify", LuaProgramSslClientVerify}, // {"ProgramSslFetchVerify", LuaProgramSslFetchVerify}, // {"ProgramTimeout", LuaProgramTimeout}, // + {"ProgramUid", LuaProgramUid}, // {"Route", LuaRoute}, // {"RouteHost", LuaRouteHost}, // {"RoutePath", LuaRoutePath}, // @@ -5036,7 +5003,9 @@ static ssize_t SendString(const char *s) { n = strlen(s); iov.iov_base = s; iov.iov_len = n; - if (logmessages) LogMessage("sending", s, n); + if (logmessages) { + LogMessage("sending", s, n); + } for (;;) { if ((rc = writer(client, &iov, 1)) != -1 || errno != EINTR) { return rc; @@ -5469,6 +5438,7 @@ static char *HandleRequest(void) { static char *Route(const char *host, size_t hostlen, const char *path, size_t pathlen) { char *p; + if (logmessages) LogMessage("received", inbuf.p, hdrsize); if (hostlen && (p = RouteHost(host, hostlen, path, pathlen))) { return p; } @@ -5563,41 +5533,6 @@ static char *HandleAsset(struct Asset *a, const char *path, size_t pathlen) { } } -static inline int CompareInts(const uint64_t x, uint64_t y) { - return x > y ? 1 : x < y ? -1 : 0; -} - -static const char *BisectContentType(uint64_t ext) { - int c, m, l, r; - l = 0; - r = ARRAYLEN(kContentTypeExtension) - 1; - while (l <= r) { - m = (l + r) >> 1; - c = CompareInts(READ64BE(kContentTypeExtension[m].ext), ext); - if (c < 0) { - l = m + 1; - } else if (c > 0) { - r = m - 1; - } else { - return kContentTypeExtension[m].mime; - } - } - return NULL; -} - -static const char *FindContentType(const char *p, size_t n) { - int c; - uint64_t w; - for (w = 0; n--;) { - c = p[n] & 255; - if (c == '.') return BisectContentType(bswap_64(w)); - w <<= 8; - w |= c; - w |= 0100; - } - return NULL; -} - static const char *GetContentType(struct Asset *a, const char *path, size_t n) { const char *r; if (a->file && (r = FindContentType(a->file->path.s, a->file->path.n))) { @@ -5688,53 +5623,6 @@ static inline bool MustNotIncludeMessageBody(void) { /* RFC2616 § 4.4 */ statuscode == 204 || statuscode == 304; } -static inline int GetNetworkCounterIndex(int x) { - switch (x) { - case kIpLoopback: - return offsetof(struct Counters, netloopback) / sizeof(long); - case kIpPrivate: - return offsetof(struct Counters, netprivate) / sizeof(long); - case kIpTestnet: - return offsetof(struct Counters, nettestnet) / sizeof(long); - case kIpAfrinic: - return offsetof(struct Counters, netafrinic) / sizeof(long); - case kIpLacnic: - return offsetof(struct Counters, netlacnic) / sizeof(long); - case kIpApnic: - return offsetof(struct Counters, netapnic) / sizeof(long); - case kIpArin: - return offsetof(struct Counters, netarin) / sizeof(long); - case kIpRipe: - return offsetof(struct Counters, netripe) / sizeof(long); - case kIpDod: - return offsetof(struct Counters, netdod) / sizeof(long); - case kIpAtt: - return offsetof(struct Counters, netatt) / sizeof(long); - case kIpApple: - return offsetof(struct Counters, netapple) / sizeof(long); - case kIpFord: - return offsetof(struct Counters, netford) / sizeof(long); - case kIpCogent: - return offsetof(struct Counters, netcogent) / sizeof(long); - case kIpPrudential: - return offsetof(struct Counters, netprudential) / sizeof(long); - case kIpUsps: - return offsetof(struct Counters, netusps) / sizeof(long); - case kIpComcast: - return offsetof(struct Counters, netcomcast) / sizeof(long); - case kIpAnonymous: - return offsetof(struct Counters, netanonymous) / sizeof(long); - default: - return offsetof(struct Counters, netother) / sizeof(long); - } -} - -static inline void RecordNetworkOrigin(void) { - uint32_t ip; - GetRemoteAddr(&ip, 0); - LockInc(((long *)&shared->c) + GetNetworkCounterIndex(CategorizeIp(ip))); -} - static bool HandleMessage(void) { int rc; int iovlen; @@ -5745,8 +5633,6 @@ static bool HandleMessage(void) { if ((rc = ParseHttpMessage(&msg, inbuf.p, amtread)) != -1) { if (!rc) return false; hdrsize = rc; - if (logmessages) LogMessage("received", inbuf.p, hdrsize); - RecordNetworkOrigin(); p = HandleRequest(); } else { LockInc(&shared->c.badmessages); @@ -6205,6 +6091,11 @@ void RedBean(int argc, char *argv[]) { Daemonize(); } else { setpgid(getpid(), getpid()); + if (logpath) { + close(2); + open(logpath, O_APPEND | O_WRONLY | O_CREAT, 0640); + } + ChangeUser(); } UpdateCurrentDate(nowl()); freelist.c = 8; @@ -6215,6 +6106,7 @@ void RedBean(int argc, char *argv[]) { hdrbuf.p = xmalloc(hdrbuf.n); inbuf.n = maxpayloadsize; inbuf.p = xmalloc(inbuf.n); + oldloglevel = __log_level; while (!terminated) { if (zombied) { ReapZombies();