Trim down redbean a little bit

This makes redbean.c a little less long. It also reduces the size of
redbean-original.com from being 333K to 213K.
This commit is contained in:
Justine Tunney 2022-03-21 19:31:03 -07:00
parent 87029ac3f9
commit 5022f9e920
21 changed files with 999 additions and 669 deletions

43
net/http/foldheader.c Normal file
View file

@ -0,0 +1,43 @@
/*-*- 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 2022 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/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "net/http/http.h"
char *FoldHeader(struct HttpMessage *msg, char *b, int h, size_t *z) {
char *p;
size_t i, n, m;
struct HttpHeader *x;
n = msg->headers[h].b - msg->headers[h].a;
if ((p = malloc(n))) {
memcpy(p, b + msg->headers[h].a, n);
for (i = 0; i < msg->xheaders.n; ++i) {
x = msg->xheaders.p + i;
if (GetHttpHeader(b + x->k.a, x->k.b - x->k.a) == h) {
m = x->v.b - x->v.a;
if (!(p = realloc(p, n + 2 + m))) abort();
memcpy(mempcpy(p + n, ", ", 2), b + x->v.a, m);
n += 2 + m;
}
}
*z = n;
}
return p;
}

View file

@ -208,6 +208,7 @@ 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);
char *FoldHeader(struct HttpMessage *, char *, int, size_t *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -29,7 +29,6 @@ void TlsDie(const char *, int) wontreturn;
bool ChainCertificate(mbedtls_x509_crt *, mbedtls_x509_crt *);
bool CertHasIp(const mbedtls_x509_crt *, uint32_t);
bool CertHasHost(const mbedtls_x509_crt *, const void *, size_t);
bool CertHasCommonName(const mbedtls_x509_crt *, const void *, size_t);
bool IsServerCert(const struct Cert *, mbedtls_pk_type_t);
void TlsDebug(void *, int, const char *, int, const char *);

23
third_party/lua/cosmo.h vendored Normal file
View file

@ -0,0 +1,23 @@
#ifndef COSMOPOLITAN_THIRD_PARTY_LUA_COSMO_H_
#define COSMOPOLITAN_THIRD_PARTY_LUA_COSMO_H_
#include "net/http/http.h"
#include "net/http/url.h"
#include "third_party/lua/lauxlib.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
char *LuaFormatStack(lua_State *) nodiscard;
int LuaCallWithTrace(lua_State *, int, int, lua_State *);
int LuaEncodeJsonData(lua_State *, char **, int, char *);
int LuaEncodeLuaData(lua_State *, char **, int, char *);
int LuaEncodeUrl(lua_State *);
int LuaParseUrl(lua_State *);
void EscapeLuaString(char *, size_t, char **);
void LuaPushUrlParams(lua_State *, struct UrlParams *);
int LuaPushHeaders(lua_State *, struct HttpMessage *, const char *);
void LuaPushLatin1(lua_State *, const char *, size_t);
int LuaPushHeader(lua_State *, struct HttpMessage *, char *, int);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_THIRD_PARTY_LUA_COSMO_H_ */

36
third_party/lua/escapeluastring.c vendored Normal file
View file

@ -0,0 +1,36 @@
/*-*- 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 2022 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/stdio/append.internal.h"
#include "third_party/lua/cosmo.h"
#include "third_party/lua/lua.h"
void EscapeLuaString(char *s, size_t len, char **buf) {
appendw(buf, '"');
for (size_t i = 0; i < len; i++) {
if (s[i] == '\\' || s[i] == '\"' || s[i] == '\n' || s[i] == '\0' ||
s[i] == '\r') {
appendw(buf, '\\' | 'x' << 010 |
"0123456789abcdef"[(s[i] & 0xF0) >> 4] << 020 |
"0123456789abcdef"[(s[i] & 0x0F) >> 0] << 030);
} else {
appendd(buf, s + i, 1);
}
}
appendw(buf, '"');
}

View file

@ -35,6 +35,7 @@ THIRD_PARTY_LUA_DIRECTDEPS = \
LIBC_X \
LIBC_TINYMATH \
LIBC_UNICODE \
NET_HTTP \
THIRD_PARTY_LINENOISE \
THIRD_PARTY_GDTOA

66
third_party/lua/luacallwithtrace.c vendored Normal file
View file

@ -0,0 +1,66 @@
/*-*- 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 2022 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/macros.internal.h"
#include "third_party/lua/cosmo.h"
#include "third_party/lua/lauxlib.h"
// calling convention for lua stack of L is:
// -2 is function
// -1 is is argument (assuming nargs == 1)
// L will have this after the call
// -1 is error or result (assuming nres == 1)
// @param L is main Lua interpreter
// @note this needs to be reentrant
int LuaCallWithTrace(lua_State *L, int nargs, int nres, lua_State *C) {
int nresults, status;
bool canyield = !!C; // allow yield if coroutine is provided
if (!C) C = lua_newthread(L); // create a new coroutine if not passed
// move coroutine to the bottom of the stack (including one that is passed)
lua_insert(L, 1);
// make sure that there is enough stack space
if (!lua_checkstack(C, 1 + nargs)) {
lua_pushliteral(L, "too many arguments to resume");
return LUA_ERRRUN; /* error flag */
}
// move the function (and arguments) to the top of the coro stack
lua_xmove(L, C, 1 + nargs);
// resume the coroutine thus executing the function
status = lua_resume(C, L, nargs, &nresults);
lua_remove(L, 1); // remove coroutine (still) at the bottom
if (status != LUA_OK && status != LUA_YIELD) {
// move the error message
lua_xmove(C, L, 1);
// replace the error with the traceback on failure
luaL_traceback(L, C, lua_tostring(L, -1), 0);
lua_remove(L, -2); // remove the error message
} else {
if (!lua_checkstack(L, MAX(nresults, nres))) {
lua_pop(C, nresults); /* remove results anyway */
lua_pushliteral(L, "too many results to resume");
return LUA_ERRRUN; /* error flag */
}
lua_xmove(C, L, nresults); // move results to the main stack
// grow the stack in case returned fewer results
// than the caller expects, as lua_resume
// doesn't adjust the stack for needed results
for (; nresults < nres; nresults++) lua_pushnil(L);
if (!canyield) status = LUA_OK; // treat LUA_YIELD the same as LUA_OK
}
return status;
}

85
third_party/lua/luaencodejsondata.c vendored Normal file
View file

