Add UUID v7 generation to Redbean

This commit is contained in:
terror 2024-06-11 19:29:00 +12:00
parent 01267ea0f5
commit bc74d79c89
5 changed files with 308 additions and 143 deletions

View file

@ -1981,6 +1981,10 @@ function Underlong(str) end
--- @return string
function UuidV4() end
--- Generate a uuid_v7
--- @return string
function UuidV7() end
---@param x integer
---@return integer # position of first bit set.
--- Passing `0` will raise an error. Same as the Intel x86 instruction BSF.

View file

@ -1065,6 +1065,9 @@ FUNCTIONS
UuidV4() -> str
Returns an uuid v4 string.
UuidV7() -> str
Returns an uuid v7 string.
Fetch(url:str[,body:str|{method=value:str,body=value:str,headers=table,...}])
├─→ status:int, {header:str=value:str,...}, body:str
└─→ nil, error:str
@ -1612,7 +1615,7 @@ FUNCTIONS
called from `.init.lua`. This function is not available in
unsecure mode.
ProgramSslRequired(mandatory:str)
ProgramSslRequired(mandatory:bool)
Enables the blocking of HTTP so that all inbound clients and
must use the TLS transport layer. This has the same effect as
the `-J` flag. Fetch() is still allowed to make outbound HTTP

View file

