mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-03-03 15:38:22 +00:00
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
This commit is contained in:
parent
cc9366b200
commit
feb0f9fb3a
5 changed files with 271 additions and 224 deletions
146
net/http/findcontenttype.c
Normal file
146
net/http/findcontenttype.c
Normal file
|
@ -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;
|
||||||
|
}
|
|
@ -206,6 +206,7 @@ int64_t ParseIp(const char *, size_t);
|
||||||
int ParseForwarded(const char *, size_t, uint32_t *, uint16_t *);
|
int ParseForwarded(const char *, size_t, uint32_t *, uint16_t *);
|
||||||
bool IsMimeType(const char *, size_t, const char *);
|
bool IsMimeType(const char *, size_t, const char *);
|
||||||
ssize_t Unchunk(struct HttpUnchunker *, char *, size_t, size_t *);
|
ssize_t Unchunk(struct HttpUnchunker *, char *, size_t, size_t *);
|
||||||
|
const char *FindContentType(const char *, size_t);
|
||||||
|
|
||||||
COSMOPOLITAN_C_END_
|
COSMOPOLITAN_C_END_
|
||||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||||
|
|
26
test/net/http/findcontenttype_test.c
Normal file
26
test/net/http/findcontenttype_test.c
Normal file
|
@ -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));
|
||||||
|
}
|
|
@ -42,24 +42,6 @@ C(maps)
|
||||||
C(meltdowns)
|
C(meltdowns)
|
||||||
C(messageshandled)
|
C(messageshandled)
|
||||||
C(missinglengths)
|
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(notfounds)
|
||||||
C(notmodifieds)
|
C(notmodifieds)
|
||||||
C(openfails)
|
C(openfails)
|
||||||
|
|
|
@ -167,88 +167,6 @@ static const char *const kIndexPaths[] = {
|
||||||
"index.html",
|
"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] = {
|
static const char kRegCode[][8] = {
|
||||||
"OK", "NOMATCH", "BADPAT", "COLLATE", "ECTYPE", "EESCAPE", "ESUBREG",
|
"OK", "NOMATCH", "BADPAT", "COLLATE", "ECTYPE", "EESCAPE", "ESUBREG",
|
||||||
"EBRACK", "EPAREN", "EBRACE", "BADBR", "ERANGE", "ESPACE", "BADRPT",
|
"EBRACK", "EPAREN", "EBRACE", "BADBR", "ERANGE", "ESPACE", "BADRPT",
|
||||||
|
@ -390,9 +308,10 @@ static int zfd;
|
||||||
static int frags;
|
static int frags;
|
||||||
static int gmtoff;
|
static int gmtoff;
|
||||||
static int client;
|
static int client;
|
||||||
static int daemonuid;
|
static int changeuid;
|
||||||
static int daemongid;
|
static int changegid;
|
||||||
static int statuscode;
|
static int statuscode;
|
||||||
|
static int oldloglevel;
|
||||||
static int maxpayloadsize;
|
static int maxpayloadsize;
|
||||||
static int messageshandled;
|
static int messageshandled;
|
||||||
static uint32_t clientaddrsize;
|
static uint32_t clientaddrsize;
|
||||||
|
@ -544,6 +463,7 @@ static void UnmapLater(int f, void *p, size_t n) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void CollectGarbage(void) {
|
static void CollectGarbage(void) {
|
||||||
|
__log_level = oldloglevel;
|
||||||
DestroyHttpMessage(&msg);
|
DestroyHttpMessage(&msg);
|
||||||
while (freelist.n) {
|
while (freelist.n) {
|
||||||
free(freelist.p[--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 & 0x0000FF00) >> 010, p), *p++ = '.';
|
||||||
p += uint64toarray_radix10((addr & 0x000000FF) >> 000, p), *p++ = ':';
|
p += uint64toarray_radix10((addr & 0x000000FF) >> 000, p), *p++ = ':';
|
||||||
p += uint64toarray_radix10(port, p);
|
p += uint64toarray_radix10(port, p);
|
||||||
if ((s = GetIpCategoryName(CategorizeIp(addr)))) {
|
|
||||||
*p++ = ' ';
|
|
||||||
p = stpcpy(p, s);
|
|
||||||
}
|
|
||||||
*p++ = '\0';
|
*p++ = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -992,6 +908,14 @@ static void ProgramBrand(const char *s) {
|
||||||
free(p);
|
free(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ProgramUid(long x) {
|
||||||
|
changeuid = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ProgramGid(long x) {
|
||||||
|
changegid = x;
|
||||||
|
}
|
||||||
|
|
||||||
static void ProgramTimeout(long ms) {
|
static void ProgramTimeout(long ms) {
|
||||||
ldiv_t d;
|
ldiv_t d;
|
||||||
if (ms < 0) {
|
if (ms < 0) {
|
||||||
|
@ -1041,8 +965,11 @@ static bool HasString(struct Strings *l, const char *s, size_t n) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void AddStagingDirectory(char *s) {
|
static void ProgramDirectory(const char *path) {
|
||||||
size_t n = strlen(s);
|
char *s;
|
||||||
|
size_t n;
|
||||||
|
s = strdup(path);
|
||||||
|
n = strlen(s);
|
||||||
while (n && (s[n - 1] == '/' || s[n - 1] == '\\')) s[--n] = 0;
|
while (n && (s[n - 1] == '/' || s[n - 1] == '\\')) s[--n] = 0;
|
||||||
if (!n || !isdirectory(s)) {
|
if (!n || !isdirectory(s)) {
|
||||||
fprintf(stderr, "error: not a directory: %`'s\n", 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) {
|
static bool IsServerFd(int fd) {
|
||||||
size_t i;
|
size_t i;
|
||||||
for (i = 0; i < servers.n; ++i) {
|
for (i = 0; i < servers.n; ++i) {
|
||||||
|
@ -1089,6 +1020,11 @@ static bool IsServerFd(int fd) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ChangeUser(void) {
|
||||||
|
if (changegid) LOGIFNEG1(setgid(changegid));
|
||||||
|
if (changeuid) LOGIFNEG1(setuid(changeuid));
|
||||||
|
}
|
||||||
|
|
||||||
static void Daemonize(void) {
|
static void Daemonize(void) {
|
||||||
char ibuf[21];
|
char ibuf[21];
|
||||||
int i, fd, pid;
|
int i, fd, pid;
|
||||||
|
@ -1110,8 +1046,7 @@ static void Daemonize(void) {
|
||||||
open("/dev/null", O_RDONLY);
|
open("/dev/null", O_RDONLY);
|
||||||
open(logpath, O_APPEND | O_WRONLY | O_CREAT, 0640);
|
open(logpath, O_APPEND | O_WRONLY | O_CREAT, 0640);
|
||||||
dup2(1, 2);
|
dup2(1, 2);
|
||||||
LOGIFNEG1(setgid(daemongid));
|
ChangeUser();
|
||||||
LOGIFNEG1(setuid(daemonuid));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ReportWorkerExit(int pid, int ws) {
|
static void ReportWorkerExit(int pid, int ws) {
|
||||||
|
@ -2253,7 +2188,7 @@ static void GetOpts(int argc, char *argv[]) {
|
||||||
ProgramRedirectArg(0, optarg);
|
ProgramRedirectArg(0, optarg);
|
||||||
break;
|
break;
|
||||||
case 'D':
|
case 'D':
|
||||||
AddStagingDirectory(optarg);
|
ProgramDirectory(optarg);
|
||||||
break;
|
break;
|
||||||
case 'c':
|
case 'c':
|
||||||
ProgramCache(strtol(optarg, NULL, 0));
|
ProgramCache(strtol(optarg, NULL, 0));
|
||||||
|
@ -2272,16 +2207,16 @@ static void GetOpts(int argc, char *argv[]) {
|
||||||
ProgramHeader(optarg);
|
ProgramHeader(optarg);
|
||||||
break;
|
break;
|
||||||
case 'L':
|
case 'L':
|
||||||
logpath = optarg;
|
ProgramLogPath(optarg);
|
||||||
break;
|
break;
|
||||||
case 'P':
|
case 'P':
|
||||||
pidpath = optarg;
|
pidpath = optarg;
|
||||||
break;
|
break;
|
||||||
case 'U':
|
case 'U':
|
||||||
daemonuid = atoi(optarg);
|
ProgramUid(atoi(optarg));
|
||||||
break;
|
break;
|
||||||
case 'G':
|
case 'G':
|
||||||
daemongid = atoi(optarg);
|
ProgramGid(atoi(optarg));
|
||||||
break;
|
break;
|
||||||
#ifndef UNSECURE
|
#ifndef UNSECURE
|
||||||
case 'C':
|
case 'C':
|
||||||
|
@ -2297,9 +2232,6 @@ static void GetOpts(int argc, char *argv[]) {
|
||||||
PrintUsage(stderr, EX_USAGE);
|
PrintUsage(stderr, EX_USAGE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (logpath) {
|
|
||||||
CHECK_NOTNULL(freopen(logpath, "a", stderr));
|
|
||||||
}
|
|
||||||
if (!!keypath ^ !!certpath) {
|
if (!!keypath ^ !!certpath) {
|
||||||
fprintf(stderr, "error: the -C and -K flags need to be passed together\n");
|
fprintf(stderr, "error: the -C and -K flags need to be passed together\n");
|
||||||
exit(1);
|
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) {
|
static void LogMessage(const char *d, const char *s, size_t n) {
|
||||||
size_t n2, n3;
|
size_t n2, n3;
|
||||||
char *s2, *s3;
|
char *s2, *s3;
|
||||||
|
if (!LOGGABLE(kLogInfo)) return;
|
||||||
while (n && (s[n - 1] == '\r' || s[n - 1] == '\n')) --n;
|
while (n && (s[n - 1] == '\r' || s[n - 1] == '\n')) --n;
|
||||||
if ((s2 = DecodeLatin1(s, n, &n2))) {
|
if ((s2 = DecodeLatin1(s, n, &n2))) {
|
||||||
if ((s3 = IndentLines(s2, n2, &n3, 1))) {
|
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;
|
char *s2, *s3;
|
||||||
size_t n2, n3;
|
size_t n2, n3;
|
||||||
if (!n) return;
|
if (!n) return;
|
||||||
|
if (!LOGGABLE(kLogInfo)) return;
|
||||||
while (n && (s[n - 1] == '\r' || s[n - 1] == '\n')) --n;
|
while (n && (s[n - 1] == '\r' || s[n - 1] == '\n')) --n;
|
||||||
if ((s2 = VisualizeControlCodes(s, n, &n2))) {
|
if ((s2 = VisualizeControlCodes(s, n, &n2))) {
|
||||||
if ((s3 = IndentLines(s2, n2, &n3, 1))) {
|
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));
|
luaL_error(L, "write failed: %s", strerror(errno));
|
||||||
unreachable;
|
unreachable;
|
||||||
}
|
}
|
||||||
if (logmessages) LogMessage("sent", request, requestlen);
|
if (logmessages) {
|
||||||
|
LogMessage("sent", request, requestlen);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Handle response.
|
* Handle response.
|
||||||
|
@ -3660,7 +3596,9 @@ static int LuaFetch(lua_State *L) {
|
||||||
if (rc == -1) goto TransportError;
|
if (rc == -1) goto TransportError;
|
||||||
if (rc) {
|
if (rc) {
|
||||||
hdrsize = 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 (100 <= msg.status && msg.status <= 199) {
|
||||||
if ((HasHeader(kHttpContentLength) &&
|
if ((HasHeader(kHttpContentLength) &&
|
||||||
!HeaderEqualCase(kHttpContentLength, "0")) ||
|
!HeaderEqualCase(kHttpContentLength, "0")) ||
|
||||||
|
@ -4043,20 +3981,16 @@ static int LuaGetParam(lua_State *L) {
|
||||||
|
|
||||||
static void LuaPushUrlParams(lua_State *L, struct UrlParams *h) {
|
static void LuaPushUrlParams(lua_State *L, struct UrlParams *h) {
|
||||||
size_t i;
|
size_t i;
|
||||||
if (h->p) {
|
lua_newtable(L);
|
||||||
|
for (i = 0; i < h->n; ++i) {
|
||||||
lua_newtable(L);
|
lua_newtable(L);
|
||||||
for (i = 0; i < h->n; ++i) {
|
lua_pushlstring(L, h->p[i].key.p, h->p[i].key.n);
|
||||||
lua_newtable(L);
|
lua_seti(L, -2, 1);
|
||||||
lua_pushlstring(L, h->p[i].key.p, h->p[i].key.n);
|
if (h->p[i].val.p) {
|
||||||
lua_seti(L, -2, 1);
|
lua_pushlstring(L, h->p[i].val.p, h->p[i].val.n);
|
||||||
if (h->p[i].val.p) {
|
lua_seti(L, -2, 2);
|
||||||
lua_pushlstring(L, h->p[i].val.p, h->p[i].val.n);
|
|
||||||
lua_seti(L, -2, 2);
|
|
||||||
}
|
|
||||||
lua_seti(L, -2, i + 1);
|
|
||||||
}
|
}
|
||||||
} else {
|
lua_seti(L, -2, i + 1);
|
||||||
lua_pushnil(L);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4468,11 +4402,6 @@ static noinline int LuaProgramInt(lua_State *L, void P(long)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int LuaProgramAddr(lua_State *L) {
|
|
||||||
ProgramAddr(luaL_checkstring(L, 1));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int LuaProgramPort(lua_State *L) {
|
static int LuaProgramPort(lua_State *L) {
|
||||||
return LuaProgramInt(L, ProgramPort);
|
return LuaProgramInt(L, ProgramPort);
|
||||||
}
|
}
|
||||||
|
@ -4485,11 +4414,35 @@ static int LuaProgramTimeout(lua_State *L) {
|
||||||
return LuaProgramInt(L, ProgramTimeout);
|
return LuaProgramInt(L, ProgramTimeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int LuaProgramBrand(lua_State *L) {
|
static int LuaProgramUid(lua_State *L) {
|
||||||
ProgramBrand(luaL_checkstring(L, 1));
|
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;
|
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) {
|
static int LuaProgramPrivateKey(lua_State *L) {
|
||||||
#ifndef UNSECURE
|
#ifndef UNSECURE
|
||||||
size_t n;
|
size_t n;
|
||||||
|
@ -4526,7 +4479,7 @@ static int LuaProgramRedirect(lua_State *L) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int LuaProgramBool(lua_State *L, bool *b) {
|
static noinline int LuaProgramBool(lua_State *L, bool *b) {
|
||||||
*b = lua_toboolean(L, 1);
|
*b = lua_toboolean(L, 1);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -4539,6 +4492,14 @@ static int LuaProgramSslFetchVerify(lua_State *L) {
|
||||||
return LuaProgramBool(L, &sslfetchverify);
|
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) {
|
static int LuaGetLogLevel(lua_State *L) {
|
||||||
lua_pushinteger(L, __log_level);
|
lua_pushinteger(L, __log_level);
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -4916,13 +4877,19 @@ static const luaL_Reg kLuaFuncs[] = {
|
||||||
{"ProgramBrand", LuaProgramBrand}, //
|
{"ProgramBrand", LuaProgramBrand}, //
|
||||||
{"ProgramCache", LuaProgramCache}, //
|
{"ProgramCache", LuaProgramCache}, //
|
||||||
{"ProgramCertificate", LuaProgramCertificate}, //
|
{"ProgramCertificate", LuaProgramCertificate}, //
|
||||||
|
{"ProgramDirectory", LuaProgramDirectory}, //
|
||||||
|
{"ProgramGid", LuaProgramGid}, //
|
||||||
{"ProgramHeader", LuaProgramHeader}, //
|
{"ProgramHeader", LuaProgramHeader}, //
|
||||||
|
{"ProgramLogBodies", LuaProgramLogBodies}, //
|
||||||
|
{"ProgramLogMessages", LuaProgramLogMessages}, //
|
||||||
|
{"ProgramLogPath", LuaProgramLogPath}, //
|
||||||
{"ProgramPort", LuaProgramPort}, //
|
{"ProgramPort", LuaProgramPort}, //
|
||||||
{"ProgramPrivateKey", LuaProgramPrivateKey}, //
|
{"ProgramPrivateKey", LuaProgramPrivateKey}, //
|
||||||
{"ProgramRedirect", LuaProgramRedirect}, //
|
{"ProgramRedirect", LuaProgramRedirect}, //
|
||||||
{"ProgramSslClientVerify", LuaProgramSslClientVerify}, //
|
{"ProgramSslClientVerify", LuaProgramSslClientVerify}, //
|
||||||
{"ProgramSslFetchVerify", LuaProgramSslFetchVerify}, //
|
{"ProgramSslFetchVerify", LuaProgramSslFetchVerify}, //
|
||||||
{"ProgramTimeout", LuaProgramTimeout}, //
|
{"ProgramTimeout", LuaProgramTimeout}, //
|
||||||
|
{"ProgramUid", LuaProgramUid}, //
|
||||||
{"Route", LuaRoute}, //
|
{"Route", LuaRoute}, //
|
||||||
{"RouteHost", LuaRouteHost}, //
|
{"RouteHost", LuaRouteHost}, //
|
||||||
{"RoutePath", LuaRoutePath}, //
|
{"RoutePath", LuaRoutePath}, //
|
||||||
|
@ -5036,7 +5003,9 @@ static ssize_t SendString(const char *s) {
|
||||||
n = strlen(s);
|
n = strlen(s);
|
||||||
iov.iov_base = s;
|
iov.iov_base = s;
|
||||||
iov.iov_len = n;
|
iov.iov_len = n;
|
||||||
if (logmessages) LogMessage("sending", s, n);
|
if (logmessages) {
|
||||||
|
LogMessage("sending", s, n);
|
||||||
|
}
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if ((rc = writer(client, &iov, 1)) != -1 || errno != EINTR) {
|
if ((rc = writer(client, &iov, 1)) != -1 || errno != EINTR) {
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -5469,6 +5438,7 @@ static char *HandleRequest(void) {
|
||||||
static char *Route(const char *host, size_t hostlen, const char *path,
|
static char *Route(const char *host, size_t hostlen, const char *path,
|
||||||
size_t pathlen) {
|
size_t pathlen) {
|
||||||
char *p;
|
char *p;
|
||||||
|
if (logmessages) LogMessage("received", inbuf.p, hdrsize);
|
||||||
if (hostlen && (p = RouteHost(host, hostlen, path, pathlen))) {
|
if (hostlen && (p = RouteHost(host, hostlen, path, pathlen))) {
|
||||||
return p;
|
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) {
|
static const char *GetContentType(struct Asset *a, const char *path, size_t n) {
|
||||||
const char *r;
|
const char *r;
|
||||||
if (a->file && (r = FindContentType(a->file->path.s, a->file->path.n))) {
|
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;
|
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) {
|
static bool HandleMessage(void) {
|
||||||
int rc;
|
int rc;
|
||||||
int iovlen;
|
int iovlen;
|
||||||
|
@ -5745,8 +5633,6 @@ static bool HandleMessage(void) {
|
||||||
if ((rc = ParseHttpMessage(&msg, inbuf.p, amtread)) != -1) {
|
if ((rc = ParseHttpMessage(&msg, inbuf.p, amtread)) != -1) {
|
||||||
if (!rc) return false;
|
if (!rc) return false;
|
||||||
hdrsize = rc;
|
hdrsize = rc;
|
||||||
if (logmessages) LogMessage("received", inbuf.p, hdrsize);
|
|
||||||
RecordNetworkOrigin();
|
|
||||||
p = HandleRequest();
|
p = HandleRequest();
|
||||||
} else {
|
} else {
|
||||||
LockInc(&shared->c.badmessages);
|
LockInc(&shared->c.badmessages);
|
||||||
|
@ -6205,6 +6091,11 @@ void RedBean(int argc, char *argv[]) {
|
||||||
Daemonize();
|
Daemonize();
|
||||||
} else {
|
} else {
|
||||||
setpgid(getpid(), getpid());
|
setpgid(getpid(), getpid());
|
||||||
|
if (logpath) {
|
||||||
|
close(2);
|
||||||
|
open(logpath, O_APPEND | O_WRONLY | O_CREAT, 0640);
|
||||||
|
}
|
||||||
|
ChangeUser();
|
||||||
}
|
}
|
||||||
UpdateCurrentDate(nowl());
|
UpdateCurrentDate(nowl());
|
||||||
freelist.c = 8;
|
freelist.c = 8;
|
||||||
|
@ -6215,6 +6106,7 @@ void RedBean(int argc, char *argv[]) {
|
||||||
hdrbuf.p = xmalloc(hdrbuf.n);
|
hdrbuf.p = xmalloc(hdrbuf.n);
|
||||||
inbuf.n = maxpayloadsize;
|
inbuf.n = maxpayloadsize;
|
||||||
inbuf.p = xmalloc(inbuf.n);
|
inbuf.p = xmalloc(inbuf.n);
|
||||||
|
oldloglevel = __log_level;
|
||||||
while (!terminated) {
|
while (!terminated) {
|
||||||
if (zombied) {
|
if (zombied) {
|
||||||
ReapZombies();
|
ReapZombies();
|
||||||
|
|
Loading…
Add table
Reference in a new issue