@ -0,0 +1,85 @@
/*-*- 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 2022 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/runtime/gc.internal.h"
#include "libc/stdio/append.internal.h"
#include "net/http/escape.h"
#include "third_party/lua/cosmo.h"
#include "third_party/lua/lauxlib.h"
#include "third_party/lua/lua.h"
int LuaEncodeJsonData(lua_State *L, char **buf, int level, char *numformat) {
size_t idx = -1;
size_t tbllen, buflen;
bool isarray;
int t = lua_type(L, idx);
if (level < 0) return luaL_argerror(L, 1, "too many nested tables");
if (LUA_TSTRING == t) {
appendw(buf, '"');
appends(buf, gc(EscapeJsStringLiteral(lua_tostring(L, idx), -1, 0)));
appendw(buf, '"');
} else if (LUA_TNUMBER == t) {
appendf(buf, numformat, lua_tonumber(L, idx));
} else if (LUA_TBOOLEAN == t) {
appends(buf, lua_toboolean(L, idx) ? "true" : "false");
} else if (LUA_TTABLE == t) {
tbllen = lua_rawlen(L, idx);
// encode tables with numeric indices and empty tables as arrays
isarray = tbllen > 0 || // integer keys present
(lua_pushnil(L), lua_next(L, -2) == 0) || // no non-integer keys
(lua_pop(L, 2), false); // pop key/value pushed by lua_next
appendw(buf, isarray ? '[' : '{');
if (isarray) {
for (int i = 1; i <= tbllen; i++) {
if (i > 1) appendw(buf, ',');
lua_rawgeti(L, -1, i); // table/-2, value/-1
LuaEncodeJsonData(L, buf, level - 1, numformat);
lua_pop(L, 1);
}
} else {
int i = 1;
lua_pushnil(L); // push the first key
while (lua_next(L, -2) != 0) {
if (!lua_isstring(L, -2))
return luaL_argerror(L, 1, "expected number or string as key value");
if (i++ > 1) appendw(buf, ',');
appendw(buf, '"');
if (lua_type(L, -2) == LUA_TSTRING) {
appends(buf, gc(EscapeJsStringLiteral(lua_tostring(L, -2), -1, 0)));
} else {
// we'd still prefer to use lua_tostring on a numeric index, but can't
// use it in-place, as it breaks lua_next (changes numeric key to a
// string)
lua_pushvalue(L, -2); // table/-4, key/-3, value/-2, key/-1
appends(buf, lua_tostring(L, idx)); // use the copy
lua_remove(L, -1); // remove copied key: table/-3, key/-2, value/-1
}
appendw(buf, '"' | ':' << 010);
LuaEncodeJsonData(L, buf, level - 1, numformat);
lua_pop(L, 1); // table/-2, key/-1
}
// stack: table/-1, as the key was popped by lua_next
}
appendw(buf, isarray ? ']' : '}');
} else if (LUA_TNIL == t) {
appendd(buf, "null", 4);
} else {
return luaL_argerror(L, 1, "can't serialize value of this type");
}
return 0;
}

66
third_party/lua/luaencodeluadata.c vendored Normal file
View file

@ -0,0 +1,66 @@
/*-*- 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 2022 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/math.h"
#include "libc/stdio/append.internal.h"
#include "third_party/lua/cosmo.h"
#include "third_party/lua/lauxlib.h"
#include "third_party/lua/lua.h"
int LuaEncodeLuaData(lua_State *L, char **buf, int level, char *numformat) {
size_t idx = -1;
size_t tbllen, buflen, slen;
char *s;
int ktype;
int t = lua_type(L, idx);
if (level < 0) return luaL_argerror(L, 1, "too many nested tables");
if (LUA_TSTRING == t) {
s = lua_tolstring(L, idx, &slen);
EscapeLuaString(s, slen, buf);
} else if (LUA_TNUMBER == t) {
appendf(buf, numformat, lua_tonumber(L, idx));
} else if (LUA_TBOOLEAN == t) {
appends(buf, lua_toboolean(L, idx) ? "true" : "false");
} else if (LUA_TTABLE == t) {
appendw(buf, '{');
int i = 0;
lua_pushnil(L); // push the first key
while (lua_next(L, -2) != 0) {
ktype = lua_type(L, -2);
if (ktype == LUA_TTABLE)
return luaL_argerror(L, 1, "can't serialize key of this type");
if (i++ > 0) appendd(buf, ",", 1);
if (ktype != LUA_TNUMBER || floor(lua_tonumber(L, -2)) != i) {
appendw(buf, '[');
lua_pushvalue(L, -2); // table/-4, key/-3, value/-2, key/-1
LuaEncodeLuaData(L, buf, level, numformat);
lua_remove(L, -1); // remove copied key: table/-3, key/-2, value/-1
appendw(buf, ']' | '=' << 010);
}
LuaEncodeLuaData(L, buf, level - 1, numformat);
lua_pop(L, 1); // table/-2, key/-1
}
// stack: table/-1, as the key was popped by lua_next
appendw(buf, '}');
} else if (LUA_TNIL == t) {
appendd(buf, "nil", 3);
} else {
return luaL_argerror(L, 1, "can't serialize value of this type");
}
return 0;
}

78
third_party/lua/luaencodeurl.c vendored Normal file
View file

@ -0,0 +1,78 @@
/*-*- 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 2022 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/x/x.h"
#include "net/http/url.h"
#include "third_party/lua/cosmo.h"
#include "third_party/lua/lauxlib.h"
#include "third_party/lua/lua.h"
int LuaEncodeUrl(lua_State *L) {
size_t size;
struct Url h;
int i, j, k, n, m;
const char *data;
if (!lua_isnil(L, 1)) {
bzero(&h, sizeof(h));
luaL_checktype(L, 1, LUA_TTABLE);
if (lua_getfield(L, 1, "scheme"))
h.scheme.p = lua_tolstring(L, -1, &h.scheme.n);
if (lua_getfield(L, 1, "fragment"))
h.fragment.p = lua_tolstring(L, -1, &h.fragment.n);
if (lua_getfield(L, 1, "user")) h.user.p = lua_tolstring(L, -1, &h.user.n);
if (lua_getfield(L, 1, "pass")) h.pass.p = lua_tolstring(L, -1, &h.pass.n);
if (lua_getfield(L, 1, "host")) h.host.p = lua_tolstring(L, -1, &h.host.n);
if (lua_getfield(L, 1, "port")) h.port.p = lua_tolstring(L, -1, &h.port.n);
if (lua_getfield(L, 1, "path")) h.path.p = lua_tolstring(L, -1, &h.path.n);
if (lua_getfield(L, 1, "params")) {
luaL_checktype(L, -1, LUA_TTABLE);
lua_len(L, -1);
n = lua_tointeger(L, -1);
for (i = -2, k = 0, j = 1; j <= n; ++j) {
if (lua_geti(L, i--, j)) {
luaL_checktype(L, -1, LUA_TTABLE);
lua_len(L, -1);
m = lua_tointeger(L, -1);
lua_pop(L, 1); // remove the table length
if (m >= 1 && lua_geti(L, -1, 1)) {
h.params.p =
xrealloc(h.params.p, ++h.params.n * sizeof(*h.params.p));
h.params.p[h.params.n - 1].key.p =
lua_tolstring(L, -1, &h.params.p[h.params.n - 1].key.n);
if (m >= 2 && lua_geti(L, -2, 2)) {
h.params.p[h.params.n - 1].val.p =
lua_tolstring(L, -1, &h.params.p[h.params.n - 1].val.n);
} else {
h.params.p[h.params.n - 1].val.p = 0;
h.params.p[h.params.n - 1].val.n = 0;
}
}
i--;
}
i--;
}
}
data = EncodeUrl(&h, &size);
lua_pushlstring(L, data, size);
free(h.params.p);
free(data);
} else {
lua_pushnil(L);
}
return 1;
}

48
third_party/lua/luaformatstack.c vendored Normal file
View file

@ -0,0 +1,48 @@
/*-*- 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 2022 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/stdio/append.internal.h"
#include "third_party/lua/cosmo.h"
nodiscard char *LuaFormatStack(lua_State *L) {
int i, top;
char *b = 0;
top = lua_gettop(L);
for (i = 1; i <= top; i++) {
if (i > 1) appendw(&b, '\n');
appendf(&b, "\t%d\t%s\t", i, luaL_typename(L, i));
switch (lua_type(L, i)) {
case LUA_TNUMBER:
appendf(&b, "%g", lua_tonumber(L, i));
break;
case LUA_TSTRING:
appends(&b, lua_tostring(L, i));
break;
case LUA_TBOOLEAN:
appends(&b, lua_toboolean(L, i) ? "true" : "false");
break;
case LUA_TNIL:
appends(&b, "nil");
break;
default:
appendf(&b, "%p", lua_topointer(L, i));
break;
}
}
return b;
}

58
third_party/lua/luaparseurl.c vendored Normal file
View file

@ -0,0 +1,58 @@
/*-*- 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 2022 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/mem/mem.h"
#include "net/http/url.h"
#include "third_party/lua/cosmo.h"
#include "third_party/lua/lauxlib.h"
#include "third_party/lua/lua.h"
static void LuaPushUrlView(lua_State *L, struct UrlView *v) {
if (v->p) {
lua_pushlstring(L, v->p, v->n);
} else {
lua_pushnil(L);
}
}
static void LuaSetUrlView(lua_State *L, struct UrlView *v, const char *k) {
LuaPushUrlView(L, v);
lua_setfield(L, -2, k);
}
int LuaParseUrl(lua_State *L) {
void *m;
size_t n;
struct Url h;
const char *p;
p = luaL_checklstring(L, 1, &n);
m = ParseUrl(p, n, &h);
lua_newtable(L);
LuaSetUrlView(L, &h.scheme, "scheme");
LuaSetUrlView(L, &h.user, "user");
LuaSetUrlView(L, &h.pass, "pass");
LuaSetUrlView(L, &h.host, "host");
LuaSetUrlView(L, &h.port, "port");
LuaSetUrlView(L, &h.path, "path");
LuaSetUrlView(L, &h.fragment, "fragment");
LuaPushUrlParams(L, &h.params);
lua_setfield(L, -2, "params");
free(h.params.p);
free(m);
return 1;
}

35
third_party/lua/luapushheader.c vendored Normal file
View file

@ -0,0 +1,35 @@
/*-*- 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 2022 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 "net/http/http.h"
#include "third_party/lua/cosmo.h"
#include "third_party/lua/lauxlib.h"
#include "third_party/lua/lua.h"
int LuaPushHeader(lua_State *L, struct HttpMessage *m, char *b, int h) {
char *val;
size_t vallen;
if (!kHttpRepeatable[h]) {
LuaPushLatin1(L, b + m->headers[h].a, m->headers[h].b - m->headers[h].a);
} else {
val = FoldHeader(m, b, h, &vallen);
LuaPushLatin1(L, val, vallen);
free(val);
}
return 1;
}

44
third_party/lua/luapushheaders.c vendored Normal file
View file

@ -0,0 +1,44 @@
/*-*- 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 2022 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 "net/http/escape.h"
#include "net/http/http.h"
#include "third_party/lua/cosmo.h"
#include "third_party/lua/lua.h"
int LuaPushHeaders(lua_State *L, struct HttpMessage *m, const char *b) {
char *s;
size_t i, h;
struct HttpHeader *x;
lua_newtable(L);
for (h = 0; h < kHttpHeadersMax; ++h) {
if (m->headers[h].a) {
LuaPushHeader(L, m, b, h);
lua_setfield(L, -2, GetHttpHeaderName(h));
}
}
for (i = 0; i < m->xheaders.n; ++i) {
x = m->xheaders.p + i;
if ((h = GetHttpHeader(b + x->v.a, x->v.b - x->v.a)) == -1) {
LuaPushLatin1(L, b + x->v.a, x->v.b - x->v.a);
lua_setfield(L, -2, (s = DecodeLatin1(b + x->k.a, x->k.b - x->k.a, 0)));
free(s);
}
}
return 1;
}

31
third_party/lua/luapushlatin1.c vendored Normal file
View file

@ -0,0 +1,31 @@
/*-*- 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 2022 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/mem/mem.h"
#include "net/http/escape.h"
#include "third_party/lua/cosmo.h"
#include "third_party/lua/lauxlib.h"
#include "third_party/lua/lua.h"
void LuaPushLatin1(lua_State *L, const char *s, size_t n) {
char *t;
size_t m;
t = DecodeLatin1(s, n, &m);
lua_pushlstring(L, t, m);
free(t);
}

37
third_party/lua/luapushurlparams.c vendored Normal file
View file

@ -0,0 +1,37 @@
/*-*- 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 2022 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 "net/http/url.h"
#include "third_party/lua/cosmo.h"
#include "third_party/lua/lauxlib.h"
#include "third_party/lua/lua.h"
void LuaPushUrlParams(lua_State *L, struct UrlParams *h) {
size_t 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);
}
}

View file

@ -1,10 +1,9 @@
#ifndef COSMOPOLITAN_THIRD_PARTY_QUICKJS_CUTILS_H_
#define COSMOPOLITAN_THIRD_PARTY_QUICKJS_CUTILS_H_
#include "libc/bits/bswap.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
/* clang-format off */
#include "libc/bits/bswap.h"
#include "libc/bits/bswap.h"
/* set if CPU is big endian */
#undef WORDS_BIGENDIAN
@ -16,9 +15,6 @@ COSMOPOLITAN_C_START_
#define stringify(s) tostring(s)
#define tostring(s) #s
#ifndef offsetof
#define offsetof(type, field) ((size_t) &((type *)0)->field)
#endif
#ifndef countof
#define countof(x) (sizeof(x) / sizeof((x)[0]))
#endif
@ -32,10 +28,10 @@ enum {
};
#endif
void pstrcpy(char *buf, int buf_size, const char *str);
char *pstrcat(char *buf, int buf_size, const char *s);
int strstart(const char *str, const char *val, const char **ptr);
int has_suffix(const char *str, const char *suffix);
void pstrcpy(char *, int, const char *);
char *pstrcat(char *, int, const char *);
int strstart(const char *, const char *, const char **);
int has_suffix(const char *, const char *);
static inline int max_int(int a, int b)
{

View file

@ -12983,9 +12983,13 @@ static JSValue js_create_function(JSContext *ctx, JSFunctionDef *fd)
}
} else {
b->vardefs = (void *)((uint8_t*)b + vardefs_offset);
if (fd->arg_count) {
memcpy(b->vardefs, fd->args, fd->arg_count * sizeof(fd->args[0]));
}
if (fd->var_count) {
memcpy(b->vardefs + fd->arg_count, fd->vars, fd->var_count * sizeof(fd->vars[0]));
}
}
b->var_count = fd->var_count;
b->arg_count = fd->arg_count;
b->defined_arg_count = fd->defined_arg_count;