@ -52,7 +52,7 @@
#include "libc/sysv/consts/rusage.h"
#include "libc/sysv/consts/sock.h"
#include "libc/thread/thread.h"
#include "libc/time/time.h"
#include "libc/time.h"
#include "libc/x/x.h"
#include "net/http/escape.h"
#include "net/http/http.h"
@ -475,7 +475,8 @@ int LuaSlurp(lua_State *L) {
}
if (rc != -1) {
got = rc;
if (!got) break;
if (!got)
break;
luaL_addlstring(&b, tb, got);
} else if (errno == EINTR) {
errno = olderr;
@ -617,7 +618,8 @@ dontinline int LuaBase32Impl(lua_State *L,
const char *a = luaL_optlstring(L, 2, "", &al);
if (!IS2POW(al) || al > 128 || al == 1)
return luaL_error(L, "alphabet length is not a power of 2 in range 2..128");
if (!(p = B32(s, sl, a, al, &sl))) return luaL_error(L, "out of memory");
if (!(p = B32(s, sl, a, al, &sl)))
return luaL_error(L, "out of memory");
lua_pushlstring(L, p, sl);
free(p);
return 1;
@ -693,10 +695,12 @@ int LuaGetCryptoHash(lua_State *L) {
const void *p = luaL_checklstring(L, 2, &pl);
const void *k = luaL_optlstring(L, 3, "", &kl);
const mbedtls_md_info_t *digest = mbedtls_md_info_from_string(h);
if (!digest) return luaL_argerror(L, 1, "unknown hash type");
if (!digest)
return luaL_argerror(L, 1, "unknown hash type");
if (kl == 0) {
// no key provided, run generic hash function
if ((digest->f_md)(p, pl, d)) return luaL_error(L, "bad input data");
if ((digest->f_md)(p, pl, d))
return luaL_error(L, "bad input data");
} else if (mbedtls_md_hmac(digest, k, kl, p, pl, d)) {
return luaL_error(L, "bad input data");
}
@ -854,6 +858,22 @@ int LuaUuidV4(lua_State *L) {
return 1;
}
int LuaUuidV7(lua_State *L) {
char uuid_str[37] = {0};
struct timespec now = timespec_real();
uint64_t time_now = timespec_tonanos(now);
uint64_t random_data = _rand64();
snprintf(uuid_str, sizeof(uuid_str), "%08x-%04x-%04x-%04x-%012llx",
(uint32_t)(time_now >> 32), //8
(uint16_t)(time_now >> 16), //4
(uint16_t)((0x7 << 12) | (time_now >> 4 & 0x0fff)), //4
(uint16_t)((0b10 << 14 | ((time_now & 0x000f) << 10)) | (random_data & 0x03FF)), //4
(uint64_t)(random_data >> 4 & 0xFFFFFFFFFFFF) //12
);
lua_pushfstring(L, uuid_str);
return 1;
}
static dontinline int LuaHasherImpl(lua_State *L, size_t k,
int H(const void *, size_t, uint8_t *)) {
size_t n;

View file

@ -91,6 +91,7 @@ int LuaSlurp(lua_State *);
int LuaUncompress(lua_State *);
int LuaUnderlong(lua_State *);
int LuaUuidV4(lua_State *);
int LuaUuidV7(lua_State *);
int LuaVisualizeControlCodes(lua_State *);
void LuaPushUrlView(lua_State *, struct UrlView *);

View file

@ -644,11 +644,14 @@ static bool ShouldAvoidGzip(void) {
static char *MergePaths(const char *p, size_t n, const char *q, size_t m,
size_t *z) {
char *r;
if (n && p[n - 1] == '/') --n;
if (m && q[0] == '/') ++q, --m;
if (n && p[n - 1] == '/')
--n;
if (m && q[0] == '/')
++q, --m;
r = xmalloc(n + 1 + m + 1);
mempcpy(mempcpy(mempcpy(mempcpy(r, p, n), "/", 1), q, m), "", 1);
if (z) *z = n + 1 + m;
if (z)
*z = n + 1 + m;
return r;
}
@ -698,7 +701,8 @@ static void AppendCert(mbedtls_x509_crt *cert, mbedtls_pk_context *key) {
static void InternCertificate(mbedtls_x509_crt *cert, mbedtls_x509_crt *prev) {
int r;
size_t i;
if (cert->next) InternCertificate(cert->next, cert);
if (cert->next)
InternCertificate(cert->next, cert);
if (prev) {
if (mbedtls_x509_crt_check_parent(prev, cert, 1)) {
DEBUGF("(ssl) unbundling %`'s from %`'s",
@ -728,18 +732,22 @@ static void InternCertificate(mbedtls_x509_crt *cert, mbedtls_x509_crt *prev) {
LogCertificate("loaded certificate", cert);
if (!cert->next && !IsSelfSigned(cert) && cert->max_pathlen) {
for (i = 0; i < certs.n; ++i) {
if (!certs.p[i].cert) continue;
if (!certs.p[i].cert)
continue;
if (mbedtls_pk_can_do(&cert->pk, certs.p[i].cert->sig_pk) &&
!mbedtls_x509_crt_check_parent(cert, certs.p[i].cert, 1) &&
!IsSelfSigned(certs.p[i].cert)) {
if (ChainCertificate(cert, certs.p[i].cert)) break;
if (ChainCertificate(cert, certs.p[i].cert))
break;
}
}
}
if (!IsSelfSigned(cert)) {
for (i = 0; i < certs.n; ++i) {
if (!certs.p[i].cert) continue;
if (certs.p[i].cert->next) continue;
if (!certs.p[i].cert)
continue;
if (certs.p[i].cert->next)
continue;
if (certs.p[i].cert->max_pathlen &&
mbedtls_pk_can_do(&certs.p[i].cert->pk, cert->sig_pk) &&
!mbedtls_x509_crt_check_parent(certs.p[i].cert, cert, 1)) {
@ -782,7 +790,8 @@ static void ProgramPrivateKey(const char *p, size_t n) {
rc = mbedtls_pk_parse_key(key, waqapi, n + 1, 0, 0);
mbedtls_platform_zeroize(waqapi, n);
free(waqapi);
if (rc != 0) FATALF("(ssl) error: load key (grep -0x%04x)", -rc);
if (rc != 0)
FATALF("(ssl) error: load key (grep -0x%04x)", -rc);
for (i = 0; i < certs.n; ++i) {
if (certs.p[i].cert && !certs.p[i].key &&
!mbedtls_pk_check_pair(&certs.p[i].cert->pk, key)) {
@ -811,7 +820,8 @@ static void ProgramPort(long port) {
if (!(0 <= port && port <= 65535)) {
FATALF("(cfg) error: bad port: %d", port);
}
if (port == 443) listeningonport443 = true;
if (port == 443)
listeningonport443 = true;
ports.p = realloc(ports.p, ++ports.n * sizeof(*ports.p));
ports.p[ports.n - 1] = port;
}
@ -942,13 +952,15 @@ static void DescribeAddress(char buf[40], uint32_t addr, uint16_t port) {
static inline int GetServerAddr(uint32_t *ip, uint16_t *port) {
*ip = ntohl(serveraddr->sin_addr.s_addr);
if (port) *port = ntohs(serveraddr->sin_port);
if (port)
*port = ntohs(serveraddr->sin_port);
return 0;
}
static inline int GetClientAddr(uint32_t *ip, uint16_t *port) {
*ip = ntohl(clientaddr.sin_addr.s_addr);
if (port) *port = ntohs(clientaddr.sin_port);
if (port)
*port = ntohs(clientaddr.sin_port);
return 0;
}
@ -1038,7 +1050,8 @@ static void ProgramTimeout(long ms) {
static void ProgramCache(long x, const char *s) {
cacheseconds = x;
if (s) cachedirective = strdup(s);
if (s)
cachedirective = strdup(s);
}
static void SetDefaults(void) {
@ -1183,9 +1196,11 @@ static void ChangeUser(void) {
}
static void Daemonize(void) {
if (fork() > 0) exit(0);
if (fork() > 0)
exit(0);
setsid();
if (fork() > 0) _exit(0);
if (fork() > 0)
_exit(0);
umask(0);
}
@ -1209,7 +1224,8 @@ static void LuaEvalCode(const char *code) {
// handle `-F PATH` arg
static void LuaEvalFile(const char *path) {
char *f = gc(xslurp(path, 0));
if (!f) FATALF("(cfg) error: failed to read file %`'s", path);
if (!f)
FATALF("(cfg) error: failed to read file %`'s", path);
LuaEvalCode(f);
}
@ -1465,8 +1481,10 @@ static ssize_t WritevAll(int fd, struct iovec *iov, int iovlen) {
total = 0;
do {
if (i) {
while (i < iovlen && !iov[i].iov_len) ++i;
if (i == iovlen) break;
while (i < iovlen && !iov[i].iov_len)
++i;
if (i == iovlen)
break;
}
if ((rc = writev(fd, iov + i, iovlen - i)) != -1) {
wrote = rc;
@ -1501,7 +1519,8 @@ static int TlsFlush(struct TlsBio *bio, const unsigned char *buf, size_t len) {
v[1].iov_base = (void *)buf;
v[1].iov_len = len;
if (WritevAll(bio->fd, v, 2) != -1) {
if (bio->c > 0) bio->c = 0;
if (bio->c > 0)
bio->c = 0;
} else if (errno == EINTR) {
errno = 0;
return MBEDTLS_ERR_NET_CONN_RESET;
@ -1526,7 +1545,8 @@ static int TlsSend(void *ctx, const unsigned char *buf, size_t len) {
bio->c += len;
return len;
}
if ((rc = TlsFlush(bio, buf, len)) < 0) return rc;
if ((rc = TlsFlush(bio, buf, len)) < 0)
return rc;
return len;
}
@ -1534,11 +1554,13 @@ static int TlsRecvImpl(void *ctx, unsigned char *p, size_t n, uint32_t o) {
int r;
struct iovec v[2];
struct TlsBio *bio = ctx;
if ((r = TlsFlush(bio, 0, 0)) < 0) return r;
if ((r = TlsFlush(bio, 0, 0)) < 0)
return r;
if (bio->a < bio->b) {
r = MIN(n, bio->b - bio->a);
memcpy(p, bio->t + bio->a, r);
if ((bio->a += r) == bio->b) bio->a = bio->b = 0;
if ((bio->a += r) == bio->b)
bio->a = bio->b = 0;
return r;
}
v[0].iov_base = p;
@ -1559,7 +1581,8 @@ static int TlsRecvImpl(void *ctx, unsigned char *p, size_t n, uint32_t o) {
return MBEDTLS_ERR_NET_RECV_FAILED;
}
}
if (r > n) bio->b = r - n;
if (r > n)
bio->b = r - n;
return MIN(n, r);
}
@ -1655,11 +1678,15 @@ static void NotifyClose(void) {
static void WipeSigningKeys(void) {
size_t i;
if (uniprocess) return;
if (uniprocess)
return;
for (i = 0; i < certs.n; ++i) {
if (!certs.p[i].key) continue;
if (!certs.p[i].cert) continue;
if (!certs.p[i].cert->ca_istrue) continue;
if (!certs.p[i].key)
continue;
if (!certs.p[i].cert)
continue;
if (!certs.p[i].cert->ca_istrue)
continue;
mbedtls_pk_free(certs.p[i].key);
Free(&certs.p[i].key);
}
@ -1695,7 +1722,8 @@ static void CertsDestroy(void) {
}
static void WipeServingKeys(void) {
if (uniprocess) return;
if (uniprocess)
return;
mbedtls_ssl_ticket_free(&ssltick);
mbedtls_ssl_key_cert_free(conf.key_cert), conf.key_cert = 0;
CertsDestroy();
@ -1897,13 +1925,15 @@ static void ConfigureCertificate(mbedtls_x509write_cert *cw, struct Cert *ca,
//
for (int i = 0; i < ips.n; ++i) {
uint32_t ip = ips.p[i];
if (IsLoopbackIp(ip)) continue;
if (IsLoopbackIp(ip))
continue;
char rname[NI_MAXHOST];
struct sockaddr_in addr4 = {AF_INET, 0, {htonl(ip)}};
if (getnameinfo((struct sockaddr *)&addr4, sizeof(addr4), rname,
sizeof(rname), 0, 0, NI_NAMEREQD) == 0) {
char *s = gc(strdup(rname));
if (!name) name = s;
if (!name)
name = s;
bool isduplicate = false;
for (int j = 0; j < nsan; ++j) {
if (san[j].tag == MBEDTLS_X509_SAN_DNS_NAME &&
@ -1925,7 +1955,8 @@ static void ConfigureCertificate(mbedtls_x509write_cert *cw, struct Cert *ca,
// add san entry to cert for each ip address owned by system
for (int i = 0; i < ips.n; ++i) {
uint32_t ip = ips.p[i];
if (IsLoopbackIp(ip)) continue;
if (IsLoopbackIp(ip))
continue;
san = realloc(san, ++nsan * sizeof(*san));
san[nsan - 1].tag = MBEDTLS_X509_SAN_IP_ADDRESS;
san[nsan - 1].ip4 = ip;
@ -1974,9 +2005,12 @@ static void ConfigureCertificate(mbedtls_x509write_cert *cw, struct Cert *ca,
static struct Cert GetKeySigningKey(void) {
size_t i;
for (i = 0; i < certs.n; ++i) {
if (!certs.p[i].key) continue;
if (!certs.p[i].cert) continue;
if (!certs.p[i].cert->ca_istrue) continue;
if (!certs.p[i].key)
continue;
if (!certs.p[i].cert)
continue;
if (!certs.p[i].cert->ca_istrue)
continue;
if (mbedtls_x509_crt_check_key_usage(certs.p[i].cert,
MBEDTLS_X509_KU_KEY_CERT_SIGN)) {
continue;
@ -2059,7 +2093,8 @@ static void LoadCertificates(void) {
}
#ifdef MBEDTLS_ECP_C
ecp = GenerateEcpCertificate(ksk.key ? &ksk : 0);
if (!havecert) UseCertificate(&conf, &ecp, "server");
if (!havecert)
UseCertificate(&conf, &ecp, "server");
if (!haveclientcert && ksk.key) {
UseCertificate(&confcli, &ecp, "client");
}
@ -2068,7 +2103,8 @@ static void LoadCertificates(void) {
#ifdef MBEDTLS_RSA_C
if (!norsagen) {
rsa = GenerateRsaCertificate(ksk.key ? &ksk : 0);
if (!havecert) UseCertificate(&conf, &rsa, "server");
if (!havecert)
UseCertificate(&conf, &rsa, "server");
if (!haveclientcert && ksk.key) {
UseCertificate(&confcli, &rsa, "client");
}
@ -2237,11 +2273,13 @@ static bool OpenZip(bool force) {
static struct Asset *GetAssetZip(const char *path, size_t pathlen) {
uint32_t i, step, hash;
if (pathlen > 1 && path[0] == '/') ++path, --pathlen;
if (pathlen > 1 && path[0] == '/')
++path, --pathlen;
hash = Hash(path, pathlen);
for (step = 0;; ++step) {
i = (hash + ((step * (step + 1)) >> 1)) & (assets.n - 1);
if (!assets.p[i].hash) return NULL;
if (!assets.p[i].hash)
return NULL;
if (hash == assets.p[i].hash &&
pathlen == ZIP_CFILE_NAMESIZE(zmap + assets.p[i].cf) &&
memcmp(path, ZIP_CFILE_NAME(zmap + assets.p[i].cf), pathlen) == 0) {
@ -2288,7 +2326,8 @@ static struct Asset *GetAsset(const char *path, size_t pathlen) {
}
static char *AppendHeader(char *p, const char *k, const char *v) {
if (!v) return p;
if (!v)
return p;
return AppendCrlf(stpcpy(stpcpy(stpcpy(p, k), ": "), v));
}
@ -2316,7 +2355,8 @@ static char *AppendExpires(char *p, int64_t t) {
}
static char *AppendCache(char *p, int64_t seconds, char *directive) {
if (seconds < 0) return p;
if (seconds < 0)
return p;
p = stpcpy(p, "Cache-Control: max-age=");
p = FormatUint64(p, seconds);
if (!seconds) {
@ -2392,7 +2432,8 @@ static void *LoadAsset(struct Asset *a, size_t *out_size) {
}
if (!a->file) {
size = GetZipLfileUncompressedSize(zmap + a->lf);
if (size == SIZE_MAX || !(data = malloc(size + 1))) return NULL;
if (size == SIZE_MAX || !(data = malloc(size + 1)))
return NULL;
if (IsCompressed(a)) {
if (!Inflate(data, size, ZIP_LFILE_CONTENT(zmap + a->lf),
GetZipCfileCompressedSize(zmap + a->cf))) {
@ -2407,7 +2448,8 @@ static void *LoadAsset(struct Asset *a, size_t *out_size) {
return NULL;
}
data[size] = '\0';
if (out_size) *out_size = size;
if (out_size)
*out_size = size;
return data;
} else {
LockInc(&shared->c.slurps);
@ -2622,7 +2664,8 @@ static ssize_t YieldGenerator(struct iovec v[3]) {
int nresults, status;
if (cpm.isyielding > 1) {
do {
if (!YL || lua_status(YL) != LUA_YIELD) return 0; // done yielding
if (!YL || lua_status(YL) != LUA_YIELD)
return 0; // done yielding
cpm.contentlength = 0;
status = lua_resume(YL, NULL, 0, &nresults);
if (status != LUA_OK && status != LUA_YIELD) {
@ -2631,7 +2674,8 @@ static ssize_t YieldGenerator(struct iovec v[3]) {
return -1;
}
lua_pop(YL, nresults);
if (!cpm.contentlength) UseOutput();
if (!cpm.contentlength)
UseOutput();
// continue yielding if nothing to return to keep generator running
} while (!cpm.contentlength);
}
@ -2667,7 +2711,8 @@ static int LuaCallWithYield(lua_State *L) {
CHECK_GT(lua_gettop(L), 0); // make sure that coroutine is anchored
YL = co;
cpm.generator = YieldGenerator;
if (!cpm.isyielding) cpm.isyielding = 1;
if (!cpm.isyielding)
cpm.isyielding = 1;
status = LUA_OK;
}
return status;
@ -2770,7 +2815,8 @@ static ssize_t InflateGenerator(struct iovec v[3]) {
dg.s.next_out = dg.b;
dg.s.avail_out = dg.z;
rc = inflate(&dg.s, Z_NO_FLUSH);
if (rc != Z_OK && rc != Z_STREAM_END) DIEF("(zip) inflate()→%d", rc);
if (rc != Z_OK && rc != Z_STREAM_END)
DIEF("(zip) inflate()→%d", rc);
no = dg.z - dg.s.avail_out;
if (no) {
v[i].iov_base = dg.b;
@ -2877,7 +2923,8 @@ static char *GetAssetPath(uint8_t *zcf, size_t *out_size) {
p2[0] = '/';
memcpy(p2 + 1, p1, n1);
p2[1 + n1] = '\0';
if (out_size) *out_size = 1 + n1;
if (out_size)
*out_size = 1 + n1;
return p2;
}
@ -2928,8 +2975,10 @@ static void LaunchBrowser(const char *path) {
port = ntohs(servers.p[0].addr.sin_port);
}
// assign a loopback address if no server or unknown server address
if (!servers.n || !addr.s_addr) addr.s_addr = htonl(INADDR_LOOPBACK);
if (*path != '/') path = gc(xasprintf("/%s", path));
if (!servers.n || !addr.s_addr)
addr.s_addr = htonl(INADDR_LOOPBACK);
if (*path != '/')
path = gc(xasprintf("/%s", path));
launch_browser(gc(xasprintf("http://%s:%d%s", inet_ntoa(addr), port, path)));
}
@ -3102,11 +3151,13 @@ static const char *MergeNames(const char *a, const char *b) {
}
static void AppendLong1(const char *a, long x) {
if (x) appendf(&cpm.outbuf, "%s: %ld\r\n", a, x);
if (x)
appendf(&cpm.outbuf, "%s: %ld\r\n", a, x);
}
static void AppendLong2(const char *a, const char *b, long x) {
if (x) appendf(&cpm.outbuf, "%s.%s: %ld\r\n", a, b, x);
if (x)
appendf(&cpm.outbuf, "%s.%s: %ld\r\n", a, b, x);
}
static void AppendTimeval(const char *a, struct timeval *tv) {
@ -3282,7 +3333,8 @@ static char *HandleRedirect(struct Redirect *r) {
} else {
LockInc(&shared->c.redirects);
code = r->code;
if (!code) code = 307;
if (!code)
code = 307;
DEBUGF("(rsp) %d redirect to %`'s", code, r->location.s);
return AppendHeader(
SetStatus(code, GetHttpReason(code)), "Location",
@ -3629,8 +3681,10 @@ static void StoreAsset(const char *path, size_t pathlen, const char *data,
}
INFOF("(srvr) storing asset %`'s", path);
disk = gflags = iattrs = 0;
if (isutf8(path, pathlen)) gflags |= kZipGflagUtf8;
if (istext(data, datalen)) iattrs |= kZipIattrText;
if (isutf8(path, pathlen))
gflags |= kZipGflagUtf8;
if (istext(data, datalen))
iattrs |= kZipIattrText;
crc = crc32_z(0, data, datalen);
if (datalen < 100) {
method = kZipCompressionNone;
@ -3661,9 +3715,12 @@ static void StoreAsset(const char *path, size_t pathlen, const char *data,
OpenZip(false);
now = timespec_real();
a = GetAssetZip(path, pathlen);
if (!mode) mode = a ? GetMode(a) : 0644;
if (!(mode & S_IFMT)) mode |= S_IFREG;
if (pathlen > 1 && path[0] == '/') ++path, --pathlen;
if (!mode)
mode = a ? GetMode(a) : 0644;
if (!(mode & S_IFMT))
mode |= S_IFREG;
if (pathlen > 1 && path[0] == '/')
++path, --pathlen;
dosmode = !(mode & 0200) ? kNtFileAttributeReadonly : 0;
ft = (now.tv_sec + MODERNITYSECONDS) * HECTONANOSECONDS;
GetDosLocalTime(now.tv_sec, &mtime, &mdate);
@ -3812,12 +3869,14 @@ static void StoreFile(const char *path) {
struct stat st;
size_t plen, tlen;
const char *target = path;
if (startswith(target, "./")) target += 2;
if (startswith(target, "./"))
target += 2;
tlen = strlen(target);
if (!IsReasonablePath(target, tlen))
FATALF("(cfg) error: can't store %`'s: contains '.' or '..' segments",
target);
if (lstat(path, &st) == -1) FATALF("(cfg) error: can't stat %`'s: %m", path);
if (lstat(path, &st) == -1)
FATALF("(cfg) error: can't stat %`'s: %m", path);
if (!(p = xslurp(path, &plen)))
FATALF("(cfg) error: can't read %`'s: %m", path);
StoreAsset(target, tlen, p, plen, st.st_mode & 0777);
@ -3831,10 +3890,13 @@ static void StorePath(const char *dirpath) {
if (!isdirectory(dirpath) && !endswith(dirpath, "/")) {
return StoreFile(dirpath);
}
if (!(d = opendir(dirpath))) FATALF("(cfg) error: can't open %`'s", dirpath);
if (!(d = opendir(dirpath)))
FATALF("(cfg) error: can't open %`'s", dirpath);
while ((e = readdir(d))) {
if (strcmp(e->d_name, ".") == 0) continue;
if (strcmp(e->d_name, "..") == 0) continue;
if (strcmp(e->d_name, ".") == 0)
continue;
if (strcmp(e->d_name, "..") == 0)
continue;
path = gc(xjoinpaths(dirpath, e->d_name));
if (e->d_type == DT_DIR) {
StorePath(path);
@ -3861,7 +3923,8 @@ static int LuaStoreAsset(lua_State *L) {
static void ReseedRng(mbedtls_ctr_drbg_context *r, const char *s) {
#ifndef UNSECURE
if (unsecure) return;
if (unsecure)
return;
CHECK_EQ(0, mbedtls_ctr_drbg_reseed(r, (void *)s, strlen(s)));
#endif
}
@ -3869,8 +3932,10 @@ static void ReseedRng(mbedtls_ctr_drbg_context *r, const char *s) {
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 (!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))) {
INFOF("(stat) %s %,ld byte message\r\n%.*s", d, n, n3, s3);
@ -3883,9 +3948,12 @@ static void LogMessage(const char *d, const char *s, size_t n) {
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 (!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))) {
INFOF("(stat) %s %,ld byte payload\r\n%.*s", d, n, n3, s3);
@ -4107,7 +4175,8 @@ static int LuaGetUser(lua_State *L) {
if (url.user.p) {
LuaPushUrlView(L, &url.user);
} else if ((p = gc(GetBasicAuthorization(&n)))) {
if (!(q = memchr(p, ':', n))) q = p + n;
if (!(q = memchr(p, ':', n)))
q = p + n;
lua_pushlstring(L, p, q - p);
} else {
lua_pushnil(L);
@ -4148,8 +4217,10 @@ static int LuaGetHost(lua_State *L) {
static int LuaGetPort(lua_State *L) {
int i, x = 0;
OnlyCallDuringRequest(L, "GetPort");
for (i = 0; i < url.port.n; ++i) x = url.port.p[i] - '0' + x * 10;
if (!x) x = ntohs(serveraddr->sin_port);
for (i = 0; i < url.port.n; ++i)
x = url.port.p[i] - '0' + x * 10;
if (!x)
x = ntohs(serveraddr->sin_port);
lua_pushinteger(L, x);
return 1;
}
@ -4219,7 +4290,8 @@ static int LuaSetHeader(lua_State *L) {
OnlyCallDuringRequest(L, "SetHeader");
key = luaL_checklstring(L, 1, &keylen);
val = luaL_optlstring(L, 2, 0, &vallen);
if (!val) return 0;
if (!val)
return 0;
if ((h = GetHttpHeader(key, keylen)) == -1) {
if (!IsValidHttpToken(key, keylen)) {
luaL_argerror(L, 1, "invalid");
@ -4283,7 +4355,8 @@ static int LuaGetCookie(lua_State *L) {
} else {
lua_pushnil(L);
}
if (cookie) free(cookie);
if (cookie)
free(cookie);
return 1;
}
@ -4503,7 +4576,8 @@ static int LuaProgramUniprocess(lua_State *L) {
return luaL_argerror(L, 1, "invalid uniprocess mode; boolean expected");
}
lua_pushboolean(L, uniprocess);
if (lua_isboolean(L, 1)) uniprocess = lua_toboolean(L, 1);
if (lua_isboolean(L, 1))
uniprocess = lua_toboolean(L, 1);
return 1;
}
@ -4525,7 +4599,8 @@ static int LuaProgramMaxWorkers(lua_State *L) {
return luaL_argerror(L, 1, "invalid number of workers; integer expected");
}
lua_pushinteger(L, maxworkers);
if (lua_isinteger(L, 1)) maxworkers = lua_tointeger(L, 1);
if (lua_isinteger(L, 1))
maxworkers = lua_tointeger(L, 1);
maxworkers = MAX(maxworkers, 1);
return 1;
}
@ -4803,7 +4878,8 @@ static int LuaIsAssetCompressed(lua_State *L) {
static bool Blackhole(uint32_t ip) {
char buf[4];
if (blackhole.fd <= 0) return false;
if (blackhole.fd <= 0)
return false;
WRITE32BE(buf, ip);
if (sendto(blackhole.fd, &buf, 4, 0, (struct sockaddr *)&blackhole.addr,
sizeof(blackhole.addr)) != -1) {
@ -4927,8 +5003,10 @@ static int LuaProgramTokenBucket(lua_State *L) {
reject, //
ignore, //
ban);
if (ignore == -1) ignore = -128;
if (ban == -1) ban = -128;
if (ignore == -1)
ignore = -128;
if (ban == -1)
ban = -128;
if (ban >= 0 && (IsLinux() || IsBsd())) {
uint32_t testip = 0;
blackhole.addr.sun_family = AF_UNIX;
@ -4955,14 +5033,16 @@ static int LuaProgramTokenBucket(lua_State *L) {
tokenbucket.replenish = timespec_fromnanos(1 / replenish * 1e9);
int pid = fork();
npassert(pid != -1);
if (!pid) Replenisher();
if (!pid)
Replenisher();
++shared->workers;
return 0;
}
static const char *GetContentTypeExt(const char *path, size_t n) {
const char *r = NULL, *e;
if ((r = FindContentType(path, n))) return r;
if ((r = FindContentType(path, n)))
return r;
#ifndef STATIC
int top;
lua_State *L = GL;
@ -5053,7 +5133,8 @@ static bool LuaRunAsset(const char *path, bool mandatory) {
if (status != LUA_OK || LuaCallWithTrace(L, 0, 0, NULL) != LUA_OK) {
LogLuaError("lua code", lua_tostring(L, -1));
lua_pop(L, 1); // pop error
if (mandatory) exit(1);
if (mandatory)
exit(1);
}
}
}
@ -5288,6 +5369,7 @@ static const luaL_Reg kLuaFuncs[] = {
{"Uncompress", LuaUncompress}, //
{"Underlong", LuaUnderlong}, //
{"UuidV4", LuaUuidV4}, //
{"UuidV7", LuaUuidV7}, //
{"VisualizeControlCodes", LuaVisualizeControlCodes}, //
{"Write", LuaWrite}, //
{"bin", LuaBin}, //
@ -5416,7 +5498,8 @@ static void LuaPrint(lua_State *L) {
n = lua_gettop(L);
if (n > 0) {
for (i = 1; i <= n; i++) {
if (i > 1) appendw(&b, '\t');
if (i > 1)
appendw(&b, '\t');
struct EncoderConfig conf = {
.maxdepth = 64,
.sorted = true,
@ -5450,12 +5533,14 @@ static int LuaInterpreter(lua_State *L) {
const char *script;
if (optind < __argc) {
script = __argv[optind];
if (!strcmp(script, "-")) script = 0;
if (!strcmp(script, "-"))
script = 0;
if ((status = luaL_loadfile(L, script)) == LUA_OK) {
lua_getglobal(L, "arg");
n = luaL_len(L, -1);
luaL_checkstack(L, n + 3, "too many script args");
for (i = 1; i <= n; i++) lua_rawgeti(L, -i, i);
for (i = 1; i <= n; i++)
lua_rawgeti(L, -i, i);
lua_remove(L, -i); // remove arg table from stack
TRACE_BEGIN;
status = lua_runchunk(L, n, LUA_MULTRET);
@ -5469,7 +5554,8 @@ static int LuaInterpreter(lua_State *L) {
EnableRawMode();
for (;;) {
status = lua_loadline(L);
if (status == -1) break; // eof
if (status == -1)
break; // eof
if (status == -2) {
if (errno == EINTR) {
if ((sig = linenoiseGetInterrupt())) {
@ -5579,10 +5665,14 @@ static void LuaOnServerReload(bool reindex) {
}
static const char *DescribeClose(void) {
if (killed) return "killed";
if (meltdown) return "meltdown";
if (terminated) return "terminated";
if (connectionclose) return "connection closed";
if (killed)
return "killed";
if (meltdown)
return "meltdown";
if (terminated)
return "terminated";
if (connectionclose)
return "connection closed";
return "destroyed";
}
@ -5859,7 +5949,8 @@ static char *ReadMore(void) {
ssize_t rc;
LockInc(&shared->c.frags);
if ((rc = reader(client, inbuf.p + amtread, inbuf.n - amtread)) != -1) {
if (!(got = rc)) return HandlePayloadDisconnect();
if (!(got = rc))
return HandlePayloadDisconnect();
amtread += got;
} else if (errno == EINTR) {
LockInc(&shared->c.readinterrupts);
@ -5877,10 +5968,12 @@ static char *ReadMore(void) {
static char *SynchronizeLength(void) {
char *p;
if (hdrsize + payloadlength > amtread) {
if (hdrsize + payloadlength > inbuf.n) return HandleHugePayload();
if (hdrsize + payloadlength > inbuf.n)
return HandleHugePayload();
SendContinueIfNeeded();
while (amtread < hdrsize + payloadlength) {
if ((p = ReadMore())) return p;
if ((p = ReadMore()))
return p;
}
}
cpm.msgsize = hdrsize + payloadlength;
@ -5894,9 +5987,11 @@ static char *SynchronizeChunked(void) {
SendContinueIfNeeded();
while (!(transferlength = Unchunk(&u, inbuf.p + hdrsize, amtread - hdrsize,
&payloadlength))) {
if ((p = ReadMore())) return p;
if ((p = ReadMore()))
return p;
}
if (transferlength == -1) return HandleHugePayload();
if (transferlength == -1)
return HandleHugePayload();
cpm.msgsize = hdrsize + transferlength;
return NULL;
}
@ -5987,8 +6082,10 @@ static char *HandleRequest(void) {
} else {
return HandleVersionNotSupported();
}
if ((p = SynchronizeStream())) return p;
if (logbodies) LogBody("received", inbuf.p + hdrsize, payloadlength);
if ((p = SynchronizeStream()))
return p;
if (logbodies)
LogBody("received", inbuf.p + hdrsize, payloadlength);
if (cpm.msg.version < 11 || HeaderEqualCase(kHttpConnection, "close")) {
connectionclose = true;
}
@ -6025,7 +6122,8 @@ static char *HandleRequest(void) {
}
FreeLater(url.params.p);
#ifndef STATIC
if (hasonhttprequest) return LuaOnHttpRequest();
if (hasonhttprequest)
return LuaOnHttpRequest();
#endif
return Route(url.host.p, url.host.n, url.path.p, url.path.n);
}
@ -6041,7 +6139,8 @@ static char *Route(const char *host, size_t hostlen, const char *path,
return p;
}
if (SlicesEqual(path, pathlen, "/", 1)) {
if ((p = ServeIndex("/", 1))) return p;
if ((p = ServeIndex("/", 1)))
return p;
return ServeListing();
} else if ((p = RoutePath(path, pathlen))) {
return p;
@ -6090,16 +6189,19 @@ static char *RouteHost(const char *host, size_t hostlen, const char *path,
hp = hm <= sizeof(b) ? b : FreeLater(xmalloc(hm));
hp[0] = '/';
mempcpy(mempcpy(hp + 1, host, hostlen), path, pathlen);
if ((p = RoutePath(hp, hn))) return p;
if ((p = RoutePath(hp, hn)))
return p;
if (!isdigit(host[0])) {
if (hostlen > 4 &&
READ32LE(host) == ('w' | 'w' << 8 | 'w' << 16 | '.' << 24)) {
mempcpy(mempcpy(hp + 1, host + 4, hostlen - 4), path, pathlen);
if ((p = RoutePath(hp, hn - 4))) return p;
if ((p = RoutePath(hp, hn - 4)))
return p;
} else {
mempcpy(mempcpy(mempcpy(hp + 1, "www.", 4), host, hostlen), path,
pathlen);
if ((p = RoutePath(hp, hn + 4))) return p;
if ((p = RoutePath(hp, hn + 4)))
return p;
}
}
}
@ -6123,7 +6225,8 @@ static inline bool IsLua(struct Asset *a) {
static char *HandleAsset(struct Asset *a, const char *path, size_t pathlen) {
char *p;
#ifndef STATIC
if (IsLua(a)) return ServeLua(a, path, pathlen);
if (IsLua(a))
return ServeLua(a, path, pathlen);
#endif
if (cpm.msg.method == kHttpGet || cpm.msg.method == kHttpHead) {
LockInc(&shared->c.staticrequests);
@ -6150,8 +6253,10 @@ static const char *GetContentType(struct Asset *a, const char *path, size_t n) {
}
static bool IsNotModified(struct Asset *a) {
if (cpm.msg.version < 10) return false;
if (!HasHeader(kHttpIfModifiedSince)) return false;
if (cpm.msg.version < 10)
return false;
if (!HasHeader(kHttpIfModifiedSince))
return false;
return a->lastmodified <=
ParseHttpDateTime(HeaderData(kHttpIfModifiedSince),
HeaderLength(kHttpIfModifiedSince));
@ -6217,8 +6322,10 @@ static char *ServeAsset(struct Asset *a, const char *path, size_t pathlen) {
static char *SetStatus(unsigned code, const char *reason) {
if (cpm.msg.version == 10) {
if (code == 307) code = 302;
if (code == 308) code = 301;
if (code == 307)
code = 302;
if (code == 308)
code = 301;
}
cpm.statuscode = code;
cpm.hascontenttype = false;
@ -6321,7 +6428,8 @@ static bool StreamResponse(char *p) {
iov[3].iov_len = 0;
iov[4].iov_base = 0;
iov[4].iov_len = 0;
if ((rc = cpm.generator(iov + 2)) <= 0) break;
if ((rc = cpm.generator(iov + 2)) <= 0)
break;
if (cpm.msg.version >= 11) {
s = chunkbuf;
s += uint64toarray_radix16(rc, s);
@ -6329,7 +6437,8 @@ static bool StreamResponse(char *p) {
iov[1].iov_base = chunkbuf;
iov[1].iov_len = s - chunkbuf;
}
if (Send(iov, 6) == -1) break;
if (Send(iov, 6) == -1)
break;
iov[0].iov_base = 0;
iov[0].iov_len = 0;
}
@ -6350,8 +6459,9 @@ static bool HandleMessageActual(void) {
long reqtime, contime;
char *p;
struct timespec now;
if ((rc = ParseHttpMessage(&cpm.msg, inbuf.p, amtread)) != -1) {
if (!rc) return false;
if ((rc = ParseHttpMessage(&cpm.msg, inbuf.p, amtread, inbuf.n)) != -1) {
if (!rc)
return false;
hdrsize = rc;
if (logmessages) {
LogMessage("received", inbuf.p, hdrsize);
@ -6373,8 +6483,10 @@ static bool HandleMessageActual(void) {
}
if (cpm.msg.version >= 10) {
p = AppendCrlf(stpcpy(stpcpy(p, "Date: "), shared->currentdate));
if (!cpm.branded) p = stpcpy(p, serverheader);
if (extrahdrs) p = stpcpy(p, extrahdrs);
if (!cpm.branded)
p = stpcpy(p, serverheader);
if (extrahdrs)
p = stpcpy(p, extrahdrs);
if (connectionclose) {
p = stpcpy(p, "Connection: close\r\n");
} else if (timeout.tv_sec < 0 && cpm.msg.version >= 11) {
@ -6395,7 +6507,8 @@ static bool HandleMessageActual(void) {
now = timespec_real();
reqtime = timespec_tomicros(timespec_sub(now, startrequest));
contime = timespec_tomicros(timespec_sub(now, startconnection));
if (hasonloglatency) LuaOnLogLatency(reqtime, contime);
if (hasonloglatency)
LuaOnLogLatency(reqtime, contime);
if (loglatency || LOGGABLE(kLogDebug))
LOGF(kLogDebug, "(stat) %`'.*s latency r: %,ldµs c: %,ldµs",
cpm.msg.uri.b - cpm.msg.uri.a, inbuf.p + cpm.msg.uri.a, reqtime,
@ -6422,8 +6535,10 @@ static void InitRequest(void) {
}
static bool IsSsl(unsigned char c) {
if (c == 22) return true;
if (!(c & 128)) return false;
if (c == 22)
return true;
if (!(c & 128))
return false;
/* RHEL5 sends SSLv2 hello but supports TLS */
DEBUGF("(ssl) %s SSLv2 hello D:", DescribeClient());
return true;
@ -6440,7 +6555,8 @@ static void HandleMessages(void) {
for (;;) {
if (!cpm.msg.i && amtread) {
startrequest = timespec_real();
if (HandleMessage()) break;
if (HandleMessage())
break;
}
if ((rc = reader(client, inbuf.p + amtread, inbuf.n - amtread)) != -1) {
startrequest = timespec_real();
@ -6483,7 +6599,8 @@ static void HandleMessages(void) {
errno = 0;
} else if (errno == EAGAIN) {
LockInc(&shared->c.readtimeouts);
if (amtread) SendTimeout();
if (amtread)
SendTimeout();
NotifyClose();
LogClose("read timeout");
return;
@ -6646,7 +6763,8 @@ static void *MemoryMonitor(void *arg) {
if (tty != -1) {
for (gen = 0, mi = 0, b = 0; !terminatemonitor;) {
workers = atomic_load_explicit(&shared->workers, memory_order_relaxed);
if (id) id = MAX(1, MIN(id, workers));
if (id)
id = MAX(1, MIN(id, workers));
if (!id && workers) {
usleep(50000);
continue;
@ -6931,11 +7049,16 @@ static int HandleConnection(size_t i) {
static void MakeExecutableModifiable(void) {
#ifdef __x86_64__
int ft;
if (!(SUPPORT_VECTOR & (_HOSTMETAL | _HOSTWINDOWS | _HOSTXNU))) return;
if (IsWindows()) return; // TODO
if (IsOpenbsd()) return; // TODO
if (IsNetbsd()) return; // TODO
if (endswith(zpath, ".dbg")) return;
if (!(SUPPORT_VECTOR & (_HOSTMETAL | _HOSTWINDOWS | _HOSTXNU)))
return;
if (IsWindows())
return; // TODO
if (IsOpenbsd())
return; // TODO
if (IsNetbsd())
return; // TODO
if (endswith(zpath, ".dbg"))
return;
close(zfd);
ft = ftrace_enabled(0);
if ((zfd = __open_executable()) == -1) {
@ -6999,8 +7122,10 @@ static int HandlePoll(int ms) {
if (nfds) {
// handle pollid/o events
for (pollid = 0; pollid < 1 + servers.n; ++pollid) {
if (!polls[pollid].revents) continue;
if (polls[pollid].fd < 0) continue;
if (!polls[pollid].revents)
continue;
if (polls[pollid].fd < 0)
continue;
if (polls[pollid].fd) {
// handle listen socket
lua_repl_lock();
@ -7011,12 +7136,14 @@ static int HandlePoll(int ms) {
rc = HandleConnection(serverid);
ishandlingconnection = false;
lua_repl_unlock();
if (rc == -1) return -1;
if (rc == -1)
return -1;
#ifndef STATIC
} else {
// handle standard input
rc = HandleReadline();
if (rc == -1) return rc;
if (rc == -1)
return rc;
#endif
}
}
@ -7024,7 +7151,8 @@ static int HandlePoll(int ms) {
} else if (__ttyconf.replmode) {
// handle refresh repl line
rc = HandleReadline();
if (rc < 0) return rc;
if (rc < 0)
return rc;
#endif
}
} else {
@ -7094,7 +7222,8 @@ static void Listen(void) {
}
port = ntohs(servers.p[n].addr.sin_port);
ip = ntohl(servers.p[n].addr.sin_addr.s_addr);
if (ip == INADDR_ANY) ip = INADDR_LOOPBACK;
if (ip == INADDR_ANY)
ip = INADDR_LOOPBACK;
INFOF("(srvr) listen http://%hhu.%hhu.%hhu.%hhu:%d", ip >> 24, ip >> 16,
ip >> 8, ip, port);
if (printport && !ports.p[j]) {
@ -7122,7 +7251,8 @@ static void HandleShutdown(void) {
CloseServerFds();
INFOF("(srvr) received %s", strsignal(shutdownsig));
if (shutdownsig != SIGINT && shutdownsig != SIGQUIT) {
if (!killed) terminated = false;
if (!killed)
terminated = false;
INFOF("(srvr) killing process group");
KillGroup();
}
@ -7193,7 +7323,8 @@ static void SigInit(void) {
static void TlsInit(void) {
#ifndef UNSECURE
int suite;
if (unsecure) return;
if (unsecure)
return;
if (suiteb && !mbedtls_aes_uses_hardware()) {
WARNF("(srvr) requested suiteb crypto, but hardware aes not present");
@ -7227,7 +7358,8 @@ static void TlsInit(void) {
mbedtls_ssl_ticket_parse, &ssltick);
}
if (sslinitialized) return;
if (sslinitialized)
return;
sslinitialized = true;
LoadCertificates();
@ -7257,7 +7389,8 @@ static void TlsInit(void) {
static void TlsDestroy(void) {
#ifndef UNSECURE
if (unsecure) return;
if (unsecure)
return;
mbedtls_ssl_free(&ssl);
mbedtls_ssl_free(&sslcli);
mbedtls_ctr_drbg_free(&rng);
@ -7352,9 +7485,11 @@ static void GetOpts(int argc, char *argv[]) {
}
}
// if storing asset(s) is requested, don't need to continue
if (storeasset) exit(0);
if (storeasset)
exit(0);
// we don't want to drop into a repl after using -e in -i mode
if (interpretermode && got_e_arg) exit(0);
if (interpretermode && got_e_arg)
exit(0);
}
void RedBean(int argc, char *argv[]) {
@ -7362,7 +7497,8 @@ void RedBean(int argc, char *argv[]) {
int fd;
// don't complain about --assimilate if it's the only parameter,
// as it can only get here if it's already native or assimilated
if (argc == 2 && strcmp(argv[1], "--assimilate") == 0) return;
if (argc == 2 && strcmp(argv[1], "--assimilate") == 0)
return;
if (IsLinux()) {
// disable weird linux capabilities
for (int e = errno, i = 0;; ++i) {
@ -7415,7 +7551,8 @@ void RedBean(int argc, char *argv[]) {
shared->workers = 1;
}
if (daemonize) {
if (!logpath) ProgramLogPath("/dev/null");
if (!logpath)
ProgramLogPath("/dev/null");
dup2(2, 1);
}
SigInit();