165
tool/net/lre.c Normal file
View file

@ -0,0 +1,165 @@
/*-*- 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 2022 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/macros.internal.h"
#include "libc/x/x.h"
#include "third_party/lua/lauxlib.h"
#include "third_party/regex/regex.h"
static const char kRegCode[][8] = {
"OK", "NOMATCH", "BADPAT", "COLLATE", "ECTYPE", "EESCAPE", "ESUBREG",
"EBRACK", "EPAREN", "EBRACE", "BADBR", "ERANGE", "ESPACE", "BADRPT",
};
static void LuaSetIntField(lua_State *L, const char *k, lua_Integer v) {
lua_pushinteger(L, v);
lua_setfield(L, -2, k);
}
static regex_t *LuaReCompileImpl(lua_State *L, const char *p, int f) {
int e;
regex_t *r;
r = xmalloc(sizeof(regex_t));
f &= REG_EXTENDED | REG_ICASE | REG_NEWLINE | REG_NOSUB;
f ^= REG_EXTENDED;
if ((e = regcomp(r, p, f)) != REG_OK) {
free(r);
luaL_error(L, "regcomp(%s) → REG_%s", p,
kRegCode[MAX(0, MIN(ARRAYLEN(kRegCode) - 1, e))]);
unreachable;
}
return r;
}
static int LuaReSearchImpl(lua_State *L, regex_t *r, const char *s, int f) {
int i, n;
regmatch_t *m;
n = r->re_nsub + 1;
m = xcalloc(n, sizeof(regmatch_t));
if (regexec(r, s, n, m, f >> 8) == REG_OK) {
for (i = 0; i < n; ++i) {
lua_pushlstring(L, s + m[i].rm_so, m[i].rm_eo - m[i].rm_so);
}
} else {
n = 0;
}
free(m);
return n;
}
static int LuaReSearch(lua_State *L) {
regex_t *r;
int i, e, n, f;
const char *p, *s;
p = luaL_checkstring(L, 1);
s = luaL_checkstring(L, 2);
f = luaL_optinteger(L, 3, 0);
if (f & ~(REG_EXTENDED | REG_ICASE | REG_NEWLINE | REG_NOSUB |
REG_NOTBOL << 8 | REG_NOTEOL << 8)) {
luaL_argerror(L, 3, "invalid flags");
unreachable;
}
r = LuaReCompileImpl(L, p, f);
n = LuaReSearchImpl(L, r, s, f);
regfree(r);
free(r);
return n;
}
static int LuaReCompile(lua_State *L) {
int f, e;
const char *p;
regex_t *r, **u;
p = luaL_checkstring(L, 1);
f = luaL_optinteger(L, 2, 0);
if (f & ~(REG_EXTENDED | REG_ICASE | REG_NEWLINE | REG_NOSUB)) {
luaL_argerror(L, 3, "invalid flags");
unreachable;
}
r = LuaReCompileImpl(L, p, f);
u = lua_newuserdata(L, sizeof(regex_t *));
luaL_setmetatable(L, "regex_t*");
*u = r;
return 1;
}
static int LuaReRegexSearch(lua_State *L) {
int f;
regex_t **u;
const char *s;
u = luaL_checkudata(L, 1, "regex_t*");
s = luaL_checkstring(L, 2);
f = luaL_optinteger(L, 3, 0);
if (!*u) {
luaL_argerror(L, 1, "destroyed");
unreachable;
}
if (f & ~(REG_NOTBOL << 8 | REG_NOTEOL << 8)) {
luaL_argerror(L, 3, "invalid flags");
unreachable;
}
return LuaReSearchImpl(L, *u, s, f);
}
static int LuaReRegexGc(lua_State *L) {
regex_t **u;
u = luaL_checkudata(L, 1, "regex_t*");
if (*u) {
regfree(*u);
free(*u);
*u = NULL;
}
return 0;
}
static const luaL_Reg kLuaRe[] = {
{"compile", LuaReCompile}, //
{"search", LuaReSearch}, //
{NULL, NULL}, //
};
static const luaL_Reg kLuaReRegexMeth[] = {
{"search", LuaReRegexSearch}, //
{NULL, NULL}, //
};
static const luaL_Reg kLuaReRegexMeta[] = {
{"__gc", LuaReRegexGc}, //
{NULL, NULL}, //
};
static void LuaReRegex(lua_State *L) {
luaL_newmetatable(L, "regex_t*");
luaL_setfuncs(L, kLuaReRegexMeta, 0);
luaL_newlibtable(L, kLuaReRegexMeth);
luaL_setfuncs(L, kLuaReRegexMeth, 0);
lua_setfield(L, -2, "__index");
lua_pop(L, 1);
}
int LuaRe(lua_State *L) {
luaL_newlib(L, kLuaRe);
LuaSetIntField(L, "BASIC", REG_EXTENDED);
LuaSetIntField(L, "ICASE", REG_ICASE);
LuaSetIntField(L, "NEWLINE", REG_NEWLINE);
LuaSetIntField(L, "NOSUB", REG_NOSUB);
LuaSetIntField(L, "NOTBOL", REG_NOTBOL << 8);
LuaSetIntField(L, "NOTEOL", REG_NOTEOL << 8);
LuaReRegex(L);
return 1;
}

View file

@ -86,6 +86,7 @@ o/$(MODE)/tool/net/%.com.dbg: \
o/$(MODE)/tool/net/redbean.com.dbg: \
$(TOOL_NET_DEPS) \
o/$(MODE)/tool/net/redbean.o \
o/$(MODE)/tool/net/lre.o \
o/$(MODE)/tool/net/lmaxmind.o \
o/$(MODE)/tool/net/lsqlite3.o \
o/$(MODE)/tool/net/largon2.o \
@ -148,9 +149,11 @@ o/$(MODE)/tool/net/demo/virtualbean.html.zip.o: \
o/$(MODE)/tool/net/redbean-demo.com.dbg: \
$(TOOL_NET_DEPS) \
o/$(MODE)/tool/net/redbean.o \
o/$(MODE)/tool/net/lre.o \
o/$(MODE)/tool/net/lmaxmind.o \
o/$(MODE)/tool/net/lsqlite3.o \
o/$(MODE)/tool/net/largon2.o \
o/$(MODE)/tool/net/lre.o \
o/$(MODE)/tool/net/net.pkg \
o/$(MODE)/tool/net/demo/sql.lua.zip.o \
o/$(MODE)/tool/net/demo/fetch.lua.zip.o \
@ -235,6 +238,7 @@ o/$(MODE)/tool/net/redbean-unsecure.com: \
o/$(MODE)/tool/net/redbean-unsecure.com.dbg: \
$(TOOL_NET_DEPS) \
o/$(MODE)/tool/net/redbean-unsecure.o \
o/$(MODE)/tool/net/lre.o \
o/$(MODE)/tool/net/lmaxmind.o \
o/$(MODE)/tool/net/lsqlite3.o \
o/$(MODE)/tool/net/net.pkg \

View file

@ -97,6 +97,7 @@
#include "net/http/url.h"
#include "net/https/https.h"
#include "third_party/getopt/getopt.h"
#include "third_party/lua/cosmo.h"
#include "third_party/lua/lauxlib.h"
#include "third_party/lua/ltests.h"
#include "third_party/lua/lua.h"
@ -203,11 +204,6 @@ static const char *const kAlpn[] = {
NULL,
};
static const char kRegCode[][8] = {
"OK", "NOMATCH", "BADPAT", "COLLATE", "ECTYPE", "EESCAPE", "ESUBREG",
"EBRACK", "EPAREN", "EBRACE", "BADBR", "ERANGE", "ESPACE", "BADRPT",
};
struct Buffer {
size_t n, c;
char *p;
@ -1029,79 +1025,6 @@ static void Daemonize(void) {
ChangeUser();
}
static nodiscard char *LuaFormatStack(lua_State *L) {
int i, top;
char *b = 0;
top = lua_gettop(L);
for (i = 1; i <= top; i++) {
if (i > 1) appendw(&b, '\n');
appendf(&b, "\t%d\t%s\t", i, luaL_typename(L, i));
switch (lua_type(L, i)) {
case LUA_TNUMBER:
appendf(&b, "%g", lua_tonumber(L, i));
break;
case LUA_TSTRING:
appends(&b, lua_tostring(L, i));
break;
case LUA_TBOOLEAN:
appends(&b, lua_toboolean(L, i) ? "true" : "false");
break;
case LUA_TNIL:
appends(&b, "nil");
break;
default:
appendf(&b, "%p", lua_topointer(L, i));
break;
}
}
return b;
}
// calling convention for lua stack of L is:
// -2 is function
// -1 is is argument (assuming nargs == 1)
// L will have this after the call
// -1 is error or result (assuming nres == 1)
// @param L is main Lua interpreter
// @note this needs to be reentrant
static int LuaCallWithTrace(lua_State *L, int nargs, int nres, lua_State *C) {
int nresults, status;
bool canyield = !!C; // allow yield if coroutine is provided
if (!C) C = lua_newthread(L); // create a new coroutine if not passed
// move coroutine to the bottom of the stack (including one that is passed)
lua_insert(L, 1);
// make sure that there is enough stack space
if (!lua_checkstack(C, 1 + nargs)) {
lua_pushliteral(L, "too many arguments to resume");
return LUA_ERRRUN; /* error flag */
}
// move the function (and arguments) to the top of the coro stack
lua_xmove(L, C, 1 + nargs);
// resume the coroutine thus executing the function
status = lua_resume(C, L, nargs, &nresults);
lua_remove(L, 1); // remove coroutine (still) at the bottom
if (status != LUA_OK && status != LUA_YIELD) {
// move the error message
lua_xmove(C, L, 1);
// replace the error with the traceback on failure
luaL_traceback(L, C, lua_tostring(L, -1), 0);
lua_remove(L, -2); // remove the error message
} else {
if (!lua_checkstack(L, MAX(nresults, nres))) {
lua_pop(C, nresults); /* remove results anyway */
lua_pushliteral(L, "too many results to resume");
return LUA_ERRRUN; /* error flag */
}
lua_xmove(C, L, nresults); // move results to the main stack
// grow the stack in case returned fewer results
// than the caller expects, as lua_resume
// doesn't adjust the stack for needed results
for (; nresults < nres; nresults++) lua_pushnil(L);
if (!canyield) status = LUA_OK; // treat LUA_YIELD the same as LUA_OK
}
return status;
}
static void LogLuaError(char *hook, char *err) {
ERRORF("(lua) failed to run %s: %s", hook, err);
}
@ -1119,6 +1042,7 @@ static bool LuaRunCode(const char *code) {
}
static bool LuaOnClientConnection(void) {
#ifndef STATIC
bool dropit;
uint32_t ip, serverip;
uint16_t port, serverport;
@ -1139,9 +1063,13 @@ static bool LuaOnClientConnection(void) {
}
AssertLuaStackIsEmpty(L);
return dropit;
#else
return false;
#endif
}
static void LuaOnProcessCreate(int pid) {
#ifndef STATIC
uint32_t ip, serverip;
uint16_t port, serverport;
lua_State *L = GL;
@ -1158,9 +1086,11 @@ static void LuaOnProcessCreate(int pid) {
lua_pop(L, 1); // pop error
}
AssertLuaStackIsEmpty(L);
#endif
}
static void LuaOnProcessDestroy(int pid) {
#ifndef STATIC
lua_State *L = GL;
lua_getglobal(L, "OnProcessDestroy");
lua_pushinteger(L, pid);
@ -1169,6 +1099,7 @@ static void LuaOnProcessDestroy(int pid) {
lua_pop(L, 1); // pop error
}
AssertLuaStackIsEmpty(L);
#endif
}
static inline bool IsHookDefined(const char *s) {
@ -1183,6 +1114,7 @@ static inline bool IsHookDefined(const char *s) {
}
static void CallSimpleHook(const char *s) {
#ifndef STATIC
lua_State *L = GL;
lua_getglobal(L, s);
if (LuaCallWithTrace(L, 0, 0, NULL) != LUA_OK) {
@ -1190,6 +1122,7 @@ static void CallSimpleHook(const char *s) {
lua_pop(L, 1); // pop error
}
AssertLuaStackIsEmpty(L);
#endif
}
static void CallSimpleHookIfDefined(const char *s) {
@ -1528,7 +1461,8 @@ static void WipeServingKeys(void) {
PsksDestroy();
}
bool CertHasCommonName(const mbedtls_x509_crt *cert, const void *s, size_t n) {
static bool CertHasCommonName(const mbedtls_x509_crt *cert, const void *s,
size_t n) {
const mbedtls_x509_name *name;
for (name = &cert->subject; name; name = name->next) {
if (!MBEDTLS_OID_CMP(MBEDTLS_OID_AT_CN, &name->oid)) {
@ -3639,69 +3573,6 @@ static wontreturn void LuaThrowTlsError(lua_State *L, const char *s, int r) {
unreachable;
}
static char *FoldHeader(struct HttpMessage *msg, char *b, int h, size_t *z) {
char *p;
size_t i, n, m;
struct HttpHeader *x;
n = msg->headers[h].b - msg->headers[h].a;
p = xmalloc(n);
memcpy(p, b + msg->headers[h].a, n);
for (i = 0; i < msg->xheaders.n; ++i) {
x = msg->xheaders.p + i;
if (GetHttpHeader(b + x->k.a, x->k.b - x->k.a) == h) {
m = x->v.b - x->v.a;
p = xrealloc(p, n + 2 + m);
memcpy(mempcpy(p + n, ", ", 2), b + x->v.a, m);
n += 2 + m;
}
}
*z = n;
return p;
}
static void LuaPushLatin1(lua_State *L, const char *s, size_t n) {
char *t;
size_t m;
t = DecodeLatin1(s, n, &m);
lua_pushlstring(L, t, m);
free(t);
}
static int LuaPushHeader(lua_State *L, struct HttpMessage *m, char *b, int h) {
char *val;
size_t vallen;
if (!kHttpRepeatable[h]) {
LuaPushLatin1(L, b + m->headers[h].a, m->headers[h].b - m->headers[h].a);
} else {
val = FoldHeader(m, b, h, &vallen);
LuaPushLatin1(L, val, vallen);
free(val);
}
return 1;
}
static int LuaPushHeaders(lua_State *L, struct HttpMessage *m, const char *b) {
char *s;
size_t i, h;
struct HttpHeader *x;
lua_newtable(L);
for (h = 0; h < kHttpHeadersMax; ++h) {
if (m->headers[h].a) {
LuaPushHeader(L, m, b, h);
lua_setfield(L, -2, GetHttpHeaderName(h));
}
}
for (i = 0; i < m->xheaders.n; ++i) {
x = m->xheaders.p + i;
if ((h = GetHttpHeader(b + x->v.a, x->v.b - x->v.a)) == -1) {
LuaPushLatin1(L, b + x->v.a, x->v.b - x->v.a);
lua_setfield(L, -2, (s = DecodeLatin1(b + x->k.a, x->k.b - x->k.a, 0)));
free(s);
}
}
return 1;
}
static void LogMessage(const char *d, const char *s, size_t n) {
size_t n2, n3;
char *s2, *s3;
@ -4418,7 +4289,6 @@ static int LuaGetCookie(lua_State *L) {
char *cookie = 0, *cookietmpl, *cookieval;
OnlyCallDuringRequest(L, "GetCookie");
cookietmpl = gc(xasprintf(" %s=", luaL_checkstring(L, 1)));
if (HasHeader(kHttpCookie)) {
appends(&cookie, " "); // prepend space to simplify cookie search
appendd(&cookie, HeaderData(kHttpCookie), HeaderLength(kHttpCookie));
@ -4573,21 +4443,6 @@ static int LuaGetParam(lua_State *L) {
return 1;
}
static void LuaPushUrlParams(lua_State *L, struct UrlParams *h) {
size_t 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);
}
}
static int LuaGetParams(lua_State *L) {
OnlyCallDuringRequest(L, "GetParams");
LuaPushUrlParams(L, &url.params);
@ -4608,33 +4463,6 @@ static int LuaParseParams(lua_State *L) {
return 1;
}
static void LuaSetUrlView(lua_State *L, struct UrlView *v, const char *k) {
LuaPushUrlView(L, v);
lua_setfield(L, -2, k);
}
static int LuaParseUrl(lua_State *L) {
void *m;
size_t n;
struct Url h;
const char *p;
p = luaL_checklstring(L, 1, &n);
m = ParseUrl(p, n, &h);
lua_newtable(L);
LuaSetUrlView(L, &h.scheme, "scheme");
LuaSetUrlView(L, &h.user, "user");
LuaSetUrlView(L, &h.pass, "pass");
LuaSetUrlView(L, &h.host, "host");
LuaSetUrlView(L, &h.port, "port");
LuaSetUrlView(L, &h.path, "path");
LuaSetUrlView(L, &h.fragment, "fragment");
LuaPushUrlParams(L, &h.params);
lua_setfield(L, -2, "params");
free(h.params.p);
free(m);
return 1;
}
static int LuaParseHost(lua_State *L) {
void *m;
size_t n;
@ -4650,61 +4478,6 @@ static int LuaParseHost(lua_State *L) {
return 1;
}
static int LuaEncodeUrl(lua_State *L) {
size_t size;
struct Url h;
int i, j, k, n, m;
const char *data;
if (!lua_isnil(L, 1)) {
bzero(&h, sizeof(h));
luaL_checktype(L, 1, LUA_TTABLE);
if (lua_getfield(L, 1, "scheme"))
h.scheme.p = lua_tolstring(L, -1, &h.scheme.n);
if (lua_getfield(L, 1, "fragment"))
h.fragment.p = lua_tolstring(L, -1, &h.fragment.n);
if (lua_getfield(L, 1, "user")) h.user.p = lua_tolstring(L, -1, &h.user.n);
if (lua_getfield(L, 1, "pass")) h.pass.p = lua_tolstring(L, -1, &h.pass.n);
if (lua_getfield(L, 1, "host")) h.host.p = lua_tolstring(L, -1, &h.host.n);
if (lua_getfield(L, 1, "port")) h.port.p = lua_tolstring(L, -1, &h.port.n);
if (lua_getfield(L, 1, "path")) h.path.p = lua_tolstring(L, -1, &h.path.n);
if (lua_getfield(L, 1, "params")) {
luaL_checktype(L, -1, LUA_TTABLE);
lua_len(L, -1);
n = lua_tointeger(L, -1);
for (i = -2, k = 0, j = 1; j <= n; ++j) {
if (lua_geti(L, i--, j)) {
luaL_checktype(L, -1, LUA_TTABLE);
lua_len(L, -1);
m = lua_tointeger(L, -1);
lua_pop(L, 1); // remove the table length
if (m >= 1 && lua_geti(L, -1, 1)) {
h.params.p =
xrealloc(h.params.p, ++h.params.n * sizeof(*h.params.p));
h.params.p[h.params.n - 1].key.p =
lua_tolstring(L, -1, &h.params.p[h.params.n - 1].key.n);
if (m >= 2 && lua_geti(L, -2, 2)) {
h.params.p[h.params.n - 1].val.p =
lua_tolstring(L, -1, &h.params.p[h.params.n - 1].val.n);
} else {
h.params.p[h.params.n - 1].val.p = 0;
h.params.p[h.params.n - 1].val.n = 0;
}
}
i--;
}
i--;
}
}
data = EncodeUrl(&h, &size);
lua_pushlstring(L, data, size);
free(h.params.p);
free(data);
} else {
lua_pushnil(L);
}
return 1;
}
static int LuaWrite(lua_State *L) {
size_t size;
const char *data;
@ -4923,126 +4696,6 @@ static int LuaGetHttpReason(lua_State *L) {
return 1;
}
static int EncodeJsonData(lua_State *L, char **buf, int level,
char *numformat) {
size_t idx = -1;
size_t tbllen, buflen;
bool isarray;
int t = lua_type(L, idx);
if (level < 0) return luaL_argerror(L, 1, "too many nested tables");
if (LUA_TSTRING == t) {
appendw(buf, '"');
appends(buf, gc(EscapeJsStringLiteral(lua_tostring(L, idx), -1, 0)));
appendw(buf, '"');
} else if (LUA_TNUMBER == t) {
appendf(buf, numformat, lua_tonumber(L, idx));
} else if (LUA_TBOOLEAN == t) {
appends(buf, lua_toboolean(L, idx) ? "true" : "false");
} else if (LUA_TTABLE == t) {
tbllen = lua_rawlen(L, idx);
// encode tables with numeric indices and empty tables as arrays
isarray = tbllen > 0 || // integer keys present
(lua_pushnil(L), lua_next(L, -2) == 0) || // no non-integer keys
(lua_pop(L, 2), false); // pop key/value pushed by lua_next
appendw(buf, isarray ? '[' : '{');
if (isarray) {
for (int i = 1; i <= tbllen; i++) {
if (i > 1) appendw(buf, ',');
lua_rawgeti(L, -1, i); // table/-2, value/-1
EncodeJsonData(L, buf, level - 1, numformat);
lua_pop(L, 1);
}
} else {
int i = 1;
lua_pushnil(L); // push the first key
while (lua_next(L, -2) != 0) {
if (!lua_isstring(L, -2))
return luaL_argerror(L, 1, "expected number or string as key value");
if (i++ > 1) appendw(buf, ',');
appendw(buf, '"');
if (lua_type(L, -2) == LUA_TSTRING) {
appends(buf, gc(EscapeJsStringLiteral(lua_tostring(L, -2), -1, 0)));
} else {
// we'd still prefer to use lua_tostring on a numeric index, but can't
// use it in-place, as it breaks lua_next (changes numeric key to a
// string)
lua_pushvalue(L, -2); // table/-4, key/-3, value/-2, key/-1
appends(buf, lua_tostring(L, idx)); // use the copy
lua_remove(L, -1); // remove copied key: table/-3, key/-2, value/-1
}
appendw(buf, '"' | ':' << 010);
EncodeJsonData(L, buf, level - 1, numformat);
lua_pop(L, 1); // table/-2, key/-1
}
// stack: table/-1, as the key was popped by lua_next
}
appendw(buf, isarray ? ']' : '}');
} else if (LUA_TNIL == t) {
appendd(buf, "null", 4);
} else {
return luaL_argerror(L, 1, "can't serialize value of this type");
}
return 0;
}
static void EscapeLuaString(char *s, size_t len, char **buf) {
appendw(buf, '"');
for (size_t i = 0; i < len; i++) {
if (s[i] == '\\' || s[i] == '\"' || s[i] == '\n' || s[i] == '\0' ||
s[i] == '\r') {
appendw(buf, '\\' | 'x' << 010 |
"0123456789abcdef"[(s[i] & 0xF0) >> 4] << 020 |
"0123456789abcdef"[(s[i] & 0x0F) >> 0] << 030);
} else {
appendd(buf, s + i, 1);
}
}
appendw(buf, '"');
}
static int EncodeLuaData(lua_State *L, char **buf, int level, char *numformat) {
size_t idx = -1;
size_t tbllen, buflen, slen;
char *s;
int ktype;
int t = lua_type(L, idx);
if (level < 0) return luaL_argerror(L, 1, "too many nested tables");
if (LUA_TSTRING == t) {
s = lua_tolstring(L, idx, &slen);
EscapeLuaString(s, slen, buf);
} else if (LUA_TNUMBER == t) {
appendf(buf, numformat, lua_tonumber(L, idx));
} else if (LUA_TBOOLEAN == t) {
appends(buf, lua_toboolean(L, idx) ? "true" : "false");
} else if (LUA_TTABLE == t) {
appendw(buf, '{');
int i = 0;
lua_pushnil(L); // push the first key
while (lua_next(L, -2) != 0) {
ktype = lua_type(L, -2);
if (ktype == LUA_TTABLE)
return luaL_argerror(L, 1, "can't serialize key of this type");
if (i++ > 0) appendd(buf, ",", 1);
if (ktype != LUA_TNUMBER || floor(lua_tonumber(L, -2)) != i) {
appendw(buf, '[');
lua_pushvalue(L, -2); // table/-4, key/-3, value/-2, key/-1
EncodeLuaData(L, buf, level, numformat);
lua_remove(L, -1); // remove copied key: table/-3, key/-2, value/-1
appendw(buf, ']' | '=' << 010);
}
EncodeLuaData(L, buf, level - 1, numformat);
lua_pop(L, 1); // table/-2, key/-1
}
// stack: table/-1, as the key was popped by lua_next
appendw(buf, '}');
} else if (LUA_TNIL == t)
appendd(buf, "nil", 3);
else {
return luaL_argerror(L, 1, "can't serialize value of this type");
}
return 0;
}
static int LuaEncodeSmth(lua_State *L,
int Encoder(lua_State *, char **, int, char *)) {
int useoutput = false;
@ -5072,11 +4725,11 @@ static int LuaEncodeSmth(lua_State *L,
}
static int LuaEncodeJson(lua_State *L) {
return LuaEncodeSmth(L, EncodeJsonData);
return LuaEncodeSmth(L, LuaEncodeJsonData);
}
static int LuaEncodeLua(lua_State *L) {
return LuaEncodeSmth(L, EncodeLuaData);
return LuaEncodeSmth(L, LuaEncodeLuaData);
}
static int LuaEncodeLatin1(lua_State *L) {
@ -5255,7 +4908,6 @@ static int LuaProgramPidPath(lua_State *L) {
}
static int LuaProgramSslPresharedKey(lua_State *L) {
#ifndef UNSECURE
struct Psk psk;
size_t n1, n2, i;
const char *p1, *p2;
@ -5282,7 +4934,6 @@ static int LuaProgramSslPresharedKey(lua_State *L) {
}
psks.p = realloc(psks.p, ++psks.n * sizeof(*psks.p));
psks.p[psks.n - 1] = psk;
#endif
return 0;
}
@ -5299,24 +4950,20 @@ static int LuaProgramSslCiphersuite(lua_State *L) {
}
static int LuaProgramPrivateKey(lua_State *L) {
#ifndef UNSECURE
size_t n;
const char *p;
OnlyCallFromInitLua(L, "ProgramPrivateKey");
p = luaL_checklstring(L, 1, &n);
ProgramPrivateKey(p, n);
#endif
return 0;
}
static int LuaProgramCertificate(lua_State *L) {
#ifndef UNSECURE
size_t n;
const char *p;
OnlyCallFromInitLua(L, "ProgramCertificate");
p = luaL_checklstring(L, 1, &n);
ProgramCertificate(p, n);
#endif
return 0;
}
@ -5577,150 +5224,12 @@ static int LuaGetHostOs(lua_State *L) {
return 1;
}
static void LuaSetIntField(lua_State *L, const char *k, lua_Integer v) {
lua_pushinteger(L, v);
lua_setfield(L, -2, k);
}
static int LuaLaunchBrowser(lua_State *L) {
OnlyCallFromInitLua(L, "LaunchBrowser");
launchbrowser = strdup(luaL_optstring(L, 1, "/"));
return 0;
}
static regex_t *LuaReCompileImpl(lua_State *L, const char *p, int f) {
int e;
regex_t *r;
r = xmalloc(sizeof(regex_t));
f &= REG_EXTENDED | REG_ICASE | REG_NEWLINE | REG_NOSUB;
f ^= REG_EXTENDED;
if ((e = regcomp(r, p, f)) != REG_OK) {
free(r);
luaL_error(L, "regcomp(%s) → REG_%s", p,
kRegCode[MAX(0, MIN(ARRAYLEN(kRegCode) - 1, e))]);
unreachable;
}
return r;
}
static int LuaReSearchImpl(lua_State *L, regex_t *r, const char *s, int f) {
int i, n;
regmatch_t *m;
n = r->re_nsub + 1;
m = xcalloc(n, sizeof(regmatch_t));
if (regexec(r, s, n, m, f >> 8) == REG_OK) {
for (i = 0; i < n; ++i) {
lua_pushlstring(L, s + m[i].rm_so, m[i].rm_eo - m[i].rm_so);
}
} else {
n = 0;
}
free(m);
return n;
}
static int LuaReSearch(lua_State *L) {
regex_t *r;
int i, e, n, f;
const char *p, *s;
p = luaL_checkstring(L, 1);
s = luaL_checkstring(L, 2);
f = luaL_optinteger(L, 3, 0);
if (f & ~(REG_EXTENDED | REG_ICASE | REG_NEWLINE | REG_NOSUB |
REG_NOTBOL << 8 | REG_NOTEOL << 8)) {
luaL_argerror(L, 3, "invalid flags");
unreachable;
}
r = LuaReCompileImpl(L, p, f);
n = LuaReSearchImpl(L, r, s, f);
regfree(r);
free(r);
return n;
}
static int LuaReCompile(lua_State *L) {
int f, e;
const char *p;
regex_t *r, **u;
p = luaL_checkstring(L, 1);
f = luaL_optinteger(L, 2, 0);
if (f & ~(REG_EXTENDED | REG_ICASE | REG_NEWLINE | REG_NOSUB)) {
luaL_argerror(L, 3, "invalid flags");
unreachable;
}
r = LuaReCompileImpl(L, p, f);
u = lua_newuserdata(L, sizeof(regex_t *));
luaL_setmetatable(L, "regex_t*");
*u = r;
return 1;
}
static int LuaReRegexSearch(lua_State *L) {
int f;
regex_t **u;
const char *s;
u = luaL_checkudata(L, 1, "regex_t*");
s = luaL_checkstring(L, 2);
f = luaL_optinteger(L, 3, 0);
if (!*u) {
luaL_argerror(L, 1, "destroyed");
unreachable;
}
if (f & ~(REG_NOTBOL << 8 | REG_NOTEOL << 8)) {
luaL_argerror(L, 3, "invalid flags");
unreachable;
}
return LuaReSearchImpl(L, *u, s, f);
}
static int LuaReRegexGc(lua_State *L) {
regex_t **u;
u = luaL_checkudata(L, 1, "regex_t*");
if (*u) {
regfree(*u);
free(*u);
*u = NULL;
}
return 0;
}
static const luaL_Reg kLuaRe[] = {
{"compile", LuaReCompile}, //
{"search", LuaReSearch}, //
{NULL, NULL}, //
};
static const luaL_Reg kLuaReRegexMeth[] = {
{"search", LuaReRegexSearch}, //
{NULL, NULL}, //
};
static const luaL_Reg kLuaReRegexMeta[] = {
{"__gc", LuaReRegexGc}, //
{NULL, NULL}, //
};
static void LuaReRegex(lua_State *L) {
luaL_newmetatable(L, "regex_t*");
luaL_setfuncs(L, kLuaReRegexMeta, 0);
luaL_newlibtable(L, kLuaReRegexMeth);
luaL_setfuncs(L, kLuaReRegexMeth, 0);
lua_setfield(L, -2, "__index");
lua_pop(L, 1);
}
static int LuaRe(lua_State *L) {
luaL_newlib(L, kLuaRe);
LuaSetIntField(L, "BASIC", REG_EXTENDED);
LuaSetIntField(L, "ICASE", REG_ICASE);
LuaSetIntField(L, "NEWLINE", REG_NEWLINE);
LuaSetIntField(L, "NOSUB", REG_NOSUB);
LuaSetIntField(L, "NOTBOL", REG_NOTBOL << 8);
LuaSetIntField(L, "NOTEOL", REG_NOTEOL << 8);
LuaReRegex(L);
return 1;
}
static bool LuaRunAsset(const char *path, bool mandatory) {
struct Asset *a;
const char *code;
@ -5768,8 +5277,6 @@ static const luaL_Reg kLuaFuncs[] = {
{"EscapePath", LuaEscapePath}, //
{"EscapeSegment", LuaEscapeSegment}, //
{"EscapeUser", LuaEscapeUser}, //
{"EvadeDragnetSurveillance", LuaEvadeDragnetSurveillance}, //
{"Fetch", LuaFetch}, //
{"FormatHttpDateTime", LuaFormatHttpDateTime}, //
{"FormatIp", LuaFormatIp}, //
{"GetAssetComment", LuaGetAssetComment}, //
@ -5804,7 +5311,6 @@ static const luaL_Reg kLuaFuncs[] = {
{"GetRemoteAddr", LuaGetRemoteAddr}, //
{"GetScheme", LuaGetScheme}, //
{"GetServerAddr", LuaGetServerAddr}, //
{"GetSslIdentity", LuaGetSslIdentity}, //
{"GetStatus", LuaGetStatus}, //
{"GetTime", LuaGetTime}, //
{"GetUrl", LuaGetUrl}, //
@ -5852,13 +5358,6 @@ static const luaL_Reg kLuaFuncs[] = {
{"ProgramPort", LuaProgramPort}, //
{"ProgramPrivateKey", LuaProgramPrivateKey}, //
{"ProgramRedirect", LuaProgramRedirect}, //
{"ProgramSslCiphersuite", LuaProgramSslCiphersuite}, //
{"ProgramSslClientVerify", LuaProgramSslClientVerify}, //
{"ProgramSslCompression", LuaProgramSslCompression}, //
{"ProgramSslInit", LuaProgramSslInit}, //
{"ProgramSslFetchVerify", LuaProgramSslFetchVerify}, //
{"ProgramSslPresharedKey", LuaProgramSslPresharedKey}, //
{"ProgramSslTicketLifetime", LuaProgramSslTicketLifetime}, //
{"ProgramTimeout", LuaProgramTimeout}, //
{"ProgramUid", LuaProgramUid}, //
{"ProgramUniprocess", LuaProgramUniprocess}, //
@ -5891,14 +5390,24 @@ static const luaL_Reg kLuaFuncs[] = {
{"crc32", LuaCrc32}, //
{"crc32c", LuaCrc32c}, //
{"popcnt", LuaPopcnt}, //
#ifndef UNSECURE
{"Fetch", LuaFetch}, //
{"EvadeDragnetSurveillance", LuaEvadeDragnetSurveillance}, //
{"GetSslIdentity", LuaGetSslIdentity}, //
{"ProgramSslCiphersuite", LuaProgramSslCiphersuite}, //
{"ProgramSslClientVerify", LuaProgramSslClientVerify}, //
{"ProgramSslCompression", LuaProgramSslCompression}, //
{"ProgramSslFetchVerify", LuaProgramSslFetchVerify}, //
{"ProgramSslInit", LuaProgramSslInit}, //
{"ProgramSslPresharedKey", LuaProgramSslPresharedKey}, //
{"ProgramSslTicketLifetime", LuaProgramSslTicketLifetime}, //
#endif
};
extern int luaopen_lsqlite3(lua_State *);
extern int LuaMaxmind(lua_State *);
#ifndef UNSECURE
extern int luaopen_argon2(lua_State *);
#endif
int LuaMaxmind(lua_State *);
int LuaRe(lua_State *);
int luaopen_argon2(lua_State *);
int luaopen_lsqlite3(lua_State *);
static const luaL_Reg kLuaLibs[] = {
{"re", LuaRe}, //
@ -7315,8 +6824,6 @@ static void GetOpts(int argc, char *argv[]) {
switch (opt) {
CASE('v', ++__log_level);
CASE('s', --__log_level);
CASE('V', ++mbedtls_debug_threshold);
CASE('B', suiteb = true);
CASE('f', funtrace = true);
CASE('b', logbodies = true);
CASE('z', printport = true);
@ -7325,10 +6832,6 @@ static void GetOpts(int argc, char *argv[]) {
CASE('u', uniprocess = true);
CASE('g', loglatency = true);
CASE('m', logmessages = true);
CASE('k', sslfetchverify = false);
CASE('j', sslclientverify = true);
CASE('e', LuaRunCode(optarg));
CASE('A', storeasset = true; StorePath(optarg));
CASE('l', ProgramAddr(optarg));
CASE('H', ProgramHeader(optarg));
CASE('L', ProgramLogPath(optarg));
@ -7342,9 +6845,17 @@ static void GetOpts(int argc, char *argv[]) {
CASE('r', ProgramRedirectArg(307, optarg));
CASE('t', ProgramTimeout(ParseInt(optarg)));
CASE('h', PrintUsage(stdout, EXIT_SUCCESS));
CASE('T', ProgramSslTicketLifetime(ParseInt(optarg)));
CASE('M', ProgramMaxPayloadSize(ParseInt(optarg)));
#ifndef STATIC
CASE('e', LuaRunCode(optarg));
CASE('A', storeasset = true; StorePath(optarg));
#endif
#ifndef UNSECURE
CASE('B', suiteb = true);
CASE('V', ++mbedtls_debug_threshold);
CASE('k', sslfetchverify = false);
CASE('j', sslclientverify = true);
CASE('T', ProgramSslTicketLifetime(ParseInt(optarg)));
CASE('C', ProgramFile(optarg, ProgramCertificate));
CASE('K', ProgramFile(optarg, ProgramPrivateKey));
#endif
@ -7413,7 +6924,6 @@ void RedBean(int argc, char *argv[]) {
}
int main(int argc, char *argv[]) {
int fd;
if (!IsTiny()) {
setenv("GDB", "", true);
ShowCrashReports();