2020-09-07 04:39:00 +00:00
|
|
|
|
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
|
|
|
|
│ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │
|
|
|
|
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
|
|
|
|
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
|
|
|
|
│ │
|
2020-12-28 01:18:44 +00:00
|
|
|
|
│ 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. │
|
2020-09-07 04:39:00 +00:00
|
|
|
|
│ │
|
2020-12-28 01:18:44 +00:00
|
|
|
|
│ 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. │
|
2020-09-07 04:39:00 +00:00
|
|
|
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
2023-05-19 02:05:08 +00:00
|
|
|
|
#include "ape/sections.internal.h"
|
2022-10-17 18:02:04 +00:00
|
|
|
|
#include "libc/assert.h"
|
2022-09-11 18:02:07 +00:00
|
|
|
|
#include "libc/atomic.h"
|
2020-09-07 04:39:00 +00:00
|
|
|
|
#include "libc/calls/calls.h"
|
2022-08-08 18:41:08 +00:00
|
|
|
|
#include "libc/calls/pledge.h"
|
2022-06-09 03:01:28 +00:00
|
|
|
|
#include "libc/calls/struct/dirent.h"
|
2021-05-14 12:36:58 +00:00
|
|
|
|
#include "libc/calls/struct/flock.h"
|
2022-05-23 17:15:53 +00:00
|
|
|
|
#include "libc/calls/struct/iovec.h"
|
2021-04-18 18:34:59 +00:00
|
|
|
|
#include "libc/calls/struct/rusage.h"
|
2021-05-03 18:52:24 +00:00
|
|
|
|
#include "libc/calls/struct/sigaction.h"
|
2022-10-17 18:02:04 +00:00
|
|
|
|
#include "libc/calls/struct/sigset.h"
|
2020-10-06 06:11:49 +00:00
|
|
|
|
#include "libc/calls/struct/stat.h"
|
2022-05-14 11:33:58 +00:00
|
|
|
|
#include "libc/calls/struct/termios.h"
|
2022-10-17 18:02:04 +00:00
|
|
|
|
#include "libc/calls/struct/timespec.h"
|
2023-06-15 00:02:57 +00:00
|
|
|
|
#include "libc/calls/termios.h"
|
2024-08-26 23:44:05 +00:00
|
|
|
|
#include "libc/cosmo.h"
|
2024-07-21 22:54:17 +00:00
|
|
|
|
#include "libc/ctype.h"
|
2022-06-23 20:01:01 +00:00
|
|
|
|
#include "libc/dce.h"
|
2023-06-10 01:02:06 +00:00
|
|
|
|
#include "libc/dos.h"
|
2022-08-07 23:18:33 +00:00
|
|
|
|
#include "libc/errno.h"
|
2020-12-09 23:04:54 +00:00
|
|
|
|
#include "libc/fmt/conv.h"
|
|
|
|
|
#include "libc/fmt/itoa.h"
|
2023-10-03 02:25:19 +00:00
|
|
|
|
#include "libc/fmt/wintime.internal.h"
|
2022-08-12 12:17:06 +00:00
|
|
|
|
#include "libc/intrin/atomic.h"
|
2022-09-13 06:10:38 +00:00
|
|
|
|
#include "libc/intrin/bsr.h"
|
2022-08-12 12:17:06 +00:00
|
|
|
|
#include "libc/intrin/likely.h"
|
2022-04-17 03:29:08 +00:00
|
|
|
|
#include "libc/intrin/nomultics.h"
|
2022-08-12 12:17:06 +00:00
|
|
|
|
#include "libc/intrin/safemacros.h"
|
2022-09-13 06:10:38 +00:00
|
|
|
|
#include "libc/log/appendresourcereport.internal.h"
|
2020-09-07 04:39:00 +00:00
|
|
|
|
#include "libc/log/check.h"
|
|
|
|
|
#include "libc/log/log.h"
|
2022-05-29 15:14:55 +00:00
|
|
|
|
#include "libc/macros.h"
|
2020-10-06 06:11:49 +00:00
|
|
|
|
#include "libc/math.h"
|
2021-05-14 12:36:58 +00:00
|
|
|
|
#include "libc/mem/alloca.h"
|
2022-09-13 06:10:38 +00:00
|
|
|
|
#include "libc/mem/gc.h"
|
2024-06-23 17:08:48 +00:00
|
|
|
|
#include "libc/mem/leaks.h"
|
2022-06-26 01:17:31 +00:00
|
|
|
|
#include "libc/mem/mem.h"
|
2020-10-06 06:11:49 +00:00
|
|
|
|
#include "libc/nexgen32e/crc32.h"
|
2022-04-13 15:49:17 +00:00
|
|
|
|
#include "libc/nexgen32e/rdtsc.h"
|
2022-11-03 16:32:12 +00:00
|
|
|
|
#include "libc/nexgen32e/vendor.internal.h"
|
2022-05-23 17:15:53 +00:00
|
|
|
|
#include "libc/nexgen32e/x86feature.h"
|
2021-05-03 19:09:35 +00:00
|
|
|
|
#include "libc/nt/enum/fileflagandattributes.h"
|
2021-04-18 18:34:59 +00:00
|
|
|
|
#include "libc/runtime/clktck.h"
|
2022-05-29 15:14:55 +00:00
|
|
|
|
#include "libc/runtime/internal.h"
|
2022-08-14 00:20:50 +00:00
|
|
|
|
#include "libc/runtime/memtrack.internal.h"
|
2022-06-26 01:17:31 +00:00
|
|
|
|
#include "libc/runtime/runtime.h"
|
2021-10-14 00:27:13 +00:00
|
|
|
|
#include "libc/runtime/stack.h"
|
2023-12-29 06:58:17 +00:00
|
|
|
|
#include "libc/serialize.h"
|
2021-08-14 13:17:56 +00:00
|
|
|
|
#include "libc/sock/goodsocket.internal.h"
|
2020-09-07 04:39:00 +00:00
|
|
|
|
#include "libc/sock/sock.h"
|
2022-08-06 10:51:50 +00:00
|
|
|
|
#include "libc/sock/struct/pollfd.h"
|
2022-10-17 18:02:04 +00:00
|
|
|
|
#include "libc/sock/struct/sockaddr.h"
|
2022-09-13 06:10:38 +00:00
|
|
|
|
#include "libc/stdio/append.h"
|
2021-08-09 14:00:23 +00:00
|
|
|
|
#include "libc/stdio/hex.internal.h"
|
2022-08-12 12:17:06 +00:00
|
|
|
|
#include "libc/stdio/rand.h"
|
2022-07-09 12:49:19 +00:00
|
|
|
|
#include "libc/stdio/stdio.h"
|
2024-08-17 13:45:35 +00:00
|
|
|
|
#include "libc/str/locale.h"
|
2021-08-14 13:17:56 +00:00
|
|
|
|
#include "libc/str/slice.h"
|
2022-10-17 18:02:04 +00:00
|
|
|
|
#include "libc/str/str.h"
|
2022-09-06 14:04:13 +00:00
|
|
|
|
#include "libc/str/strwidth.h"
|
2020-09-07 04:39:00 +00:00
|
|
|
|
#include "libc/sysv/consts/af.h"
|
2023-07-07 17:00:49 +00:00
|
|
|
|
#include "libc/sysv/consts/auxv.h"
|
2022-10-17 18:02:04 +00:00
|
|
|
|
#include "libc/sysv/consts/clock.h"
|
2022-05-14 11:33:58 +00:00
|
|
|
|
#include "libc/sysv/consts/clone.h"
|
2021-06-24 19:31:26 +00:00
|
|
|
|
#include "libc/sysv/consts/dt.h"
|
2020-09-07 04:39:00 +00:00
|
|
|
|
#include "libc/sysv/consts/ex.h"
|
|
|
|
|
#include "libc/sysv/consts/exit.h"
|
2021-05-14 12:36:58 +00:00
|
|
|
|
#include "libc/sysv/consts/f.h"
|
2023-07-07 17:00:49 +00:00
|
|
|
|
#include "libc/sysv/consts/hwcap.h"
|
2020-09-07 04:39:00 +00:00
|
|
|
|
#include "libc/sysv/consts/inaddr.h"
|
|
|
|
|
#include "libc/sysv/consts/ipproto.h"
|
2022-05-29 15:14:55 +00:00
|
|
|
|
#include "libc/sysv/consts/madv.h"
|
2020-10-06 06:11:49 +00:00
|
|
|
|
#include "libc/sysv/consts/map.h"
|
|
|
|
|
#include "libc/sysv/consts/o.h"
|
2021-06-24 19:31:26 +00:00
|
|
|
|
#include "libc/sysv/consts/poll.h"
|
2022-04-18 07:01:26 +00:00
|
|
|
|
#include "libc/sysv/consts/pr.h"
|
2020-10-06 06:11:49 +00:00
|
|
|
|
#include "libc/sysv/consts/prot.h"
|
2021-04-23 17:45:19 +00:00
|
|
|
|
#include "libc/sysv/consts/rusage.h"
|
2022-06-09 03:01:28 +00:00
|
|
|
|
#include "libc/sysv/consts/s.h"
|
2022-05-14 18:47:16 +00:00
|
|
|
|
#include "libc/sysv/consts/sa.h"
|
2021-06-24 19:31:26 +00:00
|
|
|
|
#include "libc/sysv/consts/sig.h"
|
2020-09-07 04:39:00 +00:00
|
|
|
|
#include "libc/sysv/consts/sock.h"
|
2022-05-14 11:33:58 +00:00
|
|
|
|
#include "libc/sysv/consts/termios.h"
|
2022-10-17 18:02:04 +00:00
|
|
|
|
#include "libc/sysv/consts/timer.h"
|
2021-03-25 09:21:13 +00:00
|
|
|
|
#include "libc/sysv/consts/w.h"
|
2022-04-17 03:29:08 +00:00
|
|
|
|
#include "libc/sysv/errfuns.h"
|
2022-09-11 18:02:07 +00:00
|
|
|
|
#include "libc/thread/thread.h"
|
|
|
|
|
#include "libc/thread/tls.h"
|
2020-09-07 04:39:00 +00:00
|
|
|
|
#include "libc/x/x.h"
|
2022-09-13 06:10:38 +00:00
|
|
|
|
#include "libc/x/xasprintf.h"
|
2023-06-10 01:02:06 +00:00
|
|
|
|
#include "libc/zip.h"
|
2021-03-25 09:21:13 +00:00
|
|
|
|
#include "net/http/escape.h"
|
2020-09-07 04:39:00 +00:00
|
|
|
|
#include "net/http/http.h"
|
2021-04-23 17:45:19 +00:00
|
|
|
|
#include "net/http/ip.h"
|
2022-10-17 18:02:04 +00:00
|
|
|
|
#include "net/http/tokenbucket.h"
|
2022-09-20 02:23:24 +00:00
|
|
|
|
#include "net/http/url.h"
|
2021-07-08 04:44:27 +00:00
|
|
|
|
#include "net/https/https.h"
|
2023-07-03 02:57:43 +00:00
|
|
|
|
#include "third_party/getopt/getopt.internal.h"
|
2022-03-22 02:31:03 +00:00
|
|
|
|
#include "third_party/lua/cosmo.h"
|
2021-03-22 00:27:53 +00:00
|
|
|
|
#include "third_party/lua/lauxlib.h"
|
2022-04-17 03:29:08 +00:00
|
|
|
|
#include "third_party/lua/lrepl.h"
|
2021-03-22 00:27:53 +00:00
|
|
|
|
#include "third_party/lua/lualib.h"
|
2022-06-18 08:10:29 +00:00
|
|
|
|
#include "third_party/lua/lunix.h"
|
2021-06-24 19:31:26 +00:00
|
|
|
|
#include "third_party/mbedtls/ctr_drbg.h"
|
|
|
|
|
#include "third_party/mbedtls/debug.h"
|
2021-07-06 20:39:18 +00:00
|
|
|
|
#include "third_party/mbedtls/iana.h"
|
2022-05-22 15:13:13 +00:00
|
|
|
|
#include "third_party/mbedtls/net_sockets.h"
|
2021-06-24 19:31:26 +00:00
|
|
|
|
#include "third_party/mbedtls/oid.h"
|
|
|
|
|
#include "third_party/mbedtls/san.h"
|
|
|
|
|
#include "third_party/mbedtls/ssl.h"
|
2021-07-12 06:17:47 +00:00
|
|
|
|
#include "third_party/mbedtls/ssl_ticket.h"
|
2021-06-24 19:31:26 +00:00
|
|
|
|
#include "third_party/mbedtls/x509.h"
|
|
|
|
|
#include "third_party/mbedtls/x509_crt.h"
|
2023-12-29 06:58:17 +00:00
|
|
|
|
#include "third_party/musl/netdb.h"
|
2020-10-06 06:11:49 +00:00
|
|
|
|
#include "third_party/zlib/zlib.h"
|
2021-07-12 06:17:47 +00:00
|
|
|
|
#include "tool/build/lib/case.h"
|
2022-07-17 09:40:39 +00:00
|
|
|
|
#include "tool/net/lfinger.h"
|
2022-04-24 16:59:22 +00:00
|
|
|
|
#include "tool/net/lfuncs.h"
|
2022-07-09 18:44:19 +00:00
|
|
|
|
#include "tool/net/ljson.h"
|
2022-07-20 22:13:39 +00:00
|
|
|
|
#include "tool/net/lpath.h"
|
2022-04-13 21:43:42 +00:00
|
|
|
|
#include "tool/net/luacheck.h"
|
2022-04-18 15:54:42 +00:00
|
|
|
|
#include "tool/net/sandbox.h"
|
2020-09-07 04:39:00 +00:00
|
|
|
|
|
2023-09-02 03:49:13 +00:00
|
|
|
|
#pragma GCC diagnostic ignored "-Wunused-variable"
|
|
|
|
|
|
2023-07-26 20:54:49 +00:00
|
|
|
|
__static_yoink("zipos");
|
2023-06-17 14:55:35 +00:00
|
|
|
|
|
2023-07-25 12:43:04 +00:00
|
|
|
|
#ifdef USE_BLINK
|
2023-07-26 20:54:49 +00:00
|
|
|
|
__static_yoink("blink_linux_aarch64"); // for raspberry pi
|
|
|
|
|
__static_yoink("blink_xnu_aarch64"); // is apple silicon
|
2023-06-17 14:55:35 +00:00
|
|
|
|
#endif
|
|
|
|
|
|
2021-06-24 19:31:26 +00:00
|
|
|
|
/**
|
|
|
|
|
* @fileoverview redbean - single-file distributable web server
|
|
|
|
|
*
|
|
|
|
|
* redbean makes it possible to share web applications that run offline
|
|
|
|
|
* as a single-file αcτµαlly pδrταblε εxεcµταblε zip archive which
|
2024-03-03 00:57:56 +00:00
|
|
|
|
* contains your assets.
|
2021-06-24 19:31:26 +00:00
|
|
|
|
*
|
|
|
|
|
* redbean can serve 1 million+ gzip encoded responses per second on a
|
|
|
|
|
* cheap personal computer. That performance is thanks to zip and gzip
|
|
|
|
|
* using the same compression format, which enables kernelspace copies.
|
|
|
|
|
* Another reason redbean goes fast is that it's a tiny static binary,
|
|
|
|
|
* which makes fork memory paging nearly free.
|
|
|
|
|
*
|
|
|
|
|
* redbean is also easy to modify to suit your own needs. The program
|
|
|
|
|
* itself is written as a single .c file. It embeds the Lua programming
|
|
|
|
|
* language and SQLite which let you write dynamic pages.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#ifndef REDBEAN
|
|
|
|
|
#define REDBEAN "redbean"
|
|
|
|
|
#endif
|
|
|
|
|
|
2024-08-17 13:45:35 +00:00
|
|
|
|
// XXYYZZ
|
|
|
|
|
#define VERSION 0x030000
|
2021-03-25 09:21:13 +00:00
|
|
|
|
#define HASH_LOAD_FACTOR /* 1. / */ 4
|
2022-04-20 16:56:53 +00:00
|
|
|
|
#define READ(F, P, N) readv(F, &(struct iovec){P, N}, 1)
|
|
|
|
|
#define WRITE(F, P, N) writev(F, &(struct iovec){P, N}, 1)
|
2021-06-24 19:31:26 +00:00
|
|
|
|
#define AppendCrlf(P) mempcpy(P, "\r\n", 2)
|
2022-08-06 00:34:53 +00:00
|
|
|
|
#define HasHeader(H) (!!cpm.msg.headers[H].a)
|
|
|
|
|
#define HeaderData(H) (inbuf.p + cpm.msg.headers[H].a)
|
|
|
|
|
#define HeaderLength(H) (cpm.msg.headers[H].b - cpm.msg.headers[H].a)
|
2021-04-21 02:14:21 +00:00
|
|
|
|
#define HeaderEqualCase(H, S) \
|
|
|
|
|
SlicesEqualCase(S, strlen(S), HeaderData(H), HeaderLength(H))
|
2024-12-02 22:05:38 +00:00
|
|
|
|
#define LockInc(P) atomic_fetch_add_explicit(P, +1, memory_order_relaxed)
|
|
|
|
|
#define LockDec(P) atomic_fetch_add_explicit(P, -1, memory_order_relaxed)
|
2021-04-18 18:34:59 +00:00
|
|
|
|
|
2022-11-02 05:36:03 +00:00
|
|
|
|
#define TRACE_BEGIN \
|
|
|
|
|
do { \
|
|
|
|
|
if (!IsTiny()) { \
|
|
|
|
|
if (funtrace) { \
|
|
|
|
|
ftrace_enabled(+1); \
|
|
|
|
|
} \
|
|
|
|
|
if (systrace) { \
|
|
|
|
|
strace_enabled(+1); \
|
|
|
|
|
} \
|
|
|
|
|
} \
|
2022-04-29 13:06:23 +00:00
|
|
|
|
} while (0)
|
|
|
|
|
|
2022-11-02 05:36:03 +00:00
|
|
|
|
#define TRACE_END \
|
|
|
|
|
do { \
|
|
|
|
|
if (!IsTiny()) { \
|
|
|
|
|
if (funtrace) { \
|
|
|
|
|
ftrace_enabled(-1); \
|
|
|
|
|
} \
|
|
|
|
|
if (systrace) { \
|
|
|
|
|
strace_enabled(-1); \
|
|
|
|
|
} \
|
|
|
|
|
} \
|
2022-04-29 13:06:23 +00:00
|
|
|
|
} while (0)
|
|
|
|
|
|
2022-07-17 13:11:13 +00:00
|
|
|
|
// letters not used: INOQYnoqwxy
|
2022-04-18 07:01:26 +00:00
|
|
|
|
// digits not used: 0123456789
|
2022-07-09 08:18:55 +00:00
|
|
|
|
// puncts not used: !"#$&'()+,-./;<=>@[\]^_`{|}~
|
2022-07-17 13:11:13 +00:00
|
|
|
|
#define GETOPTS \
|
|
|
|
|
"*%BEJSVXZabdfghijkmsuvzA:C:D:F:G:H:K:L:M:P:R:T:U:W:c:e:l:p:r:t:w:"
|
2022-04-26 04:16:05 +00:00
|
|
|
|
|
2020-10-06 06:11:49 +00:00
|
|
|
|
static const uint8_t kGzipHeader[] = {
|
|
|
|
|
0x1F, // MAGNUM
|
|
|
|
|
0x8B, // MAGNUM
|
|
|
|
|
0x08, // CM: DEFLATE
|
|
|
|
|
0x00, // FLG: NONE
|
|
|
|
|
0x00, // MTIME: NONE
|
|
|
|
|
0x00, //
|
|
|
|
|
0x00, //
|
|
|
|
|
0x00, //
|
|
|
|
|
0x00, // XFL
|
|
|
|
|
kZipOsUnix, // OS
|
|
|
|
|
};
|
|
|
|
|
|
2021-04-21 02:14:21 +00:00
|
|
|
|
static const char *const kIndexPaths[] = {
|
|
|
|
|
#ifndef STATIC
|
|
|
|
|
"index.lua",
|
|
|
|
|
#endif
|
|
|
|
|
"index.html",
|
|
|
|
|
};
|
|
|
|
|
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
static const char *const kAlpn[] = {
|
|
|
|
|
"http/1.1",
|
|
|
|
|
NULL,
|
|
|
|
|
};
|
|
|
|
|
|
2021-03-25 09:21:13 +00:00
|
|
|
|
struct Buffer {
|
2021-04-24 20:58:34 +00:00
|
|
|
|
size_t n, c;
|
2021-03-25 09:21:13 +00:00
|
|
|
|
char *p;
|
|
|
|
|
};
|
|
|
|
|
|
2021-07-09 04:54:21 +00:00
|
|
|
|
struct TlsBio {
|
2021-07-12 06:17:47 +00:00
|
|
|
|
int fd, c;
|
2021-07-09 04:54:21 +00:00
|
|
|
|
unsigned a, b;
|
|
|
|
|
unsigned char t[4000];
|
2021-07-12 06:17:47 +00:00
|
|
|
|
unsigned char u[1430];
|
2021-07-09 04:54:21 +00:00
|
|
|
|
};
|
|
|
|
|
|
2021-03-28 14:54:21 +00:00
|
|
|
|
struct Strings {
|
2021-05-14 12:36:58 +00:00
|
|
|
|
size_t n, c;
|
|
|
|
|
struct String {
|
|
|
|
|
size_t n;
|
|
|
|
|
const char *s;
|
2023-11-18 22:35:57 +00:00
|
|
|
|
} *p;
|
2021-03-28 14:54:21 +00:00
|
|
|
|
};
|
|
|
|
|
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
struct DeflateGenerator {
|
|
|
|
|
int t;
|
|
|
|
|
void *b;
|
|
|
|
|
size_t i;
|
|
|
|
|
uint32_t c;
|
2021-07-19 21:55:20 +00:00
|
|
|
|
uint32_t z;
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
z_stream s;
|
2021-07-12 06:17:47 +00:00
|
|
|
|
struct Asset *a;
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
};
|
|
|
|
|
|
2021-06-24 19:31:26 +00:00
|
|
|
|
static struct Ips {
|
|
|
|
|
size_t n;
|
|
|
|
|
uint32_t *p;
|
|
|
|
|
} ips;
|
|
|
|
|
|
|
|
|
|
static struct Ports {
|
|
|
|
|
size_t n;
|
|
|
|
|
uint16_t *p;
|
|
|
|
|
} ports;
|
|
|
|
|
|
|
|
|
|
static struct Servers {
|
|
|
|
|
size_t n;
|
|
|
|
|
struct Server {
|
|
|
|
|
int fd;
|
|
|
|
|
struct sockaddr_in addr;
|
2023-11-18 22:35:57 +00:00
|
|
|
|
} *p;
|
2021-06-24 19:31:26 +00:00
|
|
|
|
} servers;
|
|
|
|
|
|
2021-03-25 09:21:13 +00:00
|
|
|
|
static struct Freelist {
|
2021-04-18 18:34:59 +00:00
|
|
|
|
size_t n, c;
|
2021-03-25 09:21:13 +00:00
|
|
|
|
void **p;
|
|
|
|
|
} freelist;
|
|
|
|
|
|
2021-04-23 17:45:19 +00:00
|
|
|
|
static struct Unmaplist {
|
|
|
|
|
size_t n, c;
|
|
|
|
|
struct Unmap {
|
|
|
|
|
int f;
|
|
|
|
|
void *p;
|
|
|
|
|
size_t n;
|
2023-11-18 22:35:57 +00:00
|
|
|
|
} *p;
|
2021-04-23 17:45:19 +00:00
|
|
|
|
} unmaplist;
|
|
|
|
|
|
2021-08-09 14:00:23 +00:00
|
|
|
|
static struct Psks {
|
|
|
|
|
size_t n;
|
|
|
|
|
struct Psk {
|
|
|
|
|
char *key;
|
|
|
|
|
size_t key_len;
|
|
|
|
|
char *identity;
|
|
|
|
|
size_t identity_len;
|
|
|
|
|
char *s;
|
2023-11-18 22:35:57 +00:00
|
|
|
|
} *p;
|
2021-08-09 14:00:23 +00:00
|
|
|
|
} psks;
|
|
|
|
|
|
|
|
|
|
static struct Suites {
|
|
|
|
|
size_t n;
|
|
|
|
|
uint16_t *p;
|
|
|
|
|
} suites;
|
|
|
|
|
|
2021-06-24 19:31:26 +00:00
|
|
|
|
static struct Certs {
|
|
|
|
|
size_t n;
|
2021-08-14 13:17:56 +00:00
|
|
|
|
struct Cert *p;
|
2021-06-24 19:31:26 +00:00
|
|
|
|
} certs;
|
|
|
|
|
|
2020-10-06 06:11:49 +00:00
|
|
|
|
static struct Redirects {
|
2021-03-25 09:21:13 +00:00
|
|
|
|
size_t n;
|
2020-10-06 06:11:49 +00:00
|
|
|
|
struct Redirect {
|
2021-03-29 08:22:49 +00:00
|
|
|
|
int code;
|
2021-05-14 12:36:58 +00:00
|
|
|
|
struct String path;
|
|
|
|
|
struct String location;
|
2023-11-18 22:35:57 +00:00
|
|
|
|
} *p;
|
2020-10-06 06:11:49 +00:00
|
|
|
|
} redirects;
|
|
|
|
|
|
|
|
|
|
static struct Assets {
|
|
|
|
|
uint32_t n;
|
|
|
|
|
struct Asset {
|
2021-04-18 18:34:59 +00:00
|
|
|
|
bool istext;
|
2020-10-06 06:11:49 +00:00
|
|
|
|
uint32_t hash;
|
2021-04-18 18:34:59 +00:00
|
|
|
|
uint64_t cf;
|
|
|
|
|
uint64_t lf;
|
2020-10-06 06:11:49 +00:00
|
|
|
|
int64_t lastmodified;
|
|
|
|
|
char *lastmodifiedstr;
|
2021-03-28 14:54:21 +00:00
|
|
|
|
struct File {
|
2021-05-14 12:36:58 +00:00
|
|
|
|
struct String path;
|
2021-03-28 14:54:21 +00:00
|
|
|
|
struct stat st;
|
2023-11-18 22:35:57 +00:00
|
|
|
|
} *file;
|
|
|
|
|
} *p;
|
2020-10-06 06:11:49 +00:00
|
|
|
|
} assets;
|
|
|
|
|
|
2022-10-17 18:02:04 +00:00
|
|
|
|
static struct TrustedIps {
|
2022-09-17 08:37:33 +00:00
|
|
|
|
size_t n;
|
2022-10-17 18:02:04 +00:00
|
|
|
|
struct TrustedIp {
|
2022-09-17 08:37:33 +00:00
|
|
|
|
uint32_t ip;
|
|
|
|
|
uint32_t mask;
|
2023-11-18 22:35:57 +00:00
|
|
|
|
} *p;
|
2022-10-17 18:02:04 +00:00
|
|
|
|
} trustedips;
|
|
|
|
|
|
|
|
|
|
struct TokenBucket {
|
|
|
|
|
signed char cidr;
|
|
|
|
|
signed char reject;
|
|
|
|
|
signed char ignore;
|
|
|
|
|
signed char ban;
|
|
|
|
|
struct timespec replenish;
|
|
|
|
|
union {
|
|
|
|
|
atomic_schar *b;
|
|
|
|
|
atomic_uint_fast64_t *w;
|
|
|
|
|
};
|
|
|
|
|
} tokenbucket;
|
|
|
|
|
|
|
|
|
|
struct Blackhole {
|
|
|
|
|
struct sockaddr_un addr;
|
|
|
|
|
int fd;
|
|
|
|
|
} blackhole;
|
2022-09-17 08:37:33 +00:00
|
|
|
|
|
2021-03-29 08:22:49 +00:00
|
|
|
|
static struct Shared {
|
2024-12-02 22:05:38 +00:00
|
|
|
|
_Atomic(int) workers;
|
2022-08-06 02:24:05 +00:00
|
|
|
|
struct timespec lastmeltdown;
|
2024-12-02 22:05:38 +00:00
|
|
|
|
struct timespec nowish;
|
2021-04-23 17:45:19 +00:00
|
|
|
|
char currentdate[32];
|
|
|
|
|
struct rusage server;
|
|
|
|
|
struct rusage children;
|
2021-05-03 19:09:35 +00:00
|
|
|
|
struct Counters {
|
2024-12-02 22:05:38 +00:00
|
|
|
|
#define C(x) _Atomic(long) x;
|
2021-05-03 19:09:35 +00:00
|
|
|
|
#include "tool/net/counters.inc"
|
|
|
|
|
#undef C
|
|
|
|
|
} c;
|
2024-12-02 22:05:38 +00:00
|
|
|
|
pthread_mutex_t datetime_mu;
|
|
|
|
|
pthread_mutex_t server_mu;
|
|
|
|
|
pthread_mutex_t children_mu;
|
|
|
|
|
pthread_mutex_t lastmeltdown_mu;
|
2023-11-18 22:35:57 +00:00
|
|
|
|
} *shared;
|
2021-03-29 08:22:49 +00:00
|
|
|
|
|
2021-05-03 19:09:35 +00:00
|
|
|
|
static const char kCounterNames[] =
|
|
|
|
|
#define C(x) #x "\0"
|
|
|
|
|
#include "tool/net/counters.inc"
|
|
|
|
|
#undef C
|
|
|
|
|
;
|
|
|
|
|
|
2021-06-24 19:31:26 +00:00
|
|
|
|
typedef ssize_t (*reader_f)(int, void *, size_t);
|
|
|
|
|
typedef ssize_t (*writer_f)(int, struct iovec *, int);
|
|
|
|
|
|
2022-08-06 00:34:53 +00:00
|
|
|
|
struct ClearedPerMessage {
|
|
|
|
|
bool istext;
|
|
|
|
|
bool branded;
|
|
|
|
|
bool hascontenttype;
|
|
|
|
|
bool gotcachecontrol;
|
|
|
|
|
bool gotxcontenttypeoptions;
|
|
|
|
|
int frags;
|
|
|
|
|
int statuscode;
|
|
|
|
|
int isyielding;
|
|
|
|
|
char *outbuf;
|
|
|
|
|
char *content;
|
2022-08-22 05:26:41 +00:00
|
|
|
|
size_t gzipped;
|
2022-08-06 00:34:53 +00:00
|
|
|
|
size_t contentlength;
|
|
|
|
|
char *luaheaderp;
|
|
|
|
|
const char *referrerpolicy;
|
|
|
|
|
size_t msgsize;
|
|
|
|
|
ssize_t (*generator)(struct iovec[3]);
|
|
|
|
|
struct Strings loops;
|
|
|
|
|
struct HttpMessage msg;
|
|
|
|
|
} cpm;
|
|
|
|
|
|
2021-06-24 19:31:26 +00:00
|
|
|
|
static bool suiteb;
|
2020-10-06 06:11:49 +00:00
|
|
|
|
static bool killed;
|
2021-03-25 09:21:13 +00:00
|
|
|
|
static bool zombied;
|
2022-05-29 15:14:55 +00:00
|
|
|
|
static bool usingssl;
|
2021-04-24 20:58:34 +00:00
|
|
|
|
static bool funtrace;
|
2022-04-18 07:01:26 +00:00
|
|
|
|
static bool systrace;
|
2021-03-25 09:21:13 +00:00
|
|
|
|
static bool meltdown;
|
2022-05-18 23:41:29 +00:00
|
|
|
|
static bool unsecure;
|
2022-05-29 15:14:55 +00:00
|
|
|
|
static bool norsagen;
|
2021-02-27 18:47:19 +00:00
|
|
|
|
static bool printport;
|
2020-10-06 06:11:49 +00:00
|
|
|
|
static bool daemonize;
|
2021-04-23 17:45:19 +00:00
|
|
|
|
static bool logrusage;
|
2021-03-28 07:10:17 +00:00
|
|
|
|
static bool logbodies;
|
2022-05-29 15:14:55 +00:00
|
|
|
|
static bool requiressl;
|
2021-07-08 04:44:27 +00:00
|
|
|
|
static bool sslcliused;
|
2021-04-23 17:45:19 +00:00
|
|
|
|
static bool loglatency;
|
2020-10-06 06:11:49 +00:00
|
|
|
|
static bool terminated;
|
|
|
|
|
static bool uniprocess;
|
|
|
|
|
static bool invalidated;
|
|
|
|
|
static bool logmessages;
|
2021-08-09 21:45:52 +00:00
|
|
|
|
static bool isinitialized;
|
2022-03-15 00:11:05 +00:00
|
|
|
|
static bool sslinitialized;
|
2021-07-08 04:44:27 +00:00
|
|
|
|
static bool sslfetchverify;
|
2022-07-09 08:18:55 +00:00
|
|
|
|
static bool selfmodifiable;
|
2022-04-25 15:30:14 +00:00
|
|
|
|
static bool interpretermode;
|
2021-07-08 04:44:27 +00:00
|
|
|
|
static bool sslclientverify;
|
2021-03-25 09:21:13 +00:00
|
|
|
|
static bool connectionclose;
|
2022-07-19 03:17:14 +00:00
|
|
|
|
static bool hasonloglatency;
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
static bool hasonworkerstop;
|
2022-04-17 03:29:08 +00:00
|
|
|
|
static bool isexitingworker;
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
static bool hasonworkerstart;
|
2022-04-13 15:49:17 +00:00
|
|
|
|
static bool leakcrashreports;
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
static bool hasonhttprequest;
|
2024-02-14 09:55:50 +00:00
|
|
|
|
static bool hasonerror;
|
2021-08-09 21:45:52 +00:00
|
|
|
|
static bool ishandlingrequest;
|
2021-06-24 19:31:26 +00:00
|
|
|
|
static bool listeningonport443;
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
static bool hasonprocesscreate;
|
|
|
|
|
static bool hasonprocessdestroy;
|
2021-08-09 21:45:52 +00:00
|
|
|
|
static bool ishandlingconnection;
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
static bool hasonclientconnection;
|
2021-07-19 21:55:20 +00:00
|
|
|
|
static bool evadedragnetsurveillance;
|
2020-10-06 06:11:49 +00:00
|
|
|
|
|
2021-05-03 19:09:35 +00:00
|
|
|
|
static int zfd;
|
2020-10-06 06:11:49 +00:00
|
|
|
|
static int gmtoff;
|
|
|
|
|
static int client;
|
2022-05-14 11:33:58 +00:00
|
|
|
|
static int mainpid;
|
2022-04-18 15:54:42 +00:00
|
|
|
|
static int sandboxed;
|
2021-07-08 22:56:23 +00:00
|
|
|
|
static int changeuid;
|
|
|
|
|
static int changegid;
|
2022-08-05 22:21:27 +00:00
|
|
|
|
static int maxworkers;
|
2022-04-13 05:11:00 +00:00
|
|
|
|
static int shutdownsig;
|
2022-03-15 00:11:05 +00:00
|
|
|
|
static int sslpskindex;
|
2021-07-08 22:56:23 +00:00
|
|
|
|
static int oldloglevel;
|
2021-04-23 17:45:19 +00:00
|
|
|
|
static int messageshandled;
|
2021-07-19 21:55:20 +00:00
|
|
|
|
static int sslticketlifetime;
|
2020-10-06 06:11:49 +00:00
|
|
|
|
static uint32_t clientaddrsize;
|
|
|
|
|
|
2023-09-02 03:49:13 +00:00
|
|
|
|
static char *brand;
|
2021-03-28 14:54:21 +00:00
|
|
|
|
static size_t zsize;
|
2022-04-13 21:43:42 +00:00
|
|
|
|
static lua_State *GL;
|
|
|
|
|
static lua_State *YL;
|
2021-03-28 07:10:17 +00:00
|
|
|
|
static uint8_t *zmap;
|
2021-05-02 18:50:43 +00:00
|
|
|
|
static uint8_t *zcdir;
|
2021-03-27 14:29:55 +00:00
|
|
|
|
static size_t hdrsize;
|
2021-03-25 09:21:13 +00:00
|
|
|
|
static size_t amtread;
|
2021-06-24 19:31:26 +00:00
|
|
|
|
static reader_f reader;
|
|
|
|
|
static writer_f writer;
|
2021-04-23 17:45:19 +00:00
|
|
|
|
static char *extrahdrs;
|
2021-05-02 18:50:43 +00:00
|
|
|
|
static const char *zpath;
|
2023-09-02 03:49:13 +00:00
|
|
|
|
static char *serverheader;
|
2021-06-24 19:31:26 +00:00
|
|
|
|
static char gzip_footer[8];
|
2022-07-08 13:29:24 +00:00
|
|
|
|
static long maxpayloadsize;
|
2020-10-06 06:11:49 +00:00
|
|
|
|
static const char *pidpath;
|
|
|
|
|
static const char *logpath;
|
2022-10-17 18:02:04 +00:00
|
|
|
|
static uint32_t *interfaces;
|
2021-06-24 19:31:26 +00:00
|
|
|
|
static struct pollfd *polls;
|
2021-07-05 08:03:45 +00:00
|
|
|
|
static size_t payloadlength;
|
2021-03-25 09:21:13 +00:00
|
|
|
|
static int64_t cacheseconds;
|
2023-09-02 03:49:13 +00:00
|
|
|
|
static char *cachedirective;
|
2021-03-29 09:39:20 +00:00
|
|
|
|
static struct Strings stagedirs;
|
|
|
|
|
static struct Strings hidepaths;
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
static const char *launchbrowser;
|
2022-08-23 05:02:58 +00:00
|
|
|
|
static const char ctIdx = 'c'; // a pseudo variable to get address of
|
2021-03-25 09:21:13 +00:00
|
|
|
|
|
2022-03-18 09:33:37 +00:00
|
|
|
|
static struct Buffer inbuf_actual;
|
2021-03-25 09:21:13 +00:00
|
|
|
|
static struct Buffer inbuf;
|
2021-06-24 19:31:26 +00:00
|
|
|
|
static struct Buffer oldin;
|
2021-03-25 09:21:13 +00:00
|
|
|
|
static struct Buffer hdrbuf;
|
2021-04-23 17:45:19 +00:00
|
|
|
|
static struct timeval timeout;
|
|
|
|
|
static struct Buffer effectivepath;
|
2022-08-06 02:24:05 +00:00
|
|
|
|
static struct timespec heartbeatinterval;
|
2020-10-06 06:11:49 +00:00
|
|
|
|
|
2021-04-21 02:14:21 +00:00
|
|
|
|
static struct Url url;
|
|
|
|
|
|
2021-05-02 18:50:43 +00:00
|
|
|
|
static struct stat zst;
|
2022-08-06 02:24:05 +00:00
|
|
|
|
static struct timespec startread;
|
|
|
|
|
static struct timespec lastrefresh;
|
|
|
|
|
static struct timespec startserver;
|
|
|
|
|
static struct timespec startrequest;
|
|
|
|
|
static struct timespec lastheartbeat;
|
|
|
|
|
static struct timespec startconnection;
|
2020-10-06 06:11:49 +00:00
|
|
|
|
static struct sockaddr_in clientaddr;
|
2021-06-24 19:31:26 +00:00
|
|
|
|
static struct sockaddr_in *serveraddr;
|
2020-10-06 06:11:49 +00:00
|
|
|
|
|
2021-07-08 04:44:27 +00:00
|
|
|
|
static mbedtls_ssl_config conf;
|
|
|
|
|
static mbedtls_ssl_context ssl;
|
|
|
|
|
static mbedtls_ctr_drbg_context rng;
|
2021-07-12 06:17:47 +00:00
|
|
|
|
static mbedtls_ssl_ticket_context ssltick;
|
2021-07-08 04:44:27 +00:00
|
|
|
|
|
|
|
|
|
static mbedtls_ssl_config confcli;
|
|
|
|
|
static mbedtls_ssl_context sslcli;
|
|
|
|
|
static mbedtls_ctr_drbg_context rngcli;
|
|
|
|
|
|
2021-07-09 04:54:21 +00:00
|
|
|
|
static struct TlsBio g_bio;
|
2021-07-08 04:44:27 +00:00
|
|
|
|
static char slashpath[PATH_MAX];
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
static struct DeflateGenerator dg;
|
2021-07-08 04:44:27 +00:00
|
|
|
|
|
2021-05-03 19:09:35 +00:00
|
|
|
|
static char *Route(const char *, size_t, const char *, size_t);
|
|
|
|
|
static char *RouteHost(const char *, size_t, const char *, size_t);
|
|
|
|
|
static char *RoutePath(const char *, size_t);
|
|
|
|
|
static char *HandleAsset(struct Asset *, const char *, size_t);
|
|
|
|
|
static char *ServeAsset(struct Asset *, const char *, size_t);
|
|
|
|
|
static char *SetStatus(unsigned, const char *);
|
|
|
|
|
|
2022-03-15 00:11:05 +00:00
|
|
|
|
static void TlsInit(void);
|
|
|
|
|
|
2021-03-25 09:21:13 +00:00
|
|
|
|
static void OnChld(void) {
|
|
|
|
|
zombied = true;
|
2020-10-06 06:11:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-03-25 09:21:13 +00:00
|
|
|
|
static void OnUsr1(void) {
|
|
|
|
|
invalidated = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void OnUsr2(void) {
|
|
|
|
|
meltdown = true;
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-13 05:11:00 +00:00
|
|
|
|
static void OnTerm(int sig) {
|
2021-03-25 09:21:13 +00:00
|
|
|
|
if (!terminated) {
|
2022-04-13 05:11:00 +00:00
|
|
|
|
shutdownsig = sig;
|
2020-10-06 06:11:49 +00:00
|
|
|
|
terminated = true;
|
2021-03-25 09:21:13 +00:00
|
|
|
|
} else {
|
|
|
|
|
killed = true;
|
2020-10-06 06:11:49 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-13 05:11:00 +00:00
|
|
|
|
static void OnInt(int sig) {
|
|
|
|
|
OnTerm(sig);
|
2020-10-06 06:11:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-04-13 05:11:00 +00:00
|
|
|
|
static void OnHup(int sig) {
|
2021-03-25 09:21:13 +00:00
|
|
|
|
if (daemonize) {
|
|
|
|
|
OnUsr1();
|
|
|
|
|
} else {
|
2022-04-13 05:11:00 +00:00
|
|
|
|
OnTerm(sig);
|
2021-03-25 09:21:13 +00:00
|
|
|
|
}
|
2020-10-06 06:11:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-03-18 09:33:37 +00:00
|
|
|
|
static void Free(void *p) {
|
|
|
|
|
free(*(void **)p);
|
|
|
|
|
*(void **)p = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-12 06:17:47 +00:00
|
|
|
|
static long ParseInt(const char *s) {
|
|
|
|
|
return strtol(s, 0, 0);
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-23 17:45:19 +00:00
|
|
|
|
static void *FreeLater(void *p) {
|
|
|
|
|
if (p) {
|
|
|
|
|
if (++freelist.n > freelist.c) {
|
2021-05-14 12:36:58 +00:00
|
|
|
|
freelist.c = freelist.n + (freelist.n >> 1);
|
2021-04-23 17:45:19 +00:00
|
|
|
|
freelist.p = xrealloc(freelist.p, freelist.c * sizeof(*freelist.p));
|
|
|
|
|
}
|
|
|
|
|
freelist.p[freelist.n - 1] = p;
|
|
|
|
|
}
|
|
|
|
|
return p;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void UnmapLater(int f, void *p, size_t n) {
|
|
|
|
|
if (++unmaplist.n > unmaplist.c) {
|
2021-05-14 12:36:58 +00:00
|
|
|
|
unmaplist.c = unmaplist.n + (unmaplist.n >> 1);
|
2021-04-23 17:45:19 +00:00
|
|
|
|
unmaplist.p = xrealloc(unmaplist.p, unmaplist.c * sizeof(*unmaplist.p));
|
|
|
|
|
}
|
|
|
|
|
unmaplist.p[unmaplist.n - 1].f = f;
|
|
|
|
|
unmaplist.p[unmaplist.n - 1].p = p;
|
|
|
|
|
unmaplist.p[unmaplist.n - 1].n = n;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void CollectGarbage(void) {
|
2021-07-08 22:56:23 +00:00
|
|
|
|
__log_level = oldloglevel;
|
2022-08-06 00:34:53 +00:00
|
|
|
|
DestroyHttpMessage(&cpm.msg);
|
2021-04-23 17:45:19 +00:00
|
|
|
|
while (freelist.n) {
|
|
|
|
|
free(freelist.p[--freelist.n]);
|
|
|
|
|
}
|
|
|
|
|
while (unmaplist.n) {
|
|
|
|
|
--unmaplist.n;
|
|
|
|
|
LOGIFNEG1(munmap(unmaplist.p[unmaplist.n].p, unmaplist.p[unmaplist.n].n));
|
|
|
|
|
LOGIFNEG1(close(unmaplist.p[unmaplist.n].f));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void UseOutput(void) {
|
2022-08-06 00:34:53 +00:00
|
|
|
|
cpm.content = FreeLater(cpm.outbuf);
|
|
|
|
|
cpm.contentlength = appendz(cpm.outbuf).i;
|
|
|
|
|
cpm.outbuf = 0;
|
2021-04-23 17:45:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void DropOutput(void) {
|
2022-08-06 00:34:53 +00:00
|
|
|
|
FreeLater(cpm.outbuf);
|
|
|
|
|
cpm.outbuf = 0;
|
2021-04-23 17:45:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-12-18 10:22:58 +00:00
|
|
|
|
static bool ShouldAvoidGzip(void) {
|
2023-01-18 08:56:09 +00:00
|
|
|
|
return (IsGenuineBlink() && !X86_HAVE(JIT));
|
2022-12-18 10:22:58 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-04-21 02:14:21 +00:00
|
|
|
|
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;
|
|
|
|
|
r = xmalloc(n + 1 + m + 1);
|
|
|
|
|
mempcpy(mempcpy(mempcpy(mempcpy(r, p, n), "/", 1), q, m), "", 1);
|
|
|
|
|
if (z)
|
|
|
|
|
*z = n + 1 + m;
|
|
|
|
|
return r;
|
2021-04-18 18:34:59 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-05-14 12:36:58 +00:00
|
|
|
|
static long FindRedirect(const char *s, size_t n) {
|
2023-09-02 03:49:13 +00:00
|
|
|
|
int c, m, l, r;
|
2020-10-06 06:11:49 +00:00
|
|
|
|
l = 0;
|
2021-03-25 09:21:13 +00:00
|
|
|
|
r = redirects.n - 1;
|
2020-10-06 06:11:49 +00:00
|
|
|
|
while (l <= r) {
|
2023-07-10 17:16:55 +00:00
|
|
|
|
m = (l & r) + ((l ^ r) >> 1); // floor((a+b)/2)
|
2021-05-14 12:36:58 +00:00
|
|
|
|
c = CompareSlices(redirects.p[m].path.s, redirects.p[m].path.n, s, n);
|
2020-10-06 06:11:49 +00:00
|
|
|
|
if (c < 0) {
|
|
|
|
|
l = m + 1;
|
|
|
|
|
} else if (c > 0) {
|
|
|
|
|
r = m - 1;
|
|
|
|
|
} else {
|
2021-03-25 09:21:13 +00:00
|
|
|
|
return m;
|
2020-10-06 06:11:49 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2021-03-25 09:21:13 +00:00
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-24 19:31:26 +00:00
|
|
|
|
static mbedtls_x509_crt *GetTrustedCertificate(mbedtls_x509_name *name) {
|
|
|
|
|
size_t i;
|
|
|
|
|
for (i = 0; i < certs.n; ++i) {
|
|
|
|
|
if (certs.p[i].cert &&
|
|
|
|
|
!mbedtls_x509_name_cmp(name, &certs.p[i].cert->subject)) {
|
|
|
|
|
return certs.p[i].cert;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-06 21:12:11 +00:00
|
|
|
|
static void UseCertificate(mbedtls_ssl_config *c, struct Cert *kp,
|
|
|
|
|
const char *role) {
|
2021-08-22 22:01:52 +00:00
|
|
|
|
VERBOSEF("(ssl) using %s certificate %`'s for HTTPS %s",
|
2021-08-06 21:12:11 +00:00
|
|
|
|
mbedtls_pk_get_name(&kp->cert->pk),
|
2024-01-08 18:07:35 +00:00
|
|
|
|
gc(FormatX509Name(&kp->cert->subject)), role);
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
CHECK_EQ(0, mbedtls_ssl_conf_own_cert(c, kp->cert, kp->key));
|
2021-06-24 19:31:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
static void AppendCert(mbedtls_x509_crt *cert, mbedtls_pk_context *key) {
|
|
|
|
|
certs.p = realloc(certs.p, ++certs.n * sizeof(*certs.p));
|
|
|
|
|
certs.p[certs.n - 1].cert = cert;
|
|
|
|
|
certs.p[certs.n - 1].key = key;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-09 00:28:44 +00:00
|
|
|
|
static void InternCertificate(mbedtls_x509_crt *cert, mbedtls_x509_crt *prev) {
|
2021-06-24 19:31:26 +00:00
|
|
|
|
int r;
|
|
|
|
|
size_t i;
|
|
|
|
|
if (cert->next)
|
|
|
|
|
InternCertificate(cert->next, cert);
|
2021-07-09 00:28:44 +00:00
|
|
|
|
if (prev) {
|
|
|
|
|
if (mbedtls_x509_crt_check_parent(prev, cert, 1)) {
|
2021-09-07 18:40:11 +00:00
|
|
|
|
DEBUGF("(ssl) unbundling %`'s from %`'s",
|
2024-01-08 18:07:35 +00:00
|
|
|
|
gc(FormatX509Name(&prev->subject)),
|
|
|
|
|
gc(FormatX509Name(&cert->subject)));
|
2021-07-09 00:28:44 +00:00
|
|
|
|
prev->next = 0;
|
|
|
|
|
} else if ((r = mbedtls_x509_crt_check_signature(prev, cert, 0))) {
|
2021-08-22 22:01:52 +00:00
|
|
|
|
WARNF("(ssl) invalid signature for %`'s -> %`'s (-0x%04x)",
|
2024-01-08 18:07:35 +00:00
|
|
|
|
gc(FormatX509Name(&prev->subject)),
|
|
|
|
|
gc(FormatX509Name(&cert->subject)), -r);
|
2021-06-24 19:31:26 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (mbedtls_x509_time_is_past(&cert->valid_to)) {
|
2022-03-18 09:33:37 +00:00
|
|
|
|
WARNF("(ssl) certificate %`'s is expired",
|
2024-01-08 18:07:35 +00:00
|
|
|
|
gc(FormatX509Name(&cert->subject)));
|
2021-06-24 19:31:26 +00:00
|
|
|
|
} else if (mbedtls_x509_time_is_future(&cert->valid_from)) {
|
2022-03-15 00:11:05 +00:00
|
|
|
|
WARNF("(ssl) certificate %`'s is from the future",
|
2024-01-08 18:07:35 +00:00
|
|
|
|
gc(FormatX509Name(&cert->subject)));
|
2021-06-24 19:31:26 +00:00
|
|
|
|
}
|
|
|
|
|
for (i = 0; i < certs.n; ++i) {
|
|
|
|
|
if (!certs.p[i].cert && certs.p[i].key &&
|
|
|
|
|
!mbedtls_pk_check_pair(&cert->pk, certs.p[i].key)) {
|
|
|
|
|
certs.p[i].cert = cert;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
LogCertificate("loaded certificate", cert);
|
2021-07-19 21:55:20 +00:00
|
|
|
|
if (!cert->next && !IsSelfSigned(cert) && cert->max_pathlen) {
|
2021-06-24 19:31:26 +00:00
|
|
|
|
for (i = 0; i < certs.n; ++i) {
|
|
|
|
|
if (!certs.p[i].cert)
|
|
|
|
|
continue;
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
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)) {
|
2021-06-24 19:31:26 +00:00
|
|
|
|
if (ChainCertificate(cert, certs.p[i].cert))
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
if (!IsSelfSigned(cert)) {
|
|
|
|
|
for (i = 0; i < certs.n; ++i) {
|
|
|
|
|
if (!certs.p[i].cert)
|
|
|
|
|
continue;
|
|
|
|
|
if (certs.p[i].cert->next)
|
|
|
|
|
continue;
|
2021-07-19 21:55:20 +00:00
|
|
|
|
if (certs.p[i].cert->max_pathlen &&
|
|
|
|
|
mbedtls_pk_can_do(&certs.p[i].cert->pk, cert->sig_pk) &&
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
!mbedtls_x509_crt_check_parent(certs.p[i].cert, cert, 1)) {
|
|
|
|
|
ChainCertificate(certs.p[i].cert, cert);
|
|
|
|
|
}
|
2021-06-24 19:31:26 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
AppendCert(cert, 0);
|
2021-06-24 19:31:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void ProgramCertificate(const char *p, size_t n) {
|
|
|
|
|
int rc;
|
|
|
|
|
unsigned char *waqapi;
|
|
|
|
|
mbedtls_x509_crt *cert;
|
|
|
|
|
waqapi = malloc(n + 1);
|
|
|
|
|
memcpy(waqapi, p, n);
|
|
|
|
|
waqapi[n] = 0;
|
|
|
|
|
cert = calloc(1, sizeof(mbedtls_x509_crt));
|
|
|
|
|
rc = mbedtls_x509_crt_parse(cert, waqapi, n + 1);
|
|
|
|
|
mbedtls_platform_zeroize(waqapi, n);
|
|
|
|
|
free(waqapi);
|
|
|
|
|
if (rc < 0) {
|
2021-08-22 22:01:52 +00:00
|
|
|
|
WARNF("(ssl) failed to load certificate (grep -0x%04x)", rc);
|
2021-06-24 19:31:26 +00:00
|
|
|
|
return;
|
|
|
|
|
} else if (rc > 0) {
|
2021-08-22 22:01:52 +00:00
|
|
|
|
VERBOSEF("(ssl) certificate bundle partially loaded");
|
2021-06-24 19:31:26 +00:00
|
|
|
|
}
|
|
|
|
|
InternCertificate(cert, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void ProgramPrivateKey(const char *p, size_t n) {
|
|
|
|
|
int rc;
|
|
|
|
|
size_t i;
|
|
|
|
|
unsigned char *waqapi;
|
|
|
|
|
mbedtls_pk_context *key;
|
|
|
|
|
waqapi = malloc(n + 1);
|
|
|
|
|
memcpy(waqapi, p, n);
|
|
|
|
|
waqapi[n] = 0;
|
|
|
|
|
key = calloc(1, sizeof(mbedtls_pk_context));
|
|
|
|
|
rc = mbedtls_pk_parse_key(key, waqapi, n + 1, 0, 0);
|
|
|
|
|
mbedtls_platform_zeroize(waqapi, n);
|
|
|
|
|
free(waqapi);
|
2022-06-27 04:25:02 +00:00
|
|
|
|
if (rc != 0)
|
|
|
|
|
FATALF("(ssl) error: load key (grep -0x%04x)", -rc);
|
2021-06-24 19:31:26 +00:00
|
|
|
|
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)) {
|
|
|
|
|
certs.p[i].key = key;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-08-22 22:01:52 +00:00
|
|
|
|
VERBOSEF("(ssl) loaded private key");
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
AppendCert(0, key);
|
2021-06-24 19:31:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void ProgramFile(const char *path, void program(const char *, size_t)) {
|
|
|
|
|
char *p;
|
|
|
|
|
size_t n;
|
2021-08-22 22:01:52 +00:00
|
|
|
|
DEBUGF("(srvr) ProgramFile(%`'s)", path);
|
2021-06-24 19:31:26 +00:00
|
|
|
|
if ((p = xslurp(path, &n))) {
|
|
|
|
|
program(p, n);
|
|
|
|
|
mbedtls_platform_zeroize(p, n);
|
|
|
|
|
free(p);
|
|
|
|
|
} else {
|
2022-06-27 04:25:02 +00:00
|
|
|
|
FATALF("(srvr) error: failed to read file %`'s", path);
|
2021-06-24 19:31:26 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void ProgramPort(long port) {
|
|
|
|
|
if (!(0 <= port && port <= 65535)) {
|
2022-06-27 04:25:02 +00:00
|
|
|
|
FATALF("(cfg) error: bad port: %d", port);
|
2021-06-24 19:31:26 +00:00
|
|
|
|
}
|
|
|
|
|
if (port == 443)
|
|
|
|
|
listeningonport443 = true;
|
|
|
|
|
ports.p = realloc(ports.p, ++ports.n * sizeof(*ports.p));
|
|
|
|
|
ports.p[ports.n - 1] = port;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-12 06:17:47 +00:00
|
|
|
|
static void ProgramMaxPayloadSize(long x) {
|
|
|
|
|
maxpayloadsize = MAX(1450, x);
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-19 21:55:20 +00:00
|
|
|
|
static void ProgramSslTicketLifetime(long x) {
|
|
|
|
|
sslticketlifetime = x;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-04 19:21:29 +00:00
|
|
|
|
static void ProgramAddr(const char *addr) {
|
2022-06-24 00:59:35 +00:00
|
|
|
|
ssize_t rc;
|
|
|
|
|
int64_t ip;
|
|
|
|
|
if ((ip = ParseIp(addr, -1)) == -1) {
|
|
|
|
|
if (!IsTiny()) {
|
|
|
|
|
struct addrinfo *ai = NULL;
|
|
|
|
|
struct addrinfo hint = {AI_NUMERICSERV, AF_INET, SOCK_STREAM,
|
|
|
|
|
IPPROTO_TCP};
|
2023-12-29 06:58:17 +00:00
|
|
|
|
if ((rc = getaddrinfo(addr, "0", &hint, &ai)) != 0) {
|
2022-06-27 04:25:02 +00:00
|
|
|
|
FATALF("(cfg) error: bad addr: %s (EAI_%s)", addr, gai_strerror(rc));
|
2022-06-24 00:59:35 +00:00
|
|
|
|
}
|
2023-12-29 06:58:17 +00:00
|
|
|
|
ip = ntohl(((struct sockaddr_in *)ai->ai_addr)->sin_addr.s_addr);
|
2022-06-24 00:59:35 +00:00
|
|
|
|
freeaddrinfo(ai);
|
|
|
|
|
} else {
|
2022-06-27 04:25:02 +00:00
|
|
|
|
FATALF("(cfg) error: ProgramAddr() needs an IP in MODE=tiny: %s", addr);
|
2022-06-24 00:59:35 +00:00
|
|
|
|
}
|
2021-07-04 19:21:29 +00:00
|
|
|
|
}
|
|
|
|
|
ips.p = realloc(ips.p, ++ips.n * sizeof(*ips.p));
|
|
|
|
|
ips.p[ips.n - 1] = ip;
|
2021-06-24 19:31:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-05-14 12:36:58 +00:00
|
|
|
|
static void ProgramRedirect(int code, const char *sp, size_t sn, const char *dp,
|
|
|
|
|
size_t dn) {
|
2021-03-25 09:21:13 +00:00
|
|
|
|
long i, j;
|
|
|
|
|
struct Redirect r;
|
2021-03-29 08:22:49 +00:00
|
|
|
|
if (code && code != 301 && code != 302 && code != 307 && code != 308) {
|
2022-06-27 04:25:02 +00:00
|
|
|
|
FATALF("(cfg) error: unsupported redirect code %d", code);
|
2021-03-29 08:22:49 +00:00
|
|
|
|
}
|
2021-08-19 16:34:50 +00:00
|
|
|
|
|
|
|
|
|
if (!(FreeLater(EncodeHttpHeaderValue(dp, dn, 0)))) {
|
2022-06-27 04:25:02 +00:00
|
|
|
|
FATALF("(cfg) error: invalid location %s", dp);
|
2021-08-19 16:34:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-03-29 08:22:49 +00:00
|
|
|
|
r.code = code;
|
2021-05-14 12:36:58 +00:00
|
|
|
|
r.path.s = sp;
|
|
|
|
|
r.path.n = sn;
|
|
|
|
|
r.location.s = dp;
|
|
|
|
|
r.location.n = dn;
|
|
|
|
|
if ((i = FindRedirect(r.path.s, r.path.n)) != -1) {
|
2021-03-25 09:21:13 +00:00
|
|
|
|
redirects.p[i] = r;
|
|
|
|
|
} else {
|
|
|
|
|
i = redirects.n;
|
|
|
|
|
redirects.p = xrealloc(redirects.p, (i + 1) * sizeof(*redirects.p));
|
2021-04-02 01:51:12 +00:00
|
|
|
|
for (j = i; j; --j) {
|
2021-05-14 12:36:58 +00:00
|
|
|
|
if (CompareSlices(r.path.s, r.path.n, redirects.p[j - 1].path.s,
|
|
|
|
|
redirects.p[j - 1].path.n) < 0) {
|
2021-03-25 09:21:13 +00:00
|
|
|
|
redirects.p[j] = redirects.p[j - 1];
|
|
|
|
|
} else {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
redirects.p[j] = r;
|
|
|
|
|
++redirects.n;
|
|
|
|
|
}
|
2020-09-07 04:39:00 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-05-14 12:36:58 +00:00
|
|
|
|
static void ProgramRedirectArg(int code, const char *s) {
|
|
|
|
|
size_t n;
|
2021-03-29 08:22:49 +00:00
|
|
|
|
const char *p;
|
2021-05-14 12:36:58 +00:00
|
|
|
|
n = strlen(s);
|
|
|
|
|
if (!(p = memchr(s, '=', n))) {
|
2022-06-27 04:25:02 +00:00
|
|
|
|
FATALF("(cfg) error: redirect arg missing '='");
|
2021-03-29 08:22:49 +00:00
|
|
|
|
}
|
2021-05-14 12:36:58 +00:00
|
|
|
|
ProgramRedirect(code, s, p - s, p + 1, n - (p - s + 1));
|
2021-03-29 08:22:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-10-17 18:02:04 +00:00
|
|
|
|
static void ProgramTrustedIp(uint32_t ip, int cidr) {
|
2022-09-17 08:37:33 +00:00
|
|
|
|
uint32_t mask;
|
|
|
|
|
mask = 0xffffffffu << (32 - cidr);
|
2022-10-17 18:02:04 +00:00
|
|
|
|
trustedips.p = xrealloc(trustedips.p, ++trustedips.n * sizeof(*trustedips.p));
|
|
|
|
|
trustedips.p[trustedips.n - 1].ip = ip;
|
|
|
|
|
trustedips.p[trustedips.n - 1].mask = mask;
|
2022-09-17 08:37:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-10-17 18:02:04 +00:00
|
|
|
|
static bool IsTrustedIp(uint32_t ip) {
|
2022-09-17 08:37:33 +00:00
|
|
|
|
int i;
|
2022-10-17 18:02:04 +00:00
|
|
|
|
uint32_t *p;
|
|
|
|
|
if (interfaces) {
|
|
|
|
|
for (p = interfaces; *p; ++p) {
|
2022-10-19 20:10:00 +00:00
|
|
|
|
if (ip == *p && !IsTestnetIp(ip)) {
|
|
|
|
|
DEBUGF("(token) ip is trusted because it's %s", "a local interface");
|
2022-10-17 18:02:04 +00:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (trustedips.n) {
|
|
|
|
|
for (i = 0; i < trustedips.n; ++i) {
|
|
|
|
|
if ((ip & trustedips.p[i].mask) == trustedips.p[i].ip) {
|
2022-10-19 20:10:00 +00:00
|
|
|
|
DEBUGF("(token) ip is trusted because it's %s", "whitelisted");
|
2022-09-17 08:37:33 +00:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
2022-10-19 20:10:00 +00:00
|
|
|
|
} else if (IsPrivateIp(ip) && !IsTestnetIp(ip)) {
|
|
|
|
|
DEBUGF("(token) ip is trusted because it's %s", "private");
|
|
|
|
|
return true;
|
|
|
|
|
} else if (IsLoopbackIp(ip)) {
|
|
|
|
|
DEBUGF("(token) ip is trusted because it's %s", "loopback");
|
|
|
|
|
return true;
|
2022-09-17 08:37:33 +00:00
|
|
|
|
} else {
|
2022-10-19 20:10:00 +00:00
|
|
|
|
return false;
|
2022-09-17 08:37:33 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-05 21:43:53 +00:00
|
|
|
|
static void DescribeAddress(char buf[40], uint32_t addr, uint16_t port) {
|
2021-04-23 17:45:19 +00:00
|
|
|
|
char *p;
|
|
|
|
|
p = buf;
|
2022-06-20 10:08:00 +00:00
|
|
|
|
p = FormatUint32(p, (addr & 0xFF000000) >> 030), *p++ = '.';
|
|
|
|
|
p = FormatUint32(p, (addr & 0x00FF0000) >> 020), *p++ = '.';
|
|
|
|
|
p = FormatUint32(p, (addr & 0x0000FF00) >> 010), *p++ = '.';
|
|
|
|
|
p = FormatUint32(p, (addr & 0x000000FF) >> 000), *p++ = ':';
|
|
|
|
|
p = FormatUint32(p, port);
|
2022-04-23 01:55:28 +00:00
|
|
|
|
*p = '\0';
|
|
|
|
|
assert(p - buf < 40);
|
2021-04-23 17:45:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-09-17 08:37:33 +00:00
|
|
|
|
static inline int GetServerAddr(uint32_t *ip, uint16_t *port) {
|
2021-06-24 19:31:26 +00:00
|
|
|
|
*ip = ntohl(serveraddr->sin_addr.s_addr);
|
|
|
|
|
if (port)
|
|
|
|
|
*port = ntohs(serveraddr->sin_port);
|
2022-09-17 08:37:33 +00:00
|
|
|
|
return 0;
|
2021-04-23 17:45:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-09-17 08:37:33 +00:00
|
|
|
|
static inline int GetClientAddr(uint32_t *ip, uint16_t *port) {
|
2021-04-23 17:45:19 +00:00
|
|
|
|
*ip = ntohl(clientaddr.sin_addr.s_addr);
|
|
|
|
|
if (port)
|
|
|
|
|
*port = ntohs(clientaddr.sin_port);
|
2022-09-17 08:37:33 +00:00
|
|
|
|
return 0;
|
2021-04-23 17:45:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-09-17 08:37:33 +00:00
|
|
|
|
static inline int GetRemoteAddr(uint32_t *ip, uint16_t *port) {
|
2021-04-23 17:45:19 +00:00
|
|
|
|
GetClientAddr(ip, port);
|
2022-09-17 08:37:33 +00:00
|
|
|
|
if (HasHeader(kHttpXForwardedFor)) {
|
2022-10-17 18:02:04 +00:00
|
|
|
|
if (IsTrustedIp(*ip)) {
|
2022-09-17 08:37:33 +00:00
|
|
|
|
if (ParseForwarded(HeaderData(kHttpXForwardedFor),
|
|
|
|
|
HeaderLength(kHttpXForwardedFor), ip, port) == -1) {
|
|
|
|
|
VERBOSEF("could not parse x-forwarded-for %`'.*s len=%ld",
|
|
|
|
|
HeaderLength(kHttpXForwardedFor),
|
|
|
|
|
HeaderData(kHttpXForwardedFor),
|
|
|
|
|
HeaderLength(kHttpXForwardedFor));
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
WARNF(
|
|
|
|
|
"%hhu.%hhu.%hhu.%hhu isn't authorized to send x-forwarded-for %`'.*s",
|
|
|
|
|
*ip >> 24, *ip >> 16, *ip >> 8, *ip, HeaderLength(kHttpXForwardedFor),
|
|
|
|
|
HeaderData(kHttpXForwardedFor));
|
|
|
|
|
}
|
2021-04-23 17:45:19 +00:00
|
|
|
|
}
|
2022-09-17 08:37:33 +00:00
|
|
|
|
return 0;
|
2021-04-23 17:45:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *DescribeClient(void) {
|
2022-09-17 08:37:33 +00:00
|
|
|
|
char str[40];
|
2021-04-23 17:45:19 +00:00
|
|
|
|
uint16_t port;
|
2022-09-17 08:37:33 +00:00
|
|
|
|
uint32_t client;
|
|
|
|
|
static char description[128];
|
|
|
|
|
GetClientAddr(&client, &port);
|
2022-10-17 18:02:04 +00:00
|
|
|
|
if (HasHeader(kHttpXForwardedFor) && IsTrustedIp(client)) {
|
2022-09-17 08:37:33 +00:00
|
|
|
|
DescribeAddress(str, client, port);
|
|
|
|
|
snprintf(description, sizeof(description), "%'.*s via %s",
|
|
|
|
|
HeaderLength(kHttpXForwardedFor), HeaderData(kHttpXForwardedFor),
|
|
|
|
|
str);
|
|
|
|
|
} else {
|
|
|
|
|
DescribeAddress(description, client, port);
|
|
|
|
|
}
|
|
|
|
|
return description;
|
2021-04-23 17:45:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *DescribeServer(void) {
|
|
|
|
|
uint32_t ip;
|
|
|
|
|
uint16_t port;
|
2021-08-05 21:43:53 +00:00
|
|
|
|
static char serveraddrstr[40];
|
2021-04-23 17:45:19 +00:00
|
|
|
|
GetServerAddr(&ip, &port);
|
|
|
|
|
DescribeAddress(serveraddrstr, ip, port);
|
|
|
|
|
return serveraddrstr;
|
2020-09-07 04:39:00 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-03-29 08:22:49 +00:00
|
|
|
|
static void ProgramBrand(const char *s) {
|
2021-05-05 14:25:39 +00:00
|
|
|
|
char *p;
|
2021-03-29 08:22:49 +00:00
|
|
|
|
free(brand);
|
|
|
|
|
free(serverheader);
|
2021-05-05 14:25:39 +00:00
|
|
|
|
if (!(p = EncodeHttpHeaderValue(s, -1, 0))) {
|
2022-06-27 04:25:02 +00:00
|
|
|
|
FATALF("(cfg) error: brand isn't latin1 encodable: %`'s", s);
|
2021-03-29 08:22:49 +00:00
|
|
|
|
}
|
2021-05-05 14:25:39 +00:00
|
|
|
|
brand = strdup(s);
|
|
|
|
|
serverheader = xasprintf("Server: %s\r\n", p);
|
|
|
|
|
free(p);
|
2021-03-29 08:22:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-07-08 22:56:23 +00:00
|
|
|
|
static void ProgramUid(long x) {
|
|
|
|
|
changeuid = x;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void ProgramGid(long x) {
|
|
|
|
|
changegid = x;
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-25 21:44:04 +00:00
|
|
|
|
#define MINTIMEOUT 10
|
2021-04-23 17:45:19 +00:00
|
|
|
|
static void ProgramTimeout(long ms) {
|
|
|
|
|
ldiv_t d;
|
2021-07-08 04:44:27 +00:00
|
|
|
|
if (ms < 0) {
|
|
|
|
|
timeout.tv_sec = ms; /* -(keepalive seconds) */
|
|
|
|
|
timeout.tv_usec = 0;
|
|
|
|
|
} else {
|
2021-10-25 21:44:04 +00:00
|
|
|
|
if (ms < MINTIMEOUT) {
|
2022-06-27 04:25:02 +00:00
|
|
|
|
FATALF("(cfg) error: timeout needs to be %dms or greater", MINTIMEOUT);
|
2021-07-08 04:44:27 +00:00
|
|
|
|
}
|
|
|
|
|
d = ldiv(ms, 1000);
|
|
|
|
|
timeout.tv_sec = d.quot;
|
|
|
|
|
timeout.tv_usec = d.rem * 1000;
|
2021-04-23 17:45:19 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-24 06:24:40 +00:00
|
|
|
|
static void ProgramCache(long x, const char *s) {
|
2021-03-29 08:22:49 +00:00
|
|
|
|
cacheseconds = x;
|
2023-09-02 03:49:13 +00:00
|
|
|
|
if (s)
|
|
|
|
|
cachedirective = strdup(s);
|
2021-03-29 08:22:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-03-25 09:21:13 +00:00
|
|
|
|
static void SetDefaults(void) {
|
2024-01-08 18:07:35 +00:00
|
|
|
|
ProgramBrand(gc(xasprintf("%s/%hhd.%hhd.%hhd", REDBEAN, VERSION >> 020,
|
|
|
|
|
VERSION >> 010, VERSION >> 000)));
|
2021-05-01 12:28:15 +00:00
|
|
|
|
__log_level = kLogInfo;
|
2021-05-01 12:11:35 +00:00
|
|
|
|
maxpayloadsize = 64 * 1024;
|
2023-02-24 06:24:40 +00:00
|
|
|
|
ProgramCache(-1, "must-revalidate");
|
2021-06-24 19:31:26 +00:00
|
|
|
|
ProgramTimeout(60 * 1000);
|
2021-07-19 21:55:20 +00:00
|
|
|
|
ProgramSslTicketLifetime(24 * 60 * 60);
|
2021-07-08 04:44:27 +00:00
|
|
|
|
sslfetchverify = true;
|
2021-03-25 09:21:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-05-14 12:36:58 +00:00
|
|
|
|
static void AddString(struct Strings *l, const char *s, size_t n) {
|
|
|
|
|
if (++l->n > l->c) {
|
|
|
|
|
l->c = l->n + (l->n >> 1);
|
2021-06-24 19:31:26 +00:00
|
|
|
|
l->p = realloc(l->p, l->c * sizeof(*l->p));
|
2021-05-14 12:36:58 +00:00
|
|
|
|
}
|
|
|
|
|
l->p[l->n - 1].s = s;
|
|
|
|
|
l->p[l->n - 1].n = n;
|
2021-03-29 09:39:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-05-14 12:36:58 +00:00
|
|
|
|
static bool HasString(struct Strings *l, const char *s, size_t n) {
|
2021-04-25 00:09:01 +00:00
|
|
|
|
size_t i;
|
|
|
|
|
for (i = 0; i < l->n; ++i) {
|
2021-05-14 12:36:58 +00:00
|
|
|
|
if (SlicesEqual(l->p[i].s, l->p[i].n, s, n)) {
|
2021-04-25 00:09:01 +00:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-02 03:49:13 +00:00
|
|
|
|
const char *DEFAULTLUAPATH = "/zip/.lua/?.lua;/zip/.lua/?/init.lua";
|
2023-08-17 07:43:11 +00:00
|
|
|
|
|
2023-05-27 01:29:00 +00:00
|
|
|
|
static void UpdateLuaPath(const char *s) {
|
|
|
|
|
#ifndef STATIC
|
|
|
|
|
lua_State *L = GL;
|
2023-08-17 07:43:11 +00:00
|
|
|
|
char *curpath = "";
|
|
|
|
|
char *respath = 0;
|
|
|
|
|
char *t;
|
2023-05-27 01:29:00 +00:00
|
|
|
|
int n = lua_gettop(L);
|
|
|
|
|
lua_getglobal(L, "package");
|
|
|
|
|
if (lua_istable(L, -1)) {
|
|
|
|
|
lua_getfield(L, -1, "path");
|
2023-09-02 03:49:13 +00:00
|
|
|
|
curpath = (void *)luaL_optstring(L, -1, "");
|
|
|
|
|
if ((t = strstr(curpath, DEFAULTLUAPATH))) {
|
2023-08-17 07:43:11 +00:00
|
|
|
|
// if the DEFAULT path is found, prepend the path in front of it
|
|
|
|
|
respath = xasprintf("%.*s%s/.lua/?.lua;%s/.lua/?/init.lua;%s",
|
2023-08-21 09:28:24 +00:00
|
|
|
|
t - curpath, curpath, s, s, t);
|
2023-08-17 07:43:11 +00:00
|
|
|
|
} else {
|
|
|
|
|
// if the DEFAULT path is not found, append to the end
|
2023-08-21 09:28:24 +00:00
|
|
|
|
respath = xasprintf("%s;%s/.lua/?.lua;%s/.lua/?/init.lua", curpath, s, s);
|
2023-08-17 07:43:11 +00:00
|
|
|
|
}
|
2024-01-08 18:07:35 +00:00
|
|
|
|
lua_pushstring(L, gc(respath));
|
2023-05-27 01:29:00 +00:00
|
|
|
|
lua_setfield(L, -3, "path");
|
|
|
|
|
}
|
|
|
|
|
lua_settop(L, n);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-08 22:56:23 +00:00
|
|
|
|
static void ProgramDirectory(const char *path) {
|
|
|
|
|
char *s;
|
|
|
|
|
size_t n;
|
2022-03-21 12:43:49 +00:00
|
|
|
|
struct stat st;
|
2022-03-21 14:34:19 +00:00
|
|
|
|
if (stat(path, &st) == -1 || !S_ISDIR(st.st_mode)) {
|
2022-06-27 04:25:02 +00:00
|
|
|
|
FATALF("(cfg) error: not a directory: %`'s", path);
|
2022-03-21 12:43:49 +00:00
|
|
|
|
}
|
2021-07-08 22:56:23 +00:00
|
|
|
|
s = strdup(path);
|
|
|
|
|
n = strlen(s);
|
2022-03-21 12:43:49 +00:00
|
|
|
|
INFOF("(cfg) program directory: %s", s);
|
2021-05-14 12:36:58 +00:00
|
|
|
|
AddString(&stagedirs, s, n);
|
2023-05-27 01:29:00 +00:00
|
|
|
|
UpdateLuaPath(s);
|
2021-03-28 14:54:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-04-23 17:45:19 +00:00
|
|
|
|
static void ProgramHeader(const char *s) {
|
2023-09-02 03:49:13 +00:00
|
|
|
|
char *p, *v;
|
2021-04-23 17:45:19 +00:00
|
|
|
|
if ((p = strchr(s, ':')) && IsValidHttpToken(s, p - s) &&
|
|
|
|
|
(v = EncodeLatin1(p + 1, -1, 0, kControlC0 | kControlC1 | kControlWs))) {
|
|
|
|
|
switch (GetHttpHeader(s, p - s)) {
|
|
|
|
|
case kHttpDate:
|
|
|
|
|
case kHttpConnection:
|
|
|
|
|
case kHttpContentLength:
|
|
|
|
|
case kHttpContentEncoding:
|
|
|
|
|
case kHttpContentRange:
|
2021-08-19 16:34:50 +00:00
|
|
|
|
case kHttpLocation:
|
2022-06-27 04:25:02 +00:00
|
|
|
|
FATALF("(cfg) error: can't program header: %`'s", s);
|
2021-04-23 17:45:19 +00:00
|
|
|
|
case kHttpServer:
|
|
|
|
|
ProgramBrand(p + 1);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
p = xasprintf("%s%.*s:%s\r\n", extrahdrs ? extrahdrs : "", p - s, s, v);
|
|
|
|
|
free(extrahdrs);
|
|
|
|
|
extrahdrs = p;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
free(v);
|
|
|
|
|
} else {
|
2022-06-27 04:25:02 +00:00
|
|
|
|
FATALF("(cfg) error: illegal header: %`'s", s);
|
2021-04-23 17:45:19 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-08 22:56:23 +00:00
|
|
|
|
static void ProgramLogPath(const char *s) {
|
2022-10-17 18:02:04 +00:00
|
|
|
|
int fd;
|
2021-07-08 22:56:23 +00:00
|
|
|
|
logpath = strdup(s);
|
2022-10-17 18:02:04 +00:00
|
|
|
|
fd = open(logpath, O_APPEND | O_WRONLY | O_CREAT, 0640);
|
|
|
|
|
if (fd == -1) {
|
|
|
|
|
WARNF("(srvr) open(%`'s) failed: %m", logpath);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (fd != 2) {
|
|
|
|
|
dup2(fd, 2);
|
|
|
|
|
close(fd);
|
|
|
|
|
}
|
2021-07-08 22:56:23 +00:00
|
|
|
|
}
|
|
|
|
|
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
static void ProgramPidPath(const char *s) {
|
|
|
|
|
pidpath = strdup(s);
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-24 19:31:26 +00:00
|
|
|
|
static bool IsServerFd(int fd) {
|
|
|
|
|
size_t i;
|
|
|
|
|
for (i = 0; i < servers.n; ++i) {
|
|
|
|
|
if (servers.p[i].fd == fd) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-08 22:56:23 +00:00
|
|
|
|
static void ChangeUser(void) {
|
2022-04-24 16:59:22 +00:00
|
|
|
|
if (changegid) {
|
|
|
|
|
if (setgid(changegid)) {
|
2022-06-27 04:16:13 +00:00
|
|
|
|
FATALF("(cfg) setgid() failed: %m");
|
2022-04-24 16:59:22 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// order matters
|
|
|
|
|
if (changeuid) {
|
|
|
|
|
if (setuid(changeuid)) {
|
2022-06-27 04:16:13 +00:00
|
|
|
|
FATALF("(cfg) setuid() failed: %m");
|
2022-04-24 16:59:22 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2021-07-08 22:56:23 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-10-06 06:11:49 +00:00
|
|
|
|
static void Daemonize(void) {
|
2022-07-24 01:58:31 +00:00
|
|
|
|
if (fork() > 0)
|
|
|
|
|
exit(0);
|
2021-03-02 08:38:11 +00:00
|
|
|
|
setsid();
|
2022-07-24 01:58:31 +00:00
|
|
|
|
if (fork() > 0)
|
|
|
|
|
_exit(0);
|
2021-03-02 08:38:11 +00:00
|
|
|
|
umask(0);
|
2020-09-07 04:39:00 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-09-02 03:49:13 +00:00
|
|
|
|
static void LogLuaError(const char *hook, const char *err) {
|
2021-08-22 22:01:52 +00:00
|
|
|
|
ERRORF("(lua) failed to run %s: %s", hook, err);
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-25 08:52:13 +00:00
|
|
|
|
// handles `-e CODE` (frontloads web server code)
|
|
|
|
|
// handles `-i -e CODE` (interprets expression and exits)
|
|
|
|
|
static void LuaEvalCode(const char *code) {
|
2022-03-05 02:47:15 +00:00
|
|
|
|
lua_State *L = GL;
|
|
|
|
|
int status = luaL_loadstring(L, code);
|
2022-03-22 01:07:30 +00:00
|
|
|
|
if (status != LUA_OK || LuaCallWithTrace(L, 0, 0, NULL) != LUA_OK) {
|
2022-03-05 02:47:15 +00:00
|
|
|
|
LogLuaError("lua code", lua_tostring(L, -1));
|
2022-03-22 01:07:30 +00:00
|
|
|
|
lua_pop(L, 1); // pop error
|
2023-04-25 08:52:13 +00:00
|
|
|
|
exit(1);
|
2022-03-05 02:47:15 +00:00
|
|
|
|
}
|
2022-04-28 04:57:52 +00:00
|
|
|
|
AssertLuaStackIsAt(L, 0);
|
2022-03-05 02:47:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-04-25 08:52:13 +00:00
|
|
|
|
// handle `-F PATH` arg
|
|
|
|
|
static void LuaEvalFile(const char *path) {
|
2024-01-08 18:07:35 +00:00
|
|
|
|
char *f = gc(xslurp(path, 0));
|
2022-08-24 03:54:51 +00:00
|
|
|
|
if (!f)
|
|
|
|
|
FATALF("(cfg) error: failed to read file %`'s", path);
|
2023-04-25 08:52:13 +00:00
|
|
|
|
LuaEvalCode(f);
|
2022-04-13 21:43:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
static bool LuaOnClientConnection(void) {
|
2022-07-08 14:17:25 +00:00
|
|
|
|
bool dropit = false;
|
2022-03-22 02:31:03 +00:00
|
|
|
|
#ifndef STATIC
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
uint32_t ip, serverip;
|
|
|
|
|
uint16_t port, serverport;
|
2021-10-25 21:54:56 +00:00
|
|
|
|
lua_State *L = GL;
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
lua_getglobal(L, "OnClientConnection");
|
|
|
|
|
GetClientAddr(&ip, &port);
|
|
|
|
|
GetServerAddr(&serverip, &serverport);
|
2021-08-12 07:15:39 +00:00
|
|
|
|
lua_pushinteger(L, ip);
|
|
|
|
|
lua_pushinteger(L, port);
|
|
|
|
|
lua_pushinteger(L, serverip);
|
|
|
|
|
lua_pushinteger(L, serverport);
|
2022-03-22 01:07:30 +00:00
|
|
|
|
if (LuaCallWithTrace(L, 4, 1, NULL) == LUA_OK) {
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
dropit = lua_toboolean(L, -1);
|
|
|
|
|
} else {
|
2021-08-22 22:01:52 +00:00
|
|
|
|
LogLuaError("OnClientConnection", lua_tostring(L, -1));
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
}
|
2022-04-09 19:36:05 +00:00
|
|
|
|
lua_pop(L, 1); // pop result or error
|
2022-04-28 04:57:52 +00:00
|
|
|
|
AssertLuaStackIsAt(L, 0);
|
2022-03-22 02:31:03 +00:00
|
|
|
|
#endif
|
2022-07-08 14:17:25 +00:00
|
|
|
|
return dropit;
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-07-19 03:17:14 +00:00
|
|
|
|
static void LuaOnLogLatency(long reqtime, long contime) {
|
|
|
|
|
#ifndef STATIC
|
|
|
|
|
lua_State *L = GL;
|
|
|
|
|
int n = lua_gettop(L);
|
|
|
|
|
lua_getglobal(L, "OnLogLatency");
|
|
|
|
|
lua_pushinteger(L, reqtime);
|
|
|
|
|
lua_pushinteger(L, contime);
|
|
|
|
|
if (LuaCallWithTrace(L, 2, 0, NULL) != LUA_OK) {
|
|
|
|
|
LogLuaError("OnLogLatency", lua_tostring(L, -1));
|
|
|
|
|
lua_pop(L, 1); // pop error
|
|
|
|
|
}
|
|
|
|
|
AssertLuaStackIsAt(L, n);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
static void LuaOnProcessCreate(int pid) {
|
2022-03-22 02:31:03 +00:00
|
|
|
|
#ifndef STATIC
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
uint32_t ip, serverip;
|
|
|
|
|
uint16_t port, serverport;
|
2021-10-25 21:54:56 +00:00
|
|
|
|
lua_State *L = GL;
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
lua_getglobal(L, "OnProcessCreate");
|
|
|
|
|
GetClientAddr(&ip, &port);
|
|
|
|
|
GetServerAddr(&serverip, &serverport);
|
2021-08-12 07:15:39 +00:00
|
|
|
|
lua_pushinteger(L, pid);
|
|
|
|
|
lua_pushinteger(L, ip);
|
|
|
|
|
lua_pushinteger(L, port);
|
|
|
|
|
lua_pushinteger(L, serverip);
|
|
|
|
|
lua_pushinteger(L, serverport);
|
2022-03-22 01:07:30 +00:00
|
|
|
|
if (LuaCallWithTrace(L, 5, 0, NULL) != LUA_OK) {
|
2021-08-22 22:01:52 +00:00
|
|
|
|
LogLuaError("OnProcessCreate", lua_tostring(L, -1));
|
2022-03-18 09:33:37 +00:00
|
|
|
|
lua_pop(L, 1); // pop error
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
}
|
2022-04-28 04:57:52 +00:00
|
|
|
|
AssertLuaStackIsAt(L, 0);
|
2022-03-22 02:31:03 +00:00
|
|
|
|
#endif
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-07-08 14:17:25 +00:00
|
|
|
|
static bool LuaOnServerListen(int fd, uint32_t ip, uint16_t port) {
|
|
|
|
|
bool nouse = false;
|
|
|
|
|
#ifndef STATIC
|
|
|
|
|
lua_State *L = GL;
|
|
|
|
|
lua_getglobal(L, "OnServerListen");
|
|
|
|
|
lua_pushinteger(L, fd);
|
|
|
|
|
lua_pushinteger(L, ip);
|
|
|
|
|
lua_pushinteger(L, port);
|
|
|
|
|
if (LuaCallWithTrace(L, 3, 1, NULL) == LUA_OK) {
|
|
|
|
|
nouse = lua_toboolean(L, -1);
|
|
|
|
|
} else {
|
|
|
|
|
LogLuaError("OnServerListen", lua_tostring(L, -1));
|
|
|
|
|
}
|
|
|
|
|
lua_pop(L, 1); // pop result or error
|
|
|
|
|
AssertLuaStackIsAt(L, 0);
|
|
|
|
|
#endif
|
|
|
|
|
return nouse;
|
|
|
|
|
}
|
|
|
|
|
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
static void LuaOnProcessDestroy(int pid) {
|
2022-03-22 02:31:03 +00:00
|
|
|
|
#ifndef STATIC
|
2021-10-25 21:54:56 +00:00
|
|
|
|
lua_State *L = GL;
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
lua_getglobal(L, "OnProcessDestroy");
|
2021-08-12 07:15:39 +00:00
|
|
|
|
lua_pushinteger(L, pid);
|
2022-03-22 01:07:30 +00:00
|
|
|
|
if (LuaCallWithTrace(L, 1, 0, NULL) != LUA_OK) {
|
2021-08-22 22:01:52 +00:00
|
|
|
|
LogLuaError("OnProcessDestroy", lua_tostring(L, -1));
|
2022-03-18 09:33:37 +00:00
|
|
|
|
lua_pop(L, 1); // pop error
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
}
|
2022-04-28 04:57:52 +00:00
|
|
|
|
AssertLuaStackIsAt(L, 0);
|
2022-03-22 02:31:03 +00:00
|
|
|
|
#endif
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline bool IsHookDefined(const char *s) {
|
|
|
|
|
#ifndef STATIC
|
2021-10-25 21:54:56 +00:00
|
|
|
|
lua_State *L = GL;
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
bool res = !!lua_getglobal(L, s);
|
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
return res;
|
|
|
|
|
#else
|
|
|
|
|
return false;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void CallSimpleHook(const char *s) {
|
2022-03-22 02:31:03 +00:00
|
|
|
|
#ifndef STATIC
|
2021-10-25 21:54:56 +00:00
|
|
|
|
lua_State *L = GL;
|
2022-04-28 04:57:52 +00:00
|
|
|
|
int n = lua_gettop(L);
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
lua_getglobal(L, s);
|
2022-03-22 01:07:30 +00:00
|
|
|
|
if (LuaCallWithTrace(L, 0, 0, NULL) != LUA_OK) {
|
2021-08-22 22:01:52 +00:00
|
|
|
|
LogLuaError(s, lua_tostring(L, -1));
|
2022-03-18 09:33:37 +00:00
|
|
|
|
lua_pop(L, 1); // pop error
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
}
|
2022-04-28 04:57:52 +00:00
|
|
|
|
AssertLuaStackIsAt(L, n);
|
2022-03-22 02:31:03 +00:00
|
|
|
|
#endif
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void CallSimpleHookIfDefined(const char *s) {
|
|
|
|
|
if (IsHookDefined(s)) {
|
|
|
|
|
CallSimpleHook(s);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-18 18:34:59 +00:00
|
|
|
|
static void ReportWorkerExit(int pid, int ws) {
|
2024-12-02 22:05:38 +00:00
|
|
|
|
int workers =
|
|
|
|
|
atomic_fetch_sub_explicit(&shared->workers, 1, memory_order_release);
|
2021-03-25 09:21:13 +00:00
|
|
|
|
if (WIFEXITED(ws)) {
|
|
|
|
|
if (WEXITSTATUS(ws)) {
|
2021-05-03 19:09:35 +00:00
|
|
|
|
LockInc(&shared->c.failedchildren);
|
2021-09-07 18:40:11 +00:00
|
|
|
|
WARNF("(stat) %d exited with %d (%,d workers remain)", pid,
|
2022-05-14 11:33:58 +00:00
|
|
|
|
WEXITSTATUS(ws), workers);
|
2021-03-25 09:21:13 +00:00
|
|
|
|
} else {
|
2022-05-14 11:33:58 +00:00
|
|
|
|
DEBUGF("(stat) %d exited (%,d workers remain)", pid, workers);
|
2021-03-25 09:21:13 +00:00
|
|
|
|
}
|
|
|
|
|
} else {
|
2021-05-03 19:09:35 +00:00
|
|
|
|
LockInc(&shared->c.terminatedchildren);
|
2021-08-22 22:01:52 +00:00
|
|
|
|
WARNF("(stat) %d terminated with %s (%,d workers remain)", pid,
|
2022-05-14 11:33:58 +00:00
|
|
|
|
strsignal(WTERMSIG(ws)), workers);
|
2021-04-18 18:34:59 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-23 17:45:19 +00:00
|
|
|
|
static void ReportWorkerResources(int pid, struct rusage *ru) {
|
2021-08-06 21:12:11 +00:00
|
|
|
|
char *s, *b = 0;
|
2021-04-23 17:45:19 +00:00
|
|
|
|
if (logrusage || LOGGABLE(kLogDebug)) {
|
2022-04-25 15:30:14 +00:00
|
|
|
|
AppendResourceReport(&b, ru, "\n");
|
2021-08-06 21:12:11 +00:00
|
|
|
|
if (b) {
|
|
|
|
|
if ((s = IndentLines(b, appendz(b).i - 1, 0, 1))) {
|
2022-04-25 15:30:14 +00:00
|
|
|
|
LOGF(kLogDebug, "(stat) resource report for pid %d\n%s", pid, s);
|
2021-04-23 17:45:19 +00:00
|
|
|
|
free(s);
|
|
|
|
|
}
|
2021-08-06 21:12:11 +00:00
|
|
|
|
free(b);
|
2021-04-23 17:45:19 +00:00
|
|
|
|
}
|
2021-03-25 09:21:13 +00:00
|
|
|
|
}
|
2020-10-06 06:11:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-04-23 17:45:19 +00:00
|
|
|
|
static void HandleWorkerExit(int pid, int ws, struct rusage *ru) {
|
2021-05-03 19:09:35 +00:00
|
|
|
|
LockInc(&shared->c.connectionshandled);
|
2024-12-02 22:05:38 +00:00
|
|
|
|
unassert(!pthread_mutex_lock(&shared->children_mu));
|
2022-11-06 02:49:41 +00:00
|
|
|
|
rusage_add(&shared->children, ru);
|
2024-12-02 22:05:38 +00:00
|
|
|
|
unassert(!pthread_mutex_unlock(&shared->children_mu));
|
2021-04-23 17:45:19 +00:00
|
|
|
|
ReportWorkerExit(pid, ws);
|
|
|
|
|
ReportWorkerResources(pid, ru);
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
if (hasonprocessdestroy) {
|
|
|
|
|
LuaOnProcessDestroy(pid);
|
|
|
|
|
}
|
2021-04-23 17:45:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-04-13 05:11:00 +00:00
|
|
|
|
static void KillGroupImpl(int sig) {
|
|
|
|
|
LOGIFNEG1(kill(0, sig));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void KillGroup(void) {
|
2022-04-15 06:39:48 +00:00
|
|
|
|
KillGroupImpl(SIGTERM);
|
2022-04-13 05:11:00 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-10-06 06:11:49 +00:00
|
|
|
|
static void WaitAll(void) {
|
2021-03-25 09:21:13 +00:00
|
|
|
|
int ws, pid;
|
2021-04-18 18:34:59 +00:00
|
|
|
|
struct rusage ru;
|
2020-10-06 06:11:49 +00:00
|
|
|
|
for (;;) {
|
2021-04-18 18:34:59 +00:00
|
|
|
|
if ((pid = wait4(-1, &ws, 0, &ru)) != -1) {
|
2021-04-23 17:45:19 +00:00
|
|
|
|
HandleWorkerExit(pid, ws, &ru);
|
2021-03-25 09:21:13 +00:00
|
|
|
|
} else {
|
2022-03-19 10:37:00 +00:00
|
|
|
|
if (errno == ECHILD) {
|
|
|
|
|
errno = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2021-03-25 09:21:13 +00:00
|
|
|
|
if (errno == EINTR) {
|
|
|
|
|
if (killed) {
|
2021-03-29 08:22:49 +00:00
|
|
|
|
killed = false;
|
|
|
|
|
terminated = false;
|
2022-06-27 04:16:13 +00:00
|
|
|
|
WARNF("(srvr) server shall terminate harder");
|
2022-04-13 05:11:00 +00:00
|
|
|
|
KillGroup();
|
2021-03-25 09:21:13 +00:00
|
|
|
|
}
|
2022-03-19 10:37:00 +00:00
|
|
|
|
errno = 0;
|
2021-03-25 09:21:13 +00:00
|
|
|
|
continue;
|
2020-10-06 06:11:49 +00:00
|
|
|
|
}
|
2021-10-25 21:44:04 +00:00
|
|
|
|
DIEF("(srvr) wait error: %m");
|
2020-10-06 06:11:49 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-25 09:21:13 +00:00
|
|
|
|
static void ReapZombies(void) {
|
|
|
|
|
int ws, pid;
|
2021-04-18 18:34:59 +00:00
|
|
|
|
struct rusage ru;
|
2021-03-25 09:21:13 +00:00
|
|
|
|
do {
|
2021-04-18 18:34:59 +00:00
|
|
|
|
zombied = false;
|
|
|
|
|
if ((pid = wait4(-1, &ws, WNOHANG, &ru)) != -1) {
|
2021-03-25 09:21:13 +00:00
|
|
|
|
if (pid) {
|
2021-04-23 17:45:19 +00:00
|
|
|
|
HandleWorkerExit(pid, ws, &ru);
|
2021-03-25 09:21:13 +00:00
|
|
|
|
} else {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2022-03-19 10:37:00 +00:00
|
|
|
|
if (errno == ECHILD) {
|
|
|
|
|
errno = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (errno == EINTR) {
|
|
|
|
|
errno = 0;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2021-10-25 21:44:04 +00:00
|
|
|
|
DIEF("(srvr) wait error: %m");
|
2021-03-25 09:21:13 +00:00
|
|
|
|
}
|
|
|
|
|
} while (!terminated);
|
2020-10-06 06:11:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-03-23 13:31:55 +00:00
|
|
|
|
static ssize_t ReadAll(int fd, char *p, size_t n) {
|
2022-03-21 14:34:19 +00:00
|
|
|
|
ssize_t rc;
|
|
|
|
|
size_t i, got;
|
|
|
|
|
for (i = 0; i < n;) {
|
2022-04-20 16:56:53 +00:00
|
|
|
|
rc = READ(fd, p + i, n - i);
|
2022-03-21 14:34:19 +00:00
|
|
|
|
if (rc != -1) {
|
|
|
|
|
got = rc;
|
|
|
|
|
i += got;
|
|
|
|
|
} else if (errno != EINTR) {
|
|
|
|
|
WARNF("(file) read error: %m");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-06 02:24:05 +00:00
|
|
|
|
static bool IsTakingTooLong(void) {
|
2022-11-06 02:49:41 +00:00
|
|
|
|
return meltdown && timespec_cmp(timespec_sub(timespec_real(), startread),
|
|
|
|
|
(struct timespec){2}) >= 0;
|
2022-08-06 02:24:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-05-05 14:25:39 +00:00
|
|
|
|
static ssize_t WritevAll(int fd, struct iovec *iov, int iovlen) {
|
2021-07-12 06:17:47 +00:00
|
|
|
|
int i;
|
2020-09-07 04:39:00 +00:00
|
|
|
|
ssize_t rc;
|
2021-07-12 06:17:47 +00:00
|
|
|
|
size_t wrote, total;
|
|
|
|
|
i = 0;
|
|
|
|
|
total = 0;
|
2020-09-07 04:39:00 +00:00
|
|
|
|
do {
|
2021-07-12 06:17:47 +00:00
|
|
|
|
if (i) {
|
|
|
|
|
while (i < iovlen && !iov[i].iov_len)
|
|
|
|
|
++i;
|
|
|
|
|
if (i == iovlen)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if ((rc = writev(fd, iov + i, iovlen - i)) != -1) {
|
2020-09-07 04:39:00 +00:00
|
|
|
|
wrote = rc;
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
total += wrote;
|
2020-10-06 06:11:49 +00:00
|
|
|
|
do {
|
2021-07-12 06:17:47 +00:00
|
|
|
|
if (wrote >= iov[i].iov_len) {
|
|
|
|
|
wrote -= iov[i++].iov_len;
|
2020-10-06 06:11:49 +00:00
|
|
|
|
} else {
|
2021-07-12 06:17:47 +00:00
|
|
|
|
iov[i].iov_base = (char *)iov[i].iov_base + wrote;
|
|
|
|
|
iov[i].iov_len -= wrote;
|
2020-10-06 06:11:49 +00:00
|
|
|
|
wrote = 0;
|
|
|
|
|
}
|
|
|
|
|
} while (wrote);
|
|
|
|
|
} else if (errno == EINTR) {
|
2022-03-19 10:37:00 +00:00
|
|
|
|
errno = 0;
|
2021-05-03 19:09:35 +00:00
|
|
|
|
LockInc(&shared->c.writeinterruputs);
|
2022-08-06 02:24:05 +00:00
|
|
|
|
if (killed || IsTakingTooLong()) {
|
2021-07-12 06:17:47 +00:00
|
|
|
|
return total ? total : -1;
|
2021-03-28 14:54:21 +00:00
|
|
|
|
}
|
2020-09-07 04:39:00 +00:00
|
|
|
|
} else {
|
2021-07-12 06:17:47 +00:00
|
|
|
|
return total ? total : -1;
|
2020-09-07 04:39:00 +00:00
|
|
|
|
}
|
2021-07-12 06:17:47 +00:00
|
|
|
|
} while (i < iovlen);
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
return total;
|
2020-09-07 04:39:00 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-07-12 06:17:47 +00:00
|
|
|
|
static int TlsFlush(struct TlsBio *bio, const unsigned char *buf, size_t len) {
|
|
|
|
|
struct iovec v[2];
|
|
|
|
|
if (len || bio->c > 0) {
|
|
|
|
|
v[0].iov_base = bio->u;
|
|
|
|
|
v[0].iov_len = MAX(0, bio->c);
|
2023-09-02 03:49:13 +00:00
|
|
|
|
v[1].iov_base = (void *)buf;
|
2021-07-12 06:17:47 +00:00
|
|
|
|
v[1].iov_len = len;
|
|
|
|
|
if (WritevAll(bio->fd, v, 2) != -1) {
|
|
|
|
|
if (bio->c > 0)
|
|
|
|
|
bio->c = 0;
|
|
|
|
|
} else if (errno == EINTR) {
|
2022-03-19 10:37:00 +00:00
|
|
|
|
errno = 0;
|
2021-07-12 06:17:47 +00:00
|
|
|
|
return MBEDTLS_ERR_NET_CONN_RESET;
|
|
|
|
|
} else if (errno == EAGAIN) {
|
2022-03-19 10:37:00 +00:00
|
|
|
|
errno = 0;
|
2021-07-12 06:17:47 +00:00
|
|
|
|
return MBEDTLS_ERR_SSL_TIMEOUT;
|
|
|
|
|
} else if (errno == EPIPE || errno == ECONNRESET || errno == ENETRESET) {
|
|
|
|
|
return MBEDTLS_ERR_NET_CONN_RESET;
|
|
|
|
|
} else {
|
2021-10-25 21:44:04 +00:00
|
|
|
|
WARNF("(ssl) TlsSend error: %m");
|
2021-07-12 06:17:47 +00:00
|
|
|
|
return MBEDTLS_ERR_NET_SEND_FAILED;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int TlsSend(void *ctx, const unsigned char *buf, size_t len) {
|
|
|
|
|
int rc;
|
|
|
|
|
struct TlsBio *bio = ctx;
|
|
|
|
|
if (bio->c >= 0 && bio->c + len <= sizeof(bio->u)) {
|
|
|
|
|
memcpy(bio->u + bio->c, buf, len);
|
|
|
|
|
bio->c += len;
|
|
|
|
|
return len;
|
|
|
|
|
}
|
|
|
|
|
if ((rc = TlsFlush(bio, buf, len)) < 0)
|
|
|
|
|
return rc;
|
|
|
|
|
return len;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-09 04:54:21 +00:00
|
|
|
|
static int TlsRecvImpl(void *ctx, unsigned char *p, size_t n, uint32_t o) {
|
|
|
|
|
int r;
|
|
|
|
|
struct iovec v[2];
|
|
|
|
|
struct TlsBio *bio = ctx;
|
2021-07-12 06:17:47 +00:00
|
|
|
|
if ((r = TlsFlush(bio, 0, 0)) < 0)
|
|
|
|
|
return r;
|
2021-07-09 04:54:21 +00:00
|
|
|
|
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;
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
v[0].iov_base = p;
|
|
|
|
|
v[0].iov_len = n;
|
|
|
|
|
v[1].iov_base = bio->t;
|
|
|
|
|
v[1].iov_len = sizeof(bio->t);
|
|
|
|
|
while ((r = readv(bio->fd, v, 2)) == -1) {
|
2021-06-24 19:31:26 +00:00
|
|
|
|
if (errno == EINTR) {
|
2022-03-19 10:37:00 +00:00
|
|
|
|
errno = 0;
|
2021-06-24 19:31:26 +00:00
|
|
|
|
return MBEDTLS_ERR_SSL_WANT_READ;
|
|
|
|
|
} else if (errno == EAGAIN) {
|
2022-03-19 10:37:00 +00:00
|
|
|
|
errno = 0;
|
2021-06-24 19:31:26 +00:00
|
|
|
|
return MBEDTLS_ERR_SSL_TIMEOUT;
|
|
|
|
|
} else if (errno == EPIPE || errno == ECONNRESET || errno == ENETRESET) {
|
|
|
|
|
return MBEDTLS_ERR_NET_CONN_RESET;
|
|
|
|
|
} else {
|
2021-10-25 21:44:04 +00:00
|
|
|
|
WARNF("(ssl) tls read() error: %m");
|
2021-06-24 19:31:26 +00:00
|
|
|
|
return MBEDTLS_ERR_NET_RECV_FAILED;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-07-09 04:54:21 +00:00
|
|
|
|
if (r > n)
|
|
|
|
|
bio->b = r - n;
|
|
|
|
|
return MIN(n, r);
|
2021-06-24 19:31:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-07-08 04:44:27 +00:00
|
|
|
|
static int TlsRecv(void *ctx, unsigned char *buf, size_t len, uint32_t tmo) {
|
|
|
|
|
int rc;
|
|
|
|
|
if (oldin.n) {
|
|
|
|
|
rc = MIN(oldin.n, len);
|
|
|
|
|
memcpy(buf, oldin.p, rc);
|
|
|
|
|
oldin.p += rc;
|
|
|
|
|
oldin.n -= rc;
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
return TlsRecvImpl(ctx, buf, len, tmo);
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-24 19:31:26 +00:00
|
|
|
|
static ssize_t SslRead(int fd, void *buf, size_t size) {
|
|
|
|
|
int rc;
|
|
|
|
|
rc = mbedtls_ssl_read(&ssl, buf, size);
|
|
|
|
|
if (!rc) {
|
|
|
|
|
errno = ECONNRESET;
|
|
|
|
|
rc = -1;
|
|
|
|
|
} else if (rc < 0) {
|
|
|
|
|
if (rc == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {
|
|
|
|
|
rc = 0;
|
|
|
|
|
} else if (rc == MBEDTLS_ERR_NET_CONN_RESET ||
|
|
|
|
|
rc == MBEDTLS_ERR_SSL_TIMEOUT) {
|
|
|
|
|
errno = ECONNRESET;
|
|
|
|
|
rc = -1;
|
|
|
|
|
} else if (rc == MBEDTLS_ERR_SSL_WANT_READ) {
|
|
|
|
|
errno = EINTR;
|
|
|
|
|
rc = -1;
|
2022-03-19 10:37:00 +00:00
|
|
|
|
errno = 0;
|
2022-05-17 18:38:35 +00:00
|
|
|
|
} else if (rc == MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE) {
|
|
|
|
|
WARNF("(ssl) %s SslRead error -0x%04x (%s)", DescribeClient(), -rc,
|
|
|
|
|
"fatal alert message");
|
|
|
|
|
errno = EIO;
|
|
|
|
|
rc = -1;
|
|
|
|
|
} else if (rc == MBEDTLS_ERR_SSL_INVALID_RECORD) {
|
|
|
|
|
WARNF("(ssl) %s SslRead error -0x%04x (%s)", DescribeClient(), -rc,
|
|
|
|
|
"invalid record");
|
|
|
|
|
errno = EIO;
|
|
|
|
|
rc = -1;
|
|
|
|
|
} else if (rc == MBEDTLS_ERR_SSL_INVALID_MAC) {
|
|
|
|
|
WARNF("(ssl) %s SslRead error -0x%04x (%s)", DescribeClient(), -rc,
|
|
|
|
|
"hmac verification failed");
|
|
|
|
|
errno = EIO;
|
|
|
|
|
rc = -1;
|
2021-06-24 19:31:26 +00:00
|
|
|
|
} else {
|
2021-08-22 22:01:52 +00:00
|
|
|
|
WARNF("(ssl) %s SslRead error -0x%04x", DescribeClient(), -rc);
|
2021-06-24 19:31:26 +00:00
|
|
|
|
errno = EIO;
|
|
|
|
|
rc = -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static ssize_t SslWrite(int fd, struct iovec *iov, int iovlen) {
|
|
|
|
|
int i;
|
|
|
|
|
size_t n;
|
|
|
|
|
ssize_t rc;
|
|
|
|
|
const unsigned char *p;
|
|
|
|
|
for (i = 0; i < iovlen; ++i) {
|
|
|
|
|
p = iov[i].iov_base;
|
|
|
|
|
n = iov[i].iov_len;
|
|
|
|
|
while (n) {
|
|
|
|
|
if ((rc = mbedtls_ssl_write(&ssl, p, n)) > 0) {
|
|
|
|
|
p += rc;
|
|
|
|
|
n -= rc;
|
2022-05-17 18:38:35 +00:00
|
|
|
|
} else if (rc == MBEDTLS_ERR_NET_CONN_RESET) {
|
|
|
|
|
errno = ECONNRESET;
|
|
|
|
|
return -1;
|
|
|
|
|
} else if (rc == MBEDTLS_ERR_SSL_TIMEOUT) {
|
|
|
|
|
errno = ETIMEDOUT;
|
|
|
|
|
return -1;
|
2021-06-24 19:31:26 +00:00
|
|
|
|
} else {
|
2021-08-22 22:01:52 +00:00
|
|
|
|
WARNF("(ssl) %s SslWrite error -0x%04x", DescribeClient(), -rc);
|
2021-06-24 19:31:26 +00:00
|
|
|
|
errno = EIO;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-08 04:44:27 +00:00
|
|
|
|
static void NotifyClose(void) {
|
|
|
|
|
#ifndef UNSECURE
|
2022-05-29 15:14:55 +00:00
|
|
|
|
if (usingssl) {
|
2021-08-22 22:01:52 +00:00
|
|
|
|
DEBUGF("(ssl) SSL notifying close");
|
2021-07-08 04:44:27 +00:00
|
|
|
|
mbedtls_ssl_close_notify(&ssl);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-18 09:33:37 +00:00
|
|
|
|
static void WipeSigningKeys(void) {
|
2021-07-12 06:17:47 +00:00
|
|
|
|
size_t i;
|
2021-07-19 21:55:20 +00:00
|
|
|
|
if (uniprocess)
|
|
|
|
|
return;
|
2021-07-12 06:17:47 +00:00
|
|
|
|
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;
|
|
|
|
|
mbedtls_pk_free(certs.p[i].key);
|
2022-04-06 17:53:17 +00:00
|
|
|
|
Free(&certs.p[i].key);
|
2021-07-12 06:17:47 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-18 09:33:37 +00:00
|
|
|
|
static void PsksDestroy(void) {
|
2021-08-09 14:00:23 +00:00
|
|
|
|
size_t i;
|
|
|
|
|
for (i = 0; i < psks.n; ++i) {
|
|
|
|
|
mbedtls_platform_zeroize(psks.p[i].key, psks.p[i].key_len);
|
2022-03-18 09:33:37 +00:00
|
|
|
|
free(psks.p[i].key);
|
|
|
|
|
free(psks.p[i].identity);
|
|
|
|
|
}
|
|
|
|
|
Free(&psks.p);
|
|
|
|
|
psks.n = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void CertsDestroy(void) {
|
|
|
|
|
size_t i;
|
2022-04-06 17:53:17 +00:00
|
|
|
|
// break up certificate chains to prevent double free
|
|
|
|
|
for (i = 0; i < certs.n; ++i) {
|
|
|
|
|
if (certs.p[i].cert) {
|
|
|
|
|
certs.p[i].cert->next = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-03-18 09:33:37 +00:00
|
|
|
|
for (i = 0; i < certs.n; ++i) {
|
|
|
|
|
mbedtls_x509_crt_free(certs.p[i].cert);
|
|
|
|
|
free(certs.p[i].cert);
|
|
|
|
|
mbedtls_pk_free(certs.p[i].key);
|
|
|
|
|
free(certs.p[i].key);
|
2021-08-09 14:00:23 +00:00
|
|
|
|
}
|
2022-03-18 09:33:37 +00:00
|
|
|
|
Free(&certs.p);
|
|
|
|
|
certs.n = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void WipeServingKeys(void) {
|
|
|
|
|
if (uniprocess)
|
|
|
|
|
return;
|
|
|
|
|
mbedtls_ssl_ticket_free(&ssltick);
|
|
|
|
|
mbedtls_ssl_key_cert_free(conf.key_cert), conf.key_cert = 0;
|
|
|
|
|
CertsDestroy();
|
|
|
|
|
PsksDestroy();
|
2021-07-19 21:55:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-03-22 02:31:03 +00:00
|
|
|
|
static bool CertHasCommonName(const mbedtls_x509_crt *cert, const void *s,
|
|
|
|
|
size_t n) {
|
2021-08-06 21:12:11 +00:00
|
|
|
|
const mbedtls_x509_name *name;
|
|
|
|
|
for (name = &cert->subject; name; name = name->next) {
|
|
|
|
|
if (!MBEDTLS_OID_CMP(MBEDTLS_OID_AT_CN, &name->oid)) {
|
2021-08-14 13:17:56 +00:00
|
|
|
|
if (SlicesEqualCase(s, n, name->val.p, name->val.len)) {
|
2021-08-06 21:12:11 +00:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
2021-07-19 21:55:20 +00:00
|
|
|
|
}
|
2021-08-06 21:12:11 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool TlsRouteFind(mbedtls_pk_type_t type, mbedtls_ssl_context *ssl,
|
|
|
|
|
const unsigned char *host, size_t size, int64_t ip) {
|
|
|
|
|
int i;
|
|
|
|
|
for (i = 0; i < certs.n; ++i) {
|
2021-08-14 13:17:56 +00:00
|
|
|
|
if (IsServerCert(certs.p + i, type) &&
|
2021-08-06 21:12:11 +00:00
|
|
|
|
(((certs.p[i].cert->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME) &&
|
|
|
|
|
(ip == -1 ? CertHasHost(certs.p[i].cert, host, size)
|
|
|
|
|
: CertHasIp(certs.p[i].cert, ip))) ||
|
|
|
|
|
CertHasCommonName(certs.p[i].cert, host, size))) {
|
|
|
|
|
CHECK_EQ(
|
|
|
|
|
0, mbedtls_ssl_set_hs_own_cert(ssl, certs.p[i].cert, certs.p[i].key));
|
2021-09-07 18:40:11 +00:00
|
|
|
|
DEBUGF("(ssl) TlsRoute(%s, %`'.*s) %s %`'s", mbedtls_pk_type_name(type),
|
|
|
|
|
size, host, mbedtls_pk_get_name(&certs.p[i].cert->pk),
|
2024-01-08 18:07:35 +00:00
|
|
|
|
gc(FormatX509Name(&certs.p[i].cert->subject)));
|
2021-08-06 21:12:11 +00:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool TlsRouteFirst(mbedtls_pk_type_t type, mbedtls_ssl_context *ssl) {
|
|
|
|
|
int i;
|
|
|
|
|
for (i = 0; i < certs.n; ++i) {
|
2021-08-14 13:17:56 +00:00
|
|
|
|
if (IsServerCert(certs.p + i, type)) {
|
2021-08-06 21:12:11 +00:00
|
|
|
|
CHECK_EQ(
|
|
|
|
|
0, mbedtls_ssl_set_hs_own_cert(ssl, certs.p[i].cert, certs.p[i].key));
|
2021-08-22 22:01:52 +00:00
|
|
|
|
DEBUGF("(ssl) TlsRoute(%s) %s %`'s", mbedtls_pk_type_name(type),
|
2021-08-06 21:12:11 +00:00
|
|
|
|
mbedtls_pk_get_name(&certs.p[i].cert->pk),
|
2024-01-08 18:07:35 +00:00
|
|
|
|
gc(FormatX509Name(&certs.p[i].cert->subject)));
|
2021-08-06 21:12:11 +00:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
2021-07-19 21:55:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int TlsRoute(void *ctx, mbedtls_ssl_context *ssl,
|
|
|
|
|
const unsigned char *host, size_t size) {
|
|
|
|
|
int64_t ip;
|
2021-08-06 21:12:11 +00:00
|
|
|
|
bool ok1, ok2;
|
2021-07-19 21:55:20 +00:00
|
|
|
|
ip = ParseIp((const char *)host, size);
|
2021-08-06 21:12:11 +00:00
|
|
|
|
ok1 = TlsRouteFind(MBEDTLS_PK_ECKEY, ssl, host, size, ip);
|
|
|
|
|
ok2 = TlsRouteFind(MBEDTLS_PK_RSA, ssl, host, size, ip);
|
|
|
|
|
if (!ok1 && !ok2) {
|
2021-08-22 22:01:52 +00:00
|
|
|
|
WARNF("(ssl) TlsRoute(%`'.*s) not found", size, host);
|
2021-08-06 21:12:11 +00:00
|
|
|
|
ok1 = TlsRouteFirst(MBEDTLS_PK_ECKEY, ssl);
|
|
|
|
|
ok2 = TlsRouteFirst(MBEDTLS_PK_RSA, ssl);
|
2021-07-19 21:55:20 +00:00
|
|
|
|
}
|
2021-08-06 21:12:11 +00:00
|
|
|
|
return ok1 || ok2 ? 0 : -1;
|
2021-07-12 06:17:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-09 14:00:23 +00:00
|
|
|
|
static int TlsRoutePsk(void *ctx, mbedtls_ssl_context *ssl,
|
|
|
|
|
const unsigned char *identity, size_t identity_len) {
|
|
|
|
|
size_t i;
|
|
|
|
|
for (i = 0; i < psks.n; ++i) {
|
|
|
|
|
if (SlicesEqual((void *)identity, identity_len, psks.p[i].identity,
|
|
|
|
|
psks.p[i].identity_len)) {
|
2021-08-22 22:01:52 +00:00
|
|
|
|
DEBUGF("(ssl) TlsRoutePsk(%`'.*s)", identity_len, identity);
|
2021-08-09 14:00:23 +00:00
|
|
|
|
mbedtls_ssl_set_hs_psk(ssl, psks.p[i].key, psks.p[i].key_len);
|
2022-03-15 00:11:05 +00:00
|
|
|
|
// keep track of selected psk to report its identity
|
2022-03-18 09:33:37 +00:00
|
|
|
|
sslpskindex = i + 1; // use index+1 to check against 0 (when not set)
|
2021-08-09 14:00:23 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-08-22 22:01:52 +00:00
|
|
|
|
WARNF("(ssl) TlsRoutePsk(%`'.*s) not found", identity_len, identity);
|
2021-08-09 14:00:23 +00:00
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-24 19:31:26 +00:00
|
|
|
|
static bool TlsSetup(void) {
|
|
|
|
|
int r;
|
|
|
|
|
oldin.p = inbuf.p;
|
|
|
|
|
oldin.n = amtread;
|
|
|
|
|
inbuf.p += amtread;
|
|
|
|
|
inbuf.n -= amtread;
|
|
|
|
|
inbuf.c = amtread;
|
|
|
|
|
amtread = 0;
|
2021-07-09 04:54:21 +00:00
|
|
|
|
g_bio.fd = client;
|
|
|
|
|
g_bio.a = 0;
|
|
|
|
|
g_bio.b = 0;
|
2021-07-12 06:17:47 +00:00
|
|
|
|
g_bio.c = 0;
|
2022-03-15 00:11:05 +00:00
|
|
|
|
sslpskindex = 0;
|
2021-06-24 19:31:26 +00:00
|
|
|
|
for (;;) {
|
2021-07-12 06:17:47 +00:00
|
|
|
|
if (!(r = mbedtls_ssl_handshake(&ssl)) && TlsFlush(&g_bio, 0, 0) != -1) {
|
2021-06-24 19:31:26 +00:00
|
|
|
|
LockInc(&shared->c.sslhandshakes);
|
2021-07-12 06:17:47 +00:00
|
|
|
|
g_bio.c = -1;
|
2022-05-29 15:14:55 +00:00
|
|
|
|
usingssl = true;
|
2021-06-24 19:31:26 +00:00
|
|
|
|
reader = SslRead;
|
|
|
|
|
writer = SslWrite;
|
2021-07-12 06:17:47 +00:00
|
|
|
|
WipeServingKeys();
|
2021-08-22 22:01:52 +00:00
|
|
|
|
VERBOSEF("(ssl) shaken %s %s %s%s %s", DescribeClient(),
|
2021-08-09 14:00:23 +00:00
|
|
|
|
mbedtls_ssl_get_ciphersuite(&ssl), mbedtls_ssl_get_version(&ssl),
|
|
|
|
|
ssl.session->compression ? " COMPRESSED" : "",
|
2022-03-18 09:33:37 +00:00
|
|
|
|
ssl.curve ? ssl.curve->name : "uncurved");
|
|
|
|
|
DEBUGF("(ssl) client ciphersuite preference was %s",
|
2024-01-08 18:07:35 +00:00
|
|
|
|
gc(FormatSslClientCiphers(&ssl)));
|
2021-06-24 19:31:26 +00:00
|
|
|
|
return true;
|
|
|
|
|
} else if (r == MBEDTLS_ERR_SSL_WANT_READ) {
|
|
|
|
|
LockInc(&shared->c.handshakeinterrupts);
|
2022-08-06 02:24:05 +00:00
|
|
|
|
if (terminated || killed || IsTakingTooLong()) {
|
2021-06-24 19:31:26 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
LockInc(&shared->c.sslhandshakefails);
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
mbedtls_ssl_session_reset(&ssl);
|
2021-06-24 19:31:26 +00:00
|
|
|
|
switch (r) {
|
|
|
|
|
case MBEDTLS_ERR_SSL_CONN_EOF:
|
2021-08-22 22:01:52 +00:00
|
|
|
|
DEBUGF("(ssl) %s SSL handshake EOF", DescribeClient());
|
2021-06-24 19:31:26 +00:00
|
|
|
|
return false;
|
|
|
|
|
case MBEDTLS_ERR_NET_CONN_RESET:
|
2021-08-22 22:01:52 +00:00
|
|
|
|
DEBUGF("(ssl) %s SSL handshake reset", DescribeClient());
|
2021-06-24 19:31:26 +00:00
|
|
|
|
return false;
|
|
|
|
|
case MBEDTLS_ERR_SSL_TIMEOUT:
|
|
|
|
|
LockInc(&shared->c.ssltimeouts);
|
2021-08-22 22:01:52 +00:00
|
|
|
|
DEBUGF("(ssl) %s %s", DescribeClient(), "ssltimeouts");
|
2021-06-24 19:31:26 +00:00
|
|
|
|
return false;
|
|
|
|
|
case MBEDTLS_ERR_SSL_NO_CIPHER_CHOSEN:
|
|
|
|
|
LockInc(&shared->c.sslnociphers);
|
2022-03-18 09:33:37 +00:00
|
|
|
|
WARNF("(ssl) %s %s %s", DescribeClient(), "sslnociphers",
|
2024-01-08 18:07:35 +00:00
|
|
|
|
gc(FormatSslClientCiphers(&ssl)));
|
2021-06-24 19:31:26 +00:00
|
|
|
|
return false;
|
|
|
|
|
case MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE:
|
|
|
|
|
LockInc(&shared->c.sslcantciphers);
|
2022-03-18 09:33:37 +00:00
|
|
|
|
WARNF("(ssl) %s %s %s", DescribeClient(), "sslcantciphers",
|
2024-01-08 18:07:35 +00:00
|
|
|
|
gc(FormatSslClientCiphers(&ssl)));
|
2021-06-24 19:31:26 +00:00
|
|
|
|
return false;
|
2021-06-24 22:22:24 +00:00
|
|
|
|
case MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION:
|
|
|
|
|
LockInc(&shared->c.sslnoversion);
|
2022-03-18 09:33:37 +00:00
|
|
|
|
WARNF("(ssl) %s %s %s", DescribeClient(), "sslnoversion",
|
|
|
|
|
mbedtls_ssl_get_version(&ssl));
|
2021-06-24 22:22:24 +00:00
|
|
|
|
return false;
|
2021-06-24 19:31:26 +00:00
|
|
|
|
case MBEDTLS_ERR_SSL_INVALID_MAC:
|
|
|
|
|
LockInc(&shared->c.sslshakemacs);
|
2021-08-22 22:01:52 +00:00
|
|
|
|
WARNF("(ssl) %s %s", DescribeClient(), "sslshakemacs");
|
2021-07-08 04:44:27 +00:00
|
|
|
|
return false;
|
|
|
|
|
case MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE:
|
|
|
|
|
LockInc(&shared->c.sslnoclientcert);
|
2021-08-22 22:01:52 +00:00
|
|
|
|
WARNF("(ssl) %s %s", DescribeClient(), "sslnoclientcert");
|
2021-07-08 04:44:27 +00:00
|
|
|
|
NotifyClose();
|
|
|
|
|
return false;
|
|
|
|
|
case MBEDTLS_ERR_X509_CERT_VERIFY_FAILED:
|
|
|
|
|
LockInc(&shared->c.sslverifyfailed);
|
2021-08-22 22:01:52 +00:00
|
|
|
|
WARNF("(ssl) %s SSL %s", DescribeClient(),
|
2024-01-08 18:07:35 +00:00
|
|
|
|
gc(DescribeSslVerifyFailure(
|
2021-07-08 04:44:27 +00:00
|
|
|
|
ssl.session_negotiate->verify_result)));
|
2021-06-24 19:31:26 +00:00
|
|
|
|
return false;
|
|
|
|
|
case MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE:
|
|
|
|
|
switch (ssl.fatal_alert) {
|
|
|
|
|
case MBEDTLS_SSL_ALERT_MSG_CERT_UNKNOWN:
|
|
|
|
|
LockInc(&shared->c.sslunknowncert);
|
2021-08-22 22:01:52 +00:00
|
|
|
|
DEBUGF("(ssl) %s %s", DescribeClient(), "sslunknowncert");
|
2021-06-24 19:31:26 +00:00
|
|
|
|
return false;
|
|
|
|
|
case MBEDTLS_SSL_ALERT_MSG_UNKNOWN_CA:
|
|
|
|
|
LockInc(&shared->c.sslunknownca);
|
2021-08-22 22:01:52 +00:00
|
|
|
|
DEBUGF("(ssl) %s %s", DescribeClient(), "sslunknownca");
|
2021-06-24 19:31:26 +00:00
|
|
|
|
return false;
|
|
|
|
|
default:
|
2021-08-22 22:01:52 +00:00
|
|
|
|
WARNF("(ssl) %s SSL shakealert %s", DescribeClient(),
|
2021-07-06 20:39:18 +00:00
|
|
|
|
GetAlertDescription(ssl.fatal_alert));
|
2021-06-24 19:31:26 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
default:
|
2021-08-22 22:01:52 +00:00
|
|
|
|
WARNF("(ssl) %s SSL handshake failed -0x%04x", DescribeClient(), -r);
|
2021-06-24 19:31:26 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void ConfigureCertificate(mbedtls_x509write_cert *cw, struct Cert *ca,
|
|
|
|
|
int usage, int type) {
|
2023-12-29 06:58:17 +00:00
|
|
|
|
int nsan = 0;
|
|
|
|
|
char *name = 0;
|
|
|
|
|
struct mbedtls_san *san = 0;
|
|
|
|
|
|
|
|
|
|
// for each ip address owned by this system
|
|
|
|
|
//
|
|
|
|
|
// 1. determine its full-qualified domain name
|
|
|
|
|
// 2. add subject alt name (san) entry to cert for hostname
|
|
|
|
|
// 3. add subject alt name (san) entry to cert for *.hostname
|
|
|
|
|
//
|
|
|
|
|
for (int i = 0; i < ips.n; ++i) {
|
|
|
|
|
uint32_t ip = ips.p[i];
|
|
|
|
|
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) {
|
2024-01-08 18:07:35 +00:00
|
|
|
|
char *s = gc(strdup(rname));
|
2023-12-29 06:58:17 +00:00
|
|
|
|
if (!name)
|
|
|
|
|
name = s;
|
|
|
|
|
bool isduplicate = false;
|
|
|
|
|
for (int j = 0; j < nsan; ++j) {
|
|
|
|
|
if (san[j].tag == MBEDTLS_X509_SAN_DNS_NAME &&
|
|
|
|
|
!strcasecmp(s, san[j].val)) {
|
|
|
|
|
isduplicate = true;
|
|
|
|
|
break;
|
2021-06-24 19:31:26 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2023-12-29 06:58:17 +00:00
|
|
|
|
if (!isduplicate) {
|
|
|
|
|
san = realloc(san, (nsan += 2) * sizeof(*san));
|
|
|
|
|
san[nsan - 2].tag = MBEDTLS_X509_SAN_DNS_NAME;
|
|
|
|
|
san[nsan - 2].val = s;
|
|
|
|
|
san[nsan - 1].tag = MBEDTLS_X509_SAN_DNS_NAME;
|
2024-01-08 18:07:35 +00:00
|
|
|
|
san[nsan - 1].val = gc(xasprintf("*.%s", s));
|
2023-12-29 06:58:17 +00:00
|
|
|
|
}
|
2021-06-24 19:31:26 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2023-12-29 06:58:17 +00:00
|
|
|
|
|
|
|
|
|
// 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;
|
2021-06-24 19:31:26 +00:00
|
|
|
|
san = realloc(san, ++nsan * sizeof(*san));
|
|
|
|
|
san[nsan - 1].tag = MBEDTLS_X509_SAN_IP_ADDRESS;
|
2023-12-29 06:58:17 +00:00
|
|
|
|
san[nsan - 1].ip4 = ip;
|
2021-06-24 19:31:26 +00:00
|
|
|
|
}
|
2023-12-29 06:58:17 +00:00
|
|
|
|
char notbefore[16], notafter[16];
|
2021-06-24 19:31:26 +00:00
|
|
|
|
ChooseCertificateLifetime(notbefore, notafter);
|
2023-12-29 06:58:17 +00:00
|
|
|
|
|
|
|
|
|
// pick common name for certificate
|
|
|
|
|
char hbuf[256];
|
|
|
|
|
if (!name) {
|
|
|
|
|
strcpy(hbuf, "localhost");
|
|
|
|
|
gethostname(hbuf, sizeof(hbuf));
|
|
|
|
|
name = hbuf;
|
|
|
|
|
}
|
|
|
|
|
char *subject = xasprintf("CN=%s", name);
|
|
|
|
|
|
|
|
|
|
// pick issuer name for certificate
|
|
|
|
|
char *issuer;
|
2021-06-24 19:31:26 +00:00
|
|
|
|
if (ca) {
|
|
|
|
|
issuer = calloc(1, 1000);
|
|
|
|
|
CHECK_GT(mbedtls_x509_dn_gets(issuer, 1000, &ca->cert->subject), 0);
|
|
|
|
|
} else {
|
|
|
|
|
issuer = strdup(subject);
|
|
|
|
|
}
|
2023-12-29 06:58:17 +00:00
|
|
|
|
|
|
|
|
|
// call the mbedtls apis
|
|
|
|
|
int r;
|
2021-06-24 19:31:26 +00:00
|
|
|
|
if ((r = mbedtls_x509write_crt_set_subject_alternative_name(cw, san, nsan)) ||
|
|
|
|
|
(r = mbedtls_x509write_crt_set_validity(cw, notbefore, notafter)) ||
|
|
|
|
|
(r = mbedtls_x509write_crt_set_basic_constraints(cw, false, -1)) ||
|
2021-08-14 13:17:56 +00:00
|
|
|
|
#if defined(MBEDTLS_SHA1_C)
|
2021-06-24 19:31:26 +00:00
|
|
|
|
(r = mbedtls_x509write_crt_set_subject_key_identifier(cw)) ||
|
|
|
|
|
(r = mbedtls_x509write_crt_set_authority_key_identifier(cw)) ||
|
2021-08-14 13:17:56 +00:00
|
|
|
|
#endif
|
2021-06-24 19:31:26 +00:00
|
|
|
|
(r = mbedtls_x509write_crt_set_key_usage(cw, usage)) ||
|
|
|
|
|
(r = mbedtls_x509write_crt_set_ext_key_usage(cw, type)) ||
|
|
|
|
|
(r = mbedtls_x509write_crt_set_subject_name(cw, subject)) ||
|
|
|
|
|
(r = mbedtls_x509write_crt_set_issuer_name(cw, issuer))) {
|
2022-06-27 04:25:02 +00:00
|
|
|
|
FATALF("(ssl) configure certificate (grep -0x%04x)", -r);
|
2021-06-24 19:31:26 +00:00
|
|
|
|
}
|
|
|
|
|
free(subject);
|
|
|
|
|
free(issuer);
|
|
|
|
|
free(san);
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-19 21:55:20 +00:00
|
|
|
|
static struct Cert GetKeySigningKey(void) {
|
2021-06-24 19:31:26 +00:00
|
|
|
|
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 (mbedtls_x509_crt_check_key_usage(certs.p[i].cert,
|
|
|
|
|
MBEDTLS_X509_KU_KEY_CERT_SIGN)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2021-07-19 21:55:20 +00:00
|
|
|
|
return certs.p[i];
|
2021-06-24 19:31:26 +00:00
|
|
|
|
}
|
2021-07-19 21:55:20 +00:00
|
|
|
|
return (struct Cert){0};
|
2021-06-24 19:31:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-07-08 04:44:27 +00:00
|
|
|
|
static struct Cert GenerateEcpCertificate(struct Cert *ca) {
|
2021-06-24 19:31:26 +00:00
|
|
|
|
mbedtls_pk_context *key;
|
2021-08-14 13:17:56 +00:00
|
|
|
|
mbedtls_md_type_t md_alg;
|
2021-06-24 19:31:26 +00:00
|
|
|
|
mbedtls_x509write_cert wcert;
|
2021-08-14 13:17:56 +00:00
|
|
|
|
md_alg = suiteb ? MBEDTLS_MD_SHA384 : MBEDTLS_MD_SHA256;
|
|
|
|
|
key = InitializeKey(ca, &wcert, md_alg, MBEDTLS_PK_ECKEY);
|
2021-06-24 19:31:26 +00:00
|
|
|
|
CHECK_EQ(0, mbedtls_ecp_gen_key(
|
|
|
|
|
suiteb ? MBEDTLS_ECP_DP_SECP384R1 : MBEDTLS_ECP_DP_SECP256R1,
|
2021-09-28 05:58:51 +00:00
|
|
|
|
mbedtls_pk_ec(*key), GenerateHardRandom, 0));
|
|
|
|
|
GenerateCertificateSerial(&wcert);
|
2021-06-24 19:31:26 +00:00
|
|
|
|
ConfigureCertificate(&wcert, ca, MBEDTLS_X509_KU_DIGITAL_SIGNATURE,
|
2021-07-08 04:44:27 +00:00
|
|
|
|
MBEDTLS_X509_NS_CERT_TYPE_SSL_SERVER |
|
|
|
|
|
MBEDTLS_X509_NS_CERT_TYPE_SSL_CLIENT);
|
2021-09-28 05:58:51 +00:00
|
|
|
|
return FinishCertificate(ca, &wcert, key);
|
2021-06-24 19:31:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-06-24 22:22:24 +00:00
|
|
|
|
static struct Cert GenerateRsaCertificate(struct Cert *ca) {
|
2021-06-24 19:31:26 +00:00
|
|
|
|
mbedtls_pk_context *key;
|
2021-08-14 13:17:56 +00:00
|
|
|
|
mbedtls_md_type_t md_alg;
|
2021-06-24 19:31:26 +00:00
|
|
|
|
mbedtls_x509write_cert wcert;
|
2021-08-14 13:17:56 +00:00
|
|
|
|
md_alg = suiteb ? MBEDTLS_MD_SHA384 : MBEDTLS_MD_SHA256;
|
|
|
|
|
key = InitializeKey(ca, &wcert, md_alg, MBEDTLS_PK_RSA);
|
2021-09-28 05:58:51 +00:00
|
|
|
|
CHECK_EQ(0, mbedtls_rsa_gen_key(mbedtls_pk_rsa(*key), GenerateHardRandom, 0,
|
|
|
|
|
suiteb ? 4096 : 2048, 65537));
|
|
|
|
|
GenerateCertificateSerial(&wcert);
|
2021-06-24 19:31:26 +00:00
|
|
|
|
ConfigureCertificate(
|
|
|
|
|
&wcert, ca,
|
|
|
|
|
MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_KEY_ENCIPHERMENT,
|
|
|
|
|
MBEDTLS_X509_NS_CERT_TYPE_SSL_SERVER |
|
|
|
|
|
MBEDTLS_X509_NS_CERT_TYPE_SSL_CLIENT);
|
2021-09-28 05:58:51 +00:00
|
|
|
|
return FinishCertificate(ca, &wcert, key);
|
2021-06-24 19:31:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void LoadCertificates(void) {
|
|
|
|
|
size_t i;
|
2021-07-19 21:55:20 +00:00
|
|
|
|
struct Cert ksk, ecp, rsa;
|
2021-07-08 04:44:27 +00:00
|
|
|
|
bool havecert, haveclientcert;
|
2021-06-24 19:31:26 +00:00
|
|
|
|
havecert = false;
|
2021-07-08 04:44:27 +00:00
|
|
|
|
haveclientcert = false;
|
2021-06-24 19:31:26 +00:00
|
|
|
|
for (i = 0; i < certs.n; ++i) {
|
|
|
|
|
if (certs.p[i].key && certs.p[i].cert && !certs.p[i].cert->ca_istrue &&
|
|
|
|
|
!mbedtls_x509_crt_check_key_usage(certs.p[i].cert,
|
2021-07-08 04:44:27 +00:00
|
|
|
|
MBEDTLS_X509_KU_DIGITAL_SIGNATURE)) {
|
|
|
|
|
if (!mbedtls_x509_crt_check_extended_key_usage(
|
|
|
|
|
certs.p[i].cert, MBEDTLS_OID_SERVER_AUTH,
|
|
|
|
|
MBEDTLS_OID_SIZE(MBEDTLS_OID_SERVER_AUTH))) {
|
|
|
|
|
LogCertificate("using server certificate", certs.p[i].cert);
|
2021-08-06 21:12:11 +00:00
|
|
|
|
UseCertificate(&conf, certs.p + i, "server");
|
2021-07-08 04:44:27 +00:00
|
|
|
|
havecert = true;
|
|
|
|
|
}
|
|
|
|
|
if (!mbedtls_x509_crt_check_extended_key_usage(
|
|
|
|
|
certs.p[i].cert, MBEDTLS_OID_CLIENT_AUTH,
|
|
|
|
|
MBEDTLS_OID_SIZE(MBEDTLS_OID_CLIENT_AUTH))) {
|
|
|
|
|
LogCertificate("using client certificate", certs.p[i].cert);
|
2021-08-06 21:12:11 +00:00
|
|
|
|
UseCertificate(&confcli, certs.p + i, "client");
|
2021-07-08 04:44:27 +00:00
|
|
|
|
haveclientcert = true;
|
|
|
|
|
}
|
2021-06-24 19:31:26 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2021-08-09 14:00:23 +00:00
|
|
|
|
if (!havecert && (!psks.n || ksk.key)) {
|
2021-07-19 21:55:20 +00:00
|
|
|
|
if ((ksk = GetKeySigningKey()).key) {
|
2021-08-22 22:01:52 +00:00
|
|
|
|
DEBUGF("(ssl) generating ssl certificates using %`'s",
|
2024-01-08 18:07:35 +00:00
|
|
|
|
gc(FormatX509Name(&ksk.cert->subject)));
|
2021-06-24 19:31:26 +00:00
|
|
|
|
} else {
|
2021-08-22 22:01:52 +00:00
|
|
|
|
VERBOSEF("(ssl) could not find non-CA SSL certificate key pair with"
|
2021-06-24 19:31:26 +00:00
|
|
|
|
" -addext keyUsage=digitalSignature"
|
|
|
|
|
" -addext extendedKeyUsage=serverAuth");
|
2021-08-22 22:01:52 +00:00
|
|
|
|
VERBOSEF("(ssl) could not find CA key signing key pair with"
|
2021-06-24 19:31:26 +00:00
|
|
|
|
" -addext keyUsage=keyCertSign");
|
2021-08-22 22:01:52 +00:00
|
|
|
|
VERBOSEF("(ssl) generating self-signed ssl certificates");
|
2021-06-24 19:31:26 +00:00
|
|
|
|
}
|
|
|
|
|
#ifdef MBEDTLS_ECP_C
|
2021-07-19 21:55:20 +00:00
|
|
|
|
ecp = GenerateEcpCertificate(ksk.key ? &ksk : 0);
|
2021-08-06 21:12:11 +00:00
|
|
|
|
if (!havecert)
|
|
|
|
|
UseCertificate(&conf, &ecp, "server");
|
2022-05-29 15:14:55 +00:00
|
|
|
|
if (!haveclientcert && ksk.key) {
|
|
|
|
|
UseCertificate(&confcli, &ecp, "client");
|
|
|
|
|
}
|
2021-07-19 21:55:20 +00:00
|
|
|
|
AppendCert(ecp.cert, ecp.key);
|
2021-06-24 22:22:24 +00:00
|
|
|
|
#endif
|
|
|
|
|
#ifdef MBEDTLS_RSA_C
|
2022-05-29 15:14:55 +00:00
|
|
|
|
if (!norsagen) {
|
|
|
|
|
rsa = GenerateRsaCertificate(ksk.key ? &ksk : 0);
|
|
|
|
|
if (!havecert)
|
|
|
|
|
UseCertificate(&conf, &rsa, "server");
|
|
|
|
|
if (!haveclientcert && ksk.key) {
|
|
|
|
|
UseCertificate(&confcli, &rsa, "client");
|
|
|
|
|
}
|
|
|
|
|
AppendCert(rsa.cert, rsa.key);
|
|
|
|
|
}
|
2021-06-24 19:31:26 +00:00
|
|
|
|
#endif
|
|
|
|
|
}
|
2022-03-18 09:33:37 +00:00
|
|
|
|
WipeSigningKeys();
|
2021-06-24 19:31:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-03-25 09:21:13 +00:00
|
|
|
|
static bool ClientAcceptsGzip(void) {
|
2022-08-06 00:34:53 +00:00
|
|
|
|
return cpm.msg.version >= 10 && /* RFC1945 § 3.5 */
|
|
|
|
|
HeaderHas(&cpm.msg, inbuf.p, kHttpAcceptEncoding, "gzip", 4);
|
2021-03-25 09:21:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-04-24 16:59:22 +00:00
|
|
|
|
char *FormatUnixHttpDateTime(char *s, int64_t t) {
|
|
|
|
|
struct tm tm;
|
|
|
|
|
gmtime_r(&t, &tm);
|
|
|
|
|
FormatHttpDateTime(s, &tm);
|
|
|
|
|
return s;
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-06 02:24:05 +00:00
|
|
|
|
static void UpdateCurrentDate(struct timespec now) {
|
2021-03-25 09:21:13 +00:00
|
|
|
|
int64_t t;
|
|
|
|
|
struct tm tm;
|
2022-08-06 02:24:05 +00:00
|
|
|
|
t = now.tv_sec;
|
2021-03-25 09:21:13 +00:00
|
|
|
|
gmtime_r(&t, &tm);
|
2024-12-02 22:05:38 +00:00
|
|
|
|
unassert(!pthread_mutex_lock(&shared->datetime_mu));
|
|
|
|
|
shared->nowish = now;
|
2021-04-23 17:45:19 +00:00
|
|
|
|
FormatHttpDateTime(shared->currentdate, &tm);
|
2024-12-02 22:05:38 +00:00
|
|
|
|
unassert(!pthread_mutex_unlock(&shared->datetime_mu));
|
2021-03-25 09:21:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-04-23 17:45:19 +00:00
|
|
|
|
static int64_t GetGmtOffset(int64_t t) {
|
2020-10-06 06:11:49 +00:00
|
|
|
|
struct tm tm;
|
|
|
|
|
localtime_r(&t, &tm);
|
|
|
|
|
return tm.tm_gmtoff;
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-03 19:09:35 +00:00
|
|
|
|
forceinline bool IsCompressed(struct Asset *a) {
|
2021-03-28 14:54:21 +00:00
|
|
|
|
return !a->file &&
|
2023-06-17 11:20:16 +00:00
|
|
|
|
ZIP_LFILE_COMPRESSIONMETHOD(zmap + a->lf) == kZipCompressionDeflate;
|
2020-10-06 06:11:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-05-03 19:09:35 +00:00
|
|
|
|
forceinline int GetMode(struct Asset *a) {
|
2023-06-17 11:20:16 +00:00
|
|
|
|
return a->file ? a->file->st.st_mode : GetZipCfileMode(zmap + a->cf);
|
2021-04-21 02:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-05-03 19:09:35 +00:00
|
|
|
|
forceinline bool IsCompressionMethodSupported(int method) {
|
2021-03-29 08:22:49 +00:00
|
|
|
|
return method == kZipCompressionNone || method == kZipCompressionDeflate;
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-05 14:25:39 +00:00
|
|
|
|
static inline unsigned Hash(const void *p, unsigned long n) {
|
2021-05-03 19:09:35 +00:00
|
|
|
|
unsigned h, i;
|
|
|
|
|
for (h = i = 0; i < n; i++) {
|
|
|
|
|
h += ((unsigned char *)p)[i];
|
|
|
|
|
h *= 0x9e3779b1;
|
|
|
|
|
}
|
|
|
|
|
return MAX(1, h);
|
|
|
|
|
}
|
|
|
|
|
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
static void FreeAssets(void) {
|
|
|
|
|
size_t i;
|
|
|
|
|
for (i = 0; i < assets.n; ++i) {
|
2022-03-18 09:33:37 +00:00
|
|
|
|
Free(&assets.p[i].lastmodifiedstr);
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
}
|
|
|
|
|
Free(&assets.p);
|
|
|
|
|
assets.n = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void FreeStrings(struct Strings *l) {
|
|
|
|
|
size_t i;
|
|
|
|
|
for (i = 0; i < l->n; ++i) {
|
2022-03-18 09:33:37 +00:00
|
|
|
|
Free(&l->p[i].s);
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
}
|
|
|
|
|
Free(&l->p);
|
|
|
|
|
l->n = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-30 01:44:15 +00:00
|
|
|
|
static unsigned long roundup2pow(unsigned long x) {
|
2024-03-05 01:33:26 +00:00
|
|
|
|
return x > 1 ? 2ul << bsrl(x - 1) : x ? 1 : 0;
|
2023-07-30 01:44:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-03-27 14:29:55 +00:00
|
|
|
|
static void IndexAssets(void) {
|
2021-05-03 08:21:50 +00:00
|
|
|
|
uint64_t cf;
|
2020-10-06 06:11:49 +00:00
|
|
|
|
struct Asset *p;
|
2021-08-14 13:17:56 +00:00
|
|
|
|
struct timespec lm;
|
2021-04-18 18:34:59 +00:00
|
|
|
|
uint32_t i, n, m, step, hash;
|
2021-08-22 22:01:52 +00:00
|
|
|
|
DEBUGF("(zip) indexing assets (inode %#lx)", zst.st_ino);
|
2022-03-18 09:33:37 +00:00
|
|
|
|
FreeAssets();
|
2021-03-27 14:29:55 +00:00
|
|
|
|
CHECK_GE(HASH_LOAD_FACTOR, 2);
|
2021-05-02 18:50:43 +00:00
|
|
|
|
CHECK(READ32LE(zcdir) == kZipCdir64HdrMagic ||
|
|
|
|
|
READ32LE(zcdir) == kZipCdirHdrMagic);
|
|
|
|
|
n = GetZipCdirRecords(zcdir);
|
2023-07-30 01:44:15 +00:00
|
|
|
|
m = roundup2pow(MAX(1, n) * HASH_LOAD_FACTOR);
|
2021-03-27 14:29:55 +00:00
|
|
|
|
p = xcalloc(m, sizeof(struct Asset));
|
2023-06-17 11:20:16 +00:00
|
|
|
|
for (cf = GetZipCdirOffset(zcdir); n--; cf += ZIP_CFILE_HDRSIZE(zmap + cf)) {
|
|
|
|
|
CHECK_EQ(kZipCfileHdrMagic, ZIP_CFILE_MAGIC(zmap + cf));
|
|
|
|
|
if (!IsCompressionMethodSupported(ZIP_CFILE_COMPRESSIONMETHOD(zmap + cf))) {
|
2021-08-22 22:01:52 +00:00
|
|
|
|
WARNF("(zip) don't understand zip compression method %d used by %`'.*s",
|
2023-06-17 11:20:16 +00:00
|
|
|
|
ZIP_CFILE_COMPRESSIONMETHOD(zmap + cf),
|
|
|
|
|
ZIP_CFILE_NAMESIZE(zmap + cf), ZIP_CFILE_NAME(zmap + cf));
|
2021-03-29 08:22:49 +00:00
|
|
|
|
continue;
|
|
|
|
|
}
|
2023-06-17 11:20:16 +00:00
|
|
|
|
hash = Hash(ZIP_CFILE_NAME(zmap + cf), ZIP_CFILE_NAMESIZE(zmap + cf));
|
2021-03-27 14:29:55 +00:00
|
|
|
|
step = 0;
|
|
|
|
|
do {
|
2023-09-02 03:49:13 +00:00
|
|
|
|
i = (hash + ((step * (step + 1)) >> 1)) & (m - 1);
|
2021-03-27 14:29:55 +00:00
|
|
|
|
++step;
|
|
|
|
|
} while (p[i].hash);
|
2023-06-17 11:20:16 +00:00
|
|
|
|
GetZipCfileTimestamps(zmap + cf, &lm, 0, 0, gmtoff);
|
2021-03-27 14:29:55 +00:00
|
|
|
|
p[i].hash = hash;
|
2021-04-18 18:34:59 +00:00
|
|
|
|
p[i].cf = cf;
|
2023-06-17 11:20:16 +00:00
|
|
|
|
p[i].lf = GetZipCfileOffset(zmap + cf);
|
|
|
|
|
p[i].istext = !!(ZIP_CFILE_INTERNALATTRIBUTES(zmap + cf) & kZipIattrText);
|
2021-08-14 13:17:56 +00:00
|
|
|
|
p[i].lastmodified = lm.tv_sec;
|
|
|
|
|
p[i].lastmodifiedstr = FormatUnixHttpDateTime(xmalloc(30), lm.tv_sec);
|
2021-03-27 14:29:55 +00:00
|
|
|
|
}
|
|
|
|
|
assets.p = p;
|
|
|
|
|
assets.n = m;
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-14 12:36:58 +00:00
|
|
|
|
static bool OpenZip(bool force) {
|
|
|
|
|
int fd;
|
|
|
|
|
size_t n;
|
2023-09-02 03:49:13 +00:00
|
|
|
|
uint8_t *m, *d;
|
2021-05-03 19:09:35 +00:00
|
|
|
|
struct stat st;
|
2021-05-14 12:36:58 +00:00
|
|
|
|
if (stat(zpath, &st) != -1) {
|
|
|
|
|
if (force || st.st_ino != zst.st_ino || st.st_size > zst.st_size) {
|
|
|
|
|
if (st.st_ino == zst.st_ino) {
|
|
|
|
|
fd = zfd;
|
|
|
|
|
} else if ((fd = open(zpath, O_RDWR)) == -1) {
|
2021-10-25 21:44:04 +00:00
|
|
|
|
WARNF("(zip) open() error: %m");
|
2021-05-14 12:36:58 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if ((m = mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) !=
|
|
|
|
|
MAP_FAILED) {
|
|
|
|
|
n = st.st_size;
|
2023-06-17 11:20:16 +00:00
|
|
|
|
if ((d = GetZipEocd(m, n, 0))) {
|
2021-05-14 12:36:58 +00:00
|
|
|
|
if (zmap) {
|
2023-06-17 11:20:16 +00:00
|
|
|
|
LOGIFNEG1(munmap(zmap, zsize));
|
2021-05-14 12:36:58 +00:00
|
|
|
|
}
|
|
|
|
|
zmap = m;
|
|
|
|
|
zsize = n;
|
|
|
|
|
zcdir = d;
|
2023-06-17 11:20:16 +00:00
|
|
|
|
DCHECK(IsZipEocd32(zmap, zsize, zcdir - zmap) == kZipOk ||
|
|
|
|
|
IsZipEocd64(zmap, zsize, zcdir - zmap) == kZipOk);
|
2021-05-14 12:36:58 +00:00
|
|
|
|
memcpy(&zst, &st, sizeof(st));
|
|
|
|
|
IndexAssets();
|
|
|
|
|
return true;
|
|
|
|
|
} else {
|
2021-08-22 22:01:52 +00:00
|
|
|
|
WARNF("(zip) couldn't locate central directory");
|
2021-05-14 12:36:58 +00:00
|
|
|
|
}
|
|
|
|
|
} else {
|
2021-10-25 21:44:04 +00:00
|
|
|
|
WARNF("(zip) mmap() error: %m");
|
2021-05-14 12:36:58 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2022-10-19 17:00:29 +00:00
|
|
|
|
// avoid noise if we setuid to user who can't see executable
|
|
|
|
|
if (errno == EACCES) {
|
|
|
|
|
VERBOSEF("(zip) stat(%`'s) error: %m", zpath);
|
|
|
|
|
} else {
|
|
|
|
|
WARNF("(zip) stat(%`'s) error: %m", zpath);
|
|
|
|
|
}
|
2021-05-03 19:09:35 +00:00
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-21 02:14:21 +00:00
|
|
|
|
static struct Asset *GetAssetZip(const char *path, size_t pathlen) {
|
2020-10-06 06:11:49 +00:00
|
|
|
|
uint32_t i, step, hash;
|
2021-04-21 02:14:21 +00:00
|
|
|
|
if (pathlen > 1 && path[0] == '/')
|
|
|
|
|
++path, --pathlen;
|
2020-10-06 06:11:49 +00:00
|
|
|
|
hash = Hash(path, pathlen);
|
|
|
|
|
for (step = 0;; ++step) {
|
2023-09-02 03:49:13 +00:00
|
|
|
|
i = (hash + ((step * (step + 1)) >> 1)) & (assets.n - 1);
|
2024-09-22 04:28:35 +00:00
|
|
|
|
if (i >= assets.n || !assets.p || !assets.p[i].hash)
|
2020-10-06 06:11:49 +00:00
|
|
|
|
return NULL;
|
|
|
|
|
if (hash == assets.p[i].hash &&
|
2023-06-17 11:20:16 +00:00
|
|
|
|
pathlen == ZIP_CFILE_NAMESIZE(zmap + assets.p[i].cf) &&
|
|
|
|
|
memcmp(path, ZIP_CFILE_NAME(zmap + assets.p[i].cf), pathlen) == 0) {
|
2020-10-06 06:11:49 +00:00
|
|
|
|
return &assets.p[i];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-21 02:14:21 +00:00
|
|
|
|
static struct Asset *GetAssetFile(const char *path, size_t pathlen) {
|
2021-03-28 14:54:21 +00:00
|
|
|
|
size_t i;
|
|
|
|
|
struct Asset *a;
|
|
|
|
|
if (stagedirs.n) {
|
|
|
|
|
a = FreeLater(xcalloc(1, sizeof(struct Asset)));
|
|
|
|
|
a->file = FreeLater(xmalloc(sizeof(struct File)));
|
|
|
|
|
for (i = 0; i < stagedirs.n; ++i) {
|
2021-05-03 19:09:35 +00:00
|
|
|
|
LockInc(&shared->c.stats);
|
2021-05-14 12:36:58 +00:00
|
|
|
|
a->file->path.s = FreeLater(MergePaths(stagedirs.p[i].s, stagedirs.p[i].n,
|
|
|
|
|
path, pathlen, &a->file->path.n));
|
|
|
|
|
if (stat(a->file->path.s, &a->file->st) != -1) {
|
2021-03-28 14:54:21 +00:00
|
|
|
|
a->lastmodifiedstr = FormatUnixHttpDateTime(
|
|
|
|
|
FreeLater(xmalloc(30)),
|
|
|
|
|
(a->lastmodified = a->file->st.st_mtim.tv_sec));
|
|
|
|
|
return a;
|
2021-04-23 17:45:19 +00:00
|
|
|
|
} else {
|
2021-05-03 19:09:35 +00:00
|
|
|
|
LockInc(&shared->c.statfails);
|
2021-03-28 14:54:21 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2021-03-25 09:21:13 +00:00
|
|
|
|
}
|
2021-03-28 14:54:21 +00:00
|
|
|
|
return NULL;
|
2021-03-25 09:21:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-04-21 02:14:21 +00:00
|
|
|
|
static struct Asset *GetAsset(const char *path, size_t pathlen) {
|
2021-03-28 14:54:21 +00:00
|
|
|
|
struct Asset *a;
|
2021-04-21 02:14:21 +00:00
|
|
|
|
if (!(a = GetAssetFile(path, pathlen))) {
|
|
|
|
|
if (!(a = GetAssetZip(path, pathlen))) {
|
2021-04-24 20:58:34 +00:00
|
|
|
|
if (pathlen > 1 && path[pathlen - 1] != '/' &&
|
|
|
|
|
pathlen + 1 <= sizeof(slashpath)) {
|
|
|
|
|
memcpy(mempcpy(slashpath, path, pathlen), "/", 1);
|
|
|
|
|
a = GetAssetZip(slashpath, pathlen + 1);
|
2021-04-21 02:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2021-03-28 14:54:21 +00:00
|
|
|
|
}
|
|
|
|
|
return a;
|
2021-03-25 09:21:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *AppendHeader(char *p, const char *k, const char *v) {
|
2021-03-28 07:10:17 +00:00
|
|
|
|
if (!v)
|
|
|
|
|
return p;
|
2021-04-06 19:46:52 +00:00
|
|
|
|
return AppendCrlf(stpcpy(stpcpy(stpcpy(p, k), ": "), v));
|
2020-10-06 06:11:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *AppendContentType(char *p, const char *ct) {
|
2021-04-06 19:46:52 +00:00
|
|
|
|
p = stpcpy(p, "Content-Type: ");
|
2020-10-06 06:11:49 +00:00
|
|
|
|
p = stpcpy(p, ct);
|
2023-08-14 03:31:27 +00:00
|
|
|
|
if ((cpm.istext = startswith(ct, "text/"))) {
|
2021-08-04 05:42:17 +00:00
|
|
|
|
if (!strchr(ct + 5, ';')) {
|
2021-04-18 18:34:59 +00:00
|
|
|
|
p = stpcpy(p, "; charset=utf-8");
|
|
|
|
|
}
|
2023-08-14 03:31:27 +00:00
|
|
|
|
if (!cpm.referrerpolicy && startswith(ct + 5, "html")) {
|
2022-08-06 00:34:53 +00:00
|
|
|
|
cpm.referrerpolicy = "no-referrer-when-downgrade";
|
2021-08-04 05:42:17 +00:00
|
|
|
|
}
|
2020-10-06 06:11:49 +00:00
|
|
|
|
}
|
2022-08-06 00:34:53 +00:00
|
|
|
|
cpm.hascontenttype = true;
|
2020-10-06 06:11:49 +00:00
|
|
|
|
return AppendCrlf(p);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *AppendExpires(char *p, int64_t t) {
|
|
|
|
|
struct tm tm;
|
|
|
|
|
gmtime_r(&t, &tm);
|
2021-04-06 19:46:52 +00:00
|
|
|
|
p = stpcpy(p, "Expires: ");
|
2021-03-28 14:54:21 +00:00
|
|
|
|
p = FormatHttpDateTime(p, &tm);
|
2020-10-06 06:11:49 +00:00
|
|
|
|
return AppendCrlf(p);
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-24 06:24:40 +00:00
|
|
|
|
static char *AppendCache(char *p, int64_t seconds, char *directive) {
|
2021-03-25 09:21:13 +00:00
|
|
|
|
if (seconds < 0)
|
|
|
|
|
return p;
|
2021-04-18 18:34:59 +00:00
|
|
|
|
p = stpcpy(p, "Cache-Control: max-age=");
|
2022-04-23 01:55:28 +00:00
|
|
|
|
p = FormatUint64(p, seconds);
|
2022-06-17 09:44:03 +00:00
|
|
|
|
if (!seconds) {
|
2021-04-18 18:34:59 +00:00
|
|
|
|
p = stpcpy(p, ", no-store");
|
2023-02-24 06:24:40 +00:00
|
|
|
|
} else if (directive && *directive) {
|
|
|
|
|
p = stpcpy(p, ", ");
|
|
|
|
|
p = stpcpy(p, directive);
|
2021-04-18 18:34:59 +00:00
|
|
|
|
}
|
2020-10-06 06:11:49 +00:00
|
|
|
|
p = AppendCrlf(p);
|
2024-12-02 22:05:38 +00:00
|
|
|
|
unassert(!pthread_mutex_lock(&shared->datetime_mu));
|
|
|
|
|
long nowish_sec = shared->nowish.tv_sec;
|
|
|
|
|
unassert(!pthread_mutex_unlock(&shared->datetime_mu));
|
|
|
|
|
return AppendExpires(p, nowish_sec + seconds);
|
2021-04-23 17:45:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-05-03 19:09:35 +00:00
|
|
|
|
static inline char *AppendContentLength(char *p, size_t n) {
|
2021-04-06 19:46:52 +00:00
|
|
|
|
p = stpcpy(p, "Content-Length: ");
|
2022-04-23 01:55:28 +00:00
|
|
|
|
p = FormatUint64(p, n);
|
2020-10-06 06:11:49 +00:00
|
|
|
|
return AppendCrlf(p);
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-21 02:14:21 +00:00
|
|
|
|
static char *AppendContentRange(char *p, long a, long b, long c) {
|
2021-04-06 19:46:52 +00:00
|
|
|
|
p = stpcpy(p, "Content-Range: bytes ");
|
2021-04-21 02:14:21 +00:00
|
|
|
|
if (a >= 0 && b > 0) {
|
2022-04-23 01:55:28 +00:00
|
|
|
|
p = FormatUint64(p, a);
|
2021-04-21 02:14:21 +00:00
|
|
|
|
*p++ = '-';
|
2022-04-23 01:55:28 +00:00
|
|
|
|
p = FormatUint64(p, a + b - 1);
|
2021-04-21 02:14:21 +00:00
|
|
|
|
} else {
|
|
|
|
|
*p++ = '*';
|
|
|
|
|
}
|
2020-10-06 06:11:49 +00:00
|
|
|
|
*p++ = '/';
|
2022-04-23 01:55:28 +00:00
|
|
|
|
p = FormatUint64(p, c);
|
2020-10-06 06:11:49 +00:00
|
|
|
|
return AppendCrlf(p);
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-18 18:34:59 +00:00
|
|
|
|
static bool Inflate(void *dp, size_t dn, const void *sp, size_t sn) {
|
2021-05-03 19:09:35 +00:00
|
|
|
|
LockInc(&shared->c.inflates);
|
2022-05-29 15:14:55 +00:00
|
|
|
|
return !__inflate(dp, dn, sp, sn);
|
2021-04-18 18:34:59 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool Verify(void *data, size_t size, uint32_t crc) {
|
|
|
|
|
uint32_t got;
|
2021-05-03 19:09:35 +00:00
|
|
|
|
LockInc(&shared->c.verifies);
|
2021-04-18 18:34:59 +00:00
|
|
|
|
if (crc == (got = crc32_z(0, data, size))) {
|
|
|
|
|
return true;
|
|
|
|
|
} else {
|
2021-05-03 19:09:35 +00:00
|
|
|
|
LockInc(&shared->c.thiscorruption);
|
2021-08-22 22:01:52 +00:00
|
|
|
|
WARNF("(zip) corrupt zip file at %`'.*s had crc 0x%08x but expected 0x%08x",
|
2022-08-06 00:34:53 +00:00
|
|
|
|
cpm.msg.uri.b - cpm.msg.uri.a, inbuf.p + cpm.msg.uri.a, got, crc);
|
2021-04-18 18:34:59 +00:00
|
|
|
|
return false;
|
2020-09-07 04:39:00 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-25 09:21:13 +00:00
|
|
|
|
static void *Deflate(const void *data, size_t size, size_t *out_size) {
|
|
|
|
|
void *res;
|
2022-09-17 08:37:33 +00:00
|
|
|
|
z_stream zs = {0};
|
2021-05-03 19:09:35 +00:00
|
|
|
|
LockInc(&shared->c.deflates);
|
2021-07-19 21:55:20 +00:00
|
|
|
|
CHECK_EQ(Z_OK, deflateInit2(&zs, 4, Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL,
|
|
|
|
|
Z_DEFAULT_STRATEGY));
|
2021-03-25 09:21:13 +00:00
|
|
|
|
zs.next_in = data;
|
|
|
|
|
zs.avail_in = size;
|
|
|
|
|
zs.avail_out = compressBound(size);
|
|
|
|
|
zs.next_out = res = xmalloc(zs.avail_out);
|
|
|
|
|
CHECK_EQ(Z_STREAM_END, deflate(&zs, Z_FINISH));
|
|
|
|
|
CHECK_EQ(Z_OK, deflateEnd(&zs));
|
|
|
|
|
*out_size = zs.total_out;
|
|
|
|
|
return xrealloc(res, zs.total_out);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void *LoadAsset(struct Asset *a, size_t *out_size) {
|
|
|
|
|
size_t size;
|
|
|
|
|
uint8_t *data;
|
2021-04-23 17:45:19 +00:00
|
|
|
|
if (S_ISDIR(GetMode(a))) {
|
2021-08-22 22:01:52 +00:00
|
|
|
|
WARNF("(srvr) can't load directory");
|
2021-04-21 02:14:21 +00:00
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2021-04-23 17:45:19 +00:00
|
|
|
|
if (!a->file) {
|
2023-06-17 11:20:16 +00:00
|
|
|
|
size = GetZipLfileUncompressedSize(zmap + a->lf);
|
2021-04-23 17:45:19 +00:00
|
|
|
|
if (size == SIZE_MAX || !(data = malloc(size + 1)))
|
|
|
|
|
return NULL;
|
|
|
|
|
if (IsCompressed(a)) {
|
2023-06-17 11:20:16 +00:00
|
|
|
|
if (!Inflate(data, size, ZIP_LFILE_CONTENT(zmap + a->lf),
|
|
|
|
|
GetZipCfileCompressedSize(zmap + a->cf))) {
|
2021-04-23 17:45:19 +00:00
|
|
|
|
free(data);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2023-06-17 11:20:16 +00:00
|
|
|
|
memcpy(data, ZIP_LFILE_CONTENT(zmap + a->lf), size);
|
2021-04-23 17:45:19 +00:00
|
|
|
|
}
|
2023-06-17 11:20:16 +00:00
|
|
|
|
if (!Verify(data, size, ZIP_LFILE_CRC32(zmap + a->lf))) {
|
2021-04-23 17:45:19 +00:00
|
|
|
|
free(data);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
data[size] = '\0';
|
|
|
|
|
if (out_size)
|
|
|
|
|
*out_size = size;
|
|
|
|
|
return data;
|
2020-10-06 06:11:49 +00:00
|
|
|
|
} else {
|
2021-05-03 19:09:35 +00:00
|
|
|
|
LockInc(&shared->c.slurps);
|
2021-05-14 12:36:58 +00:00
|
|
|
|
return xslurp(a->file->path.s, out_size);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-18 15:54:42 +00:00
|
|
|
|
static wontreturn void PrintUsage(int fd, int rc) {
|
2021-05-14 12:36:58 +00:00
|
|
|
|
size_t n;
|
|
|
|
|
const char *p;
|
|
|
|
|
struct Asset *a;
|
2022-04-18 15:54:42 +00:00
|
|
|
|
if (!(a = GetAssetZip("/help.txt", 9)) || !(p = LoadAsset(a, &n))) {
|
|
|
|
|
fprintf(stderr, "error: /help.txt is not a zip asset\n");
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
2022-07-09 12:49:19 +00:00
|
|
|
|
if (IsTiny()) {
|
|
|
|
|
write(fd, p, strlen(p));
|
|
|
|
|
} else {
|
|
|
|
|
__paginate(fd, p);
|
|
|
|
|
}
|
2022-04-24 16:59:22 +00:00
|
|
|
|
exit(rc);
|
2021-05-14 12:36:58 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-04-21 02:14:21 +00:00
|
|
|
|
static void AppendLogo(void) {
|
|
|
|
|
size_t n;
|
|
|
|
|
char *p, *q;
|
|
|
|
|
struct Asset *a;
|
|
|
|
|
if ((a = GetAsset("/redbean.png", 12)) && (p = LoadAsset(a, &n))) {
|
2021-08-06 21:12:11 +00:00
|
|
|
|
if ((q = EncodeBase64(p, n, &n))) {
|
2022-08-06 00:34:53 +00:00
|
|
|
|
appends(&cpm.outbuf, "<img alt=\"[logo]\" src=\"data:image/png;base64,");
|
|
|
|
|
appendd(&cpm.outbuf, q, n);
|
|
|
|
|
appends(&cpm.outbuf, "\">\r\n");
|
2021-08-06 21:12:11 +00:00
|
|
|
|
free(q);
|
|
|
|
|
}
|
2021-04-21 02:14:21 +00:00
|
|
|
|
free(p);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-24 19:31:26 +00:00
|
|
|
|
static ssize_t Send(struct iovec *iov, int iovlen) {
|
2021-03-25 09:21:13 +00:00
|
|
|
|
ssize_t rc;
|
2021-06-24 19:31:26 +00:00
|
|
|
|
if ((rc = writer(client, iov, iovlen)) == -1) {
|
2021-03-25 09:21:13 +00:00
|
|
|
|
if (errno == ECONNRESET) {
|
2021-05-03 19:09:35 +00:00
|
|
|
|
LockInc(&shared->c.writeresets);
|
2021-08-22 22:01:52 +00:00
|
|
|
|
DEBUGF("(rsp) %s write reset", DescribeClient());
|
2021-04-23 17:45:19 +00:00
|
|
|
|
} else if (errno == EAGAIN) {
|
2021-05-03 19:09:35 +00:00
|
|
|
|
LockInc(&shared->c.writetimeouts);
|
2021-08-22 22:01:52 +00:00
|
|
|
|
WARNF("(rsp) %s write timeout", DescribeClient());
|
2022-03-19 10:37:00 +00:00
|
|
|
|
errno = 0;
|
2021-03-25 09:21:13 +00:00
|
|
|
|
} else {
|
2021-05-03 19:09:35 +00:00
|
|
|
|
LockInc(&shared->c.writeerrors);
|
2022-07-08 14:14:50 +00:00
|
|
|
|
if (errno == EBADF) { // don't warn on close/bad fd
|
|
|
|
|
DEBUGF("(rsp) %s write badf", DescribeClient());
|
|
|
|
|
} else {
|
|
|
|
|
WARNF("(rsp) %s write error: %m", DescribeClient());
|
|
|
|
|
}
|
2021-03-25 09:21:13 +00:00
|
|
|
|
}
|
|
|
|
|
connectionclose = true;
|
|
|
|
|
}
|
|
|
|
|
return rc;
|
2020-10-06 06:11:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-09 14:00:23 +00:00
|
|
|
|
static bool IsSslCompressed(void) {
|
2022-05-29 15:14:55 +00:00
|
|
|
|
return usingssl && ssl.session->compression;
|
2021-08-09 14:00:23 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-04-21 02:14:21 +00:00
|
|
|
|
static char *CommitOutput(char *p) {
|
2021-04-18 18:34:59 +00:00
|
|
|
|
uint32_t crc;
|
2021-08-06 21:12:11 +00:00
|
|
|
|
size_t outbuflen;
|
2022-08-06 00:34:53 +00:00
|
|
|
|
if (!cpm.contentlength) {
|
|
|
|
|
outbuflen = appendz(cpm.outbuf).i;
|
2023-05-18 03:46:27 +00:00
|
|
|
|
if (cpm.istext && !cpm.isyielding && outbuflen >= 100) {
|
2021-08-09 14:00:23 +00:00
|
|
|
|
if (!IsTiny() && !IsSslCompressed()) {
|
|
|
|
|
p = stpcpy(p, "Vary: Accept-Encoding\r\n");
|
|
|
|
|
}
|
2022-12-18 10:22:58 +00:00
|
|
|
|
if (!IsTiny() && //
|
|
|
|
|
!IsSslCompressed() && //
|
|
|
|
|
ClientAcceptsGzip() && //
|
|
|
|
|
!ShouldAvoidGzip()) {
|
2022-08-22 05:26:41 +00:00
|
|
|
|
cpm.gzipped = outbuflen;
|
2022-08-06 00:34:53 +00:00
|
|
|
|
crc = crc32_z(0, cpm.outbuf, outbuflen);
|
2021-04-21 02:14:21 +00:00
|
|
|
|
WRITE32LE(gzip_footer + 0, crc);
|
2021-08-06 21:12:11 +00:00
|
|
|
|
WRITE32LE(gzip_footer + 4, outbuflen);
|
2022-08-06 00:34:53 +00:00
|
|
|
|
cpm.content =
|
|
|
|
|
FreeLater(Deflate(cpm.outbuf, outbuflen, &cpm.contentlength));
|
2021-04-21 02:14:21 +00:00
|
|
|
|
DropOutput();
|
2021-04-18 18:34:59 +00:00
|
|
|
|
} else {
|
2021-04-21 02:14:21 +00:00
|
|
|
|
UseOutput();
|
2021-04-18 18:34:59 +00:00
|
|
|
|
}
|
2021-03-28 14:54:21 +00:00
|
|
|
|
} else {
|
2021-04-21 02:14:21 +00:00
|
|
|
|
UseOutput();
|
2021-03-28 14:54:21 +00:00
|
|
|
|
}
|
2021-04-21 02:14:21 +00:00
|
|
|
|
} else {
|
|
|
|
|
DropOutput();
|
|
|
|
|
}
|
|
|
|
|
return p;
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-12 07:42:14 +00:00
|
|
|
|
static char *ServeDefaultErrorPage(char *p, unsigned code, const char *reason,
|
|
|
|
|
const char *details) {
|
2024-08-17 13:45:35 +00:00
|
|
|
|
p = AppendContentType(p, "text/html; charset=UTF-8");
|
2021-04-23 17:45:19 +00:00
|
|
|
|
reason = FreeLater(EscapeHtml(reason, -1, 0));
|
2022-08-06 00:34:53 +00:00
|
|
|
|
appends(&cpm.outbuf, "\
|
2021-04-21 02:14:21 +00:00
|
|
|
|
<!doctype html>\r\n\
|
|
|
|
|
<title>");
|
2022-08-06 00:34:53 +00:00
|
|
|
|
appendf(&cpm.outbuf, "%d %s", code, reason);
|
|
|
|
|
appends(&cpm.outbuf, "\
|
2021-04-21 02:14:21 +00:00
|
|
|
|
</title>\r\n\
|
|
|
|
|
<style>\r\n\
|
|
|
|
|
html { color: #111; font-family: sans-serif; }\r\n\
|
|
|
|
|
img { vertical-align: middle; }\r\n\
|
|
|
|
|
</style>\r\n\
|
|
|
|
|
<h1>\r\n");
|
|
|
|
|
AppendLogo();
|
2022-08-06 00:34:53 +00:00
|
|
|
|
appendf(&cpm.outbuf, "%d %s\r\n", code, reason);
|
|
|
|
|
appends(&cpm.outbuf, "</h1>\r\n");
|
2021-08-12 06:27:39 +00:00
|
|
|
|
if (details) {
|
2022-08-06 00:34:53 +00:00
|
|
|
|
appendf(&cpm.outbuf, "<pre>%s</pre>\r\n",
|
2021-08-12 07:42:14 +00:00
|
|
|
|
FreeLater(EscapeHtml(details, -1, 0)));
|
2021-08-12 06:27:39 +00:00
|
|
|
|
}
|
2021-04-21 02:14:21 +00:00
|
|
|
|
UseOutput();
|
|
|
|
|
return p;
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-14 09:55:50 +00:00
|
|
|
|
static char *ServeErrorImplDefault(unsigned code, const char *reason,
|
2024-02-22 22:12:18 +00:00
|
|
|
|
const char *details) {
|
2021-04-21 02:14:21 +00:00
|
|
|
|
size_t n;
|
|
|
|
|
char *p, *s;
|
|
|
|
|
struct Asset *a;
|
2021-05-03 19:09:35 +00:00
|
|
|
|
LockInc(&shared->c.errors);
|
2021-08-06 21:12:11 +00:00
|
|
|
|
DropOutput();
|
2021-04-21 02:14:21 +00:00
|
|
|
|
p = SetStatus(code, reason);
|
|
|
|
|
s = xasprintf("/%d.html", code);
|
|
|
|
|
a = GetAsset(s, strlen(s));
|
|
|
|
|
free(s);
|
2021-04-23 17:45:19 +00:00
|
|
|
|
if (!a) {
|
2021-08-12 06:27:39 +00:00
|
|
|
|
return ServeDefaultErrorPage(p, code, reason, details);
|
2021-04-21 02:14:21 +00:00
|
|
|
|
} else if (a->file) {
|
2021-05-03 19:09:35 +00:00
|
|
|
|
LockInc(&shared->c.slurps);
|
2022-08-06 00:34:53 +00:00
|
|
|
|
cpm.content = FreeLater(xslurp(a->file->path.s, &cpm.contentlength));
|
2021-04-21 02:14:21 +00:00
|
|
|
|
return AppendContentType(p, "text/html; charset=utf-8");
|
|
|
|
|
} else {
|
2023-06-17 11:20:16 +00:00
|
|
|
|
cpm.content = (char *)ZIP_LFILE_CONTENT(zmap + a->lf);
|
|
|
|
|
cpm.contentlength = GetZipCfileCompressedSize(zmap + a->cf);
|
2021-04-23 17:45:19 +00:00
|
|
|
|
if (IsCompressed(a)) {
|
2023-06-17 11:20:16 +00:00
|
|
|
|
n = GetZipLfileUncompressedSize(zmap + a->lf);
|
2022-08-06 00:34:53 +00:00
|
|
|
|
if ((s = FreeLater(malloc(n))) &&
|
|
|
|
|
Inflate(s, n, cpm.content, cpm.contentlength)) {
|
|
|
|
|
cpm.content = s;
|
|
|
|
|
cpm.contentlength = n;
|
2021-03-25 09:21:13 +00:00
|
|
|
|
} else {
|
2021-08-12 06:27:39 +00:00
|
|
|
|
return ServeDefaultErrorPage(p, code, reason, details);
|
2021-03-25 09:21:13 +00:00
|
|
|
|
}
|
2021-04-21 02:14:21 +00:00
|
|
|
|
}
|
2023-06-17 11:20:16 +00:00
|
|
|
|
if (Verify(cpm.content, cpm.contentlength, ZIP_LFILE_CRC32(zmap + a->lf))) {
|
2021-04-21 02:14:21 +00:00
|
|
|
|
return AppendContentType(p, "text/html; charset=utf-8");
|
|
|
|
|
} else {
|
2021-08-12 06:27:39 +00:00
|
|
|
|
return ServeDefaultErrorPage(p, code, reason, details);
|
2021-04-21 02:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-14 09:55:50 +00:00
|
|
|
|
static char *GetLuaResponse(void) {
|
|
|
|
|
return cpm.luaheaderp ? cpm.luaheaderp : SetStatus(200, "OK");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *ServeErrorImpl(unsigned code, const char *reason,
|
|
|
|
|
const char *details) {
|
|
|
|
|
lua_State *L = GL;
|
|
|
|
|
if (hasonerror) {
|
|
|
|
|
lua_getglobal(L, "OnError");
|
|
|
|
|
lua_pushinteger(L, code);
|
|
|
|
|
lua_pushstring(L, reason);
|
2024-11-20 21:55:45 +00:00
|
|
|
|
lua_pushstring(L, details);
|
|
|
|
|
if (LuaCallWithTrace(L, 3, 0, NULL) == LUA_OK) {
|
2024-02-14 09:55:50 +00:00
|
|
|
|
return CommitOutput(GetLuaResponse());
|
|
|
|
|
} else {
|
|
|
|
|
return ServeErrorImplDefault(code, reason, details);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
return ServeErrorImplDefault(code, reason, details);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-02 02:47:59 +00:00
|
|
|
|
static char *ServeErrorWithPath(unsigned code, const char *reason,
|
|
|
|
|
const char *path, size_t pathlen) {
|
2023-07-06 22:38:08 +00:00
|
|
|
|
ERRORF("(srvr) server error: %d %s %`'.*s", code, reason, pathlen, path);
|
2023-07-02 02:47:59 +00:00
|
|
|
|
return ServeErrorImpl(code, reason, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-12 07:42:14 +00:00
|
|
|
|
static char *ServeErrorWithDetail(unsigned code, const char *reason,
|
|
|
|
|
const char *details) {
|
2021-08-22 22:01:52 +00:00
|
|
|
|
ERRORF("(srvr) server error: %d %s", code, reason);
|
2021-08-12 06:27:39 +00:00
|
|
|
|
return ServeErrorImpl(code, reason, details);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *ServeError(unsigned code, const char *reason) {
|
|
|
|
|
return ServeErrorWithDetail(code, reason, NULL);
|
2021-04-23 17:45:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *ServeFailure(unsigned code, const char *reason) {
|
2024-02-22 22:12:18 +00:00
|
|
|
|
char method[9] = {0};
|
|
|
|
|
WRITE64LE(method, cpm.msg.method);
|
|
|
|
|
ERRORF("(srvr) failure: %d %s %s HTTP%02d %s %`'.*s %`'.*s %`'.*s %`'.*s",
|
|
|
|
|
code, reason, DescribeClient(), cpm.msg.version, method,
|
2022-08-06 00:34:53 +00:00
|
|
|
|
HeaderLength(kHttpHost), HeaderData(kHttpHost),
|
|
|
|
|
cpm.msg.uri.b - cpm.msg.uri.a, inbuf.p + cpm.msg.uri.a,
|
|
|
|
|
HeaderLength(kHttpReferer), HeaderData(kHttpReferer),
|
|
|
|
|
HeaderLength(kHttpUserAgent), HeaderData(kHttpUserAgent));
|
2021-08-12 06:27:39 +00:00
|
|
|
|
return ServeErrorImpl(code, reason, NULL);
|
2021-04-23 17:45:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-03-22 01:07:30 +00:00
|
|
|
|
static ssize_t YieldGenerator(struct iovec v[3]) {
|
|
|
|
|
int nresults, status;
|
2022-08-06 00:34:53 +00:00
|
|
|
|
if (cpm.isyielding > 1) {
|
2022-03-22 01:07:30 +00:00
|
|
|
|
do {
|
|
|
|
|
if (!YL || lua_status(YL) != LUA_YIELD)
|
|
|
|
|
return 0; // done yielding
|
2022-08-06 00:34:53 +00:00
|
|
|
|
cpm.contentlength = 0;
|
2022-03-22 01:07:30 +00:00
|
|
|
|
status = lua_resume(YL, NULL, 0, &nresults);
|
|
|
|
|
if (status != LUA_OK && status != LUA_YIELD) {
|
|
|
|
|
LogLuaError("resume", lua_tostring(YL, -1));
|
|
|
|
|
lua_pop(YL, 1);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
lua_pop(YL, nresults);
|
2022-08-06 00:34:53 +00:00
|
|
|
|
if (!cpm.contentlength)
|
|
|
|
|
UseOutput();
|
2022-03-22 01:07:30 +00:00
|
|
|
|
// continue yielding if nothing to return to keep generator running
|
2022-08-06 00:34:53 +00:00
|
|
|
|
} while (!cpm.contentlength);
|
2022-03-22 01:07:30 +00:00
|
|
|
|
}
|
2022-08-06 00:34:53 +00:00
|
|
|
|
DEBUGF("(lua) yielded with %ld bytes generated", cpm.contentlength);
|
|
|
|
|
cpm.isyielding++;
|
|
|
|
|
v[0].iov_base = cpm.content;
|
|
|
|
|
v[0].iov_len = cpm.contentlength;
|
|
|
|
|
return cpm.contentlength;
|
2022-03-22 01:07:30 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-05-14 18:47:16 +00:00
|
|
|
|
static void OnLuaServerPageCtrlc(int i) {
|
|
|
|
|
lua_sigint(GL, i);
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-22 01:07:30 +00:00
|
|
|
|
static int LuaCallWithYield(lua_State *L) {
|
|
|
|
|
int status;
|
|
|
|
|
// since yield may happen in OnHttpRequest and in ServeLua,
|
|
|
|
|
// need to fully restart the yield generator;
|
|
|
|
|
// the second set of headers is not going to be sent
|
2022-05-14 18:47:16 +00:00
|
|
|
|
struct sigaction sa, saold;
|
2022-03-22 01:07:30 +00:00
|
|
|
|
lua_State *co = lua_newthread(L);
|
2023-10-04 05:34:45 +00:00
|
|
|
|
if (__ttyconf.replmode) {
|
2022-05-14 18:47:16 +00:00
|
|
|
|
sa.sa_flags = SA_RESETHAND;
|
|
|
|
|
sa.sa_handler = OnLuaServerPageCtrlc;
|
|
|
|
|
sigemptyset(&sa.sa_mask);
|
|
|
|
|
sigaction(SIGINT, &sa, &saold);
|
|
|
|
|
}
|
|
|
|
|
status = LuaCallWithTrace(L, 0, 0, co);
|
2023-10-04 05:34:45 +00:00
|
|
|
|
if (__ttyconf.replmode) {
|
2022-05-14 18:47:16 +00:00
|
|
|
|
sigaction(SIGINT, &saold, 0);
|
|
|
|
|
}
|
|
|
|
|
if (status == LUA_YIELD) {
|
2022-04-15 01:13:53 +00:00
|
|
|
|
CHECK_GT(lua_gettop(L), 0); // make sure that coroutine is anchored
|
2022-03-22 01:07:30 +00:00
|
|
|
|
YL = co;
|
2022-08-06 00:34:53 +00:00
|
|
|
|
cpm.generator = YieldGenerator;
|
|
|
|
|
if (!cpm.isyielding)
|
|
|
|
|
cpm.isyielding = 1;
|
2022-03-22 01:07:30 +00:00
|
|
|
|
status = LUA_OK;
|
|
|
|
|
}
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
static ssize_t DeflateGenerator(struct iovec v[3]) {
|
|
|
|
|
int i, rc;
|
|
|
|
|
size_t no;
|
|
|
|
|
i = 0;
|
|
|
|
|
if (!dg.t) {
|
2023-09-02 03:49:13 +00:00
|
|
|
|
v[0].iov_base = (void *)kGzipHeader;
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
v[0].iov_len = sizeof(kGzipHeader);
|
|
|
|
|
++dg.t;
|
|
|
|
|
++i;
|
|
|
|
|
} else if (dg.t == 3) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (dg.t != 2) {
|
|
|
|
|
CHECK_EQ(0, dg.s.avail_in);
|
2022-08-06 00:34:53 +00:00
|
|
|
|
dg.s.next_in = (void *)(cpm.content + dg.i);
|
|
|
|
|
dg.s.avail_in = MIN(dg.z, cpm.contentlength - dg.i);
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
dg.c = crc32_z(dg.c, dg.s.next_in, dg.s.avail_in);
|
|
|
|
|
dg.i += dg.s.avail_in;
|
|
|
|
|
}
|
|
|
|
|
dg.s.next_out = dg.b;
|
2021-07-19 21:55:20 +00:00
|
|
|
|
dg.s.avail_out = dg.z;
|
|
|
|
|
no = dg.s.avail_in;
|
2022-08-06 00:34:53 +00:00
|
|
|
|
rc = deflate(&dg.s, dg.i < cpm.contentlength ? Z_SYNC_FLUSH : Z_FINISH);
|
2021-07-19 21:55:20 +00:00
|
|
|
|
if (rc != Z_OK && rc != Z_STREAM_END) {
|
2021-09-07 18:40:11 +00:00
|
|
|
|
DIEF("(zip) deflate()→%d oldin:%,zu/%,zu in:%,zu/%,zu out:%,zu/%,zu", rc,
|
|
|
|
|
no, dg.z, dg.s.avail_in, dg.z, dg.s.avail_out, dg.z);
|
2021-07-19 21:55:20 +00:00
|
|
|
|
} else {
|
2021-09-07 18:40:11 +00:00
|
|
|
|
NOISEF("(zip) deflate()→%d oldin:%,zu/%,zu in:%,zu/%,zu out:%,zu/%,zu", rc,
|
|
|
|
|
no, dg.z, dg.s.avail_in, dg.z, dg.s.avail_out, dg.z);
|
2021-07-19 21:55:20 +00:00
|
|
|
|
}
|
|
|
|
|
no = dg.z - dg.s.avail_out;
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
if (no) {
|
|
|
|
|
v[i].iov_base = dg.b;
|
|
|
|
|
v[i].iov_len = no;
|
|
|
|
|
++i;
|
|
|
|
|
}
|
|
|
|
|
if (rc == Z_OK) {
|
|
|
|
|
CHECK_GT(no, 0);
|
2021-07-19 21:55:20 +00:00
|
|
|
|
if (dg.s.avail_out) {
|
|
|
|
|
dg.t = 1;
|
|
|
|
|
} else {
|
|
|
|
|
dg.t = 2;
|
|
|
|
|
}
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
} else if (rc == Z_STREAM_END) {
|
2022-08-06 00:34:53 +00:00
|
|
|
|
CHECK_EQ(cpm.contentlength, dg.i);
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
CHECK_EQ(Z_OK, deflateEnd(&dg.s));
|
|
|
|
|
WRITE32LE(gzip_footer + 0, dg.c);
|
2022-08-06 00:34:53 +00:00
|
|
|
|
WRITE32LE(gzip_footer + 4, cpm.contentlength);
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
v[i].iov_base = gzip_footer;
|
|
|
|
|
v[i].iov_len = sizeof(gzip_footer);
|
|
|
|
|
dg.t = 3;
|
|
|
|
|
}
|
|
|
|
|
return v[0].iov_len + v[1].iov_len + v[2].iov_len;
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-21 02:14:21 +00:00
|
|
|
|
static char *ServeAssetCompressed(struct Asset *a) {
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
char *p;
|
|
|
|
|
LockInc(&shared->c.deflates);
|
2021-05-03 19:09:35 +00:00
|
|
|
|
LockInc(&shared->c.compressedresponses);
|
2021-08-22 22:01:52 +00:00
|
|
|
|
DEBUGF("(srvr) ServeAssetCompressed()");
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
dg.t = 0;
|
|
|
|
|
dg.i = 0;
|
|
|
|
|
dg.c = 0;
|
2022-05-29 15:14:55 +00:00
|
|
|
|
if (usingssl) {
|
2022-10-10 11:12:06 +00:00
|
|
|
|
dg.z = 512 + (_rand64() & 1023);
|
2021-07-19 21:55:20 +00:00
|
|
|
|
} else {
|
|
|
|
|
dg.z = 65536;
|
|
|
|
|
}
|
2022-08-22 05:26:41 +00:00
|
|
|
|
cpm.gzipped = -1; // signal generator usage with the exact size unknown
|
2022-08-06 00:34:53 +00:00
|
|
|
|
cpm.generator = DeflateGenerator;
|
2021-09-28 05:58:51 +00:00
|
|
|
|
bzero(&dg.s, sizeof(dg.s));
|
|
|
|
|
CHECK_EQ(Z_OK, deflateInit2(&dg.s, 4, Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL,
|
|
|
|
|
Z_DEFAULT_STRATEGY));
|
2021-07-19 21:55:20 +00:00
|
|
|
|
dg.b = FreeLater(malloc(dg.z));
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
p = SetStatus(200, "OK");
|
|
|
|
|
p = stpcpy(p, "Content-Encoding: gzip\r\n");
|
|
|
|
|
return p;
|
2021-04-21 02:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-07-12 06:17:47 +00:00
|
|
|
|
static ssize_t InflateGenerator(struct iovec v[3]) {
|
|
|
|
|
int i, rc;
|
|
|
|
|
size_t no;
|
|
|
|
|
i = 0;
|
|
|
|
|
if (!dg.t) {
|
|
|
|
|
++dg.t;
|
|
|
|
|
} else if (dg.t == 3) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (dg.t != 2) {
|
|
|
|
|
CHECK_EQ(0, dg.s.avail_in);
|
2022-08-06 00:34:53 +00:00
|
|
|
|
dg.s.next_in = (void *)(cpm.content + dg.i);
|
|
|
|
|
dg.s.avail_in = MIN(dg.z, cpm.contentlength - dg.i);
|
2021-07-12 06:17:47 +00:00
|
|
|
|
dg.i += dg.s.avail_in;
|
|
|
|
|
}
|
|
|
|
|
dg.s.next_out = dg.b;
|
2021-07-19 21:55:20 +00:00
|
|
|
|
dg.s.avail_out = dg.z;
|
2021-07-12 06:17:47 +00:00
|
|
|
|
rc = inflate(&dg.s, Z_NO_FLUSH);
|
2021-08-22 22:01:52 +00:00
|
|
|
|
if (rc != Z_OK && rc != Z_STREAM_END)
|
|
|
|
|
DIEF("(zip) inflate()→%d", rc);
|
2021-07-19 21:55:20 +00:00
|
|
|
|
no = dg.z - dg.s.avail_out;
|
2021-07-12 06:17:47 +00:00
|
|
|
|
if (no) {
|
|
|
|
|
v[i].iov_base = dg.b;
|
|
|
|
|
v[i].iov_len = no;
|
|
|
|
|
dg.c = crc32_z(dg.c, dg.b, no);
|
|
|
|
|
++i;
|
|
|
|
|
}
|
|
|
|
|
if (rc == Z_OK) {
|
|
|
|
|
CHECK_GT(no, 0);
|
|
|
|
|
dg.t = dg.s.avail_out ? 1 : 2;
|
|
|
|
|
} else if (rc == Z_STREAM_END) {
|
|
|
|
|
CHECK_EQ(Z_OK, inflateEnd(&dg.s));
|
2023-06-17 11:20:16 +00:00
|
|
|
|
CHECK_EQ(ZIP_CFILE_CRC32(zmap + dg.a->cf), dg.c);
|
2021-07-12 06:17:47 +00:00
|
|
|
|
dg.t = 3;
|
|
|
|
|
}
|
|
|
|
|
return v[0].iov_len + v[1].iov_len + v[2].iov_len;
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-03 19:09:35 +00:00
|
|
|
|
static char *ServeAssetDecompressed(struct Asset *a) {
|
2021-07-12 06:17:47 +00:00
|
|
|
|
char *p;
|
2021-04-21 02:14:21 +00:00
|
|
|
|
size_t size;
|
2021-07-12 06:17:47 +00:00
|
|
|
|
LockInc(&shared->c.inflates);
|
2021-05-03 19:09:35 +00:00
|
|
|
|
LockInc(&shared->c.decompressedresponses);
|
2023-06-17 11:20:16 +00:00
|
|
|
|
size = GetZipCfileUncompressedSize(zmap + a->cf);
|
2022-08-06 00:34:53 +00:00
|
|
|
|
DEBUGF("(srvr) ServeAssetDecompressed(%ld)→%ld", cpm.contentlength, size);
|
|
|
|
|
if (cpm.msg.method == kHttpHead) {
|
|
|
|
|
cpm.content = 0;
|
|
|
|
|
cpm.contentlength = size;
|
2021-04-23 17:45:19 +00:00
|
|
|
|
return SetStatus(200, "OK");
|
2021-07-12 06:17:47 +00:00
|
|
|
|
} else if (!IsTiny()) {
|
|
|
|
|
dg.t = 0;
|
|
|
|
|
dg.i = 0;
|
|
|
|
|
dg.c = 0;
|
|
|
|
|
dg.a = a;
|
2021-07-19 21:55:20 +00:00
|
|
|
|
dg.z = 65536;
|
|
|
|
|
CHECK_EQ(Z_OK, inflateInit2(&dg.s, -MAX_WBITS));
|
2022-08-06 00:34:53 +00:00
|
|
|
|
cpm.generator = InflateGenerator;
|
2021-07-19 21:55:20 +00:00
|
|
|
|
dg.b = FreeLater(malloc(dg.z));
|
2021-07-12 06:17:47 +00:00
|
|
|
|
return SetStatus(200, "OK");
|
|
|
|
|
} else if ((p = FreeLater(malloc(size))) &&
|
2022-08-06 00:34:53 +00:00
|
|
|
|
Inflate(p, size, cpm.content, cpm.contentlength) &&
|
2023-06-17 11:20:16 +00:00
|
|
|
|
Verify(p, size, ZIP_CFILE_CRC32(zmap + a->cf))) {
|
2022-08-06 00:34:53 +00:00
|
|
|
|
cpm.content = p;
|
|
|
|
|
cpm.contentlength = size;
|
2021-07-12 06:17:47 +00:00
|
|
|
|
return SetStatus(200, "OK");
|
2021-04-23 17:45:19 +00:00
|
|
|
|
} else {
|
2021-07-12 06:17:47 +00:00
|
|
|
|
return ServeError(500, "Internal Server Error");
|
2021-04-21 02:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-03 19:09:35 +00:00
|
|
|
|
static inline char *ServeAssetIdentity(struct Asset *a, const char *ct) {
|
|
|
|
|
LockInc(&shared->c.identityresponses);
|
2021-08-22 22:01:52 +00:00
|
|
|
|
DEBUGF("(srvr) ServeAssetIdentity(%`'s)", ct);
|
2021-05-03 19:09:35 +00:00
|
|
|
|
return SetStatus(200, "OK");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline char *ServeAssetPrecompressed(struct Asset *a) {
|
|
|
|
|
size_t size;
|
|
|
|
|
uint32_t crc;
|
2021-08-22 22:01:52 +00:00
|
|
|
|
DEBUGF("(srvr) ServeAssetPrecompressed()");
|
2021-05-03 19:09:35 +00:00
|
|
|
|
LockInc(&shared->c.precompressedresponses);
|
2023-06-17 11:20:16 +00:00
|
|
|
|
crc = ZIP_CFILE_CRC32(zmap + a->cf);
|
|
|
|
|
size = GetZipCfileUncompressedSize(zmap + a->cf);
|
2022-08-22 05:26:41 +00:00
|
|
|
|
cpm.gzipped = size;
|
2021-05-03 19:09:35 +00:00
|
|
|
|
WRITE32LE(gzip_footer + 0, crc);
|
|
|
|
|
WRITE32LE(gzip_footer + 4, size);
|
|
|
|
|
return SetStatus(200, "OK");
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-21 02:14:21 +00:00
|
|
|
|
static char *ServeAssetRange(struct Asset *a) {
|
|
|
|
|
char *p;
|
|
|
|
|
long rangestart, rangelength;
|
2021-08-22 22:01:52 +00:00
|
|
|
|
DEBUGF("(srvr) ServeAssetRange()");
|
2021-04-21 02:14:21 +00:00
|
|
|
|
if (ParseHttpRange(HeaderData(kHttpRange), HeaderLength(kHttpRange),
|
2022-08-06 00:34:53 +00:00
|
|
|
|
cpm.contentlength, &rangestart, &rangelength) &&
|
|
|
|
|
rangestart >= 0 && rangelength >= 0 && rangestart < cpm.contentlength &&
|
|
|
|
|
rangestart + rangelength <= cpm.contentlength) {
|
2021-05-03 19:09:35 +00:00
|
|
|
|
LockInc(&shared->c.partialresponses);
|
2021-04-21 02:14:21 +00:00
|
|
|
|
p = SetStatus(206, "Partial Content");
|
2022-08-06 00:34:53 +00:00
|
|
|
|
p = AppendContentRange(p, rangestart, rangelength, cpm.contentlength);
|
|
|
|
|
cpm.content += rangestart;
|
|
|
|
|
cpm.contentlength = rangelength;
|
2021-04-21 02:14:21 +00:00
|
|
|
|
return p;
|
|
|
|
|
} else {
|
2021-05-03 19:09:35 +00:00
|
|
|
|
LockInc(&shared->c.badranges);
|
2021-09-07 18:40:11 +00:00
|
|
|
|
WARNF("(client) bad range %`'.*s", HeaderLength(kHttpRange),
|
|
|
|
|
HeaderData(kHttpRange));
|
2021-04-21 02:14:21 +00:00
|
|
|
|
p = SetStatus(416, "Range Not Satisfiable");
|
2022-08-06 00:34:53 +00:00
|
|
|
|
p = AppendContentRange(p, -1, -1, cpm.contentlength);
|
|
|
|
|
cpm.content = "";
|
|
|
|
|
cpm.contentlength = 0;
|
2021-04-21 02:14:21 +00:00
|
|
|
|
return p;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-14 12:36:58 +00:00
|
|
|
|
static char *GetAssetPath(uint8_t *zcf, size_t *out_size) {
|
2023-09-02 03:49:13 +00:00
|
|
|
|
char *p2;
|
2021-03-29 09:39:20 +00:00
|
|
|
|
size_t n1, n2;
|
2023-09-02 03:49:13 +00:00
|
|
|
|
const char *p1;
|
2021-05-14 12:36:58 +00:00
|
|
|
|
p1 = ZIP_CFILE_NAME(zcf);
|
|
|
|
|
n1 = ZIP_CFILE_NAMESIZE(zcf);
|
2021-03-29 09:39:20 +00:00
|
|
|
|
n2 = 1 + n1 + 1;
|
2023-09-02 03:49:13 +00:00
|
|
|
|
p2 = xmalloc(n2);
|
2021-03-29 09:39:20 +00:00
|
|
|
|
p2[0] = '/';
|
|
|
|
|
memcpy(p2 + 1, p1, n1);
|
|
|
|
|
p2[1 + n1] = '\0';
|
|
|
|
|
if (out_size)
|
|
|
|
|
*out_size = 1 + n1;
|
|
|
|
|
return p2;
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-14 12:36:58 +00:00
|
|
|
|
static bool IsHiddenPath(const char *s, size_t n) {
|
2021-03-29 09:39:20 +00:00
|
|
|
|
size_t i;
|
|
|
|
|
for (i = 0; i < hidepaths.n; ++i) {
|
2021-05-14 12:36:58 +00:00
|
|
|
|
if (n >= hidepaths.p[i].n &&
|
|
|
|
|
!memcmp(s, hidepaths.p[i].s, hidepaths.p[i].n)) {
|
2021-03-29 09:39:20 +00:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-23 17:45:19 +00:00
|
|
|
|
static char *GetBasicAuthorization(size_t *z) {
|
|
|
|
|
size_t n;
|
|
|
|
|
const char *p, *q;
|
2021-06-24 19:31:26 +00:00
|
|
|
|
struct HttpSlice *g;
|
2022-08-06 00:34:53 +00:00
|
|
|
|
g = cpm.msg.headers + (HasHeader(kHttpProxyAuthorization)
|
|
|
|
|
? kHttpProxyAuthorization
|
|
|
|
|
: kHttpAuthorization);
|
2021-05-14 12:36:58 +00:00
|
|
|
|
p = inbuf.p + g->a;
|
|
|
|
|
n = g->b - g->a;
|
2021-04-23 17:45:19 +00:00
|
|
|
|
if ((q = memchr(p, ' ', n)) && SlicesEqualCase(p, q - p, "Basic", 5)) {
|
|
|
|
|
return DecodeBase64(q + 1, n - (q + 1 - p), z);
|
|
|
|
|
} else {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-03 18:52:24 +00:00
|
|
|
|
static const char *GetSystemUrlLauncherCommand(void) {
|
2021-04-18 14:24:36 +00:00
|
|
|
|
if (IsWindows()) {
|
2023-10-13 18:39:00 +00:00
|
|
|
|
return "explorer.exe";
|
2021-04-18 14:24:36 +00:00
|
|
|
|
} else if (IsXnu()) {
|
2021-05-03 18:52:24 +00:00
|
|
|
|
return "open";
|
2021-04-18 14:24:36 +00:00
|
|
|
|
} else {
|
2021-05-03 18:52:24 +00:00
|
|
|
|
return "xdg-open";
|
2021-04-18 14:24:36 +00:00
|
|
|
|
}
|
2021-05-03 18:52:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void LaunchBrowser(const char *path) {
|
2022-03-05 01:41:19 +00:00
|
|
|
|
uint16_t port = 80;
|
2024-02-22 22:12:18 +00:00
|
|
|
|
struct in_addr addr;
|
2021-05-03 18:52:24 +00:00
|
|
|
|
path = firstnonnull(path, "/");
|
2022-03-05 01:41:19 +00:00
|
|
|
|
// use the first server address if there is at least one server
|
|
|
|
|
if (servers.n) {
|
|
|
|
|
addr = servers.p[0].addr.sin_addr;
|
|
|
|
|
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);
|
2024-01-08 18:07:35 +00:00
|
|
|
|
if (*path != '/')
|
|
|
|
|
path = gc(xasprintf("/%s", path));
|
2024-02-22 22:12:18 +00:00
|
|
|
|
launch_browser(gc(xasprintf("http://%s:%d%s", inet_ntoa(addr), port, path)));
|
2021-04-18 14:24:36 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-04-25 00:09:01 +00:00
|
|
|
|
static char *BadMethod(void) {
|
2021-05-03 19:09:35 +00:00
|
|
|
|
LockInc(&shared->c.badmethods);
|
2021-04-25 00:09:01 +00:00
|
|
|
|
return stpcpy(ServeError(405, "Method Not Allowed"), "Allow: GET, HEAD\r\n");
|
2021-03-25 09:21:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-05-14 12:36:58 +00:00
|
|
|
|
static int GetDecimalWidth(long x) {
|
2021-10-14 00:27:13 +00:00
|
|
|
|
return LengthInt64Thousands(x);
|
2021-03-25 09:21:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-04-25 00:09:01 +00:00
|
|
|
|
static int GetOctalWidth(int x) {
|
2024-03-05 01:33:26 +00:00
|
|
|
|
return !x ? 1 : x < 8 ? 2 : 1 + bsr(x) / 3;
|
2021-03-27 14:29:55 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-05-14 12:36:58 +00:00
|
|
|
|
static const char *DescribeCompressionRatio(char rb[8], uint8_t *zcf) {
|
2021-04-25 00:09:01 +00:00
|
|
|
|
long percent;
|
2021-05-14 12:36:58 +00:00
|
|
|
|
if (ZIP_CFILE_COMPRESSIONMETHOD(zcf) == kZipCompressionNone) {
|
2021-04-25 00:09:01 +00:00
|
|
|
|
return "n/a";
|
|
|
|
|
} else {
|
2021-05-14 12:36:58 +00:00
|
|
|
|
percent = lround(100 - (double)GetZipCfileCompressedSize(zcf) /
|
|
|
|
|
GetZipCfileUncompressedSize(zcf) * 100);
|
2021-04-25 00:09:01 +00:00
|
|
|
|
sprintf(rb, "%ld%%", MIN(999, MAX(-999, percent)));
|
|
|
|
|
return rb;
|
|
|
|
|
}
|
2021-03-27 14:29:55 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-04-25 00:09:01 +00:00
|
|
|
|
static char *ServeListing(void) {
|
|
|
|
|
long x;
|
|
|
|
|
ldiv_t y;
|
|
|
|
|
int w[3];
|
2021-05-14 12:36:58 +00:00
|
|
|
|
uint8_t *zcf;
|
2021-04-25 00:09:01 +00:00
|
|
|
|
struct tm tm;
|
2023-09-02 03:49:13 +00:00
|
|
|
|
char *p, *path;
|
2021-04-25 00:09:01 +00:00
|
|
|
|
const char *and;
|
2021-08-14 13:17:56 +00:00
|
|
|
|
struct timespec lastmod;
|
2023-09-02 03:49:13 +00:00
|
|
|
|
size_t n, pathlen, rn[6];
|
2021-07-04 19:21:29 +00:00
|
|
|
|
char rb[8], tb[20], *rp[6];
|
2021-05-03 19:09:35 +00:00
|
|
|
|
LockInc(&shared->c.listingrequests);
|
2022-08-06 00:34:53 +00:00
|
|
|
|
if (cpm.msg.method != kHttpGet && cpm.msg.method != kHttpHead)
|
|
|
|
|
return BadMethod();
|
|
|
|
|
appends(&cpm.outbuf, "\
|
2021-04-25 00:09:01 +00:00
|
|
|
|
<!doctype html>\r\n\
|
|
|
|
|
<meta charset=\"utf-8\">\r\n\
|
|
|
|
|
<title>redbean zip listing</title>\r\n\
|
|
|
|
|
<style>\r\n\
|
|
|
|
|
html { color: #111; font-family: sans-serif; }\r\n\
|
|
|
|
|
a { text-decoration: none; }\r\n\
|
2021-04-25 02:49:49 +00:00
|
|
|
|
pre a:hover { color: #00e; border-bottom: 1px solid #ccc; }\r\n\
|
|
|
|
|
h1 a { color: #111; }\r\n\
|
2021-04-25 00:09:01 +00:00
|
|
|
|
img { vertical-align: middle; }\r\n\
|
|
|
|
|
footer { color: #555; font-size: 10pt; }\r\n\
|
|
|
|
|
td { padding-right: 3em; }\r\n\
|
2021-04-25 02:49:49 +00:00
|
|
|
|
.eocdcomment { max-width: 800px; color: #333; font-size: 11pt; }\r\n\
|
2021-04-25 00:09:01 +00:00
|
|
|
|
</style>\r\n\
|
|
|
|
|
<header><h1>\r\n");
|
|
|
|
|
AppendLogo();
|
|
|
|
|
rp[0] = EscapeHtml(brand, -1, &rn[0]);
|
2022-08-06 00:34:53 +00:00
|
|
|
|
appendd(&cpm.outbuf, rp[0], rn[0]);
|
2021-04-25 00:09:01 +00:00
|
|
|
|
free(rp[0]);
|
2022-08-06 00:34:53 +00:00
|
|
|
|
appendf(&cpm.outbuf,
|
2021-08-06 21:12:11 +00:00
|
|
|
|
"</h1>\r\n"
|
|
|
|
|
"<div class=\"eocdcomment\">%.*s</div>\r\n"
|
|
|
|
|
"<hr>\r\n"
|
|
|
|
|
"</header>\r\n"
|
|
|
|
|
"<pre>\r\n",
|
|
|
|
|
strnlen(GetZipCdirComment(zcdir), GetZipCdirCommentSize(zcdir)),
|
|
|
|
|
GetZipCdirComment(zcdir));
|
2021-09-28 05:58:51 +00:00
|
|
|
|
bzero(w, sizeof(w));
|
2021-05-02 18:50:43 +00:00
|
|
|
|
n = GetZipCdirRecords(zcdir);
|
2023-06-17 11:20:16 +00:00
|
|
|
|
for (zcf = zmap + GetZipCdirOffset(zcdir); n--;
|
2021-05-14 12:36:58 +00:00
|
|
|
|
zcf += ZIP_CFILE_HDRSIZE(zcf)) {
|
|
|
|
|
CHECK_EQ(kZipCfileHdrMagic, ZIP_CFILE_MAGIC(zcf));
|
|
|
|
|
path = GetAssetPath(zcf, &pathlen);
|
|
|
|
|
if (!IsHiddenPath(path, pathlen)) {
|
2021-04-25 00:09:01 +00:00
|
|
|
|
w[0] = min(80, max(w[0], strwidth(path, 0) + 2));
|
2021-05-14 12:36:58 +00:00
|
|
|
|
w[1] = max(w[1], GetOctalWidth(GetZipCfileMode(zcf)));
|
|
|
|
|
w[2] = max(w[2], GetDecimalWidth(GetZipCfileUncompressedSize(zcf)));
|
2021-04-25 00:09:01 +00:00
|
|
|
|
}
|
|
|
|
|
free(path);
|
|
|
|
|
}
|
2021-05-02 18:50:43 +00:00
|
|
|
|
n = GetZipCdirRecords(zcdir);
|
2023-06-17 11:20:16 +00:00
|
|
|
|
for (zcf = zmap + GetZipCdirOffset(zcdir); n--;
|
2021-05-14 12:36:58 +00:00
|
|
|
|
zcf += ZIP_CFILE_HDRSIZE(zcf)) {
|
|
|
|
|
CHECK_EQ(kZipCfileHdrMagic, ZIP_CFILE_MAGIC(zcf));
|
|
|
|
|
path = GetAssetPath(zcf, &pathlen);
|
|
|
|
|
if (!IsHiddenPath(path, pathlen)) {
|
2021-04-25 00:09:01 +00:00
|
|
|
|
rp[0] = VisualizeControlCodes(path, pathlen, &rn[0]);
|
|
|
|
|
rp[1] = EscapePath(path, pathlen, &rn[1]);
|
|
|
|
|
rp[2] = EscapeHtml(rp[1], rn[1], &rn[2]);
|
2021-05-14 12:36:58 +00:00
|
|
|
|
rp[3] = VisualizeControlCodes(
|
|
|
|
|
ZIP_CFILE_COMMENT(zcf),
|
|
|
|
|
strnlen(ZIP_CFILE_COMMENT(zcf), ZIP_CFILE_COMMENTSIZE(zcf)), &rn[3]);
|
2021-04-25 00:09:01 +00:00
|
|
|
|
rp[4] = EscapeHtml(rp[0], rn[0], &rn[4]);
|
2021-08-14 13:17:56 +00:00
|
|
|
|
GetZipCfileTimestamps(zcf, &lastmod, 0, 0, gmtoff);
|
|
|
|
|
localtime_r(&lastmod.tv_sec, &tm);
|
2021-07-04 19:21:29 +00:00
|
|
|
|
iso8601(tb, &tm);
|
2021-05-14 12:36:58 +00:00
|
|
|
|
if (IsCompressionMethodSupported(ZIP_CFILE_COMPRESSIONMETHOD(zcf)) &&
|
2021-04-25 00:09:01 +00:00
|
|
|
|
IsAcceptablePath(path, pathlen)) {
|
2022-08-06 00:34:53 +00:00
|
|
|
|
appendf(&cpm.outbuf,
|
2021-08-06 21:12:11 +00:00
|
|
|
|
"<a href=\"%.*s\">%-*.*s</a> %s %0*o %4s %,*ld %'s\r\n",
|
|
|
|
|
rn[2], rp[2], w[0], rn[4], rp[4], tb, w[1],
|
|
|
|
|
GetZipCfileMode(zcf), DescribeCompressionRatio(rb, zcf), w[2],
|
|
|
|
|
GetZipCfileUncompressedSize(zcf), rp[3]);
|
2021-04-25 00:09:01 +00:00
|
|
|
|
} else {
|
2022-08-06 00:34:53 +00:00
|
|
|
|
appendf(&cpm.outbuf, "%-*.*s %s %0*o %4s %,*ld %'s\r\n", w[0], rn[4],
|
2021-08-06 21:12:11 +00:00
|
|
|
|
rp[4], tb, w[1], GetZipCfileMode(zcf),
|
|
|
|
|
DescribeCompressionRatio(rb, zcf), w[2],
|
|
|
|
|
GetZipCfileUncompressedSize(zcf), rp[3]);
|
2021-04-23 17:45:19 +00:00
|
|
|
|
}
|
2021-04-25 00:09:01 +00:00
|
|
|
|
free(rp[4]);
|
|
|
|
|
free(rp[3]);
|
|
|
|
|
free(rp[2]);
|
|
|
|
|
free(rp[1]);
|
|
|
|
|
free(rp[0]);
|
2021-04-23 17:45:19 +00:00
|
|
|
|
}
|
2021-04-25 00:09:01 +00:00
|
|
|
|
free(path);
|
2021-03-25 09:21:13 +00:00
|
|
|
|
}
|
2022-08-06 00:34:53 +00:00
|
|
|
|
appends(&cpm.outbuf, "\
|
2021-08-06 21:12:11 +00:00
|
|
|
|
</pre><footer><hr>\r\n\
|
|
|
|
|
<table border=\"0\"><tr>\r\n\
|
|
|
|
|
<td valign=\"top\">\r\n\
|
|
|
|
|
<a href=\"/statusz\">/statusz</a>\r\n\
|
|
|
|
|
");
|
2024-12-02 22:05:38 +00:00
|
|
|
|
if (atomic_load_explicit(&shared->c.connectionshandled,
|
|
|
|
|
memory_order_acquire)) {
|
2022-08-06 00:34:53 +00:00
|
|
|
|
appends(&cpm.outbuf, "says your redbean<br>\r\n");
|
2024-12-02 22:05:38 +00:00
|
|
|
|
unassert(!pthread_mutex_lock(&shared->children_mu));
|
2022-08-06 00:34:53 +00:00
|
|
|
|
AppendResourceReport(&cpm.outbuf, &shared->children, "<br>\r\n");
|
2024-12-02 22:05:38 +00:00
|
|
|
|
unassert(!pthread_mutex_unlock(&shared->children_mu));
|
2021-04-25 02:49:49 +00:00
|
|
|
|
}
|
2022-08-06 00:34:53 +00:00
|
|
|
|
appends(&cpm.outbuf, "<td valign=\"top\">\r\n");
|
2021-04-25 00:09:01 +00:00
|
|
|
|
and = "";
|
2022-11-06 02:49:41 +00:00
|
|
|
|
x = timespec_sub(timespec_real(), startserver).tv_sec;
|
2021-04-25 00:09:01 +00:00
|
|
|
|
y = ldiv(x, 24L * 60 * 60);
|
|
|
|
|
if (y.quot) {
|
2022-08-06 00:34:53 +00:00
|
|
|
|
appendf(&cpm.outbuf, "%,ld day%s ", y.quot, y.quot == 1 ? "" : "s");
|
2021-04-25 00:09:01 +00:00
|
|
|
|
and = "and ";
|
|
|
|
|
}
|
|
|
|
|
y = ldiv(y.rem, 60 * 60);
|
|
|
|
|
if (y.quot) {
|
2022-08-06 00:34:53 +00:00
|
|
|
|
appendf(&cpm.outbuf, "%,ld hour%s ", y.quot, y.quot == 1 ? "" : "s");
|
2021-04-25 00:09:01 +00:00
|
|
|
|
and = "and ";
|
|
|
|
|
}
|
|
|
|
|
y = ldiv(y.rem, 60);
|
|
|
|
|
if (y.quot) {
|
2022-08-06 00:34:53 +00:00
|
|
|
|
appendf(&cpm.outbuf, "%,ld minute%s ", y.quot, y.quot == 1 ? "" : "s");
|
2021-04-25 00:09:01 +00:00
|
|
|
|
and = "and ";
|
|
|
|
|
}
|
2022-08-06 00:34:53 +00:00
|
|
|
|
appendf(&cpm.outbuf, "%s%,ld second%s of operation<br>\r\n", and, y.rem,
|
2021-08-06 21:12:11 +00:00
|
|
|
|
y.rem == 1 ? "" : "s");
|
2024-12-02 22:05:38 +00:00
|
|
|
|
x = atomic_load_explicit(&shared->c.messageshandled, memory_order_relaxed);
|
2022-08-06 00:34:53 +00:00
|
|
|
|
appendf(&cpm.outbuf, "%,ld message%s handled<br>\r\n", x, x == 1 ? "" : "s");
|
2024-12-02 22:05:38 +00:00
|
|
|
|
x = atomic_load_explicit(&shared->c.connectionshandled, memory_order_relaxed);
|
2022-08-06 00:34:53 +00:00
|
|
|
|
appendf(&cpm.outbuf, "%,ld connection%s handled<br>\r\n", x,
|
|
|
|
|
x == 1 ? "" : "s");
|
2024-12-02 22:05:38 +00:00
|
|
|
|
x = atomic_load_explicit(&shared->workers, memory_order_relaxed);
|
2022-08-06 00:34:53 +00:00
|
|
|
|
appendf(&cpm.outbuf, "%,ld connection%s active<br>\r\n", x,
|
|
|
|
|
x == 1 ? "" : "s");
|
|
|
|
|
appends(&cpm.outbuf, "</table>\r\n");
|
|
|
|
|
appends(&cpm.outbuf, "</footer>\r\n");
|
2021-04-25 00:09:01 +00:00
|
|
|
|
p = SetStatus(200, "OK");
|
|
|
|
|
p = AppendContentType(p, "text/html");
|
2022-08-06 00:34:53 +00:00
|
|
|
|
if (cpm.msg.version >= 11) {
|
2022-06-15 05:01:13 +00:00
|
|
|
|
p = stpcpy(p, "Cache-Control: no-store\r\n");
|
|
|
|
|
}
|
2021-04-25 00:09:01 +00:00
|
|
|
|
return CommitOutput(p);
|
2021-03-25 09:21:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-04-25 00:09:01 +00:00
|
|
|
|
static const char *MergeNames(const char *a, const char *b) {
|
2021-05-16 04:53:26 +00:00
|
|
|
|
return FreeLater(xasprintf("%s.%s", a, b));
|
2021-03-25 09:21:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-04-25 00:09:01 +00:00
|
|
|
|
static void AppendLong1(const char *a, long x) {
|
2022-08-06 00:34:53 +00:00
|
|
|
|
if (x)
|
|
|
|
|
appendf(&cpm.outbuf, "%s: %ld\r\n", a, x);
|
2021-03-25 09:21:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-04-25 00:09:01 +00:00
|
|
|
|
static void AppendLong2(const char *a, const char *b, long x) {
|
2022-08-06 00:34:53 +00:00
|
|
|
|
if (x)
|
|
|
|
|
appendf(&cpm.outbuf, "%s.%s: %ld\r\n", a, b, x);
|
2021-03-25 09:21:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-04-25 00:09:01 +00:00
|
|
|
|
static void AppendTimeval(const char *a, struct timeval *tv) {
|
|
|
|
|
AppendLong2(a, "tv_sec", tv->tv_sec);
|
|
|
|
|
AppendLong2(a, "tv_usec", tv->tv_usec);
|
2021-04-21 02:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-04-25 00:09:01 +00:00
|
|
|
|
static void AppendRusage(const char *a, struct rusage *ru) {
|
|
|
|
|
AppendTimeval(MergeNames(a, "ru_utime"), &ru->ru_utime);
|
|
|
|
|
AppendTimeval(MergeNames(a, "ru_stime"), &ru->ru_stime);
|
|
|
|
|
AppendLong2(a, "ru_maxrss", ru->ru_maxrss);
|
|
|
|
|
AppendLong2(a, "ru_ixrss", ru->ru_ixrss);
|
|
|
|
|
AppendLong2(a, "ru_idrss", ru->ru_idrss);
|
|
|
|
|
AppendLong2(a, "ru_isrss", ru->ru_isrss);
|
|
|
|
|
AppendLong2(a, "ru_minflt", ru->ru_minflt);
|
|
|
|
|
AppendLong2(a, "ru_majflt", ru->ru_majflt);
|
|
|
|
|
AppendLong2(a, "ru_nswap", ru->ru_nswap);
|
|
|
|
|
AppendLong2(a, "ru_inblock", ru->ru_inblock);
|
|
|
|
|
AppendLong2(a, "ru_oublock", ru->ru_oublock);
|
|
|
|
|
AppendLong2(a, "ru_msgsnd", ru->ru_msgsnd);
|
|
|
|
|
AppendLong2(a, "ru_msgrcv", ru->ru_msgrcv);
|
|
|
|
|
AppendLong2(a, "ru_nsignals", ru->ru_nsignals);
|
|
|
|
|
AppendLong2(a, "ru_nvcsw", ru->ru_nvcsw);
|
|
|
|
|
AppendLong2(a, "ru_nivcsw", ru->ru_nivcsw);
|
2021-04-21 02:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-05-03 19:09:35 +00:00
|
|
|
|
static void ServeCounters(void) {
|
2024-12-02 22:05:38 +00:00
|
|
|
|
const _Atomic(long) *c;
|
2021-05-03 19:09:35 +00:00
|
|
|
|
const char *s;
|
2024-12-02 22:05:38 +00:00
|
|
|
|
for (c = (const _Atomic(long) *)&shared->c, s = kCounterNames; *s;
|
2021-05-03 19:09:35 +00:00
|
|
|
|
++c, s += strlen(s) + 1) {
|
2024-12-02 22:05:38 +00:00
|
|
|
|
AppendLong1(s, atomic_load_explicit(c, memory_order_relaxed));
|
2021-05-03 19:09:35 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-25 00:09:01 +00:00
|
|
|
|
static char *ServeStatusz(void) {
|
|
|
|
|
char *p;
|
2021-05-03 19:09:35 +00:00
|
|
|
|
LockInc(&shared->c.statuszrequests);
|
2022-08-06 00:34:53 +00:00
|
|
|
|
if (cpm.msg.method != kHttpGet && cpm.msg.method != kHttpHead) {
|
|
|
|
|
return BadMethod();
|
|
|
|
|
}
|
2021-04-25 00:09:01 +00:00
|
|
|
|
AppendLong1("pid", getpid());
|
|
|
|
|
AppendLong1("ppid", getppid());
|
2022-11-06 02:49:41 +00:00
|
|
|
|
AppendLong1("now", timespec_real().tv_sec);
|
2024-12-02 22:05:38 +00:00
|
|
|
|
unassert(!pthread_mutex_lock(&shared->datetime_mu));
|
2022-08-06 02:24:05 +00:00
|
|
|
|
AppendLong1("nowish", shared->nowish.tv_sec);
|
2024-12-02 22:05:38 +00:00
|
|
|
|
unassert(!pthread_mutex_unlock(&shared->datetime_mu));
|
2021-04-25 00:09:01 +00:00
|
|
|
|
AppendLong1("gmtoff", gmtoff);
|
|
|
|
|
AppendLong1("CLK_TCK", CLK_TCK);
|
2022-08-06 02:24:05 +00:00
|
|
|
|
AppendLong1("startserver", startserver.tv_sec);
|
2024-12-02 22:05:38 +00:00
|
|
|
|
unassert(!pthread_mutex_lock(&shared->lastmeltdown_mu));
|
2022-08-06 02:24:05 +00:00
|
|
|
|
AppendLong1("lastmeltdown", shared->lastmeltdown.tv_sec);
|
2024-12-02 22:05:38 +00:00
|
|
|
|
unassert(!pthread_mutex_unlock(&shared->lastmeltdown_mu));
|
|
|
|
|
AppendLong1("workers",
|
|
|
|
|
atomic_load_explicit(&shared->workers, memory_order_relaxed));
|
2021-04-25 00:09:01 +00:00
|
|
|
|
AppendLong1("assets.n", assets.n);
|
2021-08-13 09:11:49 +00:00
|
|
|
|
#ifndef STATIC
|
2021-10-25 21:54:56 +00:00
|
|
|
|
lua_State *L = GL;
|
2021-08-13 10:06:23 +00:00
|
|
|
|
AppendLong1("lua.memory",
|
|
|
|
|
lua_gc(L, LUA_GCCOUNT) * 1024 + lua_gc(L, LUA_GCCOUNTB));
|
2021-08-13 09:11:49 +00:00
|
|
|
|
#endif
|
2021-05-03 19:09:35 +00:00
|
|
|
|
ServeCounters();
|
2024-12-02 22:05:38 +00:00
|
|
|
|
unassert(!pthread_mutex_lock(&shared->server_mu));
|
2021-04-25 00:09:01 +00:00
|
|
|
|
AppendRusage("server", &shared->server);
|
2024-12-02 22:05:38 +00:00
|
|
|
|
unassert(!pthread_mutex_unlock(&shared->server_mu));
|
|
|
|
|
unassert(!pthread_mutex_lock(&shared->children_mu));
|
2021-04-25 00:09:01 +00:00
|
|
|
|
AppendRusage("children", &shared->children);
|
2024-12-02 22:05:38 +00:00
|
|
|
|
unassert(!pthread_mutex_unlock(&shared->children_mu));
|
2021-04-25 00:09:01 +00:00
|
|
|
|
p = SetStatus(200, "OK");
|
|
|
|
|
p = AppendContentType(p, "text/plain");
|
2022-08-06 00:34:53 +00:00
|
|
|
|
if (cpm.msg.version >= 11) {
|
2022-06-15 05:01:13 +00:00
|
|
|
|
p = stpcpy(p, "Cache-Control: no-store\r\n");
|
|
|
|
|
}
|
2021-04-25 00:09:01 +00:00
|
|
|
|
return CommitOutput(p);
|
2021-04-21 02:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-04-25 00:09:01 +00:00
|
|
|
|
static char *RedirectSlash(void) {
|
2022-09-09 02:14:54 +00:00
|
|
|
|
size_t n, i;
|
2021-04-25 00:09:01 +00:00
|
|
|
|
char *p, *e;
|
2021-05-03 19:09:35 +00:00
|
|
|
|
LockInc(&shared->c.redirects);
|
2021-04-25 00:09:01 +00:00
|
|
|
|
p = SetStatus(307, "Temporary Redirect");
|
|
|
|
|
p = stpcpy(p, "Location: ");
|
|
|
|
|
e = EscapePath(url.path.p, url.path.n, &n);
|
|
|
|
|
p = mempcpy(p, e, n);
|
2022-09-09 02:14:54 +00:00
|
|
|
|
p = stpcpy(p, "/");
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < url.params.n; ++i) {
|
|
|
|
|
p = stpcpy(p, i == 0 ? "?" : "&");
|
|
|
|
|
p = mempcpy(p, url.params.p[i].key.p, url.params.p[i].key.n);
|
|
|
|
|
if (url.params.p[i].val.p) {
|
|
|
|
|
p = stpcpy(p, "=");
|
|
|
|
|
p = mempcpy(p, url.params.p[i].val.p, url.params.p[i].val.n);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
p = stpcpy(p, "\r\n");
|
2021-04-25 00:09:01 +00:00
|
|
|
|
free(e);
|
|
|
|
|
return p;
|
2021-04-21 02:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-04-25 00:09:01 +00:00
|
|
|
|
static char *ServeIndex(const char *path, size_t pathlen) {
|
|
|
|
|
size_t i, n;
|
|
|
|
|
char *p, *q;
|
2021-05-17 01:22:39 +00:00
|
|
|
|
for (p = 0, i = 0; !p && i < ARRAYLEN(kIndexPaths); ++i) {
|
2021-04-25 00:09:01 +00:00
|
|
|
|
q = MergePaths(path, pathlen, kIndexPaths[i], strlen(kIndexPaths[i]), &n);
|
|
|
|
|
p = RoutePath(q, n);
|
|
|
|
|
free(q);
|
|
|
|
|
}
|
|
|
|
|
return p;
|
2021-04-23 17:45:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-04-24 16:59:22 +00:00
|
|
|
|
static bool ShouldServeCrashReportDetails(void) {
|
2022-04-13 15:49:17 +00:00
|
|
|
|
uint32_t ip;
|
|
|
|
|
uint16_t port;
|
2022-04-24 16:59:22 +00:00
|
|
|
|
if (leakcrashreports) {
|
|
|
|
|
return true;
|
|
|
|
|
} else {
|
2022-09-17 08:37:33 +00:00
|
|
|
|
return !GetRemoteAddr(&ip, &port) && (IsLoopbackIp(ip) || IsPrivateIp(ip));
|
2022-04-24 16:59:22 +00:00
|
|
|
|
}
|
2022-04-13 15:49:17 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-05-03 19:09:35 +00:00
|
|
|
|
static char *LuaOnHttpRequest(void) {
|
2022-03-18 09:33:37 +00:00
|
|
|
|
char *error;
|
2021-10-25 21:54:56 +00:00
|
|
|
|
lua_State *L = GL;
|
2021-05-03 19:09:35 +00:00
|
|
|
|
effectivepath.p = url.path.p;
|
|
|
|
|
effectivepath.n = url.path.n;
|
2022-04-15 01:13:53 +00:00
|
|
|
|
lua_settop(L, 0); // clear Lua stack, as it needs to start fresh
|
2021-05-03 19:09:35 +00:00
|
|
|
|
lua_getglobal(L, "OnHttpRequest");
|
2022-03-22 01:07:30 +00:00
|
|
|
|
if (LuaCallWithYield(L) == LUA_OK) {
|
2021-05-03 19:09:35 +00:00
|
|
|
|
return CommitOutput(GetLuaResponse());
|
|
|
|
|
} else {
|
2021-08-22 22:01:52 +00:00
|
|
|
|
LogLuaError("OnHttpRequest", lua_tostring(L, -1));
|
2022-04-13 15:49:17 +00:00
|
|
|
|
error = ServeErrorWithDetail(
|
|
|
|
|
500, "Internal Server Error",
|
|
|
|
|
ShouldServeCrashReportDetails() ? lua_tostring(L, -1) : NULL);
|
2022-03-22 01:07:30 +00:00
|
|
|
|
lua_pop(L, 1); // pop error
|
2021-08-12 06:27:39 +00:00
|
|
|
|
return error;
|
2021-05-03 19:09:35 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *ServeLua(struct Asset *a, const char *s, size_t n) {
|
2021-04-25 00:09:01 +00:00
|
|
|
|
char *code;
|
2021-08-09 20:09:14 +00:00
|
|
|
|
size_t codelen;
|
2021-10-25 21:54:56 +00:00
|
|
|
|
lua_State *L = GL;
|
2021-05-03 19:09:35 +00:00
|
|
|
|
LockInc(&shared->c.dynamicrequests);
|
2023-09-02 03:49:13 +00:00
|
|
|
|
effectivepath.p = (void *)s;
|
2021-05-03 19:09:35 +00:00
|
|
|
|
effectivepath.n = n;
|
2021-08-09 20:09:14 +00:00
|
|
|
|
if ((code = FreeLater(LoadAsset(a, &codelen)))) {
|
2021-08-12 07:42:14 +00:00
|
|
|
|
int status =
|
|
|
|
|
luaL_loadbuffer(L, code, codelen,
|
|
|
|
|
FreeLater(xasprintf("@%s", FreeLater(strndup(s, n)))));
|
2022-03-22 01:07:30 +00:00
|
|
|
|
if (status == LUA_OK && LuaCallWithYield(L) == LUA_OK) {
|
2021-04-25 00:09:01 +00:00
|
|
|
|
return CommitOutput(GetLuaResponse());
|
|
|
|
|
} else {
|
2021-08-12 06:27:39 +00:00
|
|
|
|
char *error;
|
2021-08-22 22:01:52 +00:00
|
|
|
|
LogLuaError("lua code", lua_tostring(L, -1));
|
2022-04-13 15:49:17 +00:00
|
|
|
|
error = ServeErrorWithDetail(
|
|
|
|
|
500, "Internal Server Error",
|
|
|
|
|
ShouldServeCrashReportDetails() ? lua_tostring(L, -1) : NULL);
|
2022-03-22 01:07:30 +00:00
|
|
|
|
lua_pop(L, 1); // pop error
|
2021-08-12 06:27:39 +00:00
|
|
|
|
return error;
|
2021-04-25 00:09:01 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return ServeError(500, "Internal Server Error");
|
2021-03-25 09:21:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-04-25 00:09:01 +00:00
|
|
|
|
static char *HandleRedirect(struct Redirect *r) {
|
|
|
|
|
int code;
|
|
|
|
|
struct Asset *a;
|
2021-05-14 12:36:58 +00:00
|
|
|
|
if (!r->code && (a = GetAsset(r->location.s, r->location.n))) {
|
2021-05-03 19:09:35 +00:00
|
|
|
|
LockInc(&shared->c.rewrites);
|
2021-10-25 21:04:57 +00:00
|
|
|
|
DEBUGF("(rsp) internal redirect to %`'s", r->location.s);
|
2022-08-06 00:34:53 +00:00
|
|
|
|
if (!HasString(&cpm.loops, r->location.s, r->location.n)) {
|
|
|
|
|
AddString(&cpm.loops, r->location.s, r->location.n);
|
2021-05-14 12:36:58 +00:00
|
|
|
|
return RoutePath(r->location.s, r->location.n);
|
2021-04-25 00:09:01 +00:00
|
|
|
|
} else {
|
2021-05-03 19:09:35 +00:00
|
|
|
|
LockInc(&shared->c.loops);
|
2021-04-25 00:09:01 +00:00
|
|
|
|
return SetStatus(508, "Loop Detected");
|
|
|
|
|
}
|
2022-08-06 00:34:53 +00:00
|
|
|
|
} else if (cpm.msg.version < 10) {
|
2021-04-25 00:09:01 +00:00
|
|
|
|
return ServeError(505, "HTTP Version Not Supported");
|
|
|
|
|
} else {
|
2021-05-03 19:09:35 +00:00
|
|
|
|
LockInc(&shared->c.redirects);
|
2021-04-25 00:09:01 +00:00
|
|
|
|
code = r->code;
|
|
|
|
|
if (!code)
|
|
|
|
|
code = 307;
|
2021-10-25 21:04:57 +00:00
|
|
|
|
DEBUGF("(rsp) %d redirect to %`'s", code, r->location.s);
|
2021-05-14 12:36:58 +00:00
|
|
|
|
return AppendHeader(
|
|
|
|
|
SetStatus(code, GetHttpReason(code)), "Location",
|
|
|
|
|
FreeLater(EncodeHttpHeaderValue(r->location.s, r->location.n, 0)));
|
2021-04-25 00:09:01 +00:00
|
|
|
|
}
|
2021-03-25 09:21:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-04-25 00:09:01 +00:00
|
|
|
|
static char *HandleFolder(const char *path, size_t pathlen) {
|
|
|
|
|
char *p;
|
|
|
|
|
if (url.path.n && url.path.p[url.path.n - 1] != '/' &&
|
|
|
|
|
SlicesEqual(path, pathlen, url.path.p, url.path.n)) {
|
|
|
|
|
return RedirectSlash();
|
|
|
|
|
}
|
|
|
|
|
if ((p = ServeIndex(path, pathlen))) {
|
|
|
|
|
return p;
|
2021-04-21 02:14:21 +00:00
|
|
|
|
} else {
|
2021-05-03 19:09:35 +00:00
|
|
|
|
LockInc(&shared->c.forbiddens);
|
2021-08-22 22:01:52 +00:00
|
|
|
|
WARNF("(srvr) directory %`'.*s lacks index page", pathlen, path);
|
2023-07-02 02:47:59 +00:00
|
|
|
|
return ServeErrorWithPath(403, "Forbidden", path, pathlen);
|
2021-04-21 02:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-14 12:36:58 +00:00
|
|
|
|
static bool Reindex(void) {
|
|
|
|
|
if (OpenZip(false)) {
|
|
|
|
|
LockInc(&shared->c.reindexes);
|
|
|
|
|
return true;
|
|
|
|
|
} else {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2021-05-02 18:50:43 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-04-25 00:09:01 +00:00
|
|
|
|
static const char *LuaCheckPath(lua_State *L, int idx, size_t *pathlen) {
|
|
|
|
|
const char *path;
|
|
|
|
|
if (lua_isnoneornil(L, idx)) {
|
|
|
|
|
path = url.path.p;
|
|
|
|
|
*pathlen = url.path.n;
|
|
|
|
|
} else {
|
|
|
|
|
path = luaL_checklstring(L, idx, pathlen);
|
|
|
|
|
if (!IsReasonablePath(path, *pathlen)) {
|
2021-08-22 22:01:52 +00:00
|
|
|
|
WARNF("(srvr) bad path %`'.*s", *pathlen, path);
|
2021-04-25 00:09:01 +00:00
|
|
|
|
luaL_argerror(L, idx, "bad path");
|
2023-06-09 06:44:03 +00:00
|
|
|
|
__builtin_unreachable();
|
2021-04-25 00:09:01 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return path;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const char *LuaCheckHost(lua_State *L, int idx, size_t *hostlen) {
|
|
|
|
|
const char *host;
|
|
|
|
|
if (lua_isnoneornil(L, idx)) {
|
|
|
|
|
host = url.host.p;
|
|
|
|
|
*hostlen = url.host.n;
|
|
|
|
|
} else {
|
|
|
|
|
host = luaL_checklstring(L, idx, hostlen);
|
|
|
|
|
if (!IsAcceptableHost(host, *hostlen)) {
|
2021-08-22 22:01:52 +00:00
|
|
|
|
WARNF("(srvr) bad host %`'.*s", *hostlen, host);
|
2021-04-25 00:09:01 +00:00
|
|
|
|
luaL_argerror(L, idx, "bad host");
|
2023-06-09 06:44:03 +00:00
|
|
|
|
__builtin_unreachable();
|
2021-04-25 00:09:01 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return host;
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-25 21:54:56 +00:00
|
|
|
|
static void OnlyCallFromInitLua(lua_State *L, const char *api) {
|
2021-08-10 18:36:17 +00:00
|
|
|
|
if (isinitialized) {
|
2022-04-24 16:59:22 +00:00
|
|
|
|
luaL_error(L, "%s() should be called %s", api,
|
|
|
|
|
"from the global scope of .init.lua");
|
2023-06-09 06:44:03 +00:00
|
|
|
|
__builtin_unreachable();
|
2021-08-09 21:45:52 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-24 16:59:22 +00:00
|
|
|
|
static void OnlyCallFromMainProcess(lua_State *L, const char *api) {
|
|
|
|
|
if (__isworker) {
|
|
|
|
|
luaL_error(L, "%s() should be called %s", api,
|
|
|
|
|
"from .init.lua or the repl");
|
2023-06-09 06:44:03 +00:00
|
|
|
|
__builtin_unreachable();
|
2021-08-09 21:45:52 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-25 21:54:56 +00:00
|
|
|
|
static void OnlyCallDuringConnection(lua_State *L, const char *api) {
|
2021-08-09 21:45:52 +00:00
|
|
|
|
if (!ishandlingconnection) {
|
2023-03-20 15:10:32 +00:00
|
|
|
|
luaL_error(L, "%s() can only be called %s", api,
|
2022-04-24 16:59:22 +00:00
|
|
|
|
"while handling a connection");
|
2023-06-09 06:44:03 +00:00
|
|
|
|
__builtin_unreachable();
|
2021-08-09 21:45:52 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-25 21:54:56 +00:00
|
|
|
|
static void OnlyCallDuringRequest(lua_State *L, const char *api) {
|
2021-08-09 21:45:52 +00:00
|
|
|
|
if (!ishandlingrequest) {
|
2022-04-24 16:59:22 +00:00
|
|
|
|
luaL_error(L, "%s() can only be called %s", api,
|
|
|
|
|
"while handling a request");
|
2023-06-09 06:44:03 +00:00
|
|
|
|
__builtin_unreachable();
|
2021-08-09 21:45:52 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int LuaServe(lua_State *L, const char *api, char *impl(void)) {
|
2021-10-25 21:54:56 +00:00
|
|
|
|
OnlyCallDuringRequest(L, api);
|
2022-08-06 00:34:53 +00:00
|
|
|
|
cpm.luaheaderp = impl();
|
2021-04-25 00:09:01 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-09 21:45:52 +00:00
|
|
|
|
static int LuaServeListing(lua_State *L) {
|
|
|
|
|
return LuaServe(L, "ServeListing", ServeListing);
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-25 00:09:01 +00:00
|
|
|
|
static int LuaServeStatusz(lua_State *L) {
|
2021-08-09 21:45:52 +00:00
|
|
|
|
return LuaServe(L, "ServeStatusz", ServeStatusz);
|
2021-04-25 00:09:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int LuaServeAsset(lua_State *L) {
|
|
|
|
|
size_t pathlen;
|
|
|
|
|
struct Asset *a;
|
|
|
|
|
const char *path;
|
2021-10-25 21:54:56 +00:00
|
|
|
|
OnlyCallDuringRequest(L, "ServeAsset");
|
2021-04-25 00:09:01 +00:00
|
|
|
|
path = LuaCheckPath(L, 1, &pathlen);
|
|
|
|
|
if ((a = GetAsset(path, pathlen)) && !S_ISDIR(GetMode(a))) {
|
2022-08-06 00:34:53 +00:00
|
|
|
|
cpm.luaheaderp = ServeAsset(a, path, pathlen);
|
2021-04-25 00:09:01 +00:00
|
|
|
|
lua_pushboolean(L, true);
|
|
|
|
|
} else {
|
|
|
|
|
lua_pushboolean(L, false);
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int LuaServeIndex(lua_State *L) {
|
|
|
|
|
size_t pathlen;
|
|
|
|
|
const char *path;
|
2021-10-25 21:54:56 +00:00
|
|
|
|
OnlyCallDuringRequest(L, "ServeIndex");
|
2021-04-25 00:09:01 +00:00
|
|
|
|
path = LuaCheckPath(L, 1, &pathlen);
|
2022-08-06 00:34:53 +00:00
|
|
|
|
lua_pushboolean(L, !!(cpm.luaheaderp = ServeIndex(path, pathlen)));
|
2021-04-25 00:09:01 +00:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-17 21:26:33 +00:00
|
|
|
|
static int LuaServeRedirect(lua_State *L) {
|
|
|
|
|
int code;
|
2023-09-02 03:49:13 +00:00
|
|
|
|
char *eval;
|
|
|
|
|
size_t loclen;
|
|
|
|
|
const char *location;
|
2021-10-25 21:54:56 +00:00
|
|
|
|
OnlyCallDuringRequest(L, "ServeRedirect");
|
2021-08-17 21:26:33 +00:00
|
|
|
|
|
|
|
|
|
code = luaL_checkinteger(L, 1);
|
|
|
|
|
if (!(300 <= code && code <= 399)) {
|
|
|
|
|
luaL_argerror(L, 1, "bad status code");
|
2023-06-09 06:44:03 +00:00
|
|
|
|
__builtin_unreachable();
|
2021-08-17 21:26:33 +00:00
|
|
|
|
}
|
|
|
|
|
location = luaL_checklstring(L, 2, &loclen);
|
2022-08-06 00:34:53 +00:00
|
|
|
|
if (cpm.msg.version < 10) {
|
2021-08-17 21:26:33 +00:00
|
|
|
|
(void)ServeError(505, "HTTP Version Not Supported");
|
|
|
|
|
lua_pushboolean(L, false);
|
|
|
|
|
} else {
|
|
|
|
|
if (!(eval = EncodeHttpHeaderValue(location, loclen, 0))) {
|
|
|
|
|
luaL_argerror(L, 2, "invalid location");
|
2023-06-09 06:44:03 +00:00
|
|
|
|
__builtin_unreachable();
|
2021-08-17 21:26:33 +00:00
|
|
|
|
}
|
2021-08-22 22:01:52 +00:00
|
|
|
|
VERBOSEF("(rsp) %d redirect to %`'s", code, location);
|
2022-08-06 00:34:53 +00:00
|
|
|
|
cpm.luaheaderp =
|
Improve ZIP filesystem and change its prefix
The ZIP filesystem has a breaking change. You now need to use /zip/ to
open() / opendir() / etc. assets within the ZIP structure of your APE
binary, instead of the previous convention of using zip: or zip! URIs.
This is needed because Python likes to use absolute paths, and having
ZIP paths encoded like URIs simply broke too many things.
Many more system calls have been updated to be able to operate on ZIP
files and file descriptors. In particular fcntl() and ioctl() since
Python would do things like ask if a ZIP file is a terminal and get
confused when the old implementation mistakenly said yes, because the
fastest way to guarantee native file descriptors is to dup(2). This
change also improves the async signal safety of zipos and ensures it
doesn't maintain any open file descriptors beyond that which the user
has opened.
This change makes a lot of progress towards adding magic numbers that
are specific to platforms other than Linux. The philosophy here is that,
if you use an operating system like FreeBSD, then you should be able to
take advantage of FreeBSD exclusive features, even if we don't polyfill
them on other platforms. For example, you can now open() a file with the
O_VERIFY flag. If your program runs on other platforms, then Cosmo will
automatically set O_VERIFY to zero. This lets you safely use it without
the need for #ifdef or ifstatements which detract from readability.
One of the blindspots of the ASAN memory hardening we use to offer Rust
like assurances has always been that memory passed to the kernel via
system calls (e.g. writev) can't be checked automatically since the
kernel wasn't built with MODE=asan. This change makes more progress
ensuring that each system call will verify the soundness of memory
before it's passed to the kernel. The code for doing these checks is
fast, particularly for buffers, where it can verify 64 bytes a cycle.
- Correct O_LOOP definition on NT
- Introduce program_executable_name
- Add ASAN guards to more system calls
- Improve termios compatibility with BSDs
- Fix bug in Windows auxiliary value encoding
- Add BSD and XNU specific errnos and open flags
- Add check to ensure build doesn't talk to internet
2021-08-22 08:04:18 +00:00
|
|
|
|
AppendHeader(SetStatus(code, GetHttpReason(code)), "Location", eval);
|
2021-08-17 21:26:33 +00:00
|
|
|
|
free(eval);
|
|
|
|
|
lua_pushboolean(L, true);
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-25 00:09:01 +00:00
|
|
|
|
static int LuaRoutePath(lua_State *L) {
|
|
|
|
|
size_t pathlen;
|
|
|
|
|
const char *path;
|
2021-10-25 21:54:56 +00:00
|
|
|
|
OnlyCallDuringRequest(L, "RoutePath");
|
2021-04-25 00:09:01 +00:00
|
|
|
|
path = LuaCheckPath(L, 1, &pathlen);
|
2022-08-06 00:34:53 +00:00
|
|
|
|
lua_pushboolean(L, !!(cpm.luaheaderp = RoutePath(path, pathlen)));
|
2021-04-25 00:09:01 +00:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int LuaRouteHost(lua_State *L) {
|
|
|
|
|
size_t hostlen, pathlen;
|
|
|
|
|
const char *host, *path;
|
2021-10-25 21:54:56 +00:00
|
|
|
|
OnlyCallDuringRequest(L, "RouteHost");
|
2021-04-25 00:09:01 +00:00
|
|
|
|
host = LuaCheckHost(L, 1, &hostlen);
|
|
|
|
|
path = LuaCheckPath(L, 2, &pathlen);
|
2022-08-06 00:34:53 +00:00
|
|
|
|
lua_pushboolean(L,
|
|
|
|
|
!!(cpm.luaheaderp = RouteHost(host, hostlen, path, pathlen)));
|
2021-04-25 00:09:01 +00:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int LuaRoute(lua_State *L) {
|
|
|
|
|
size_t hostlen, pathlen;
|
|
|
|
|
const char *host, *path;
|
2021-10-25 21:54:56 +00:00
|
|
|
|
OnlyCallDuringRequest(L, "Route");
|
2021-04-25 00:09:01 +00:00
|
|
|
|
host = LuaCheckHost(L, 1, &hostlen);
|
|
|
|
|
path = LuaCheckPath(L, 2, &pathlen);
|
2022-08-06 00:34:53 +00:00
|
|
|
|
lua_pushboolean(L, !!(cpm.luaheaderp = Route(host, hostlen, path, pathlen)));
|
2021-04-25 00:09:01 +00:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-17 18:02:04 +00:00
|
|
|
|
static int LuaProgramTrustedIp(lua_State *L) {
|
2022-09-17 08:37:33 +00:00
|
|
|
|
lua_Integer ip, cidr;
|
|
|
|
|
uint32_t ip32, imask;
|
|
|
|
|
ip = luaL_checkinteger(L, 1);
|
|
|
|
|
cidr = luaL_optinteger(L, 2, 32);
|
|
|
|
|
if (!(0 <= ip && ip <= 0xffffffff)) {
|
|
|
|
|
luaL_argerror(L, 1, "ip out of range");
|
2023-06-09 06:44:03 +00:00
|
|
|
|
__builtin_unreachable();
|
2022-09-17 08:37:33 +00:00
|
|
|
|
}
|
|
|
|
|
if (!(0 <= cidr && cidr <= 32)) {
|
|
|
|
|
luaL_argerror(L, 2, "cidr should be 0 .. 32");
|
2023-06-09 06:44:03 +00:00
|
|
|
|
__builtin_unreachable();
|
2022-09-17 08:37:33 +00:00
|
|
|
|
}
|
|
|
|
|
ip32 = ip;
|
|
|
|
|
imask = ~(0xffffffffu << (32 - cidr));
|
|
|
|
|
if (ip32 & imask) {
|
|
|
|
|
luaL_argerror(L, 1,
|
|
|
|
|
"ip address isn't the network address; "
|
|
|
|
|
"it has bits masked by the cidr");
|
2023-06-09 06:44:03 +00:00
|
|
|
|
__builtin_unreachable();
|
2022-09-17 08:37:33 +00:00
|
|
|
|
}
|
2022-10-17 18:02:04 +00:00
|
|
|
|
ProgramTrustedIp(ip, cidr);
|
2022-09-17 08:37:33 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-17 18:02:04 +00:00
|
|
|
|
static int LuaIsTrusted(lua_State *L) {
|
2022-09-17 08:37:33 +00:00
|
|
|
|
lua_Integer ip;
|
|
|
|
|
ip = luaL_checkinteger(L, 1);
|
|
|
|
|
if (!(0 <= ip && ip <= 0xffffffff)) {
|
|
|
|
|
luaL_argerror(L, 1, "ip out of range");
|
2023-06-09 06:44:03 +00:00
|
|
|
|
__builtin_unreachable();
|
2022-09-17 08:37:33 +00:00
|
|
|
|
}
|
2022-10-17 18:02:04 +00:00
|
|
|
|
lua_pushboolean(L, IsTrustedIp(ip));
|
2022-09-17 08:37:33 +00:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-16 04:53:26 +00:00
|
|
|
|
static int LuaRespond(lua_State *L, char *R(unsigned, const char *)) {
|
2021-04-25 00:09:01 +00:00
|
|
|
|
char *p;
|
|
|
|
|
int code;
|
|
|
|
|
size_t reasonlen;
|
|
|
|
|
const char *reason;
|
2021-10-25 21:54:56 +00:00
|
|
|
|
OnlyCallDuringRequest(L, "Respond");
|
2021-04-25 00:09:01 +00:00
|
|
|
|
code = luaL_checkinteger(L, 1);
|
|
|
|
|
if (!(100 <= code && code <= 999)) {
|
|
|
|
|
luaL_argerror(L, 1, "bad status code");
|
2023-06-09 06:44:03 +00:00
|
|
|
|
__builtin_unreachable();
|
2021-04-25 00:09:01 +00:00
|
|
|
|
}
|
|
|
|
|
if (lua_isnoneornil(L, 2)) {
|
2022-08-06 00:34:53 +00:00
|
|
|
|
cpm.luaheaderp = R(code, GetHttpReason(code));
|
2021-04-25 00:09:01 +00:00
|
|
|
|
} else {
|
|
|
|
|
reason = lua_tolstring(L, 2, &reasonlen);
|
2021-11-12 23:00:41 +00:00
|
|
|
|
if ((p = EncodeHttpHeaderValue(reason, MIN(reasonlen, 128), 0))) {
|
2022-08-06 00:34:53 +00:00
|
|
|
|
cpm.luaheaderp = R(code, p);
|
2021-04-25 00:09:01 +00:00
|
|
|
|
free(p);
|
|
|
|
|
} else {
|
|
|
|
|
luaL_argerror(L, 2, "invalid");
|
2023-06-09 06:44:03 +00:00
|
|
|
|
__builtin_unreachable();
|
2021-04-25 00:09:01 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int LuaSetStatus(lua_State *L) {
|
|
|
|
|
return LuaRespond(L, SetStatus);
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-12 23:00:41 +00:00
|
|
|
|
static int LuaGetStatus(lua_State *L) {
|
|
|
|
|
OnlyCallDuringRequest(L, "GetStatus");
|
2022-08-06 00:34:53 +00:00
|
|
|
|
if (!cpm.statuscode) {
|
2021-11-12 23:00:41 +00:00
|
|
|
|
lua_pushnil(L);
|
2022-03-18 09:33:37 +00:00
|
|
|
|
} else {
|
2022-08-06 00:34:53 +00:00
|
|
|
|
lua_pushinteger(L, cpm.statuscode);
|
2022-03-18 09:33:37 +00:00
|
|
|
|
}
|
2021-11-12 23:00:41 +00:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-15 00:11:05 +00:00
|
|
|
|
static int LuaGetSslIdentity(lua_State *L) {
|
|
|
|
|
const mbedtls_x509_crt *cert;
|
|
|
|
|
OnlyCallDuringRequest(L, "GetSslIdentity");
|
2022-05-29 15:14:55 +00:00
|
|
|
|
if (!usingssl) {
|
2022-03-15 00:11:05 +00:00
|
|
|
|
lua_pushnil(L);
|
|
|
|
|
} else {
|
|
|
|
|
if (sslpskindex) {
|
2022-03-18 09:33:37 +00:00
|
|
|
|
CHECK((sslpskindex - 1) >= 0 && (sslpskindex - 1) < psks.n);
|
|
|
|
|
lua_pushlstring(L, psks.p[sslpskindex - 1].identity,
|
|
|
|
|
psks.p[sslpskindex - 1].identity_len);
|
2022-03-15 00:11:05 +00:00
|
|
|
|
} else {
|
|
|
|
|
cert = mbedtls_ssl_get_peer_cert(&ssl);
|
2024-01-08 18:07:35 +00:00
|
|
|
|
lua_pushstring(L, cert ? gc(FormatX509Name(&cert->subject)) : "");
|
2022-03-15 00:11:05 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-25 00:09:01 +00:00
|
|
|
|
static int LuaServeError(lua_State *L) {
|
|
|
|
|
return LuaRespond(L, ServeError);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int LuaLoadAsset(lua_State *L) {
|
|
|
|
|
void *data;
|
|
|
|
|
struct Asset *a;
|
|
|
|
|
const char *path;
|
|
|
|
|
size_t size, pathlen;
|
|
|
|
|
path = LuaCheckPath(L, 1, &pathlen);
|
|
|
|
|
if ((a = GetAsset(path, pathlen))) {
|
|
|
|
|
if (!a->file && !IsCompressed(a)) {
|
|
|
|
|
/* fast path: this avoids extra copy */
|
2023-06-17 11:20:16 +00:00
|
|
|
|
data = ZIP_LFILE_CONTENT(zmap + a->lf);
|
|
|
|
|
size = GetZipLfileUncompressedSize(zmap + a->lf);
|
|
|
|
|
if (Verify(data, size, ZIP_LFILE_CRC32(zmap + a->lf))) {
|
2021-04-25 00:09:01 +00:00
|
|
|
|
lua_pushlstring(L, data, size);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2021-08-22 22:01:52 +00:00
|
|
|
|
// any error from Verify has already been reported
|
2021-04-25 00:09:01 +00:00
|
|
|
|
} else if ((data = LoadAsset(a, &size))) {
|
|
|
|
|
lua_pushlstring(L, data, size);
|
|
|
|
|
free(data);
|
|
|
|
|
return 1;
|
2021-06-24 19:31:26 +00:00
|
|
|
|
} else {
|
2021-08-22 22:01:52 +00:00
|
|
|
|
WARNF("(srvr) could not load asset: %`'.*s", pathlen, path);
|
2021-04-25 00:09:01 +00:00
|
|
|
|
}
|
2021-06-24 19:31:26 +00:00
|
|
|
|
} else {
|
2021-08-22 22:01:52 +00:00
|
|
|
|
WARNF("(srvr) could not find asset: %`'.*s", pathlen, path);
|
2021-04-25 00:09:01 +00:00
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-03 20:06:43 +00:00
|
|
|
|
static void GetDosLocalTime(int64_t utcunixts, uint16_t *out_time,
|
|
|
|
|
uint16_t *out_date) {
|
|
|
|
|
struct tm tm;
|
|
|
|
|
CHECK_NOTNULL(localtime_r(&utcunixts, &tm));
|
|
|
|
|
*out_time = DOS_TIME(tm.tm_hour, tm.tm_min, tm.tm_sec);
|
|
|
|
|
*out_date = DOS_DATE(tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday + 1);
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-02 03:49:13 +00:00
|
|
|
|
static void StoreAsset(const char *path, size_t pathlen, const char *data,
|
|
|
|
|
size_t datalen, int mode) {
|
2021-05-03 20:06:43 +00:00
|
|
|
|
int64_t ft;
|
|
|
|
|
uint32_t crc;
|
2021-05-14 12:36:58 +00:00
|
|
|
|
char *comp, *p;
|
2022-08-06 02:24:05 +00:00
|
|
|
|
struct timespec now;
|
2021-05-14 12:36:58 +00:00
|
|
|
|
struct Asset *a;
|
|
|
|
|
struct iovec v[13];
|
2023-09-02 03:49:13 +00:00
|
|
|
|
uint8_t era;
|
2022-03-15 00:19:31 +00:00
|
|
|
|
const char *use;
|
2021-05-03 20:06:43 +00:00
|
|
|
|
uint16_t gflags, iattrs, mtime, mdate, dosmode, method, disk;
|
2022-03-15 00:19:31 +00:00
|
|
|
|
size_t oldcdirsize, oldcdiroffset, records, cdiroffset, cdirsize, complen,
|
|
|
|
|
uselen;
|
2021-05-03 20:06:43 +00:00
|
|
|
|
if (IsOpenbsd() || IsNetbsd() || IsWindows()) {
|
2022-06-27 04:25:02 +00:00
|
|
|
|
FATALF("(cfg) StoreAsset() not available on Windows/NetBSD/OpenBSD yet");
|
2021-05-14 12:36:58 +00:00
|
|
|
|
}
|
2022-06-27 04:16:13 +00:00
|
|
|
|
INFOF("(srvr) storing asset %`'s", path);
|
2021-05-14 12:36:58 +00:00
|
|
|
|
disk = gflags = iattrs = 0;
|
2023-08-21 09:28:24 +00:00
|
|
|
|
if (isutf8(path, pathlen))
|
|
|
|
|
gflags |= kZipGflagUtf8;
|
|
|
|
|
if (istext(data, datalen))
|
|
|
|
|
iattrs |= kZipIattrText;
|
2021-05-03 20:06:43 +00:00
|
|
|
|
crc = crc32_z(0, data, datalen);
|
|
|
|
|
if (datalen < 100) {
|
|
|
|
|
method = kZipCompressionNone;
|
2021-05-14 12:36:58 +00:00
|
|
|
|
comp = 0;
|
2021-05-03 20:06:43 +00:00
|
|
|
|
use = data;
|
|
|
|
|
uselen = datalen;
|
2021-05-14 12:36:58 +00:00
|
|
|
|
era = kZipEra1989;
|
2021-05-03 20:06:43 +00:00
|
|
|
|
} else {
|
|
|
|
|
comp = Deflate(data, datalen, &complen);
|
|
|
|
|
if (complen < datalen) {
|
|
|
|
|
method = kZipCompressionDeflate;
|
|
|
|
|
use = comp;
|
|
|
|
|
uselen = complen;
|
2021-05-14 12:36:58 +00:00
|
|
|
|
era = kZipEra1993;
|
2021-05-03 20:06:43 +00:00
|
|
|
|
} else {
|
|
|
|
|
method = kZipCompressionNone;
|
|
|
|
|
use = data;
|
|
|
|
|
uselen = datalen;
|
2021-05-14 12:36:58 +00:00
|
|
|
|
era = kZipEra1989;
|
2021-05-03 20:06:43 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2021-05-14 12:36:58 +00:00
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
2022-06-27 04:16:13 +00:00
|
|
|
|
if (-1 == fcntl(zfd, F_SETLKW, &(struct flock){F_WRLCK})) {
|
2022-07-09 19:16:44 +00:00
|
|
|
|
WARNF("(srvr) can't place write lock on file descriptor %d: %s", zfd,
|
2022-06-27 20:01:58 +00:00
|
|
|
|
strerror(errno));
|
2022-06-27 04:16:13 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
2021-05-14 12:36:58 +00:00
|
|
|
|
OpenZip(false);
|
2022-11-06 02:49:41 +00:00
|
|
|
|
now = timespec_real();
|
2022-03-15 00:19:31 +00:00
|
|
|
|
a = GetAssetZip(path, pathlen);
|
|
|
|
|
if (!mode)
|
|
|
|
|
mode = a ? GetMode(a) : 0644;
|
2021-05-14 12:36:58 +00:00
|
|
|
|
if (!(mode & S_IFMT))
|
|
|
|
|
mode |= S_IFREG;
|
|
|
|
|
if (pathlen > 1 && path[0] == '/')
|
|
|
|
|
++path, --pathlen;
|
2021-05-03 20:06:43 +00:00
|
|
|
|
dosmode = !(mode & 0200) ? kNtFileAttributeReadonly : 0;
|
2022-08-06 02:24:05 +00:00
|
|
|
|
ft = (now.tv_sec + MODERNITYSECONDS) * HECTONANOSECONDS;
|
|
|
|
|
GetDosLocalTime(now.tv_sec, &mtime, &mdate);
|
2021-05-14 12:36:58 +00:00
|
|
|
|
// local file header
|
|
|
|
|
if (uselen >= 0xffffffff || datalen >= 0xffffffff) {
|
|
|
|
|
era = kZipEra2001;
|
|
|
|
|
v[2].iov_base = p = alloca((v[2].iov_len = 2 + 2 + 8 + 8));
|
|
|
|
|
p = WRITE16LE(p, kZipExtraZip64);
|
|
|
|
|
p = WRITE16LE(p, 8 + 8);
|
|
|
|
|
p = WRITE64LE(p, uselen);
|
|
|
|
|
p = WRITE64LE(p, datalen);
|
|
|
|
|
} else {
|
|
|
|
|
v[2].iov_len = 0;
|
|
|
|
|
v[2].iov_base = 0;
|
|
|
|
|
}
|
|
|
|
|
v[0].iov_base = p = alloca((v[0].iov_len = kZipLfileHdrMinSize));
|
2021-05-03 20:06:43 +00:00
|
|
|
|
p = WRITE32LE(p, kZipLfileHdrMagic);
|
|
|
|
|
*p++ = era;
|
|
|
|
|
*p++ = kZipOsDos;
|
|
|
|
|
p = WRITE16LE(p, gflags);
|
|
|
|
|
p = WRITE16LE(p, method);
|
|
|
|
|
p = WRITE16LE(p, mtime);
|
|
|
|
|
p = WRITE16LE(p, mdate);
|
|
|
|
|
p = WRITE32LE(p, crc);
|
2023-11-18 22:35:57 +00:00
|
|
|
|
p = WRITE32LE(p, 0xffffffffu);
|
|
|
|
|
p = WRITE32LE(p, 0xffffffffu);
|
2021-05-03 20:06:43 +00:00
|
|
|
|
p = WRITE16LE(p, pathlen);
|
2021-05-14 12:36:58 +00:00
|
|
|
|
p = WRITE16LE(p, v[2].iov_len);
|
|
|
|
|
v[1].iov_len = pathlen;
|
2023-09-02 03:49:13 +00:00
|
|
|
|
v[1].iov_base = (void *)path;
|
2021-05-14 12:36:58 +00:00
|
|
|
|
// file data
|
2021-08-25 12:43:26 +00:00
|
|
|
|
v[3].iov_len = uselen;
|
2023-09-02 03:49:13 +00:00
|
|
|
|
v[3].iov_base = (void *)use;
|
2021-05-14 12:36:58 +00:00
|
|
|
|
// old central directory entries
|
|
|
|
|
oldcdirsize = GetZipCdirSize(zcdir);
|
|
|
|
|
oldcdiroffset = GetZipCdirOffset(zcdir);
|
|
|
|
|
if (a) {
|
2022-03-05 02:47:15 +00:00
|
|
|
|
// to remove an existing asset,
|
|
|
|
|
// first copy the central directory part before its record
|
2023-06-17 11:20:16 +00:00
|
|
|
|
v[4].iov_base = zmap + oldcdiroffset;
|
2021-05-14 12:36:58 +00:00
|
|
|
|
v[4].iov_len = a->cf - oldcdiroffset;
|
2022-03-05 02:47:15 +00:00
|
|
|
|
// and then the rest of the central directory
|
2023-06-17 11:20:16 +00:00
|
|
|
|
v[5].iov_base =
|
|
|
|
|
zmap + oldcdiroffset + (v[4].iov_len + ZIP_CFILE_HDRSIZE(zmap + a->cf));
|
2022-03-18 09:33:37 +00:00
|
|
|
|
v[5].iov_len =
|
2023-06-17 11:20:16 +00:00
|
|
|
|
oldcdirsize - (v[4].iov_len + ZIP_CFILE_HDRSIZE(zmap + a->cf));
|
2021-05-14 12:36:58 +00:00
|
|
|
|
} else {
|
2023-06-17 11:20:16 +00:00
|
|
|
|
v[4].iov_base = zmap + oldcdiroffset;
|
2021-05-14 12:36:58 +00:00
|
|
|
|
v[4].iov_len = oldcdirsize;
|
|
|
|
|
v[5].iov_base = 0;
|
|
|
|
|
v[5].iov_len = 0;
|
|
|
|
|
}
|
|
|
|
|
// new central directory entry
|
|
|
|
|
if (uselen >= 0xffffffff || datalen >= 0xffffffff || zsize >= 0xffffffff) {
|
|
|
|
|
v[8].iov_base = p = alloca((v[8].iov_len = 2 + 2 + 8 + 8 + 8));
|
|
|
|
|
p = WRITE16LE(p, kZipExtraZip64);
|
|
|
|
|
p = WRITE16LE(p, 8 + 8 + 8);
|
|
|
|
|
p = WRITE64LE(p, uselen);
|
|
|
|
|
p = WRITE64LE(p, datalen);
|
|
|
|
|
p = WRITE64LE(p, zsize);
|
|
|
|
|
} else {
|
|
|
|
|
v[8].iov_len = 0;
|
|
|
|
|
v[8].iov_base = 0;
|
|
|
|
|
}
|
|
|
|
|
v[9].iov_base = p = alloca((v[9].iov_len = 2 + 2 + 4 + 2 + 2 + 8 + 8 + 8));
|
|
|
|
|
p = WRITE16LE(p, kZipExtraNtfs);
|
|
|
|
|
p = WRITE16LE(p, 4 + 2 + 2 + 8 + 8 + 8);
|
|
|
|
|
p = WRITE32LE(p, 0);
|
|
|
|
|
p = WRITE16LE(p, 1);
|
|
|
|
|
p = WRITE16LE(p, 8 + 8 + 8);
|
|
|
|
|
p = WRITE64LE(p, ft);
|
|
|
|
|
p = WRITE64LE(p, ft);
|
|
|
|
|
p = WRITE64LE(p, ft);
|
|
|
|
|
v[6].iov_base = p = alloca((v[6].iov_len = kZipCfileHdrMinSize));
|
2021-05-03 20:06:43 +00:00
|
|
|
|
p = WRITE32LE(p, kZipCfileHdrMagic);
|
|
|
|
|
*p++ = kZipCosmopolitanVersion;
|
|
|
|
|
*p++ = kZipOsUnix;
|
|
|
|
|
*p++ = era;
|
|
|
|
|
*p++ = kZipOsDos;
|
|
|
|
|
p = WRITE16LE(p, gflags);
|
|
|
|
|
p = WRITE16LE(p, method);
|
|
|
|
|
p = WRITE16LE(p, mtime);
|
|
|
|
|
p = WRITE16LE(p, mdate);
|
|
|
|
|
p = WRITE32LE(p, crc);
|
2023-11-18 22:35:57 +00:00
|
|
|
|
p = WRITE32LE(p, 0xffffffffu);
|
|
|
|
|
p = WRITE32LE(p, 0xffffffffu);
|
2021-05-03 20:06:43 +00:00
|
|
|
|
p = WRITE16LE(p, pathlen);
|
2021-05-14 12:36:58 +00:00
|
|
|
|
p = WRITE16LE(p, v[8].iov_len + v[9].iov_len);
|
2021-05-03 20:06:43 +00:00
|
|
|
|
p = WRITE16LE(p, 0);
|
|
|
|
|
p = WRITE16LE(p, disk);
|
|
|
|
|
p = WRITE16LE(p, iattrs);
|
|
|
|
|
p = WRITE16LE(p, dosmode);
|
|
|
|
|
p = WRITE16LE(p, mode);
|
2023-11-18 22:35:57 +00:00
|
|
|
|
p = WRITE32LE(p, 0xffffffffu);
|
2021-05-14 12:36:58 +00:00
|
|
|
|
v[7].iov_len = pathlen;
|
2023-09-02 03:49:13 +00:00
|
|
|
|
v[7].iov_base = (void *)path;
|
2021-05-14 12:36:58 +00:00
|
|
|
|
// zip64 end of central directory
|
|
|
|
|
cdiroffset =
|
|
|
|
|
zsize + v[0].iov_len + v[1].iov_len + v[2].iov_len + v[3].iov_len;
|
|
|
|
|
cdirsize = v[4].iov_len + v[5].iov_len + v[6].iov_len + v[7].iov_len +
|
|
|
|
|
v[8].iov_len + v[9].iov_len;
|
|
|
|
|
records = GetZipCdirRecords(zcdir) + !a;
|
|
|
|
|
if (records >= 0xffff || cdiroffset >= 0xffffffff || cdirsize >= 0xffffffff) {
|
|
|
|
|
v[10].iov_base = p =
|
|
|
|
|
alloca((v[10].iov_len = kZipCdir64HdrMinSize + kZipCdir64LocatorSize));
|
|
|
|
|
p = WRITE32LE(p, kZipCdir64HdrMagic);
|
|
|
|
|
p = WRITE64LE(p, 2 + 2 + 4 + 4 + 8 + 8 + 8 + 8);
|
|
|
|
|
p = WRITE16LE(p, kZipCosmopolitanVersion);
|
|
|
|
|
p = WRITE16LE(p, kZipEra2001);
|
|
|
|
|
p = WRITE32LE(p, disk);
|
|
|
|
|
p = WRITE32LE(p, disk);
|
|
|
|
|
p = WRITE64LE(p, records);
|
|
|
|
|
p = WRITE64LE(p, records);
|
|
|
|
|
p = WRITE64LE(p, cdirsize);
|
|
|
|
|
p = WRITE64LE(p, cdiroffset);
|
|
|
|
|
p = WRITE32LE(p, kZipCdir64LocatorMagic);
|
|
|
|
|
p = WRITE32LE(p, disk);
|
|
|
|
|
p = WRITE64LE(p, cdiroffset + cdirsize);
|
|
|
|
|
p = WRITE32LE(p, disk);
|
|
|
|
|
} else {
|
|
|
|
|
v[10].iov_len = 0;
|
|
|
|
|
v[10].iov_base = 0;
|
|
|
|
|
}
|
|
|
|
|
// end of central directory
|
2023-09-02 03:49:13 +00:00
|
|
|
|
v[12].iov_base = (void *)GetZipCdirComment(zcdir);
|
2021-05-14 12:36:58 +00:00
|
|
|
|
v[12].iov_len = GetZipCdirCommentSize(zcdir);
|
|
|
|
|
v[11].iov_base = p = alloca((v[11].iov_len = kZipCdirHdrMinSize));
|
2021-05-03 20:06:43 +00:00
|
|
|
|
p = WRITE32LE(p, kZipCdirHdrMagic);
|
2021-05-14 12:36:58 +00:00
|
|
|
|
p = WRITE16LE(p, disk);
|
|
|
|
|
p = WRITE16LE(p, disk);
|
|
|
|
|
p = WRITE16LE(p, MIN(records, 0xffff));
|
|
|
|
|
p = WRITE16LE(p, MIN(records, 0xffff));
|
|
|
|
|
p = WRITE32LE(p, MIN(cdirsize, 0xffffffff));
|
|
|
|
|
p = WRITE32LE(p, MIN(cdiroffset, 0xffffffff));
|
|
|
|
|
p = WRITE16LE(p, v[12].iov_len);
|
2023-06-17 11:20:16 +00:00
|
|
|
|
CHECK_NE(-1, lseek(zfd, zmap + zsize - zmap, SEEK_SET));
|
2021-05-14 12:36:58 +00:00
|
|
|
|
CHECK_NE(-1, WritevAll(zfd, v, 13));
|
|
|
|
|
CHECK_NE(-1, fcntl(zfd, F_SETLK, &(struct flock){F_UNLCK}));
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
OpenZip(false);
|
2021-05-03 20:06:43 +00:00
|
|
|
|
free(comp);
|
2022-03-15 00:19:31 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-09-02 03:49:13 +00:00
|
|
|
|
static void StoreFile(const char *path) {
|
2022-03-15 00:19:31 +00:00
|
|
|
|
char *p;
|
|
|
|
|
struct stat st;
|
2023-09-02 03:49:13 +00:00
|
|
|
|
size_t plen, tlen;
|
|
|
|
|
const char *target = path;
|
2023-08-14 03:31:27 +00:00
|
|
|
|
if (startswith(target, "./"))
|
|
|
|
|
target += 2;
|
2022-03-21 10:20:09 +00:00
|
|
|
|
tlen = strlen(target);
|
|
|
|
|
if (!IsReasonablePath(target, tlen))
|
2022-06-27 04:25:02 +00:00
|
|
|
|
FATALF("(cfg) error: can't store %`'s: contains '.' or '..' segments",
|
2022-06-27 20:01:58 +00:00
|
|
|
|
target);
|
2022-06-27 04:25:02 +00:00
|
|
|
|
if (lstat(path, &st) == -1)
|
|
|
|
|
FATALF("(cfg) error: can't stat %`'s: %m", path);
|
2022-03-21 14:34:19 +00:00
|
|
|
|
if (!(p = xslurp(path, &plen)))
|
2022-06-27 04:25:02 +00:00
|
|
|
|
FATALF("(cfg) error: can't read %`'s: %m", path);
|
2022-03-21 10:20:09 +00:00
|
|
|
|
StoreAsset(target, tlen, p, plen, st.st_mode & 0777);
|
|
|
|
|
free(p);
|
2022-03-15 00:19:31 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void StorePath(const char *dirpath) {
|
|
|
|
|
DIR *d;
|
|
|
|
|
char *path;
|
|
|
|
|
struct dirent *e;
|
2023-09-02 03:49:13 +00:00
|
|
|
|
if (!isdirectory(dirpath) && !endswith(dirpath, "/")) {
|
2022-03-21 10:20:09 +00:00
|
|
|
|
return StoreFile(dirpath);
|
2023-09-02 03:49:13 +00:00
|
|
|
|
}
|
2022-06-27 04:25:02 +00:00
|
|
|
|
if (!(d = opendir(dirpath)))
|
|
|
|
|
FATALF("(cfg) error: can't open %`'s", dirpath);
|
2022-03-15 00:19:31 +00:00
|
|
|
|
while ((e = readdir(d))) {
|
|
|
|
|
if (strcmp(e->d_name, ".") == 0)
|
|
|
|
|
continue;
|
|
|
|
|
if (strcmp(e->d_name, "..") == 0)
|
|
|
|
|
continue;
|
2024-01-08 18:07:35 +00:00
|
|
|
|
path = gc(xjoinpaths(dirpath, e->d_name));
|
2022-03-15 00:19:31 +00:00
|
|
|
|
if (e->d_type == DT_DIR) {
|
|
|
|
|
StorePath(path);
|
|
|
|
|
} else {
|
|
|
|
|
StoreFile(path);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
closedir(d);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int LuaStoreAsset(lua_State *L) {
|
|
|
|
|
const char *path, *data;
|
|
|
|
|
size_t pathlen, datalen;
|
|
|
|
|
int mode;
|
|
|
|
|
path = LuaCheckPath(L, 1, &pathlen);
|
|
|
|
|
if (pathlen > 0xffff) {
|
|
|
|
|
return luaL_argerror(L, 1, "path too long");
|
|
|
|
|
}
|
|
|
|
|
data = luaL_checklstring(L, 2, &datalen);
|
|
|
|
|
mode = luaL_optinteger(L, 3, 0);
|
|
|
|
|
StoreAsset(path, pathlen, data, datalen, mode);
|
2021-05-03 20:06:43 +00:00
|
|
|
|
return 0;
|
2021-05-03 19:09:35 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-07-08 04:44:27 +00:00
|
|
|
|
static void ReseedRng(mbedtls_ctr_drbg_context *r, const char *s) {
|
|
|
|
|
#ifndef UNSECURE
|
2022-05-18 23:41:29 +00:00
|
|
|
|
if (unsecure)
|
|
|
|
|
return;
|
2021-07-08 04:44:27 +00:00
|
|
|
|
CHECK_EQ(0, mbedtls_ctr_drbg_reseed(r, (void *)s, strlen(s)));
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void LogMessage(const char *d, const char *s, size_t n) {
|
|
|
|
|
size_t n2, n3;
|
|
|
|
|
char *s2, *s3;
|
2021-07-08 22:56:23 +00:00
|
|
|
|
if (!LOGGABLE(kLogInfo))
|
|
|
|
|
return;
|
2021-07-08 04:44:27 +00:00
|
|
|
|
while (n && (s[n - 1] == '\r' || s[n - 1] == '\n'))
|
|
|
|
|
--n;
|
|
|
|
|
if ((s2 = DecodeLatin1(s, n, &n2))) {
|
|
|
|
|
if ((s3 = IndentLines(s2, n2, &n3, 1))) {
|
2022-04-18 15:54:42 +00:00
|
|
|
|
INFOF("(stat) %s %,ld byte message\r\n%.*s", d, n, n3, s3);
|
2021-07-08 04:44:27 +00:00
|
|
|
|
free(s3);
|
|
|
|
|
}
|
|
|
|
|
free(s2);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void LogBody(const char *d, const char *s, size_t n) {
|
|
|
|
|
char *s2, *s3;
|
|
|
|
|
size_t n2, n3;
|
|
|
|
|
if (!n)
|
|
|
|
|
return;
|
2021-07-08 22:56:23 +00:00
|
|
|
|
if (!LOGGABLE(kLogInfo))
|
|
|
|
|
return;
|
2021-07-08 04:44:27 +00:00
|
|
|
|
while (n && (s[n - 1] == '\r' || s[n - 1] == '\n'))
|
|
|
|
|
--n;
|
|
|
|
|
if ((s2 = VisualizeControlCodes(s, n, &n2))) {
|
|
|
|
|
if ((s3 = IndentLines(s2, n2, &n3, 1))) {
|
2022-04-18 15:54:42 +00:00
|
|
|
|
INFOF("(stat) %s %,ld byte payload\r\n%.*s", d, n, n3, s3);
|
2021-07-08 04:44:27 +00:00
|
|
|
|
free(s3);
|
|
|
|
|
}
|
|
|
|
|
free(s2);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-08 14:13:51 +00:00
|
|
|
|
static int LuaNilError(lua_State *L, const char *fmt, ...) {
|
|
|
|
|
va_list argp;
|
|
|
|
|
va_start(argp, fmt);
|
|
|
|
|
lua_pushnil(L);
|
|
|
|
|
lua_pushvfstring(L, fmt, argp);
|
|
|
|
|
va_end(argp);
|
|
|
|
|
return 2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int LuaNilTlsError(lua_State *L, const char *s, int r) {
|
|
|
|
|
return LuaNilError(L, "tls %s failed (%s %s)", s,
|
|
|
|
|
IsTiny() ? "grep" : GetTlsError(r),
|
2024-01-08 18:07:35 +00:00
|
|
|
|
gc(xasprintf("-0x%04x", -r)));
|
2022-07-08 14:13:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-08-22 01:06:28 +00:00
|
|
|
|
#include "tool/net/fetch.inc"
|
2021-07-08 04:44:27 +00:00
|
|
|
|
|
2021-04-25 00:09:01 +00:00
|
|
|
|
static int LuaGetDate(lua_State *L) {
|
2024-12-02 22:05:38 +00:00
|
|
|
|
unassert(!pthread_mutex_lock(&shared->datetime_mu));
|
2022-08-06 02:24:05 +00:00
|
|
|
|
lua_pushinteger(L, shared->nowish.tv_sec);
|
2024-12-02 22:05:38 +00:00
|
|
|
|
unassert(!pthread_mutex_unlock(&shared->datetime_mu));
|
2021-04-25 00:09:01 +00:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-02 21:46:43 +00:00
|
|
|
|
static int LuaGetHttpVersion(lua_State *L) {
|
2021-10-25 21:54:56 +00:00
|
|
|
|
OnlyCallDuringRequest(L, "GetHttpVersion");
|
2022-08-06 00:34:53 +00:00
|
|
|
|
lua_pushinteger(L, cpm.msg.version);
|
2021-04-25 00:09:01 +00:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-02 21:46:43 +00:00
|
|
|
|
static int LuaGetRedbeanVersion(lua_State *L) {
|
|
|
|
|
lua_pushinteger(L, VERSION);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-25 00:09:01 +00:00
|
|
|
|
static int LuaGetMethod(lua_State *L) {
|
2021-10-25 21:54:56 +00:00
|
|
|
|
OnlyCallDuringRequest(L, "GetMethod");
|
2024-02-22 22:12:18 +00:00
|
|
|
|
char method[9] = {0};
|
|
|
|
|
WRITE64LE(method, cpm.msg.method);
|
|
|
|
|
lua_pushstring(L, method);
|
2021-04-25 00:09:01 +00:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-17 08:37:33 +00:00
|
|
|
|
static int LuaGetAddr(lua_State *L, int GetAddr(uint32_t *, uint16_t *)) {
|
2021-04-25 00:09:01 +00:00
|
|
|
|
uint32_t ip;
|
|
|
|
|
uint16_t port;
|
2022-09-17 08:37:33 +00:00
|
|
|
|
if (!GetAddr(&ip, &port)) {
|
|
|
|
|
lua_pushinteger(L, ip);
|
|
|
|
|
lua_pushinteger(L, port);
|
|
|
|
|
return 2;
|
|
|
|
|
} else {
|
|
|
|
|
lua_pushnil(L);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2021-04-25 00:09:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int LuaGetServerAddr(lua_State *L) {
|
2021-10-25 21:54:56 +00:00
|
|
|
|
OnlyCallDuringConnection(L, "GetServerAddr");
|
2021-04-25 00:09:01 +00:00
|
|
|
|
return LuaGetAddr(L, GetServerAddr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int LuaGetClientAddr(lua_State *L) {
|
2021-10-25 21:54:56 +00:00
|
|
|
|
OnlyCallDuringConnection(L, "GetClientAddr");
|
2021-04-25 00:09:01 +00:00
|
|
|
|
return LuaGetAddr(L, GetClientAddr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int LuaGetRemoteAddr(lua_State *L) {
|
2021-10-25 21:54:56 +00:00
|
|
|
|
OnlyCallDuringRequest(L, "GetRemoteAddr");
|
2021-04-25 00:09:01 +00:00
|
|
|
|
return LuaGetAddr(L, GetRemoteAddr);
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-24 16:59:22 +00:00
|
|
|
|
static int LuaLog(lua_State *L) {
|
|
|
|
|
int level, line;
|
|
|
|
|
lua_Debug ar;
|
|
|
|
|
const char *msg, *module;
|
|
|
|
|
level = luaL_checkinteger(L, 1);
|
|
|
|
|
if (LOGGABLE(level)) {
|
|
|
|
|
msg = luaL_checkstring(L, 2);
|
|
|
|
|
if (lua_getstack(L, 1, &ar) && lua_getinfo(L, "Sl", &ar)) {
|
|
|
|
|
module = ar.short_src;
|
|
|
|
|
line = ar.currentline;
|
|
|
|
|
} else {
|
2024-01-08 18:07:35 +00:00
|
|
|
|
module = gc(strndup(effectivepath.p, effectivepath.n));
|
2022-04-24 16:59:22 +00:00
|
|
|
|
line = -1;
|
|
|
|
|
}
|
|
|
|
|
flogf(level, module, line, NULL, "%s", msg);
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
2021-04-25 00:09:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-07-22 17:10:33 +00:00
|
|
|
|
static int LuaEncodeSmth(lua_State *L, int Encoder(lua_State *, char **, int,
|
|
|
|
|
struct EncoderConfig)) {
|
2022-04-24 16:59:22 +00:00
|
|
|
|
char *p = 0;
|
2022-07-13 06:31:06 +00:00
|
|
|
|
int useoutput = false;
|
2022-07-22 17:10:33 +00:00
|
|
|
|
struct EncoderConfig conf = {
|
|
|
|
|
.maxdepth = 64,
|
|
|
|
|
.sorted = true,
|
|
|
|
|
.pretty = false,
|
|
|
|
|
.indent = " ",
|
|
|
|
|
};
|
2022-04-24 16:59:22 +00:00
|
|
|
|
if (lua_istable(L, 2)) {
|
|
|
|
|
lua_settop(L, 2); // discard any extra arguments
|
|
|
|
|
lua_getfield(L, 2, "useoutput");
|
|
|
|
|
// ignore useoutput outside of request handling
|
2022-04-27 12:39:39 +00:00
|
|
|
|
if (ishandlingrequest && lua_isboolean(L, -1)) {
|
2022-04-24 16:59:22 +00:00
|
|
|
|
useoutput = lua_toboolean(L, -1);
|
2022-04-27 12:39:39 +00:00
|
|
|
|
}
|
2022-07-22 17:10:33 +00:00
|
|
|
|
lua_getfield(L, 2, "maxdepth");
|
|
|
|
|
if (!lua_isnoneornil(L, -1)) {
|
|
|
|
|
lua_Integer n = lua_tointeger(L, -1);
|
|
|
|
|
n = MAX(0, MIN(n, SHRT_MAX));
|
|
|
|
|
conf.maxdepth = n;
|
|
|
|
|
}
|
2022-07-13 06:31:06 +00:00
|
|
|
|
lua_getfield(L, 2, "sorted");
|
2022-07-22 17:10:33 +00:00
|
|
|
|
if (!lua_isnoneornil(L, -1)) {
|
|
|
|
|
conf.sorted = lua_toboolean(L, -1);
|
|
|
|
|
}
|
|
|
|
|
lua_getfield(L, 2, "pretty");
|
|
|
|
|
if (!lua_isnoneornil(L, -1)) {
|
|
|
|
|
conf.pretty = lua_toboolean(L, -1);
|
|
|
|
|
lua_getfield(L, 2, "indent");
|
|
|
|
|
if (!lua_isnoneornil(L, -1)) {
|
|
|
|
|
conf.indent = luaL_checkstring(L, -1);
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-04-24 16:59:22 +00:00
|
|
|
|
}
|
|
|
|
|
lua_settop(L, 1); // keep the passed argument on top
|
2022-08-06 00:34:53 +00:00
|
|
|
|
if (Encoder(L, useoutput ? &cpm.outbuf : &p, -1, conf) == -1) {
|
2022-07-09 11:09:51 +00:00
|
|
|
|
free(p);
|
|
|
|
|
return 2;
|
|
|
|
|
}
|
|
|
|
|
if (useoutput) {
|
|
|
|
|
lua_pushboolean(L, true);
|
2022-04-24 16:59:22 +00:00
|
|
|
|
} else {
|
|
|
|
|
lua_pushstring(L, p);
|
|
|
|
|
free(p);
|
|
|
|
|
}
|
2021-11-12 23:00:41 +00:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-24 16:59:22 +00:00
|
|
|
|
static int LuaEncodeJson(lua_State *L) {
|
|
|
|
|
return LuaEncodeSmth(L, LuaEncodeJsonData);
|
2022-04-13 15:49:17 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-04-24 16:59:22 +00:00
|
|
|
|
static int LuaEncodeLua(lua_State *L) {
|
|
|
|
|
return LuaEncodeSmth(L, LuaEncodeLuaData);
|
2021-04-25 00:09:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-07-10 00:34:41 +00:00
|
|
|
|
static int LuaDecodeJson(lua_State *L) {
|
2022-07-09 18:44:19 +00:00
|
|
|
|
size_t n;
|
|
|
|
|
const char *p;
|
2022-07-12 06:06:49 +00:00
|
|
|
|
struct DecodeJson r;
|
2022-07-09 18:44:19 +00:00
|
|
|
|
p = luaL_checklstring(L, 1, &n);
|
2022-07-12 06:06:49 +00:00
|
|
|
|
r = DecodeJson(L, p, n);
|
|
|
|
|
if (UNLIKELY(!r.rc)) {
|
|
|
|
|
lua_pushnil(L);
|
|
|
|
|
lua_pushstring(L, "unexpected eof");
|
|
|
|
|
return 2;
|
|
|
|
|
}
|
|
|
|
|
if (UNLIKELY(r.rc == -1)) {
|
|
|
|
|
lua_pushnil(L);
|
|
|
|
|
lua_pushstring(L, r.p);
|
|
|
|
|
return 2;
|
|
|
|
|
}
|
|
|
|
|
r = DecodeJson(L, r.p, n - (r.p - p));
|
|
|
|
|
if (UNLIKELY(r.rc)) {
|
|
|
|
|
lua_pushnil(L);
|
|
|
|
|
lua_pushstring(L, "junk after expression");
|
|
|
|
|
return 2;
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
2022-07-09 18:44:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-04-25 00:09:01 +00:00
|
|
|
|
static int LuaGetUrl(lua_State *L) {
|
|
|
|
|
char *p;
|
|
|
|
|
size_t n;
|
2021-10-25 21:54:56 +00:00
|
|
|
|
OnlyCallDuringRequest(L, "GetUrl");
|
2021-04-25 00:09:01 +00:00
|
|
|
|
p = EncodeUrl(&url, &n);
|
|
|
|
|
lua_pushlstring(L, p, n);
|
|
|
|
|
free(p);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int LuaGetScheme(lua_State *L) {
|
2021-10-25 21:54:56 +00:00
|
|
|
|
OnlyCallDuringRequest(L, "GetScheme");
|
2021-04-25 00:09:01 +00:00
|
|
|
|
LuaPushUrlView(L, &url.scheme);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int LuaGetPath(lua_State *L) {
|
2021-10-25 21:54:56 +00:00
|
|
|
|
OnlyCallDuringRequest(L, "GetPath");
|
2021-04-25 00:09:01 +00:00
|
|
|
|
LuaPushUrlView(L, &url.path);
|
|
|
|
|
return 1;
|
2021-04-21 02:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-04-23 17:45:19 +00:00
|
|
|
|
static int LuaGetEffectivePath(lua_State *L) {
|
2021-10-25 21:54:56 +00:00
|
|
|
|
OnlyCallDuringRequest(L, "GetEffectivePath");
|
2021-04-23 17:45:19 +00:00
|
|
|
|
lua_pushlstring(L, effectivepath.p, effectivepath.n);
|
2021-04-21 02:14:21 +00:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-23 17:45:19 +00:00
|
|
|
|
static int LuaGetFragment(lua_State *L) {
|
2021-10-25 21:54:56 +00:00
|
|
|
|
OnlyCallDuringRequest(L, "GetFragment");
|
2021-04-23 17:45:19 +00:00
|
|
|
|
LuaPushUrlView(L, &url.fragment);
|
2021-04-21 02:14:21 +00:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-23 17:45:19 +00:00
|
|
|
|
static int LuaGetUser(lua_State *L) {
|
|
|
|
|
size_t n;
|
|
|
|
|
const char *p, *q;
|
2021-10-25 21:54:56 +00:00
|
|
|
|
OnlyCallDuringRequest(L, "GetUser");
|
2021-04-23 17:45:19 +00:00
|
|
|
|
if (url.user.p) {
|
|
|
|
|
LuaPushUrlView(L, &url.user);
|
2023-09-02 03:49:13 +00:00
|
|
|
|
} else if ((p = gc(GetBasicAuthorization(&n)))) {
|
2021-04-23 17:45:19 +00:00
|
|
|
|
if (!(q = memchr(p, ':', n)))
|
|
|
|
|
q = p + n;
|
|
|
|
|
lua_pushlstring(L, p, q - p);
|
|
|
|
|
} else {
|
|
|
|
|
lua_pushnil(L);
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int LuaGetPass(lua_State *L) {
|
|
|
|
|
size_t n;
|
|
|
|
|
const char *p, *q;
|
2021-10-25 21:54:56 +00:00
|
|
|
|
OnlyCallDuringRequest(L, "GetPass");
|
2021-04-23 17:45:19 +00:00
|
|
|
|
if (url.user.p) {
|
|
|
|
|
LuaPushUrlView(L, &url.pass);
|
2023-09-02 03:49:13 +00:00
|
|
|
|
} else if ((p = gc(GetBasicAuthorization(&n)))) {
|
2021-04-23 17:45:19 +00:00
|
|
|
|
if ((q = memchr(p, ':', n))) {
|
|
|
|
|
lua_pushlstring(L, q + 1, p + n - (q + 1));
|
|
|
|
|
} else {
|
|
|
|
|
lua_pushnil(L);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
lua_pushnil(L);
|
|
|
|
|
}
|
2021-04-21 02:14:21 +00:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int LuaGetHost(lua_State *L) {
|
2021-04-23 17:45:19 +00:00
|
|
|
|
char b[16];
|
2021-10-25 21:54:56 +00:00
|
|
|
|
OnlyCallDuringRequest(L, "GetHost");
|
2021-04-21 02:14:21 +00:00
|
|
|
|
if (url.host.n) {
|
|
|
|
|
lua_pushlstring(L, url.host.p, url.host.n);
|
|
|
|
|
} else {
|
2021-06-24 19:31:26 +00:00
|
|
|
|
inet_ntop(AF_INET, &serveraddr->sin_addr.s_addr, b, sizeof(b));
|
2021-04-23 17:45:19 +00:00
|
|
|
|
lua_pushstring(L, b);
|
2021-04-21 02:14:21 +00:00
|
|
|
|
}
|
2021-04-23 17:45:19 +00:00
|
|
|
|
return 1;
|
2021-04-21 02:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int LuaGetPort(lua_State *L) {
|
|
|
|
|
int i, x = 0;
|
2021-10-25 21:54:56 +00:00
|
|
|
|
OnlyCallDuringRequest(L, "GetPort");
|
2021-04-21 02:14:21 +00:00
|
|
|
|
for (i = 0; i < url.port.n; ++i)
|
|
|
|
|
x = url.port.p[i] - '0' + x * 10;
|
2021-06-24 19:31:26 +00:00
|
|
|
|
if (!x)
|
|
|
|
|
x = ntohs(serveraddr->sin_port);
|
2021-04-21 02:14:21 +00:00
|
|
|
|
lua_pushinteger(L, x);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-12 23:00:41 +00:00
|
|
|
|
static int LuaGetBody(lua_State *L) {
|
2022-04-24 16:59:22 +00:00
|
|
|
|
OnlyCallDuringRequest(L, "GetBody");
|
2021-07-05 08:03:45 +00:00
|
|
|
|
lua_pushlstring(L, inbuf.p + hdrsize, payloadlength);
|
2021-03-27 14:29:55 +00:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-22 18:22:39 +00:00
|
|
|
|
static int LuaGetResponseBody(lua_State *L) {
|
2022-08-22 05:26:41 +00:00
|
|
|
|
char *s = "";
|
|
|
|
|
// response can be gzipped (>0), text (=0), or generator (<0)
|
2022-09-04 13:57:59 +00:00
|
|
|
|
int size = cpm.gzipped > 0 ? cpm.gzipped // original size
|
|
|
|
|
: cpm.gzipped == 0 ? cpm.contentlength
|
|
|
|
|
: 0;
|
2022-07-22 18:22:39 +00:00
|
|
|
|
OnlyCallDuringRequest(L, "GetResponseBody");
|
2022-08-22 05:26:41 +00:00
|
|
|
|
if (cpm.gzipped > 0 &&
|
2022-09-04 13:57:59 +00:00
|
|
|
|
(!(s = FreeLater(malloc(cpm.gzipped))) ||
|
|
|
|
|
!Inflate(s, cpm.gzipped, cpm.content, cpm.contentlength))) {
|
2022-08-22 05:26:41 +00:00
|
|
|
|
return LuaNilError(L, "failed to decompress response");
|
|
|
|
|
}
|
2022-09-04 13:57:59 +00:00
|
|
|
|
lua_pushlstring(L,
|
|
|
|
|
cpm.gzipped > 0 ? s // return decompressed
|
|
|
|
|
: cpm.gzipped == 0 ? cpm.content
|
|
|
|
|
: "",
|
|
|
|
|
size);
|
2022-07-22 18:22:39 +00:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-25 09:21:13 +00:00
|
|
|
|
static int LuaGetHeader(lua_State *L) {
|
|
|
|
|
int h;
|
2021-03-28 07:10:17 +00:00
|
|
|
|
const char *key;
|
2021-07-08 04:44:27 +00:00
|
|
|
|
size_t i, keylen;
|
2021-10-25 21:54:56 +00:00
|
|
|
|
OnlyCallDuringRequest(L, "GetHeader");
|
2021-03-25 09:21:13 +00:00
|
|
|
|
key = luaL_checklstring(L, 1, &keylen);
|
|
|
|
|
if ((h = GetHttpHeader(key, keylen)) != -1) {
|
2022-08-06 00:34:53 +00:00
|
|
|
|
if (cpm.msg.headers[h].a) {
|
|
|
|
|
return LuaPushHeader(L, &cpm.msg, inbuf.p, h);
|
2021-03-27 14:29:55 +00:00
|
|
|
|
}
|
2021-04-18 18:34:59 +00:00
|
|
|
|
} else {
|
2022-08-06 00:34:53 +00:00
|
|
|
|
for (i = 0; i < cpm.msg.xheaders.n; ++i) {
|
|
|
|
|
if (SlicesEqualCase(
|
|
|
|
|
key, keylen, inbuf.p + cpm.msg.xheaders.p[i].k.a,
|
|
|
|
|
cpm.msg.xheaders.p[i].k.b - cpm.msg.xheaders.p[i].k.a)) {
|
|
|
|
|
LuaPushLatin1(L, inbuf.p + cpm.msg.xheaders.p[i].v.a,
|
|
|
|
|
cpm.msg.xheaders.p[i].v.b - cpm.msg.xheaders.p[i].v.a);
|
2021-04-18 18:34:59 +00:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-03-27 14:29:55 +00:00
|
|
|
|
}
|
2021-04-18 18:34:59 +00:00
|
|
|
|
lua_pushnil(L);
|
2021-03-27 14:29:55 +00:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int LuaGetHeaders(lua_State *L) {
|
2021-10-25 21:54:56 +00:00
|
|
|
|
OnlyCallDuringRequest(L, "GetHeaders");
|
2022-08-06 00:34:53 +00:00
|
|
|
|
return LuaPushHeaders(L, &cpm.msg, inbuf.p);
|
2021-03-25 09:21:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int LuaSetHeader(lua_State *L) {
|
2021-03-28 07:10:17 +00:00
|
|
|
|
int h;
|
2023-09-02 03:49:13 +00:00
|
|
|
|
char *eval;
|
2021-04-25 00:09:01 +00:00
|
|
|
|
char *p, *q;
|
2023-09-02 03:49:13 +00:00
|
|
|
|
const char *key, *val;
|
|
|
|
|
size_t keylen, vallen, evallen;
|
2021-10-25 21:54:56 +00:00
|
|
|
|
OnlyCallDuringRequest(L, "SetHeader");
|
2021-03-25 09:21:13 +00:00
|
|
|
|
key = luaL_checklstring(L, 1, &keylen);
|
2022-10-17 18:02:04 +00:00
|
|
|
|
val = luaL_optlstring(L, 2, 0, &vallen);
|
|
|
|
|
if (!val)
|
|
|
|
|
return 0;
|
2021-03-28 07:10:17 +00:00
|
|
|
|
if ((h = GetHttpHeader(key, keylen)) == -1) {
|
|
|
|
|
if (!IsValidHttpToken(key, keylen)) {
|
2021-04-23 17:45:19 +00:00
|
|
|
|
luaL_argerror(L, 1, "invalid");
|
2023-06-09 06:44:03 +00:00
|
|
|
|
__builtin_unreachable();
|
2021-03-28 07:10:17 +00:00
|
|
|
|
}
|
2021-03-25 09:21:13 +00:00
|
|
|
|
}
|
2021-03-28 07:10:17 +00:00
|
|
|
|
if (!(eval = EncodeHttpHeaderValue(val, vallen, &evallen))) {
|
2021-04-23 17:45:19 +00:00
|
|
|
|
luaL_argerror(L, 2, "invalid");
|
2023-06-09 06:44:03 +00:00
|
|
|
|
__builtin_unreachable();
|
2021-03-25 09:21:13 +00:00
|
|
|
|
}
|
2021-04-25 00:09:01 +00:00
|
|
|
|
p = GetLuaResponse();
|
|
|
|
|
while (p - hdrbuf.p + keylen + 2 + evallen + 2 + 512 > hdrbuf.n) {
|
|
|
|
|
hdrbuf.n += hdrbuf.n >> 1;
|
|
|
|
|
q = xrealloc(hdrbuf.p, hdrbuf.n);
|
2022-08-06 00:34:53 +00:00
|
|
|
|
cpm.luaheaderp = p = q + (p - hdrbuf.p);
|
2021-04-25 00:09:01 +00:00
|
|
|
|
hdrbuf.p = q;
|
2021-03-25 09:21:13 +00:00
|
|
|
|
}
|
2021-03-28 07:10:17 +00:00
|
|
|
|
switch (h) {
|
2021-03-25 09:21:13 +00:00
|
|
|
|
case kHttpConnection:
|
2022-10-17 18:02:04 +00:00
|
|
|
|
connectionclose = SlicesEqualCase(eval, evallen, "close", 5);
|
2021-03-25 09:21:13 +00:00
|
|
|
|
break;
|
|
|
|
|
case kHttpContentType:
|
2021-03-28 07:10:17 +00:00
|
|
|
|
p = AppendContentType(p, eval);
|
2021-03-25 09:21:13 +00:00
|
|
|
|
break;
|
2022-06-15 05:01:13 +00:00
|
|
|
|
case kHttpReferrerPolicy:
|
2022-08-06 00:34:53 +00:00
|
|
|
|
cpm.referrerpolicy = FreeLater(strdup(eval));
|
2022-06-15 05:01:13 +00:00
|
|
|
|
break;
|
2021-03-25 09:21:13 +00:00
|
|
|
|
case kHttpServer:
|
2022-08-06 00:34:53 +00:00
|
|
|
|
cpm.branded = true;
|
2021-03-28 07:10:17 +00:00
|
|
|
|
p = AppendHeader(p, "Server", eval);
|
2021-03-25 09:21:13 +00:00
|
|
|
|
break;
|
2022-06-15 05:01:13 +00:00
|
|
|
|
case kHttpExpires:
|
|
|
|
|
case kHttpCacheControl:
|
2022-08-06 00:34:53 +00:00
|
|
|
|
cpm.gotcachecontrol = true;
|
2022-06-15 05:01:13 +00:00
|
|
|
|
p = AppendHeader(p, key, eval);
|
|
|
|
|
break;
|
|
|
|
|
case kHttpXContentTypeOptions:
|
2022-08-06 00:34:53 +00:00
|
|
|
|
cpm.gotxcontenttypeoptions = true;
|
2022-06-15 05:01:13 +00:00
|
|
|
|
p = AppendHeader(p, key, eval);
|
2021-08-04 05:42:17 +00:00
|
|
|
|
break;
|
2021-03-25 09:21:13 +00:00
|
|
|
|
default:
|
2021-03-28 07:10:17 +00:00
|
|
|
|
p = AppendHeader(p, key, eval);
|
2021-03-25 09:21:13 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
2022-08-06 00:34:53 +00:00
|
|
|
|
cpm.luaheaderp = p;
|
2021-03-28 07:10:17 +00:00
|
|
|
|
free(eval);
|
2021-03-25 09:21:13 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-11 23:46:21 +00:00
|
|
|
|
static int LuaGetCookie(lua_State *L) {
|
|
|
|
|
char *cookie = 0, *cookietmpl, *cookieval;
|
2021-10-25 21:54:56 +00:00
|
|
|
|
OnlyCallDuringRequest(L, "GetCookie");
|
2024-01-08 18:07:35 +00:00
|
|
|
|
cookietmpl = gc(xasprintf(" %s=", luaL_checkstring(L, 1)));
|
2021-09-11 23:46:21 +00:00
|
|
|
|
if (HasHeader(kHttpCookie)) {
|
|
|
|
|
appends(&cookie, " "); // prepend space to simplify cookie search
|
|
|
|
|
appendd(&cookie, HeaderData(kHttpCookie), HeaderLength(kHttpCookie));
|
|
|
|
|
}
|
|
|
|
|
if (cookie && (cookieval = strstr(cookie, cookietmpl))) {
|
|
|
|
|
cookieval += strlen(cookietmpl);
|
|
|
|
|
lua_pushlstring(L, cookieval, strchrnul(cookieval, ';') - cookieval);
|
|
|
|
|
} else {
|
|
|
|
|
lua_pushnil(L);
|
|
|
|
|
}
|
|
|
|
|
if (cookie)
|
|
|
|
|
free(cookie);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-04 09:12:12 +00:00
|
|
|
|
static int LuaSetCookie(lua_State *L) {
|
|
|
|
|
const char *key, *val;
|
|
|
|
|
size_t keylen, vallen;
|
|
|
|
|
char *expires, *samesite = "";
|
|
|
|
|
char *buf = 0;
|
|
|
|
|
bool ishostpref, issecurepref;
|
|
|
|
|
const char *hostpref = "__Host-";
|
|
|
|
|
const char *securepref = "__Secure-";
|
|
|
|
|
|
2021-10-25 21:54:56 +00:00
|
|
|
|
OnlyCallDuringRequest(L, "SetCookie");
|
2021-09-04 09:12:12 +00:00
|
|
|
|
key = luaL_checklstring(L, 1, &keylen);
|
|
|
|
|
val = luaL_checklstring(L, 2, &vallen);
|
|
|
|
|
|
|
|
|
|
if (!IsValidHttpToken(key, keylen)) {
|
|
|
|
|
luaL_argerror(L, 1, "invalid");
|
2023-06-09 06:44:03 +00:00
|
|
|
|
__builtin_unreachable();
|
2021-09-04 09:12:12 +00:00
|
|
|
|
}
|
|
|
|
|
if (!IsValidCookieValue(val, vallen)) {
|
|
|
|
|
luaL_argerror(L, 2, "invalid");
|
2023-06-09 06:44:03 +00:00
|
|
|
|
__builtin_unreachable();
|
2021-09-04 09:12:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-09-07 18:40:11 +00:00
|
|
|
|
ishostpref = keylen > strlen(hostpref) &&
|
|
|
|
|
SlicesEqual(key, strlen(hostpref), hostpref, strlen(hostpref));
|
|
|
|
|
issecurepref =
|
|
|
|
|
keylen > strlen(securepref) &&
|
|
|
|
|
SlicesEqual(key, strlen(securepref), securepref, strlen(securepref));
|
2022-05-29 15:14:55 +00:00
|
|
|
|
if ((ishostpref || issecurepref) && !usingssl) {
|
2021-09-28 05:58:51 +00:00
|
|
|
|
luaL_argerror(
|
|
|
|
|
L, 1,
|
2024-01-08 18:07:35 +00:00
|
|
|
|
gc(xasprintf("%s and %s prefixes require SSL", hostpref, securepref)));
|
2023-06-09 06:44:03 +00:00
|
|
|
|
__builtin_unreachable();
|
2021-09-04 09:12:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
appends(&buf, key);
|
|
|
|
|
appends(&buf, "=");
|
|
|
|
|
appends(&buf, val);
|
|
|
|
|
|
|
|
|
|
if (lua_istable(L, 3)) {
|
2021-09-07 18:40:11 +00:00
|
|
|
|
if (lua_getfield(L, 3, "expires") != LUA_TNIL ||
|
|
|
|
|
lua_getfield(L, 3, "Expires") != LUA_TNIL) {
|
2021-09-04 09:12:12 +00:00
|
|
|
|
if (lua_isnumber(L, -1)) {
|
2021-09-07 18:40:11 +00:00
|
|
|
|
expires =
|
|
|
|
|
FormatUnixHttpDateTime(FreeLater(xmalloc(30)), lua_tonumber(L, -1));
|
2021-09-04 09:12:12 +00:00
|
|
|
|
} else {
|
2023-09-02 03:49:13 +00:00
|
|
|
|
expires = (void *)lua_tostring(L, -1);
|
2021-09-04 09:12:12 +00:00
|
|
|
|
if (!ParseHttpDateTime(expires, -1)) {
|
|
|
|
|
luaL_argerror(L, 3, "invalid data format in Expires");
|
2023-06-09 06:44:03 +00:00
|
|
|
|
__builtin_unreachable();
|
2021-09-04 09:12:12 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
appends(&buf, "; Expires=");
|
|
|
|
|
appends(&buf, expires);
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-07 18:40:11 +00:00
|
|
|
|
if ((lua_getfield(L, 3, "maxage") == LUA_TNUMBER ||
|
|
|
|
|
lua_getfield(L, 3, "MaxAge") == LUA_TNUMBER) &&
|
|
|
|
|
lua_isinteger(L, -1)) {
|
2021-09-04 09:12:12 +00:00
|
|
|
|
appends(&buf, "; Max-Age=");
|
|
|
|
|
appends(&buf, lua_tostring(L, -1));
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-07 18:40:11 +00:00
|
|
|
|
if (lua_getfield(L, 3, "samesite") == LUA_TSTRING ||
|
|
|
|
|
lua_getfield(L, 3, "SameSite") == LUA_TSTRING) {
|
2023-09-02 03:49:13 +00:00
|
|
|
|
samesite = (void *)lua_tostring(L, -1); // also used in the Secure check
|
2021-09-04 09:12:12 +00:00
|
|
|
|
appends(&buf, "; SameSite=");
|
|
|
|
|
appends(&buf, samesite);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Secure attribute is required for __Host and __Secure prefixes
|
|
|
|
|
// as well as for the SameSite=None
|
2021-09-07 18:40:11 +00:00
|
|
|
|
if (ishostpref || issecurepref || !strcmp(samesite, "None") ||
|
|
|
|
|
((lua_getfield(L, 3, "secure") == LUA_TBOOLEAN ||
|
|
|
|
|
lua_getfield(L, 3, "Secure") == LUA_TBOOLEAN) &&
|
|
|
|
|
lua_toboolean(L, -1))) {
|
2021-09-04 09:12:12 +00:00
|
|
|
|
appends(&buf, "; Secure");
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-07 18:40:11 +00:00
|
|
|
|
if (!ishostpref && (lua_getfield(L, 3, "domain") == LUA_TSTRING ||
|
|
|
|
|
lua_getfield(L, 3, "Domain") == LUA_TSTRING)) {
|
2021-09-04 09:12:12 +00:00
|
|
|
|
appends(&buf, "; Domain=");
|
|
|
|
|
appends(&buf, lua_tostring(L, -1));
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-07 18:40:11 +00:00
|
|
|
|
if (ishostpref || lua_getfield(L, 3, "path") == LUA_TSTRING ||
|
|
|
|
|
lua_getfield(L, 3, "Path") == LUA_TSTRING) {
|
2021-09-04 09:12:12 +00:00
|
|
|
|
appends(&buf, "; Path=");
|
|
|
|
|
appends(&buf, ishostpref ? "/" : lua_tostring(L, -1));
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-07 18:40:11 +00:00
|
|
|
|
if ((lua_getfield(L, 3, "httponly") == LUA_TBOOLEAN ||
|
|
|
|
|
lua_getfield(L, 3, "HttpOnly") == LUA_TBOOLEAN) &&
|
|
|
|
|
lua_toboolean(L, -1)) {
|
2021-09-04 09:12:12 +00:00
|
|
|
|
appends(&buf, "; HttpOnly");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
DEBUGF("(srvr) Set-Cookie: %s", buf);
|
|
|
|
|
|
2021-09-11 23:46:21 +00:00
|
|
|
|
// empty the stack and push header name/value
|
2021-09-04 09:12:12 +00:00
|
|
|
|
lua_settop(L, 0);
|
|
|
|
|
lua_pushliteral(L, "Set-Cookie");
|
|
|
|
|
lua_pushstring(L, buf);
|
|
|
|
|
free(buf);
|
|
|
|
|
return LuaSetHeader(L);
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-25 09:21:13 +00:00
|
|
|
|
static int LuaHasParam(lua_State *L) {
|
2021-04-21 02:14:21 +00:00
|
|
|
|
size_t i, n;
|
|
|
|
|
const char *s;
|
2021-10-25 21:54:56 +00:00
|
|
|
|
OnlyCallDuringRequest(L, "HasParam");
|
2021-04-21 02:14:21 +00:00
|
|
|
|
s = luaL_checklstring(L, 1, &n);
|
|
|
|
|
for (i = 0; i < url.params.n; ++i) {
|
|
|
|
|
if (SlicesEqual(s, n, url.params.p[i].key.p, url.params.p[i].key.n)) {
|
2021-03-25 09:21:13 +00:00
|
|
|
|
lua_pushboolean(L, true);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
lua_pushboolean(L, false);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int LuaGetParam(lua_State *L) {
|
2021-04-21 02:14:21 +00:00
|
|
|
|
size_t i, n;
|
|
|
|
|
const char *s;
|
2021-10-25 21:54:56 +00:00
|
|
|
|
OnlyCallDuringRequest(L, "GetParam");
|
2021-04-21 02:14:21 +00:00
|
|
|
|
s = luaL_checklstring(L, 1, &n);
|
|
|
|
|
for (i = 0; i < url.params.n; ++i) {
|
|
|
|
|
if (SlicesEqual(s, n, url.params.p[i].key.p, url.params.p[i].key.n)) {
|
|
|
|
|
if (url.params.p[i].val.p) {
|
|
|
|
|
lua_pushlstring(L, url.params.p[i].val.p, url.params.p[i].val.n);
|
|
|
|
|
return 1;
|
|
|
|
|
} else {
|
|
|
|
|
break;
|
|
|
|
|
}
|
2021-03-25 09:21:13 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
lua_pushnil(L);
|
2021-03-22 00:27:53 +00:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-18 18:34:59 +00:00
|
|
|
|
static int LuaGetParams(lua_State *L) {
|
2021-10-25 21:54:56 +00:00
|
|
|
|
OnlyCallDuringRequest(L, "GetParams");
|
2021-04-21 02:14:21 +00:00
|
|
|
|
LuaPushUrlParams(L, &url.params);
|
2021-04-18 18:34:59 +00:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-25 09:21:13 +00:00
|
|
|
|
static int LuaWrite(lua_State *L) {
|
2021-03-22 00:27:53 +00:00
|
|
|
|
size_t size;
|
|
|
|
|
const char *data;
|
2021-10-25 21:54:56 +00:00
|
|
|
|
OnlyCallDuringRequest(L, "Write");
|
2021-04-23 17:45:19 +00:00
|
|
|
|
if (!lua_isnil(L, 1)) {
|
|
|
|
|
data = luaL_checklstring(L, 1, &size);
|
2022-08-06 00:34:53 +00:00
|
|
|
|
appendd(&cpm.outbuf, data, size);
|
2021-04-23 17:45:19 +00:00
|
|
|
|
}
|
2021-03-22 00:27:53 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-12 23:12:18 +00:00
|
|
|
|
static dontinline int LuaProgramInt(lua_State *L, void P(long)) {
|
2021-05-14 12:36:58 +00:00
|
|
|
|
P(luaL_checkinteger(L, 1));
|
2021-03-29 08:22:49 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-23 17:45:19 +00:00
|
|
|
|
static int LuaProgramPort(lua_State *L) {
|
2021-10-25 21:54:56 +00:00
|
|
|
|
OnlyCallFromInitLua(L, "ProgramPort");
|
2021-04-23 17:45:19 +00:00
|
|
|
|
return LuaProgramInt(L, ProgramPort);
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-29 08:22:49 +00:00
|
|
|
|
static int LuaProgramCache(lua_State *L) {
|
2022-04-24 16:59:22 +00:00
|
|
|
|
OnlyCallFromMainProcess(L, "ProgramCache");
|
2023-02-24 06:24:40 +00:00
|
|
|
|
ProgramCache(luaL_checkinteger(L, 1), luaL_optstring(L, 2, NULL));
|
|
|
|
|
return 0;
|
2021-04-23 17:45:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int LuaProgramTimeout(lua_State *L) {
|
2021-10-25 21:54:56 +00:00
|
|
|
|
OnlyCallFromInitLua(L, "ProgramTimeout");
|
2021-04-23 17:45:19 +00:00
|
|
|
|
return LuaProgramInt(L, ProgramTimeout);
|
2021-03-29 08:22:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-07-08 22:56:23 +00:00
|
|
|
|
static int LuaProgramUid(lua_State *L) {
|
2021-10-25 21:54:56 +00:00
|
|
|
|
OnlyCallFromInitLua(L, "ProgramUid");
|
2021-07-08 22:56:23 +00:00
|
|
|
|
return LuaProgramInt(L, ProgramUid);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int LuaProgramGid(lua_State *L) {
|
2021-10-25 21:54:56 +00:00
|
|
|
|
OnlyCallFromInitLua(L, "ProgramGid");
|
2021-07-08 22:56:23 +00:00
|
|
|
|
return LuaProgramInt(L, ProgramGid);
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-10 10:28:46 +00:00
|
|
|
|
static int LuaProgramMaxPayloadSize(lua_State *L) {
|
|
|
|
|
OnlyCallFromInitLua(L, "ProgramMaxPayloadSize");
|
|
|
|
|
return LuaProgramInt(L, ProgramMaxPayloadSize);
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-24 16:59:22 +00:00
|
|
|
|
static int LuaGetClientFd(lua_State *L) {
|
|
|
|
|
OnlyCallDuringConnection(L, "GetClientFd");
|
|
|
|
|
lua_pushinteger(L, client);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int LuaIsClientUsingSsl(lua_State *L) {
|
|
|
|
|
OnlyCallDuringConnection(L, "IsClientUsingSsl");
|
2022-05-29 15:14:55 +00:00
|
|
|
|
lua_pushboolean(L, usingssl);
|
2022-04-24 16:59:22 +00:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-19 21:55:20 +00:00
|
|
|
|
static int LuaProgramSslTicketLifetime(lua_State *L) {
|
2021-10-25 21:54:56 +00:00
|
|
|
|
OnlyCallFromInitLua(L, "ProgramSslTicketLifetime");
|
2021-07-19 21:55:20 +00:00
|
|
|
|
return LuaProgramInt(L, ProgramSslTicketLifetime);
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-08 02:15:44 +00:00
|
|
|
|
static int LuaProgramUniprocess(lua_State *L) {
|
|
|
|
|
OnlyCallFromInitLua(L, "ProgramUniprocess");
|
2022-04-24 16:59:22 +00:00
|
|
|
|
if (!lua_isboolean(L, 1) && !lua_isnoneornil(L, 1)) {
|
2022-03-08 02:15:44 +00:00
|
|
|
|
return luaL_argerror(L, 1, "invalid uniprocess mode; boolean expected");
|
2022-04-24 16:59:22 +00:00
|
|
|
|
}
|
2022-03-08 02:15:44 +00:00
|
|
|
|
lua_pushboolean(L, uniprocess);
|
2022-03-21 10:20:09 +00:00
|
|
|
|
if (lua_isboolean(L, 1))
|
|
|
|
|
uniprocess = lua_toboolean(L, 1);
|
2022-03-08 02:15:44 +00:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-03 03:41:44 +00:00
|
|
|
|
static int LuaProgramHeartbeatInterval(lua_State *L) {
|
2022-08-06 02:24:05 +00:00
|
|
|
|
int64_t millis;
|
2022-08-03 03:41:44 +00:00
|
|
|
|
OnlyCallFromMainProcess(L, "ProgramHeartbeatInterval");
|
2022-08-06 02:24:05 +00:00
|
|
|
|
if (!lua_isnoneornil(L, 1)) {
|
|
|
|
|
millis = luaL_checkinteger(L, 1);
|
|
|
|
|
millis = MAX(100, millis);
|
2022-11-06 02:49:41 +00:00
|
|
|
|
heartbeatinterval = timespec_frommillis(millis);
|
2022-08-03 03:41:44 +00:00
|
|
|
|
}
|
2022-11-06 02:49:41 +00:00
|
|
|
|
lua_pushinteger(L, timespec_tomillis(heartbeatinterval));
|
2022-08-03 03:41:44 +00:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-05 22:21:27 +00:00
|
|
|
|
static int LuaProgramMaxWorkers(lua_State *L) {
|
|
|
|
|
OnlyCallFromMainProcess(L, "ProgramMaxWorkers");
|
|
|
|
|
if (!lua_isinteger(L, 1) && !lua_isnoneornil(L, 1)) {
|
|
|
|
|
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);
|
2022-08-05 22:42:17 +00:00
|
|
|
|
maxworkers = MAX(maxworkers, 1);
|
2022-08-05 22:21:27 +00:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-24 00:59:35 +00:00
|
|
|
|
static int LuaProgramAddr(lua_State *L) {
|
|
|
|
|
uint32_t ip;
|
|
|
|
|
OnlyCallFromInitLua(L, "ProgramAddr");
|
|
|
|
|
if (lua_isinteger(L, 1)) {
|
|
|
|
|
ip = luaL_checkinteger(L, 1);
|
|
|
|
|
ips.p = realloc(ips.p, ++ips.n * sizeof(*ips.p));
|
|
|
|
|
ips.p[ips.n - 1] = ip;
|
|
|
|
|
} else {
|
|
|
|
|
ProgramAddr(luaL_checkstring(L, 1));
|
|
|
|
|
}
|
2021-03-29 08:22:49 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-24 00:59:35 +00:00
|
|
|
|
static dontinline int LuaProgramString(lua_State *L, void P(const char *)) {
|
|
|
|
|
P(luaL_checkstring(L, 1));
|
|
|
|
|
return 0;
|
2021-07-08 22:56:23 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int LuaProgramBrand(lua_State *L) {
|
2022-04-24 16:59:22 +00:00
|
|
|
|
OnlyCallFromMainProcess(L, "ProgramBrand");
|
2021-07-08 22:56:23 +00:00
|
|
|
|
return LuaProgramString(L, ProgramBrand);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int LuaProgramDirectory(lua_State *L) {
|
2024-01-05 10:17:55 +00:00
|
|
|
|
size_t i;
|
|
|
|
|
// if no parameter is provided, then return current directories
|
|
|
|
|
if (lua_isnoneornil(L, 1)) {
|
|
|
|
|
lua_newtable(L);
|
|
|
|
|
if (stagedirs.n) {
|
|
|
|
|
for (i = 0; i < stagedirs.n; ++i) {
|
|
|
|
|
lua_pushlstring(L, stagedirs.p[i].s, stagedirs.p[i].n);
|
|
|
|
|
lua_seti(L, -2, i + 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2023-08-17 07:43:11 +00:00
|
|
|
|
struct stat st;
|
2023-09-02 03:49:13 +00:00
|
|
|
|
const char *path = luaL_checkstring(L, 1);
|
2023-08-17 07:43:11 +00:00
|
|
|
|
// check to raise a Lua error, to allow it to be handled
|
|
|
|
|
if (stat(path, &st) == -1 || !S_ISDIR(st.st_mode)) {
|
|
|
|
|
return luaL_argerror(L, 1, "not a directory");
|
|
|
|
|
}
|
2021-07-08 22:56:23 +00:00
|
|
|
|
return LuaProgramString(L, ProgramDirectory);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int LuaProgramLogPath(lua_State *L) {
|
2021-10-25 21:54:56 +00:00
|
|
|
|
OnlyCallFromInitLua(L, "ProgramLogPath");
|
2021-07-08 22:56:23 +00:00
|
|
|
|
return LuaProgramString(L, ProgramLogPath);
|
|
|
|
|
}
|
|
|
|
|
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
static int LuaProgramPidPath(lua_State *L) {
|
2021-10-25 21:54:56 +00:00
|
|
|
|
OnlyCallFromInitLua(L, "ProgramPidPath");
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
return LuaProgramString(L, ProgramPidPath);
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-09 14:00:23 +00:00
|
|
|
|
static int LuaProgramSslPresharedKey(lua_State *L) {
|
|
|
|
|
struct Psk psk;
|
|
|
|
|
size_t n1, n2, i;
|
|
|
|
|
const char *p1, *p2;
|
2022-04-24 16:59:22 +00:00
|
|
|
|
OnlyCallFromMainProcess(L, "ProgramSslPresharedKey");
|
2021-08-09 14:00:23 +00:00
|
|
|
|
p1 = luaL_checklstring(L, 1, &n1);
|
|
|
|
|
p2 = luaL_checklstring(L, 2, &n2);
|
|
|
|
|
if (!n1 || n1 > MBEDTLS_PSK_MAX_LEN || !n2) {
|
|
|
|
|
luaL_argerror(L, 1, "bad preshared key length");
|
2023-06-09 06:44:03 +00:00
|
|
|
|
__builtin_unreachable();
|
2021-08-09 14:00:23 +00:00
|
|
|
|
}
|
|
|
|
|
psk.key = memcpy(malloc(n1), p1, n1);
|
|
|
|
|
psk.key_len = n1;
|
|
|
|
|
psk.identity = memcpy(malloc(n2), p2, n2);
|
|
|
|
|
psk.identity_len = n2;
|
|
|
|
|
for (i = 0; i < psks.n; ++i) {
|
|
|
|
|
if (SlicesEqual(psk.identity, psk.identity_len, psks.p[i].identity,
|
|
|
|
|
psks.p[i].identity_len)) {
|
|
|
|
|
mbedtls_platform_zeroize(psks.p[i].key, psks.p[i].key_len);
|
|
|
|
|
free(psks.p[i].key);
|
|
|
|
|
free(psks.p[i].identity);
|
|
|
|
|
psks.p[i] = psk;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
psks.p = realloc(psks.p, ++psks.n * sizeof(*psks.p));
|
|
|
|
|
psks.p[psks.n - 1] = psk;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int LuaProgramSslCiphersuite(lua_State *L) {
|
2023-09-02 03:49:13 +00:00
|
|
|
|
const mbedtls_ssl_ciphersuite_t *suite;
|
2022-04-24 16:59:22 +00:00
|
|
|
|
OnlyCallFromInitLua(L, "ProgramSslCiphersuite");
|
2021-08-09 14:00:23 +00:00
|
|
|
|
if (!(suite = GetCipherSuite(luaL_checkstring(L, 1)))) {
|
|
|
|
|
luaL_argerror(L, 1, "unsupported or unknown ciphersuite");
|
2023-06-09 06:44:03 +00:00
|
|
|
|
__builtin_unreachable();
|
2021-08-09 14:00:23 +00:00
|
|
|
|
}
|
|
|
|
|
suites.p = realloc(suites.p, (++suites.n + 1) * sizeof(*suites.p));
|
|
|
|
|
suites.p[suites.n - 1] = suite->id;
|
|
|
|
|
suites.p[suites.n - 0] = 0;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-24 19:31:26 +00:00
|
|
|
|
static int LuaProgramPrivateKey(lua_State *L) {
|
|
|
|
|
size_t n;
|
|
|
|
|
const char *p;
|
2021-10-25 21:54:56 +00:00
|
|
|
|
OnlyCallFromInitLua(L, "ProgramPrivateKey");
|
2021-06-24 19:31:26 +00:00
|
|
|
|
p = luaL_checklstring(L, 1, &n);
|
|
|
|
|
ProgramPrivateKey(p, n);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int LuaProgramCertificate(lua_State *L) {
|
|
|
|
|
size_t n;
|
|
|
|
|
const char *p;
|
2021-10-25 21:54:56 +00:00
|
|
|
|
OnlyCallFromInitLua(L, "ProgramCertificate");
|
2021-06-24 19:31:26 +00:00
|
|
|
|
p = luaL_checklstring(L, 1, &n);
|
|
|
|
|
ProgramCertificate(p, n);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-23 17:45:19 +00:00
|
|
|
|
static int LuaProgramHeader(lua_State *L) {
|
2021-05-14 12:36:58 +00:00
|
|
|
|
ProgramHeader(
|
2024-01-08 18:07:35 +00:00
|
|
|
|
gc(xasprintf("%s: %s", luaL_checkstring(L, 1), luaL_checkstring(L, 2))));
|
2021-04-23 17:45:19 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-29 08:22:49 +00:00
|
|
|
|
static int LuaProgramRedirect(lua_State *L) {
|
2021-05-14 12:36:58 +00:00
|
|
|
|
int code;
|
|
|
|
|
const char *from, *to;
|
|
|
|
|
code = luaL_checkinteger(L, 1);
|
|
|
|
|
from = luaL_checkstring(L, 2);
|
|
|
|
|
to = luaL_checkstring(L, 3);
|
|
|
|
|
ProgramRedirect(code, strdup(from), strlen(from), strdup(to), strlen(to));
|
2021-03-29 08:22:49 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-12 23:12:18 +00:00
|
|
|
|
static dontinline int LuaProgramBool(lua_State *L, bool *b) {
|
2021-07-08 04:44:27 +00:00
|
|
|
|
*b = lua_toboolean(L, 1);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int LuaProgramSslClientVerify(lua_State *L) {
|
2021-10-25 21:54:56 +00:00
|
|
|
|
OnlyCallFromInitLua(L, "ProgramSslClientVerify");
|
2021-07-08 04:44:27 +00:00
|
|
|
|
return LuaProgramBool(L, &sslclientverify);
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-29 15:14:55 +00:00
|
|
|
|
static int LuaProgramSslRequired(lua_State *L) {
|
|
|
|
|
OnlyCallFromInitLua(L, "ProgramSslRequired");
|
|
|
|
|
return LuaProgramBool(L, &requiressl);
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-08 04:44:27 +00:00
|
|
|
|
static int LuaProgramSslFetchVerify(lua_State *L) {
|
2022-04-24 16:59:22 +00:00
|
|
|
|
OnlyCallFromMainProcess(L, "ProgramSslFetchVerify");
|
2021-07-08 04:44:27 +00:00
|
|
|
|
return LuaProgramBool(L, &sslfetchverify);
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-15 00:11:05 +00:00
|
|
|
|
static int LuaProgramSslInit(lua_State *L) {
|
2022-04-24 16:59:22 +00:00
|
|
|
|
OnlyCallFromInitLua(L, "SslInit");
|
2022-03-15 00:11:05 +00:00
|
|
|
|
TlsInit();
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-08 22:56:23 +00:00
|
|
|
|
static int LuaProgramLogMessages(lua_State *L) {
|
|
|
|
|
return LuaProgramBool(L, &logmessages);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int LuaProgramLogBodies(lua_State *L) {
|
|
|
|
|
return LuaProgramBool(L, &logbodies);
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-19 21:55:20 +00:00
|
|
|
|
static int LuaEvadeDragnetSurveillance(lua_State *L) {
|
|
|
|
|
return LuaProgramBool(L, &evadedragnetsurveillance);
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-29 09:39:20 +00:00
|
|
|
|
static int LuaHidePath(lua_State *L) {
|
2021-04-18 18:34:59 +00:00
|
|
|
|
size_t pathlen;
|
|
|
|
|
const char *path;
|
|
|
|
|
path = luaL_checklstring(L, 1, &pathlen);
|
2021-06-10 15:55:04 +00:00
|
|
|
|
AddString(&hidepaths, memcpy(malloc(pathlen), path, pathlen), pathlen);
|
2021-03-29 09:39:20 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int LuaIsHiddenPath(lua_State *L) {
|
2021-05-14 12:36:58 +00:00
|
|
|
|
size_t n;
|
|
|
|
|
const char *s;
|
|
|
|
|
s = luaL_checklstring(L, 1, &n);
|
|
|
|
|
lua_pushboolean(L, IsHiddenPath(s, n));
|
2021-03-29 09:39:20 +00:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int LuaGetZipPaths(lua_State *L) {
|
|
|
|
|
char *path;
|
2021-05-14 12:36:58 +00:00
|
|
|
|
uint8_t *zcf;
|
2021-11-12 23:28:05 +00:00
|
|
|
|
size_t i, n, pathlen, prefixlen;
|
2023-09-02 03:49:13 +00:00
|
|
|
|
const char *prefix = luaL_optlstring(L, 1, "", &prefixlen);
|
2021-03-29 09:39:20 +00:00
|
|
|
|
lua_newtable(L);
|
|
|
|
|
i = 0;
|
2021-05-02 18:50:43 +00:00
|
|
|
|
n = GetZipCdirRecords(zcdir);
|
2023-06-17 11:20:16 +00:00
|
|
|
|
for (zcf = zmap + GetZipCdirOffset(zcdir); n--;
|
2021-05-14 12:36:58 +00:00
|
|
|
|
zcf += ZIP_CFILE_HDRSIZE(zcf)) {
|
|
|
|
|
CHECK_EQ(kZipCfileHdrMagic, ZIP_CFILE_MAGIC(zcf));
|
|
|
|
|
path = GetAssetPath(zcf, &pathlen);
|
2023-08-14 03:31:27 +00:00
|
|
|
|
if (prefixlen == 0 || startswith(path, prefix)) {
|
2021-11-12 23:28:05 +00:00
|
|
|
|
lua_pushlstring(L, path, pathlen);
|
|
|
|
|
lua_seti(L, -2, ++i);
|
|
|
|
|
}
|
2021-03-29 09:39:20 +00:00
|
|
|
|
free(path);
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-21 02:14:21 +00:00
|
|
|
|
static int LuaGetAssetMode(lua_State *L) {
|
2021-04-23 17:45:19 +00:00
|
|
|
|
size_t pathlen;
|
2021-04-21 02:14:21 +00:00
|
|
|
|
struct Asset *a;
|
2021-04-23 17:45:19 +00:00
|
|
|
|
const char *path;
|
|
|
|
|
path = LuaCheckPath(L, 1, &pathlen);
|
|
|
|
|
if ((a = GetAsset(path, pathlen))) {
|
2021-04-21 02:14:21 +00:00
|
|
|
|
lua_pushinteger(L, GetMode(a));
|
|
|
|
|
} else {
|
|
|
|
|
lua_pushnil(L);
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-24 01:54:35 +00:00
|
|
|
|
static int LuaGetAssetLastModifiedTime(lua_State *L) {
|
2021-04-23 17:45:19 +00:00
|
|
|
|
size_t pathlen;
|
2021-04-21 02:14:21 +00:00
|
|
|
|
struct Asset *a;
|
2021-04-23 17:45:19 +00:00
|
|
|
|
const char *path;
|
2021-08-14 13:17:56 +00:00
|
|
|
|
struct timespec lm;
|
|
|
|
|
int64_t zuluseconds;
|
2021-04-23 17:45:19 +00:00
|
|
|
|
path = LuaCheckPath(L, 1, &pathlen);
|
|
|
|
|
if ((a = GetAsset(path, pathlen))) {
|
2021-04-21 02:14:21 +00:00
|
|
|
|
if (a->file) {
|
2021-08-14 13:17:56 +00:00
|
|
|
|
zuluseconds = a->file->st.st_mtim.tv_sec;
|
2021-04-21 02:14:21 +00:00
|
|
|
|
} else {
|
2023-06-17 11:20:16 +00:00
|
|
|
|
GetZipCfileTimestamps(zmap + a->cf, &lm, 0, 0, gmtoff);
|
2021-08-14 13:17:56 +00:00
|
|
|
|
zuluseconds = lm.tv_sec;
|
2021-04-21 02:14:21 +00:00
|
|
|
|
}
|
2021-08-14 13:17:56 +00:00
|
|
|
|
lua_pushinteger(L, zuluseconds);
|
2021-04-21 02:14:21 +00:00
|
|
|
|
} else {
|
|
|
|
|
lua_pushnil(L);
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int LuaGetAssetSize(lua_State *L) {
|
2021-04-23 17:45:19 +00:00
|
|
|
|
size_t pathlen;
|
2021-04-21 02:14:21 +00:00
|
|
|
|
struct Asset *a;
|
2021-04-23 17:45:19 +00:00
|
|
|
|
const char *path;
|
|
|
|
|
path = LuaCheckPath(L, 1, &pathlen);
|
|
|
|
|
if ((a = GetAsset(path, pathlen))) {
|
2021-04-21 02:14:21 +00:00
|
|
|
|
if (a->file) {
|
|
|
|
|
lua_pushinteger(L, a->file->st.st_size);
|
|
|
|
|
} else {
|
2023-06-17 11:20:16 +00:00
|
|
|
|
lua_pushinteger(L, GetZipLfileUncompressedSize(zmap + a->lf));
|
2021-04-21 02:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
lua_pushnil(L);
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-24 01:54:35 +00:00
|
|
|
|
static int LuaIsAssetCompressed(lua_State *L) {
|
2021-04-23 17:45:19 +00:00
|
|
|
|
size_t pathlen;
|
2021-04-21 02:14:21 +00:00
|
|
|
|
struct Asset *a;
|
2021-04-23 17:45:19 +00:00
|
|
|
|
const char *path;
|
|
|
|
|
path = LuaCheckPath(L, 1, &pathlen);
|
|
|
|
|
if ((a = GetAsset(path, pathlen))) {
|
2021-04-21 02:14:21 +00:00
|
|
|
|
lua_pushboolean(L, IsCompressed(a));
|
|
|
|
|
} else {
|
|
|
|
|
lua_pushnil(L);
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-19 20:10:00 +00:00
|
|
|
|
static bool Blackhole(uint32_t ip) {
|
2022-10-17 18:02:04 +00:00
|
|
|
|
char buf[4];
|
2022-10-19 20:10:00 +00:00
|
|
|
|
if (blackhole.fd <= 0)
|
|
|
|
|
return false;
|
2022-10-17 18:02:04 +00:00
|
|
|
|
WRITE32BE(buf, ip);
|
2022-10-19 17:00:29 +00:00
|
|
|
|
if (sendto(blackhole.fd, &buf, 4, 0, (struct sockaddr *)&blackhole.addr,
|
2022-10-19 20:10:00 +00:00
|
|
|
|
sizeof(blackhole.addr)) != -1) {
|
|
|
|
|
return true;
|
|
|
|
|
} else {
|
|
|
|
|
VERBOSEF("(token) sendto(%s) failed: %m", blackhole.addr.sun_path);
|
2022-10-19 17:00:29 +00:00
|
|
|
|
errno = 0;
|
2022-10-19 20:10:00 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int LuaBlackhole(lua_State *L) {
|
|
|
|
|
lua_Integer ip;
|
|
|
|
|
ip = luaL_checkinteger(L, 1);
|
|
|
|
|
if (!(0 <= ip && ip <= 0xffffffff)) {
|
|
|
|
|
luaL_argerror(L, 1, "ip out of range");
|
2023-06-09 06:44:03 +00:00
|
|
|
|
__builtin_unreachable();
|
2022-10-17 18:02:04 +00:00
|
|
|
|
}
|
2022-10-19 20:10:00 +00:00
|
|
|
|
lua_pushboolean(L, Blackhole(ip));
|
|
|
|
|
return 1;
|
2022-10-17 18:02:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-02-22 22:12:18 +00:00
|
|
|
|
static void BlockSignals(void) {
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-17 18:02:04 +00:00
|
|
|
|
wontreturn static void Replenisher(void) {
|
|
|
|
|
struct timespec ts;
|
2022-10-19 20:10:00 +00:00
|
|
|
|
VERBOSEF("(token) replenish worker started");
|
2023-10-13 15:30:18 +00:00
|
|
|
|
strace_enabled(-1);
|
2022-10-17 18:02:04 +00:00
|
|
|
|
signal(SIGINT, OnTerm);
|
|
|
|
|
signal(SIGHUP, OnTerm);
|
|
|
|
|
signal(SIGTERM, OnTerm);
|
|
|
|
|
signal(SIGUSR1, SIG_IGN); // make sure reload won't kill this
|
|
|
|
|
signal(SIGUSR2, SIG_IGN); // make sure meltdown won't kill this
|
2022-11-06 02:49:41 +00:00
|
|
|
|
ts = timespec_real();
|
2022-10-17 18:02:04 +00:00
|
|
|
|
while (!terminated) {
|
|
|
|
|
if (clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &ts, 0)) {
|
|
|
|
|
errno = 0;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
ReplenishTokens(tokenbucket.w, (1ul << tokenbucket.cidr) / 8);
|
2022-11-06 02:49:41 +00:00
|
|
|
|
ts = timespec_add(ts, tokenbucket.replenish);
|
2022-10-19 20:10:00 +00:00
|
|
|
|
DEBUGF("(token) replenished tokens");
|
2022-10-17 18:02:04 +00:00
|
|
|
|
}
|
2022-10-19 20:10:00 +00:00
|
|
|
|
VERBOSEF("(token) replenish worker exiting");
|
2022-10-17 18:02:04 +00:00
|
|
|
|
_Exit(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int LuaAcquireToken(lua_State *L) {
|
|
|
|
|
uint32_t ip;
|
|
|
|
|
if (!tokenbucket.cidr) {
|
|
|
|
|
luaL_error(L, "ProgramTokenBucket() needs to be called first");
|
2023-06-09 06:44:03 +00:00
|
|
|
|
__builtin_unreachable();
|
2022-10-17 18:02:04 +00:00
|
|
|
|
}
|
|
|
|
|
GetClientAddr(&ip, 0);
|
|
|
|
|
lua_pushinteger(L, AcquireToken(tokenbucket.b, luaL_optinteger(L, 1, ip),
|
|
|
|
|
tokenbucket.cidr));
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int LuaCountTokens(lua_State *L) {
|
|
|
|
|
uint32_t ip;
|
|
|
|
|
if (!tokenbucket.cidr) {
|
|
|
|
|
luaL_error(L, "ProgramTokenBucket() needs to be called first");
|
2023-06-09 06:44:03 +00:00
|
|
|
|
__builtin_unreachable();
|
2022-10-17 18:02:04 +00:00
|
|
|
|
}
|
|
|
|
|
GetClientAddr(&ip, 0);
|
|
|
|
|
lua_pushinteger(L, CountTokens(tokenbucket.b, luaL_optinteger(L, 1, ip),
|
|
|
|
|
tokenbucket.cidr));
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int LuaProgramTokenBucket(lua_State *L) {
|
|
|
|
|
if (tokenbucket.cidr) {
|
|
|
|
|
luaL_error(L, "ProgramTokenBucket() can only be called once");
|
2023-06-09 06:44:03 +00:00
|
|
|
|
__builtin_unreachable();
|
2022-10-17 18:02:04 +00:00
|
|
|
|
}
|
|
|
|
|
lua_Number replenish = luaL_optnumber(L, 1, 1); // per second
|
|
|
|
|
lua_Integer cidr = luaL_optinteger(L, 2, 24);
|
|
|
|
|
lua_Integer reject = luaL_optinteger(L, 3, 30);
|
|
|
|
|
lua_Integer ignore = luaL_optinteger(L, 4, MIN(reject / 2, 15));
|
|
|
|
|
lua_Integer ban = luaL_optinteger(L, 5, MIN(ignore / 10, 1));
|
|
|
|
|
if (!(1 / 3600. <= replenish && replenish <= 1e6)) {
|
|
|
|
|
luaL_argerror(L, 1, "require 1/3600 <= replenish <= 1e6");
|
2023-06-09 06:44:03 +00:00
|
|
|
|
__builtin_unreachable();
|
2022-10-17 18:02:04 +00:00
|
|
|
|
}
|
|
|
|
|
if (!(8 <= cidr && cidr <= 32)) {
|
|
|
|
|
luaL_argerror(L, 2, "require 8 <= cidr <= 32");
|
2023-06-09 06:44:03 +00:00
|
|
|
|
__builtin_unreachable();
|
2022-10-17 18:02:04 +00:00
|
|
|
|
}
|
|
|
|
|
if (!(-1 <= reject && reject <= 126)) {
|
|
|
|
|
luaL_argerror(L, 3, "require -1 <= reject <= 126");
|
2023-06-09 06:44:03 +00:00
|
|
|
|
__builtin_unreachable();
|
2022-10-17 18:02:04 +00:00
|
|
|
|
}
|
|
|
|
|
if (!(-1 <= ignore && ignore <= 126)) {
|
|
|
|
|
luaL_argerror(L, 4, "require -1 <= ignore <= 126");
|
2023-06-09 06:44:03 +00:00
|
|
|
|
__builtin_unreachable();
|
2022-10-17 18:02:04 +00:00
|
|
|
|
}
|
|
|
|
|
if (!(-1 <= ban && ban <= 126)) {
|
|
|
|
|
luaL_argerror(L, 5, "require -1 <= ban <= 126");
|
2023-06-09 06:44:03 +00:00
|
|
|
|
__builtin_unreachable();
|
2022-10-17 18:02:04 +00:00
|
|
|
|
}
|
|
|
|
|
if (!(ignore <= reject)) {
|
|
|
|
|
luaL_argerror(L, 4, "require ignore <= reject");
|
2023-06-09 06:44:03 +00:00
|
|
|
|
__builtin_unreachable();
|
2022-10-17 18:02:04 +00:00
|
|
|
|
}
|
|
|
|
|
if (!(ban <= ignore)) {
|
|
|
|
|
luaL_argerror(L, 5, "require ban <= ignore");
|
2023-06-09 06:44:03 +00:00
|
|
|
|
__builtin_unreachable();
|
2022-10-17 18:02:04 +00:00
|
|
|
|
}
|
2023-01-03 13:15:04 +00:00
|
|
|
|
VERBOSEF("(token) deploying %,ld buckets "
|
|
|
|
|
"(one for every %ld ips) "
|
|
|
|
|
"each holding 127 tokens which "
|
|
|
|
|
"replenish %g times per second, "
|
|
|
|
|
"reject at %d tokens, "
|
|
|
|
|
"ignore at %d tokens, and "
|
|
|
|
|
"ban at %d tokens",
|
|
|
|
|
1L << cidr, //
|
|
|
|
|
4294967296 / (1L << cidr), //
|
|
|
|
|
replenish, //
|
|
|
|
|
reject, //
|
|
|
|
|
ignore, //
|
|
|
|
|
ban);
|
2022-10-17 18:02:04 +00:00
|
|
|
|
if (ignore == -1)
|
|
|
|
|
ignore = -128;
|
|
|
|
|
if (ban == -1)
|
|
|
|
|
ban = -128;
|
|
|
|
|
if (ban >= 0 && (IsLinux() || IsBsd())) {
|
2022-10-19 17:00:29 +00:00
|
|
|
|
uint32_t testip = 0;
|
|
|
|
|
blackhole.addr.sun_family = AF_UNIX;
|
|
|
|
|
strlcpy(blackhole.addr.sun_path, "/var/run/blackhole.sock",
|
|
|
|
|
sizeof(blackhole.addr.sun_path));
|
2023-07-25 12:43:04 +00:00
|
|
|
|
if ((blackhole.fd = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1) {
|
2022-10-19 20:10:00 +00:00
|
|
|
|
WARNF("(token) socket(AF_UNIX) failed: %m");
|
2022-10-17 18:02:04 +00:00
|
|
|
|
ban = -1;
|
2022-10-19 17:00:29 +00:00
|
|
|
|
} else if (sendto(blackhole.fd, &testip, 4, 0,
|
|
|
|
|
(struct sockaddr *)&blackhole.addr,
|
|
|
|
|
sizeof(blackhole.addr)) == -1) {
|
2023-01-03 13:14:34 +00:00
|
|
|
|
VERBOSEF("(token) error: sendto(%`'s) failed: %m",
|
|
|
|
|
blackhole.addr.sun_path);
|
|
|
|
|
VERBOSEF("(token) redbean isn't able to protect your kernel from ddos");
|
|
|
|
|
VERBOSEF("(token) please run the blackholed program; see our website!");
|
2022-10-17 18:02:04 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2024-07-07 19:24:25 +00:00
|
|
|
|
tokenbucket.b = _mapshared(ROUNDUP(1ul << cidr, getgransize()));
|
2022-10-17 18:02:04 +00:00
|
|
|
|
memset(tokenbucket.b, 127, 1ul << cidr);
|
|
|
|
|
tokenbucket.cidr = cidr;
|
|
|
|
|
tokenbucket.reject = reject;
|
|
|
|
|
tokenbucket.ignore = ignore;
|
|
|
|
|
tokenbucket.ban = ban;
|
2022-11-06 02:49:41 +00:00
|
|
|
|
tokenbucket.replenish = timespec_fromnanos(1 / replenish * 1e9);
|
2022-10-17 18:02:04 +00:00
|
|
|
|
int pid = fork();
|
2023-07-26 20:54:49 +00:00
|
|
|
|
npassert(pid != -1);
|
2022-10-17 18:02:04 +00:00
|
|
|
|
if (!pid)
|
|
|
|
|
Replenisher();
|
2024-12-02 22:05:38 +00:00
|
|
|
|
atomic_fetch_add_explicit(&shared->workers, 1, memory_order_acquire);
|
2022-10-17 18:02:04 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-23 05:02:58 +00:00
|
|
|
|
static const char *GetContentTypeExt(const char *path, size_t n) {
|
2023-12-28 09:08:19 +00:00
|
|
|
|
const char *r = NULL, *e;
|
|
|
|
|
if ((r = FindContentType(path, n)))
|
|
|
|
|
return r;
|
|
|
|
|
#ifndef STATIC
|
2022-08-23 05:02:58 +00:00
|
|
|
|
int top;
|
|
|
|
|
lua_State *L = GL;
|
|
|
|
|
|
|
|
|
|
// extract the last .; use the entire path if none is present
|
2023-10-02 05:45:44 +00:00
|
|
|
|
if ((e = memrchr(path, '.', n))) {
|
|
|
|
|
n -= e - path + 1;
|
|
|
|
|
path = e + 1;
|
|
|
|
|
}
|
2022-08-23 05:02:58 +00:00
|
|
|
|
top = lua_gettop(L);
|
|
|
|
|
lua_pushlightuserdata(L, (void *)&ctIdx); // push address as unique key
|
|
|
|
|
CHECK_EQ(lua_gettable(L, LUA_REGISTRYINDEX), LUA_TTABLE);
|
|
|
|
|
|
2023-10-02 05:45:44 +00:00
|
|
|
|
lua_pushlstring(L, path, n);
|
2022-08-23 05:02:58 +00:00
|
|
|
|
if (lua_gettable(L, -2) == LUA_TSTRING)
|
|
|
|
|
r = FreeLater(strdup(lua_tostring(L, -1)));
|
|
|
|
|
lua_settop(L, top);
|
2023-12-28 09:08:19 +00:00
|
|
|
|
#endif
|
2022-08-23 05:02:58 +00:00
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-24 16:35:17 +00:00
|
|
|
|
static int LuaProgramContentType(lua_State *L) {
|
2022-08-23 05:02:58 +00:00
|
|
|
|
const char *ext = luaL_checkstring(L, 1);
|
|
|
|
|
const char *ct;
|
|
|
|
|
int n = lua_gettop(L);
|
|
|
|
|
|
|
|
|
|
lua_pushlightuserdata(L, (void *)&ctIdx); // push address as unique key
|
|
|
|
|
CHECK_EQ(lua_gettable(L, LUA_REGISTRYINDEX), LUA_TTABLE);
|
|
|
|
|
|
|
|
|
|
if (n == 1) {
|
|
|
|
|
ext = FreeLater(xasprintf(".%s", ext));
|
|
|
|
|
if ((ct = GetContentTypeExt(ext, strlen(ext)))) {
|
|
|
|
|
lua_pushstring(L, ct);
|
|
|
|
|
} else {
|
|
|
|
|
lua_pushnil(L);
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
} else {
|
|
|
|
|
ct = luaL_checkstring(L, 2);
|
|
|
|
|
lua_pushstring(L, ext);
|
|
|
|
|
lua_pushstring(L, ct);
|
|
|
|
|
lua_settable(L, -3); // table[ext] = ct
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
static int LuaIsDaemon(lua_State *L) {
|
|
|
|
|
lua_pushboolean(L, daemonize);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-12 23:00:41 +00:00
|
|
|
|
static int LuaGetAssetComment(lua_State *L) {
|
2021-04-21 02:14:21 +00:00
|
|
|
|
struct Asset *a;
|
2021-04-23 17:45:19 +00:00
|
|
|
|
const char *path;
|
|
|
|
|
size_t pathlen, m;
|
|
|
|
|
path = LuaCheckPath(L, 1, &pathlen);
|
|
|
|
|
if ((a = GetAssetZip(path, pathlen)) &&
|
2023-06-17 11:20:16 +00:00
|
|
|
|
(m = strnlen(ZIP_CFILE_COMMENT(zmap + a->cf),
|
|
|
|
|
ZIP_CFILE_COMMENTSIZE(zmap + a->cf)))) {
|
|
|
|
|
lua_pushlstring(L, ZIP_CFILE_COMMENT(zmap + a->cf), m);
|
2021-04-21 02:14:21 +00:00
|
|
|
|
} else {
|
|
|
|
|
lua_pushnil(L);
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-18 14:24:36 +00:00
|
|
|
|
static int LuaLaunchBrowser(lua_State *L) {
|
2021-10-25 21:54:56 +00:00
|
|
|
|
OnlyCallFromInitLua(L, "LaunchBrowser");
|
2021-06-24 19:31:26 +00:00
|
|
|
|
launchbrowser = strdup(luaL_optstring(L, 1, "/"));
|
|
|
|
|
return 0;
|
2021-04-18 14:24:36 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-03-05 02:47:15 +00:00
|
|
|
|
static bool LuaRunAsset(const char *path, bool mandatory) {
|
2022-05-14 18:47:16 +00:00
|
|
|
|
int status;
|
2021-03-27 05:31:41 +00:00
|
|
|
|
struct Asset *a;
|
|
|
|
|
const char *code;
|
2021-08-09 20:09:14 +00:00
|
|
|
|
size_t pathlen, codelen;
|
2021-04-23 17:45:19 +00:00
|
|
|
|
pathlen = strlen(path);
|
|
|
|
|
if ((a = GetAsset(path, pathlen))) {
|
2021-08-12 06:27:39 +00:00
|
|
|
|
if ((code = FreeLater(LoadAsset(a, &codelen)))) {
|
2021-10-25 21:54:56 +00:00
|
|
|
|
lua_State *L = GL;
|
2023-09-02 03:49:13 +00:00
|
|
|
|
effectivepath.p = (void *)path;
|
2021-04-23 17:45:19 +00:00
|
|
|
|
effectivepath.n = pathlen;
|
2022-03-05 02:47:15 +00:00
|
|
|
|
DEBUGF("(lua) LuaRunAsset(%`'s)", path);
|
2022-06-27 20:01:58 +00:00
|
|
|
|
status = luaL_loadbuffer(
|
|
|
|
|
L, code, codelen,
|
2022-06-27 04:13:53 +00:00
|
|
|
|
FreeLater(xasprintf("@%s%s", a->file ? "" : "/zip", path)));
|
2022-03-22 01:07:30 +00:00
|
|
|
|
if (status != LUA_OK || LuaCallWithTrace(L, 0, 0, NULL) != LUA_OK) {
|
2021-08-22 22:01:52 +00:00
|
|
|
|
LogLuaError("lua code", lua_tostring(L, -1));
|
2022-03-18 09:33:37 +00:00
|
|
|
|
lua_pop(L, 1); // pop error
|
2021-08-12 06:27:39 +00:00
|
|
|
|
if (mandatory)
|
|
|
|
|
exit(1);
|
2021-04-21 02:14:21 +00:00
|
|
|
|
}
|
2021-03-27 05:31:41 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2021-04-23 17:45:19 +00:00
|
|
|
|
return !!a;
|
2021-03-27 05:31:41 +00:00
|
|
|
|
}
|
2021-03-25 09:21:13 +00:00
|
|
|
|
|
2022-04-24 16:59:22 +00:00
|
|
|
|
// <SORTED>
|
|
|
|
|
// list of functions that can't be run from the repl
|
|
|
|
|
static const char *const kDontAutoComplete[] = {
|
2022-07-08 16:47:04 +00:00
|
|
|
|
"Compress", // deprecated
|
2022-04-24 16:59:22 +00:00
|
|
|
|
"GetBody", //
|
|
|
|
|
"GetClientAddr", //
|
|
|
|
|
"GetClientFd", //
|
2022-06-24 01:54:35 +00:00
|
|
|
|
"GetComment", // deprecated
|
2022-04-24 16:59:22 +00:00
|
|
|
|
"GetCookie", //
|
|
|
|
|
"GetEffectivePath", //
|
|
|
|
|
"GetFragment", //
|
|
|
|
|
"GetHeader", //
|
|
|
|
|
"GetHeaders", //
|
|
|
|
|
"GetHost", //
|
|
|
|
|
"GetHttpVersion", //
|
2022-06-24 01:54:35 +00:00
|
|
|
|
"GetLastModifiedTime", // deprecated
|
2022-04-24 16:59:22 +00:00
|
|
|
|
"GetMethod", //
|
|
|
|
|
"GetParam", //
|
|
|
|
|
"GetParams", //
|
|
|
|
|
"GetPass", //
|
|
|
|
|
"GetPath", //
|
2022-06-24 01:54:35 +00:00
|
|
|
|
"GetPayload", // deprecated
|
2022-04-24 16:59:22 +00:00
|
|
|
|
"GetPort", //
|
|
|
|
|
"GetRemoteAddr", //
|
2022-07-22 18:22:39 +00:00
|
|
|
|
"GetResponseBody", //
|
2022-04-24 16:59:22 +00:00
|
|
|
|
"GetScheme", //
|
|
|
|
|
"GetServerAddr", //
|
|
|
|
|
"GetSslIdentity", //
|
|
|
|
|
"GetStatus", //
|
|
|
|
|
"GetUrl", //
|
|
|
|
|
"GetUser", //
|
2022-06-24 01:54:35 +00:00
|
|
|
|
"GetVersion", // deprecated
|
2022-04-24 16:59:22 +00:00
|
|
|
|
"HasParam", //
|
|
|
|
|
"IsClientUsingSsl", //
|
2022-06-24 01:54:35 +00:00
|
|
|
|
"IsCompressed", // deprecated
|
2022-04-24 16:59:22 +00:00
|
|
|
|
"LaunchBrowser", //
|
2022-06-10 10:28:46 +00:00
|
|
|
|
"LuaProgramSslRequired", // TODO
|
2022-04-24 16:59:22 +00:00
|
|
|
|
"ProgramAddr", // TODO
|
|
|
|
|
"ProgramBrand", //
|
|
|
|
|
"ProgramCertificate", // TODO
|
|
|
|
|
"ProgramGid", //
|
|
|
|
|
"ProgramLogPath", // TODO
|
2022-06-10 10:28:46 +00:00
|
|
|
|
"ProgramMaxPayloadSize", // TODO
|
2022-04-24 16:59:22 +00:00
|
|
|
|
"ProgramPidPath", // TODO
|
|
|
|
|
"ProgramPort", // TODO
|
|
|
|
|
"ProgramPrivateKey", // TODO
|
|
|
|
|
"ProgramSslCiphersuite", // TODO
|
|
|
|
|
"ProgramSslClientVerify", // TODO
|
|
|
|
|
"ProgramSslTicketLifetime", //
|
|
|
|
|
"ProgramTimeout", // TODO
|
|
|
|
|
"ProgramUid", //
|
|
|
|
|
"ProgramUniprocess", //
|
|
|
|
|
"Respond", //
|
|
|
|
|
"Route", //
|
|
|
|
|
"RouteHost", //
|
|
|
|
|
"RoutePath", //
|
|
|
|
|
"ServeAsset", //
|
|
|
|
|
"ServeIndex", //
|
|
|
|
|
"ServeListing", //
|
|
|
|
|
"ServeRedirect", //
|
|
|
|
|
"ServeStatusz", //
|
|
|
|
|
"SetCookie", //
|
|
|
|
|
"SetHeader", //
|
|
|
|
|
"SslInit", // TODO
|
2022-07-08 16:47:04 +00:00
|
|
|
|
"Uncompress", // deprecated
|
2022-04-24 16:59:22 +00:00
|
|
|
|
"Write", //
|
|
|
|
|
};
|
|
|
|
|
// </SORTED>
|
2022-04-13 15:49:17 +00:00
|
|
|
|
|
2021-03-22 00:27:53 +00:00
|
|
|
|
static const luaL_Reg kLuaFuncs[] = {
|
2022-07-23 03:44:24 +00:00
|
|
|
|
{"Barf", LuaBarf}, //
|
2022-06-26 01:17:31 +00:00
|
|
|
|
{"Benchmark", LuaBenchmark}, //
|
|
|
|
|
{"Bsf", LuaBsf}, //
|
|
|
|
|
{"Bsr", LuaBsr}, //
|
|
|
|
|
{"CategorizeIp", LuaCategorizeIp}, //
|
|
|
|
|
{"Compress", LuaCompress}, //
|
|
|
|
|
{"Crc32", LuaCrc32}, //
|
|
|
|
|
{"Crc32c", LuaCrc32c}, //
|
2024-01-20 09:06:19 +00:00
|
|
|
|
{"Curve25519", LuaCurve25519}, //
|
2022-06-26 01:17:31 +00:00
|
|
|
|
{"Decimate", LuaDecimate}, //
|
2023-10-12 03:06:20 +00:00
|
|
|
|
{"DecodeBase32", LuaDecodeBase32}, //
|
2022-06-26 01:17:31 +00:00
|
|
|
|
{"DecodeBase64", LuaDecodeBase64}, //
|
2023-07-06 22:38:08 +00:00
|
|
|
|
{"DecodeHex", LuaDecodeHex}, //
|
2022-07-10 00:34:41 +00:00
|
|
|
|
{"DecodeJson", LuaDecodeJson}, //
|
2022-06-26 01:17:31 +00:00
|
|
|
|
{"DecodeLatin1", LuaDecodeLatin1}, //
|
2022-07-08 16:47:04 +00:00
|
|
|
|
{"Deflate", LuaDeflate}, //
|
2023-10-12 03:06:20 +00:00
|
|
|
|
{"EncodeBase32", LuaEncodeBase32}, //
|
2022-06-26 01:17:31 +00:00
|
|
|
|
{"EncodeBase64", LuaEncodeBase64}, //
|
2023-07-06 22:38:08 +00:00
|
|
|
|
{"EncodeHex", LuaEncodeHex}, //
|
2022-06-26 01:17:31 +00:00
|
|
|
|
{"EncodeJson", LuaEncodeJson}, //
|
|
|
|
|
{"EncodeLatin1", LuaEncodeLatin1}, //
|
|
|
|
|
{"EncodeLua", LuaEncodeLua}, //
|
|
|
|
|
{"EncodeUrl", LuaEncodeUrl}, //
|
|
|
|
|
{"EscapeFragment", LuaEscapeFragment}, //
|
|
|
|
|
{"EscapeHost", LuaEscapeHost}, //
|
|
|
|
|
{"EscapeHtml", LuaEscapeHtml}, //
|
|
|
|
|
{"EscapeIp", LuaEscapeIp}, //
|
|
|
|
|
{"EscapeLiteral", LuaEscapeLiteral}, //
|
|
|
|
|
{"EscapeParam", LuaEscapeParam}, //
|
|
|
|
|
{"EscapePass", LuaEscapePass}, //
|
|
|
|
|
{"EscapePath", LuaEscapePath}, //
|
|
|
|
|
{"EscapeSegment", LuaEscapeSegment}, //
|
|
|
|
|
{"EscapeUser", LuaEscapeUser}, //
|
|
|
|
|
{"Fetch", LuaFetch}, //
|
|
|
|
|
{"FormatHttpDateTime", LuaFormatHttpDateTime}, //
|
|
|
|
|
{"FormatIp", LuaFormatIp}, //
|
|
|
|
|
{"GetAssetComment", LuaGetAssetComment}, //
|
2022-06-24 01:54:35 +00:00
|
|
|
|
{"GetAssetLastModifiedTime", LuaGetAssetLastModifiedTime}, //
|
2022-06-26 01:17:31 +00:00
|
|
|
|
{"GetAssetMode", LuaGetAssetMode}, //
|
|
|
|
|
{"GetAssetSize", LuaGetAssetSize}, //
|
|
|
|
|
{"GetBody", LuaGetBody}, //
|
|
|
|
|
{"GetClientAddr", LuaGetClientAddr}, //
|
|
|
|
|
{"GetClientFd", LuaGetClientFd}, //
|
|
|
|
|
{"GetCookie", LuaGetCookie}, //
|
|
|
|
|
{"GetCpuCore", LuaGetCpuCore}, //
|
|
|
|
|
{"GetCpuCount", LuaGetCpuCount}, //
|
|
|
|
|
{"GetCpuNode", LuaGetCpuNode}, //
|
|
|
|
|
{"GetCryptoHash", LuaGetCryptoHash}, //
|
|
|
|
|
{"GetDate", LuaGetDate}, //
|
|
|
|
|
{"GetEffectivePath", LuaGetEffectivePath}, //
|
|
|
|
|
{"GetFragment", LuaGetFragment}, //
|
|
|
|
|
{"GetHeader", LuaGetHeader}, //
|
|
|
|
|
{"GetHeaders", LuaGetHeaders}, //
|
|
|
|
|
{"GetHost", LuaGetHost}, //
|
2023-06-03 15:12:13 +00:00
|
|
|
|
{"GetHostIsa", LuaGetHostIsa}, //
|
2022-06-26 01:17:31 +00:00
|
|
|
|
{"GetHostOs", LuaGetHostOs}, //
|
|
|
|
|
{"GetHttpReason", LuaGetHttpReason}, //
|
|
|
|
|
{"GetHttpVersion", LuaGetHttpVersion}, //
|
|
|
|
|
{"GetLogLevel", LuaGetLogLevel}, //
|
|
|
|
|
{"GetMethod", LuaGetMethod}, //
|
|
|
|
|
{"GetMonospaceWidth", LuaGetMonospaceWidth}, //
|
|
|
|
|
{"GetParam", LuaGetParam}, //
|
|
|
|
|
{"GetParams", LuaGetParams}, //
|
|
|
|
|
{"GetPass", LuaGetPass}, //
|
|
|
|
|
{"GetPath", LuaGetPath}, //
|
|
|
|
|
{"GetPort", LuaGetPort}, //
|
|
|
|
|
{"GetRandomBytes", LuaGetRandomBytes}, //
|
|
|
|
|
{"GetRedbeanVersion", LuaGetRedbeanVersion}, //
|
|
|
|
|
{"GetRemoteAddr", LuaGetRemoteAddr}, //
|
2022-07-22 18:22:39 +00:00
|
|
|
|
{"GetResponseBody", LuaGetResponseBody}, //
|
2022-06-26 01:17:31 +00:00
|
|
|
|
{"GetScheme", LuaGetScheme}, //
|
|
|
|
|
{"GetServerAddr", LuaGetServerAddr}, //
|
|
|
|
|
{"GetStatus", LuaGetStatus}, //
|
|
|
|
|
{"GetTime", LuaGetTime}, //
|
|
|
|
|
{"GetUrl", LuaGetUrl}, //
|
|
|
|
|
{"GetUser", LuaGetUser}, //
|
|
|
|
|
{"GetZipPaths", LuaGetZipPaths}, //
|
|
|
|
|
{"HasControlCodes", LuaHasControlCodes}, //
|
|
|
|
|
{"HasParam", LuaHasParam}, //
|
|
|
|
|
{"HidePath", LuaHidePath}, //
|
2023-07-06 22:38:08 +00:00
|
|
|
|
{"HighwayHash64", LuaHighwayHash64}, //
|
2022-06-26 01:17:31 +00:00
|
|
|
|
{"IndentLines", LuaIndentLines}, //
|
2022-07-08 16:47:04 +00:00
|
|
|
|
{"Inflate", LuaInflate}, //
|
2022-06-26 01:17:31 +00:00
|
|
|
|
{"IsAcceptableHost", LuaIsAcceptableHost}, //
|
|
|
|
|
{"IsAcceptablePath", LuaIsAcceptablePath}, //
|
|
|
|
|
{"IsAcceptablePort", LuaIsAcceptablePort}, //
|
|
|
|
|
{"IsAssetCompressed", LuaIsAssetCompressed}, //
|
2022-07-08 16:47:04 +00:00
|
|
|
|
{"IsClientUsingSsl", LuaIsClientUsingSsl}, //
|
2022-06-26 01:17:31 +00:00
|
|
|
|
{"IsDaemon", LuaIsDaemon}, //
|
|
|
|
|
{"IsHeaderRepeatable", LuaIsHeaderRepeatable}, //
|
|
|
|
|
{"IsHiddenPath", LuaIsHiddenPath}, //
|
|
|
|
|
{"IsLoopbackIp", LuaIsLoopbackIp}, //
|
|
|
|
|
{"IsPrivateIp", LuaIsPrivateIp}, //
|
|
|
|
|
{"IsPublicIp", LuaIsPublicIp}, //
|
|
|
|
|
{"IsReasonablePath", LuaIsReasonablePath}, //
|
2022-10-17 18:02:04 +00:00
|
|
|
|
{"IsTrustedIp", LuaIsTrusted}, // undocumented
|
2022-06-26 01:17:31 +00:00
|
|
|
|
{"IsValidHttpToken", LuaIsValidHttpToken}, //
|
|
|
|
|
{"LaunchBrowser", LuaLaunchBrowser}, //
|
|
|
|
|
{"Lemur64", LuaLemur64}, //
|
|
|
|
|
{"LoadAsset", LuaLoadAsset}, //
|
|
|
|
|
{"Log", LuaLog}, //
|
|
|
|
|
{"Md5", LuaMd5}, //
|
|
|
|
|
{"MeasureEntropy", LuaMeasureEntropy}, //
|
|
|
|
|
{"ParseHost", LuaParseHost}, //
|
|
|
|
|
{"ParseHttpDateTime", LuaParseHttpDateTime}, //
|
|
|
|
|
{"ParseIp", LuaParseIp}, //
|
|
|
|
|
{"ParseParams", LuaParseParams}, //
|
|
|
|
|
{"ParseUrl", LuaParseUrl}, //
|
|
|
|
|
{"Popcnt", LuaPopcnt}, //
|
|
|
|
|
{"ProgramAddr", LuaProgramAddr}, //
|
|
|
|
|
{"ProgramBrand", LuaProgramBrand}, //
|
|
|
|
|
{"ProgramCache", LuaProgramCache}, //
|
2022-08-24 16:35:17 +00:00
|
|
|
|
{"ProgramContentType", LuaProgramContentType}, //
|
2022-06-26 01:17:31 +00:00
|
|
|
|
{"ProgramDirectory", LuaProgramDirectory}, //
|
|
|
|
|
{"ProgramGid", LuaProgramGid}, //
|
|
|
|
|
{"ProgramHeader", LuaProgramHeader}, //
|
2022-08-03 03:41:44 +00:00
|
|
|
|
{"ProgramHeartbeatInterval", LuaProgramHeartbeatInterval}, //
|
2022-06-26 01:17:31 +00:00
|
|
|
|
{"ProgramLogBodies", LuaProgramLogBodies}, //
|
|
|
|
|
{"ProgramLogMessages", LuaProgramLogMessages}, //
|
|
|
|
|
{"ProgramLogPath", LuaProgramLogPath}, //
|
|
|
|
|
{"ProgramMaxPayloadSize", LuaProgramMaxPayloadSize}, //
|
2022-09-17 08:37:33 +00:00
|
|
|
|
{"ProgramMaxWorkers", LuaProgramMaxWorkers}, //
|
2022-06-26 01:17:31 +00:00
|
|
|
|
{"ProgramPidPath", LuaProgramPidPath}, //
|
|
|
|
|
{"ProgramPort", LuaProgramPort}, //
|
|
|
|
|
{"ProgramRedirect", LuaProgramRedirect}, //
|
|
|
|
|
{"ProgramTimeout", LuaProgramTimeout}, //
|
2022-10-17 18:02:04 +00:00
|
|
|
|
{"ProgramTrustedIp", LuaProgramTrustedIp}, // undocumented
|
2022-06-26 01:17:31 +00:00
|
|
|
|
{"ProgramUid", LuaProgramUid}, //
|
|
|
|
|
{"ProgramUniprocess", LuaProgramUniprocess}, //
|
|
|
|
|
{"Rand64", LuaRand64}, //
|
|
|
|
|
{"Rdrand", LuaRdrand}, //
|
|
|
|
|
{"Rdseed", LuaRdseed}, //
|
|
|
|
|
{"Rdtsc", LuaRdtsc}, //
|
|
|
|
|
{"ResolveIp", LuaResolveIp}, //
|
|
|
|
|
{"Route", LuaRoute}, //
|
|
|
|
|
{"RouteHost", LuaRouteHost}, //
|
|
|
|
|
{"RoutePath", LuaRoutePath}, //
|
|
|
|
|
{"ServeAsset", LuaServeAsset}, //
|
|
|
|
|
{"ServeError", LuaServeError}, //
|
|
|
|
|
{"ServeIndex", LuaServeIndex}, //
|
|
|
|
|
{"ServeListing", LuaServeListing}, //
|
|
|
|
|
{"ServeRedirect", LuaServeRedirect}, //
|
|
|
|
|
{"ServeStatusz", LuaServeStatusz}, //
|
|
|
|
|
{"SetCookie", LuaSetCookie}, //
|
|
|
|
|
{"SetHeader", LuaSetHeader}, //
|
|
|
|
|
{"SetLogLevel", LuaSetLogLevel}, //
|
|
|
|
|
{"SetStatus", LuaSetStatus}, //
|
|
|
|
|
{"Sha1", LuaSha1}, //
|
|
|
|
|
{"Sha224", LuaSha224}, //
|
|
|
|
|
{"Sha256", LuaSha256}, //
|
|
|
|
|
{"Sha384", LuaSha384}, //
|
|
|
|
|
{"Sha512", LuaSha512}, //
|
|
|
|
|
{"Sleep", LuaSleep}, //
|
|
|
|
|
{"Slurp", LuaSlurp}, //
|
|
|
|
|
{"StoreAsset", LuaStoreAsset}, //
|
|
|
|
|
{"Uncompress", LuaUncompress}, //
|
|
|
|
|
{"Underlong", LuaUnderlong}, //
|
2024-04-12 15:10:27 +00:00
|
|
|
|
{"UuidV4", LuaUuidV4}, //
|
2024-07-01 13:06:56 +00:00
|
|
|
|
{"UuidV7", LuaUuidV7}, //
|
2022-06-26 01:17:31 +00:00
|
|
|
|
{"VisualizeControlCodes", LuaVisualizeControlCodes}, //
|
|
|
|
|
{"Write", LuaWrite}, //
|
|
|
|
|
{"bin", LuaBin}, //
|
|
|
|
|
{"hex", LuaHex}, //
|
|
|
|
|
{"oct", LuaOct}, //
|
2022-03-22 02:31:03 +00:00
|
|
|
|
#ifndef UNSECURE
|
2022-10-17 18:02:04 +00:00
|
|
|
|
{"AcquireToken", LuaAcquireToken}, //
|
2022-10-19 20:10:00 +00:00
|
|
|
|
{"Blackhole", LuaBlackhole}, // undocumented
|
2022-10-17 18:02:04 +00:00
|
|
|
|
{"CountTokens", LuaCountTokens}, //
|
2022-03-22 02:31:03 +00:00
|
|
|
|
{"EvadeDragnetSurveillance", LuaEvadeDragnetSurveillance}, //
|
2022-03-15 00:11:05 +00:00
|
|
|
|
{"GetSslIdentity", LuaGetSslIdentity}, //
|
2022-05-29 15:14:55 +00:00
|
|
|
|
{"ProgramCertificate", LuaProgramCertificate}, //
|
|
|
|
|
{"ProgramPrivateKey", LuaProgramPrivateKey}, //
|
2021-08-09 14:00:23 +00:00
|
|
|
|
{"ProgramSslCiphersuite", LuaProgramSslCiphersuite}, //
|
2021-07-19 21:55:20 +00:00
|
|
|
|
{"ProgramSslClientVerify", LuaProgramSslClientVerify}, //
|
|
|
|
|
{"ProgramSslFetchVerify", LuaProgramSslFetchVerify}, //
|
2022-03-22 02:31:03 +00:00
|
|
|
|
{"ProgramSslInit", LuaProgramSslInit}, //
|
2021-08-09 14:00:23 +00:00
|
|
|
|
{"ProgramSslPresharedKey", LuaProgramSslPresharedKey}, //
|
2022-05-29 15:14:55 +00:00
|
|
|
|
{"ProgramSslRequired", LuaProgramSslRequired}, //
|
2021-07-19 21:55:20 +00:00
|
|
|
|
{"ProgramSslTicketLifetime", LuaProgramSslTicketLifetime}, //
|
2022-10-17 18:02:04 +00:00
|
|
|
|
{"ProgramTokenBucket", LuaProgramTokenBucket}, //
|
2022-03-22 02:31:03 +00:00
|
|
|
|
#endif
|
2022-06-24 01:54:35 +00:00
|
|
|
|
// deprecated
|
2022-06-26 01:17:31 +00:00
|
|
|
|
{"GetPayload", LuaGetBody}, //
|
|
|
|
|
{"GetComment", LuaGetAssetComment}, //
|
|
|
|
|
{"GetVersion", LuaGetHttpVersion}, //
|
|
|
|
|
{"IsCompressed", LuaIsAssetCompressed}, //
|
|
|
|
|
{"GetLastModifiedTime", LuaGetAssetLastModifiedTime}, //
|
2021-04-23 17:45:19 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const luaL_Reg kLuaLibs[] = {
|
2022-05-29 15:14:55 +00:00
|
|
|
|
{"argon2", luaopen_argon2}, //
|
2022-06-19 07:59:07 +00:00
|
|
|
|
{"lsqlite3", luaopen_lsqlite3}, //
|
|
|
|
|
{"maxmind", LuaMaxmind}, //
|
2022-07-17 09:40:39 +00:00
|
|
|
|
{"finger", LuaFinger}, //
|
2022-07-20 22:13:39 +00:00
|
|
|
|
{"path", LuaPath}, //
|
2022-06-19 07:59:07 +00:00
|
|
|
|
{"re", LuaRe}, //
|
|
|
|
|
{"unix", LuaUnix}, //
|
2021-03-22 00:27:53 +00:00
|
|
|
|
};
|
|
|
|
|
|
2021-03-29 08:22:49 +00:00
|
|
|
|
static void LuaSetArgv(lua_State *L) {
|
2022-04-25 15:30:14 +00:00
|
|
|
|
int i, j = -1;
|
2021-03-27 14:29:55 +00:00
|
|
|
|
lua_newtable(L);
|
2022-04-25 15:30:14 +00:00
|
|
|
|
lua_pushstring(L, __argv[0]);
|
|
|
|
|
lua_seti(L, -2, j++);
|
|
|
|
|
if (!interpretermode) {
|
|
|
|
|
lua_pushstring(L, "/zip/.init.lua");
|
|
|
|
|
lua_seti(L, -2, j++);
|
|
|
|
|
}
|
2021-03-27 14:29:55 +00:00
|
|
|
|
for (i = optind; i < __argc; ++i) {
|
|
|
|
|
lua_pushstring(L, __argv[i]);
|
2022-04-25 15:30:14 +00:00
|
|
|
|
lua_seti(L, -2, j++);
|
2021-03-27 14:29:55 +00:00
|
|
|
|
}
|
2022-04-25 15:30:14 +00:00
|
|
|
|
lua_pushvalue(L, -1);
|
|
|
|
|
lua_setglobal(L, "argv"); // deprecated
|
|
|
|
|
lua_setglobal(L, "arg");
|
2021-03-27 14:29:55 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-03-29 08:22:49 +00:00
|
|
|
|
static void LuaSetConstant(lua_State *L, const char *s, long x) {
|
|
|
|
|
lua_pushinteger(L, x);
|
|
|
|
|
lua_setglobal(L, s);
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-05 02:47:15 +00:00
|
|
|
|
static void LuaStart(void) {
|
2021-04-21 02:14:21 +00:00
|
|
|
|
#ifndef STATIC
|
2021-03-22 00:27:53 +00:00
|
|
|
|
size_t i;
|
2021-10-25 21:54:56 +00:00
|
|
|
|
lua_State *L = GL = luaL_newstate();
|
2023-08-17 07:43:11 +00:00
|
|
|
|
g_lua_path_default = DEFAULTLUAPATH;
|
2021-03-27 05:31:41 +00:00
|
|
|
|
luaL_openlibs(L);
|
2021-04-23 17:45:19 +00:00
|
|
|
|
for (i = 0; i < ARRAYLEN(kLuaLibs); ++i) {
|
|
|
|
|
luaL_requiref(L, kLuaLibs[i].name, kLuaLibs[i].func, 1);
|
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
}
|
2021-03-22 00:27:53 +00:00
|
|
|
|
for (i = 0; i < ARRAYLEN(kLuaFuncs); ++i) {
|
|
|
|
|
lua_pushcfunction(L, kLuaFuncs[i].func);
|
|
|
|
|
lua_setglobal(L, kLuaFuncs[i].name);
|
|
|
|
|
}
|
2021-03-29 08:22:49 +00:00
|
|
|
|
LuaSetConstant(L, "kLogDebug", kLogDebug);
|
|
|
|
|
LuaSetConstant(L, "kLogVerbose", kLogVerbose);
|
|
|
|
|
LuaSetConstant(L, "kLogInfo", kLogInfo);
|
|
|
|
|
LuaSetConstant(L, "kLogWarn", kLogWarn);
|
|
|
|
|
LuaSetConstant(L, "kLogError", kLogError);
|
|
|
|
|
LuaSetConstant(L, "kLogFatal", kLogFatal);
|
2022-09-20 02:23:24 +00:00
|
|
|
|
LuaSetConstant(L, "kUrlPlus", kUrlPlus);
|
|
|
|
|
LuaSetConstant(L, "kUrlLatin1", kUrlLatin1);
|
2022-08-23 05:02:58 +00:00
|
|
|
|
// create a list of custom content types
|
|
|
|
|
lua_pushlightuserdata(L, (void *)&ctIdx); // push address as unique key
|
|
|
|
|
lua_newtable(L);
|
|
|
|
|
lua_settable(L, LUA_REGISTRYINDEX); // registry[&ctIdx] = {}
|
2022-03-05 02:47:15 +00:00
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-25 15:30:14 +00:00
|
|
|
|
static bool ShouldAutocomplete(const char *s) {
|
|
|
|
|
int c, m, l, r;
|
|
|
|
|
l = 0;
|
|
|
|
|
r = ARRAYLEN(kDontAutoComplete) - 1;
|
|
|
|
|
while (l <= r) {
|
2023-07-10 17:16:55 +00:00
|
|
|
|
m = (l & r) + ((l ^ r) >> 1); // floor((a+b)/2)
|
2022-04-25 15:30:14 +00:00
|
|
|
|
c = strcmp(kDontAutoComplete[m], s);
|
|
|
|
|
if (c < 0) {
|
|
|
|
|
l = m + 1;
|
|
|
|
|
} else if (c > 0) {
|
|
|
|
|
r = m - 1;
|
|
|
|
|
} else {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void HandleCompletions(const char *p, linenoiseCompletions *c) {
|
|
|
|
|
size_t i, j;
|
|
|
|
|
for (j = i = 0; i < c->len; ++i) {
|
|
|
|
|
if (ShouldAutocomplete(c->cvec[i])) {
|
|
|
|
|
c->cvec[j++] = c->cvec[i];
|
|
|
|
|
} else {
|
|
|
|
|
free(c->cvec[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
c->len = j;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void LuaPrint(lua_State *L) {
|
|
|
|
|
int i, n;
|
|
|
|
|
char *b = 0;
|
|
|
|
|
n = lua_gettop(L);
|
2022-04-25 16:31:28 +00:00
|
|
|
|
if (n > 0) {
|
|
|
|
|
for (i = 1; i <= n; i++) {
|
|
|
|
|
if (i > 1)
|
|
|
|
|
appendw(&b, '\t');
|
2022-07-22 17:10:33 +00:00
|
|
|
|
struct EncoderConfig conf = {
|
|
|
|
|
.maxdepth = 64,
|
|
|
|
|
.sorted = true,
|
|
|
|
|
.pretty = true,
|
|
|
|
|
.indent = " ",
|
|
|
|
|
};
|
|
|
|
|
LuaEncodeLuaData(L, &b, i, conf);
|
2022-04-25 16:31:28 +00:00
|
|
|
|
}
|
|
|
|
|
appendw(&b, '\n');
|
|
|
|
|
WRITE(1, b, appendz(b).i);
|
|
|
|
|
free(b);
|
2022-04-25 15:30:14 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-26 01:17:31 +00:00
|
|
|
|
static void EnableRawMode(void) {
|
|
|
|
|
if (lua_repl_isterminal) {
|
2022-11-02 05:36:03 +00:00
|
|
|
|
strace_enabled(-1);
|
2022-06-26 01:17:31 +00:00
|
|
|
|
linenoiseEnableRawMode(0);
|
2022-11-02 05:36:03 +00:00
|
|
|
|
strace_enabled(+1);
|
2022-06-26 01:17:31 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void DisableRawMode(void) {
|
2022-11-02 05:36:03 +00:00
|
|
|
|
strace_enabled(-1);
|
2022-06-26 01:17:31 +00:00
|
|
|
|
linenoiseDisableRawMode();
|
2022-11-02 05:36:03 +00:00
|
|
|
|
strace_enabled(+1);
|
2022-06-26 01:17:31 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-07-08 16:47:04 +00:00
|
|
|
|
static int LuaInterpreter(lua_State *L) {
|
2022-04-25 15:30:14 +00:00
|
|
|
|
int i, n, sig, status;
|
|
|
|
|
const char *script;
|
|
|
|
|
if (optind < __argc) {
|
|
|
|
|
script = __argv[optind];
|
|
|
|
|
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);
|
|
|
|
|
lua_remove(L, -i); // remove arg table from stack
|
2022-04-29 13:06:23 +00:00
|
|
|
|
TRACE_BEGIN;
|
2022-04-25 15:30:14 +00:00
|
|
|
|
status = lua_runchunk(L, n, LUA_MULTRET);
|
2022-04-29 13:06:23 +00:00
|
|
|
|
TRACE_END;
|
2022-04-25 15:30:14 +00:00
|
|
|
|
}
|
2022-07-08 16:47:04 +00:00
|
|
|
|
return lua_report(L, status);
|
2022-04-25 15:30:14 +00:00
|
|
|
|
} else {
|
|
|
|
|
lua_repl_blocking = true;
|
|
|
|
|
lua_repl_completions_callback = HandleCompletions;
|
2023-07-09 12:11:25 +00:00
|
|
|
|
lua_initrepl(GL);
|
2022-06-26 01:17:31 +00:00
|
|
|
|
EnableRawMode();
|
2022-04-25 15:30:14 +00:00
|
|
|
|
for (;;) {
|
|
|
|
|
status = lua_loadline(L);
|
|
|
|
|
if (status == -1)
|
|
|
|
|
break; // eof
|
|
|
|
|
if (status == -2) {
|
|
|
|
|
if (errno == EINTR) {
|
|
|
|
|
if ((sig = linenoiseGetInterrupt())) {
|
2022-05-14 18:47:16 +00:00
|
|
|
|
kill(0, sig);
|
2022-04-25 15:30:14 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
fprintf(stderr, "i/o error: %m\n");
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
if (status == LUA_OK) {
|
2022-04-29 13:06:23 +00:00
|
|
|
|
TRACE_BEGIN;
|
2022-04-25 15:30:14 +00:00
|
|
|
|
status = lua_runchunk(GL, 0, LUA_MULTRET);
|
2022-04-29 13:06:23 +00:00
|
|
|
|
TRACE_END;
|
2022-04-25 15:30:14 +00:00
|
|
|
|
}
|
|
|
|
|
if (status == LUA_OK) {
|
|
|
|
|
LuaPrint(GL);
|
|
|
|
|
} else {
|
|
|
|
|
lua_report(GL, status);
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-06-26 01:17:31 +00:00
|
|
|
|
DisableRawMode();
|
2022-04-25 15:30:14 +00:00
|
|
|
|
lua_freerepl();
|
|
|
|
|
lua_settop(GL, 0); // clear stack
|
|
|
|
|
if ((sig = linenoiseGetInterrupt())) {
|
|
|
|
|
raise(sig);
|
|
|
|
|
}
|
2022-07-08 16:47:04 +00:00
|
|
|
|
return status;
|
2022-04-25 15:30:14 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-09 11:09:51 +00:00
|
|
|
|
static void LuaDestroy(void) {
|
|
|
|
|
#ifndef STATIC
|
|
|
|
|
lua_State *L = GL;
|
|
|
|
|
lua_close(L);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void MemDestroy(void) {
|
|
|
|
|
FreeAssets();
|
|
|
|
|
CollectGarbage();
|
|
|
|
|
inbuf.p = 0, inbuf.n = 0, inbuf.c = 0;
|
|
|
|
|
Free(&inbuf_actual.p), inbuf_actual.n = inbuf_actual.c = 0;
|
|
|
|
|
Free(&unmaplist.p), unmaplist.n = unmaplist.c = 0;
|
|
|
|
|
Free(&freelist.p), freelist.n = freelist.c = 0;
|
|
|
|
|
Free(&hdrbuf.p), hdrbuf.n = hdrbuf.c = 0;
|
|
|
|
|
Free(&servers.p), servers.n = 0;
|
|
|
|
|
Free(&ports.p), ports.n = 0;
|
|
|
|
|
Free(&ips.p), ips.n = 0;
|
2022-08-06 00:34:53 +00:00
|
|
|
|
Free(&cpm.outbuf);
|
2022-07-09 11:09:51 +00:00
|
|
|
|
FreeStrings(&stagedirs);
|
|
|
|
|
FreeStrings(&hidepaths);
|
2023-09-02 03:49:13 +00:00
|
|
|
|
Free(&cachedirective);
|
2022-07-09 11:09:51 +00:00
|
|
|
|
Free(&launchbrowser);
|
|
|
|
|
Free(&serverheader);
|
2022-10-17 18:02:04 +00:00
|
|
|
|
Free(&trustedips.p);
|
|
|
|
|
Free(&interfaces);
|
2022-07-09 11:09:51 +00:00
|
|
|
|
Free(&extrahdrs);
|
|
|
|
|
Free(&pidpath);
|
|
|
|
|
Free(&logpath);
|
|
|
|
|
Free(&brand);
|
|
|
|
|
Free(&polls);
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-05 02:47:15 +00:00
|
|
|
|
static void LuaInit(void) {
|
|
|
|
|
#ifndef STATIC
|
|
|
|
|
lua_State *L = GL;
|
|
|
|
|
LuaSetArgv(L);
|
2022-04-25 15:30:14 +00:00
|
|
|
|
if (interpretermode) {
|
2022-07-09 06:06:46 +00:00
|
|
|
|
int rc = LuaInterpreter(L);
|
2022-07-09 11:09:51 +00:00
|
|
|
|
LuaDestroy();
|
|
|
|
|
MemDestroy();
|
2022-07-09 06:06:46 +00:00
|
|
|
|
if (IsModeDbg()) {
|
|
|
|
|
CheckForMemoryLeaks();
|
|
|
|
|
}
|
|
|
|
|
exit(rc);
|
2022-04-25 15:30:14 +00:00
|
|
|
|
}
|
2022-03-05 02:47:15 +00:00
|
|
|
|
if (LuaRunAsset("/.init.lua", true)) {
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
hasonhttprequest = IsHookDefined("OnHttpRequest");
|
2024-02-14 09:55:50 +00:00
|
|
|
|
hasonerror = IsHookDefined("OnError");
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
hasonclientconnection = IsHookDefined("OnClientConnection");
|
|
|
|
|
hasonprocesscreate = IsHookDefined("OnProcessCreate");
|
|
|
|
|
hasonprocessdestroy = IsHookDefined("OnProcessDestroy");
|
|
|
|
|
hasonworkerstart = IsHookDefined("OnWorkerStart");
|
|
|
|
|
hasonworkerstop = IsHookDefined("OnWorkerStop");
|
2022-07-19 03:17:14 +00:00
|
|
|
|
hasonloglatency = IsHookDefined("OnLogLatency");
|
2021-04-25 00:09:01 +00:00
|
|
|
|
} else {
|
2021-08-22 22:01:52 +00:00
|
|
|
|
DEBUGF("(srvr) no /.init.lua defined");
|
2021-04-23 17:45:19 +00:00
|
|
|
|
}
|
2021-04-21 02:14:21 +00:00
|
|
|
|
#endif
|
2021-03-27 05:31:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-08-17 07:42:23 +00:00
|
|
|
|
static void LuaOnServerReload(bool reindex) {
|
2021-04-21 02:14:21 +00:00
|
|
|
|
#ifndef STATIC
|
2022-03-05 02:47:15 +00:00
|
|
|
|
if (!LuaRunAsset("/.reload.lua", false)) {
|
2021-08-22 22:01:52 +00:00
|
|
|
|
DEBUGF("(srvr) no /.reload.lua defined");
|
2021-04-23 17:45:19 +00:00
|
|
|
|
}
|
2023-08-17 07:42:23 +00:00
|
|
|
|
|
|
|
|
|
lua_State *L = GL;
|
|
|
|
|
lua_getglobal(L, "OnServerReload");
|
|
|
|
|
lua_pushboolean(L, reindex);
|
|
|
|
|
if (LuaCallWithTrace(L, 1, 0, NULL) != LUA_OK) {
|
|
|
|
|
LogLuaError("OnServerReload", lua_tostring(L, -1));
|
|
|
|
|
lua_pop(L, 1); // pop error
|
|
|
|
|
}
|
|
|
|
|
AssertLuaStackIsAt(L, 0);
|
2021-04-23 17:45:19 +00:00
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-03 19:09:35 +00:00
|
|
|
|
static const char *DescribeClose(void) {
|
|
|
|
|
if (killed)
|
|
|
|
|
return "killed";
|
|
|
|
|
if (meltdown)
|
|
|
|
|
return "meltdown";
|
|
|
|
|
if (terminated)
|
|
|
|
|
return "terminated";
|
2022-07-08 14:14:50 +00:00
|
|
|
|
if (connectionclose)
|
|
|
|
|
return "connection closed";
|
2021-05-03 19:09:35 +00:00
|
|
|
|
return "destroyed";
|
2021-04-23 17:45:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-05-03 19:09:35 +00:00
|
|
|
|
static void LogClose(const char *reason) {
|
|
|
|
|
if (amtread || meltdown || killed) {
|
|
|
|
|
LockInc(&shared->c.fumbles);
|
2021-09-04 04:14:26 +00:00
|
|
|
|
INFOF("(stat) %s %s with %,ld unprocessed and %,d handled (%,d workers)",
|
2024-12-02 22:05:38 +00:00
|
|
|
|
DescribeClient(), reason, amtread, messageshandled,
|
|
|
|
|
atomic_load_explicit(&shared->workers, memory_order_relaxed));
|
2021-05-03 19:09:35 +00:00
|
|
|
|
} else {
|
2022-05-16 20:20:08 +00:00
|
|
|
|
DEBUGF("(stat) %s %s with %,d messages handled", DescribeClient(), reason,
|
2021-05-03 19:09:35 +00:00
|
|
|
|
messageshandled);
|
2021-05-02 18:50:43 +00:00
|
|
|
|
}
|
2021-03-22 00:27:53 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-04-25 00:09:01 +00:00
|
|
|
|
static ssize_t SendString(const char *s) {
|
|
|
|
|
size_t n;
|
|
|
|
|
ssize_t rc;
|
2021-06-24 19:31:26 +00:00
|
|
|
|
struct iovec iov;
|
2021-04-25 00:09:01 +00:00
|
|
|
|
n = strlen(s);
|
2023-09-02 03:49:13 +00:00
|
|
|
|
iov.iov_base = (void *)s;
|
2021-06-24 19:31:26 +00:00
|
|
|
|
iov.iov_len = n;
|
2021-07-08 22:56:23 +00:00
|
|
|
|
if (logmessages) {
|
|
|
|
|
LogMessage("sending", s, n);
|
|
|
|
|
}
|
2021-04-25 00:09:01 +00:00
|
|
|
|
for (;;) {
|
2021-06-24 19:31:26 +00:00
|
|
|
|
if ((rc = writer(client, &iov, 1)) != -1 || errno != EINTR) {
|
2021-04-25 00:09:01 +00:00
|
|
|
|
return rc;
|
2021-03-29 08:22:49 +00:00
|
|
|
|
}
|
2022-03-19 10:37:00 +00:00
|
|
|
|
errno = 0;
|
2021-04-18 18:34:59 +00:00
|
|
|
|
}
|
2021-04-25 00:09:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static ssize_t SendContinue(void) {
|
|
|
|
|
return SendString("\
|
|
|
|
|
HTTP/1.1 100 Continue\r\n\
|
|
|
|
|
\r\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static ssize_t SendTimeout(void) {
|
|
|
|
|
return SendString("\
|
|
|
|
|
HTTP/1.1 408 Request Timeout\r\n\
|
|
|
|
|
Connection: close\r\n\
|
|
|
|
|
Content-Length: 0\r\n\
|
|
|
|
|
\r\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static ssize_t SendServiceUnavailable(void) {
|
|
|
|
|
return SendString("\
|
|
|
|
|
HTTP/1.1 503 Service Unavailable\r\n\
|
|
|
|
|
Connection: close\r\n\
|
|
|
|
|
Content-Length: 0\r\n\
|
|
|
|
|
\r\n");
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-17 18:02:04 +00:00
|
|
|
|
static ssize_t SendTooManyRequests(void) {
|
|
|
|
|
return SendString("\
|
|
|
|
|
HTTP/1.1 429 Too Many Requests\r\n\
|
|
|
|
|
Connection: close\r\n\
|
|
|
|
|
Content-Type: text/plain\r\n\
|
|
|
|
|
Content-Length: 22\r\n\
|
|
|
|
|
\r\n\
|
|
|
|
|
429 Too Many Requests\n");
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-03 19:09:35 +00:00
|
|
|
|
static void EnterMeltdownMode(void) {
|
2024-12-02 22:05:38 +00:00
|
|
|
|
unassert(!pthread_mutex_lock(&shared->lastmeltdown_mu));
|
2022-11-06 02:49:41 +00:00
|
|
|
|
if (timespec_cmp(timespec_sub(timespec_real(), shared->lastmeltdown),
|
|
|
|
|
(struct timespec){1}) < 0) {
|
2024-12-02 22:05:38 +00:00
|
|
|
|
unassert(!pthread_mutex_unlock(&shared->lastmeltdown_mu));
|
2022-08-06 02:24:05 +00:00
|
|
|
|
return;
|
2022-11-06 02:49:41 +00:00
|
|
|
|
}
|
|
|
|
|
shared->lastmeltdown = timespec_real();
|
2024-12-02 22:05:38 +00:00
|
|
|
|
pthread_mutex_unlock(&shared->lastmeltdown_mu);
|
|
|
|
|
WARNF("(srvr) server is melting down (%,d workers)",
|
|
|
|
|
atomic_load_explicit(&shared->workers, memory_order_relaxed));
|
|
|
|
|
LOGIFNEG1(kill(0, SIGUSR2));
|
|
|
|
|
LockInc(&shared->c.meltdowns);
|
2021-05-03 19:09:35 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *HandlePayloadDisconnect(void) {
|
|
|
|
|
LockInc(&shared->c.payloaddisconnects);
|
|
|
|
|
LogClose("payload disconnect");
|
|
|
|
|
return ServeFailure(400, "Bad Request"); /* XXX */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *HandlePayloadDrop(void) {
|
|
|
|
|
LockInc(&shared->c.dropped);
|
|
|
|
|
LogClose(DescribeClose());
|
|
|
|
|
return ServeFailure(503, "Service Unavailable");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *HandleBadContentLength(void) {
|
|
|
|
|
LockInc(&shared->c.badlengths);
|
|
|
|
|
return ServeFailure(400, "Bad Content Length");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *HandleLengthRequired(void) {
|
|
|
|
|
LockInc(&shared->c.missinglengths);
|
|
|
|
|
return ServeFailure(411, "Length Required");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *HandleVersionNotSupported(void) {
|
|
|
|
|
LockInc(&shared->c.http12);
|
|
|
|
|
return ServeFailure(505, "HTTP Version Not Supported");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *HandleConnectRefused(void) {
|
|
|
|
|
LockInc(&shared->c.connectsrefused);
|
|
|
|
|
return ServeFailure(501, "Not Implemented");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *HandleExpectFailed(void) {
|
|
|
|
|
LockInc(&shared->c.expectsrefused);
|
|
|
|
|
return ServeFailure(417, "Expectation Failed");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *HandleHugePayload(void) {
|
|
|
|
|
LockInc(&shared->c.hugepayloads);
|
|
|
|
|
return ServeFailure(413, "Payload Too Large");
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-05 08:03:45 +00:00
|
|
|
|
static char *HandleTransferRefused(void) {
|
|
|
|
|
LockInc(&shared->c.transfersrefused);
|
|
|
|
|
return ServeFailure(501, "Not Implemented");
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-03 19:09:35 +00:00
|
|
|
|
static char *HandleMapFailed(struct Asset *a, int fd) {
|
|
|
|
|
LockInc(&shared->c.mapfails);
|
2021-10-25 21:44:04 +00:00
|
|
|
|
WARNF("(srvr) mmap(%`'s) error: %m", a->file->path);
|
2021-05-03 19:09:35 +00:00
|
|
|
|
close(fd);
|
|
|
|
|
return ServeError(500, "Internal Server Error");
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-17 18:38:35 +00:00
|
|
|
|
static void LogAcceptError(const char *s) {
|
2022-05-18 23:41:29 +00:00
|
|
|
|
LockInc(&shared->c.accepterrors);
|
2022-05-17 18:38:35 +00:00
|
|
|
|
WARNF("(srvr) %s accept error: %s", DescribeServer(), s);
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-03 19:09:35 +00:00
|
|
|
|
static char *HandleOpenFail(struct Asset *a) {
|
|
|
|
|
LockInc(&shared->c.openfails);
|
2021-10-25 21:44:04 +00:00
|
|
|
|
WARNF("(srvr) open(%`'s) error: %m", a->file->path);
|
2021-05-03 19:09:35 +00:00
|
|
|
|
if (errno == ENFILE) {
|
|
|
|
|
LockInc(&shared->c.enfiles);
|
|
|
|
|
return ServeError(503, "Service Unavailable");
|
|
|
|
|
} else if (errno == EMFILE) {
|
|
|
|
|
LockInc(&shared->c.emfiles);
|
|
|
|
|
return ServeError(503, "Service Unavailable");
|
2021-04-25 00:09:01 +00:00
|
|
|
|
} else {
|
2021-05-03 19:09:35 +00:00
|
|
|
|
return ServeError(500, "Internal Server Error");
|
2021-04-18 18:34:59 +00:00
|
|
|
|
}
|
2021-04-25 00:09:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-05-03 19:09:35 +00:00
|
|
|
|
static char *HandlePayloadReadError(void) {
|
|
|
|
|
if (errno == ECONNRESET) {
|
|
|
|
|
LockInc(&shared->c.readresets);
|
|
|
|
|
LogClose("payload reset");
|
|
|
|
|
return ServeFailure(400, "Bad Request"); /* XXX */
|
|
|
|
|
} else if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
|
|
|
|
LockInc(&shared->c.readtimeouts);
|
|
|
|
|
LogClose("payload read timeout");
|
|
|
|
|
return ServeFailure(408, "Request Timeout");
|
|
|
|
|
} else {
|
|
|
|
|
LockInc(&shared->c.readerrors);
|
2021-10-25 21:44:04 +00:00
|
|
|
|
INFOF("(clnt) %s payload read error: %m", DescribeClient());
|
2021-05-03 19:09:35 +00:00
|
|
|
|
return ServeFailure(500, "Internal Server Error");
|
|
|
|
|
}
|
2021-04-25 00:09:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-05-03 19:09:35 +00:00
|
|
|
|
static void HandleForkFailure(void) {
|
|
|
|
|
LockInc(&shared->c.forkerrors);
|
|
|
|
|
LockInc(&shared->c.dropped);
|
|
|
|
|
EnterMeltdownMode();
|
|
|
|
|
SendServiceUnavailable();
|
2021-06-24 19:31:26 +00:00
|
|
|
|
close(client);
|
2022-06-26 01:17:31 +00:00
|
|
|
|
WARNF("(srvr) too many processes: %m");
|
2021-05-03 19:09:35 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void HandleFrag(size_t got) {
|
|
|
|
|
LockInc(&shared->c.frags);
|
2023-02-23 02:56:02 +00:00
|
|
|
|
DEBUGF("(stat) %s fragged msg added %,ld bytes to %,ld byte buffer",
|
|
|
|
|
DescribeClient(), amtread, got);
|
2021-05-03 19:09:35 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void HandleReload(void) {
|
|
|
|
|
LockInc(&shared->c.reloads);
|
2023-08-17 07:42:23 +00:00
|
|
|
|
LuaOnServerReload(Reindex());
|
|
|
|
|
invalidated = false;
|
2021-05-03 19:09:35 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void HandleHeartbeat(void) {
|
2021-06-24 19:31:26 +00:00
|
|
|
|
size_t i;
|
2022-11-06 02:49:41 +00:00
|
|
|
|
UpdateCurrentDate(timespec_real());
|
2021-05-14 12:36:58 +00:00
|
|
|
|
Reindex();
|
2024-12-02 22:05:38 +00:00
|
|
|
|
unassert(!pthread_mutex_lock(&shared->server_mu));
|
2021-05-03 19:09:35 +00:00
|
|
|
|
getrusage(RUSAGE_SELF, &shared->server);
|
2024-12-02 22:05:38 +00:00
|
|
|
|
unassert(!pthread_mutex_unlock(&shared->server_mu));
|
2021-05-03 19:09:35 +00:00
|
|
|
|
#ifndef STATIC
|
2022-08-20 08:31:58 +00:00
|
|
|
|
CallSimpleHookIfDefined("OnServerHeartbeat");
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
CollectGarbage();
|
2021-05-03 19:09:35 +00:00
|
|
|
|
#endif
|
2022-04-18 07:01:26 +00:00
|
|
|
|
for (i = 1; i < servers.n; ++i) {
|
2021-06-24 19:31:26 +00:00
|
|
|
|
if (polls[i].fd < 0) {
|
|
|
|
|
polls[i].fd = -polls[i].fd;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-03-29 08:22:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-06-15 05:01:13 +00:00
|
|
|
|
// returns 0 on success or response on error
|
2021-05-03 19:09:35 +00:00
|
|
|
|
static char *OpenAsset(struct Asset *a) {
|
|
|
|
|
int fd;
|
|
|
|
|
void *data;
|
|
|
|
|
size_t size;
|
2022-03-21 14:34:19 +00:00
|
|
|
|
struct stat *st;
|
2021-05-03 19:09:35 +00:00
|
|
|
|
if (a->file->st.st_size) {
|
|
|
|
|
size = a->file->st.st_size;
|
2022-08-06 00:34:53 +00:00
|
|
|
|
if (cpm.msg.method == kHttpHead) {
|
|
|
|
|
cpm.content = 0;
|
|
|
|
|
cpm.contentlength = size;
|
2021-05-14 12:36:58 +00:00
|
|
|
|
} else {
|
|
|
|
|
OpenAgain:
|
|
|
|
|
if ((fd = open(a->file->path.s, O_RDONLY)) != -1) {
|
|
|
|
|
data = mmap(0, size, PROT_READ, MAP_PRIVATE, fd, 0);
|
|
|
|
|
if (data != MAP_FAILED) {
|
|
|
|
|
LockInc(&shared->c.maps);
|
|
|
|
|
UnmapLater(fd, data, size);
|
2022-08-06 00:34:53 +00:00
|
|
|
|
cpm.content = data;
|
|
|
|
|
cpm.contentlength = size;
|
2024-01-08 18:07:35 +00:00
|
|
|
|
} else if ((st = gc(malloc(sizeof(struct stat)))) &&
|
2022-03-21 14:34:19 +00:00
|
|
|
|
fstat(fd, st) != -1 && (data = malloc(st->st_size))) {
|
|
|
|
|
/* probably empty file or zipos handle */
|
|
|
|
|
LockInc(&shared->c.slurps);
|
|
|
|
|
FreeLater(data);
|
|
|
|
|
if (ReadAll(fd, data, st->st_size) != -1) {
|
2022-08-06 00:34:53 +00:00
|
|
|
|
cpm.content = data;
|
|
|
|
|
cpm.contentlength = st->st_size;
|
2022-03-21 14:34:19 +00:00
|
|
|
|
close(fd);
|
|
|
|
|
} else {
|
|
|
|
|
return HandleMapFailed(a, fd);
|
|
|
|
|
}
|
2021-05-14 12:36:58 +00:00
|
|
|
|
} else {
|
|
|
|
|
return HandleMapFailed(a, fd);
|
|
|
|
|
}
|
|
|
|
|
} else if (errno == EINTR) {
|
2022-03-19 10:37:00 +00:00
|
|
|
|
errno = 0;
|
2021-05-14 12:36:58 +00:00
|
|
|
|
goto OpenAgain;
|
2021-05-03 19:09:35 +00:00
|
|
|
|
} else {
|
2021-05-14 12:36:58 +00:00
|
|
|
|
return HandleOpenFail(a);
|
2021-05-03 19:09:35 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2022-08-06 00:34:53 +00:00
|
|
|
|
cpm.content = "";
|
|
|
|
|
cpm.contentlength = 0;
|
2021-05-03 19:09:35 +00:00
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *ServeServerOptions(void) {
|
2021-04-23 17:45:19 +00:00
|
|
|
|
char *p;
|
2021-05-03 19:09:35 +00:00
|
|
|
|
LockInc(&shared->c.serveroptions);
|
2021-04-23 17:45:19 +00:00
|
|
|
|
p = SetStatus(200, "OK");
|
|
|
|
|
#ifdef STATIC
|
|
|
|
|
p = stpcpy(p, "Allow: GET, HEAD, OPTIONS\r\n");
|
|
|
|
|
#else
|
|
|
|
|
p = stpcpy(p, "Accept: */*\r\n"
|
2021-05-01 12:11:35 +00:00
|
|
|
|
"Accept-Charset: utf-8,ISO-8859-1;q=0.7,*;q=0.5\r\n"
|
2021-04-23 17:45:19 +00:00
|
|
|
|
"Allow: GET, HEAD, POST, PUT, DELETE, OPTIONS\r\n");
|
|
|
|
|
#endif
|
|
|
|
|
return p;
|
|
|
|
|
}
|
2021-04-21 02:14:21 +00:00
|
|
|
|
|
2021-07-05 08:03:45 +00:00
|
|
|
|
static void SendContinueIfNeeded(void) {
|
2022-08-06 00:34:53 +00:00
|
|
|
|
if (cpm.msg.version >= 11 && HeaderEqualCase(kHttpExpect, "100-continue")) {
|
2021-07-05 08:03:45 +00:00
|
|
|
|
LockInc(&shared->c.continues);
|
|
|
|
|
SendContinue();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *ReadMore(void) {
|
2021-04-21 02:14:21 +00:00
|
|
|
|
size_t got;
|
|
|
|
|
ssize_t rc;
|
2021-07-05 08:03:45 +00:00
|
|
|
|
LockInc(&shared->c.frags);
|
|
|
|
|
if ((rc = reader(client, inbuf.p + amtread, inbuf.n - amtread)) != -1) {
|
|
|
|
|
if (!(got = rc))
|
|
|
|
|
return HandlePayloadDisconnect();
|
|
|
|
|
amtread += got;
|
|
|
|
|
} else if (errno == EINTR) {
|
|
|
|
|
LockInc(&shared->c.readinterrupts);
|
2022-08-06 02:24:05 +00:00
|
|
|
|
if (killed || ((meltdown || terminated) &&
|
2022-11-06 02:49:41 +00:00
|
|
|
|
timespec_cmp(timespec_sub(timespec_real(), startread),
|
|
|
|
|
(struct timespec){1}) >= 0)) {
|
2021-07-05 08:03:45 +00:00
|
|
|
|
return HandlePayloadDrop();
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
return HandlePayloadReadError();
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *SynchronizeLength(void) {
|
|
|
|
|
char *p;
|
|
|
|
|
if (hdrsize + payloadlength > amtread) {
|
|
|
|
|
if (hdrsize + payloadlength > inbuf.n)
|
|
|
|
|
return HandleHugePayload();
|
|
|
|
|
SendContinueIfNeeded();
|
|
|
|
|
while (amtread < hdrsize + payloadlength) {
|
|
|
|
|
if ((p = ReadMore()))
|
|
|
|
|
return p;
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-08-06 00:34:53 +00:00
|
|
|
|
cpm.msgsize = hdrsize + payloadlength;
|
2021-07-05 08:03:45 +00:00
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *SynchronizeChunked(void) {
|
|
|
|
|
char *p;
|
|
|
|
|
ssize_t transferlength;
|
|
|
|
|
struct HttpUnchunker u = {0};
|
|
|
|
|
SendContinueIfNeeded();
|
|
|
|
|
while (!(transferlength = Unchunk(&u, inbuf.p + hdrsize, amtread - hdrsize,
|
|
|
|
|
&payloadlength))) {
|
|
|
|
|
if ((p = ReadMore()))
|
|
|
|
|
return p;
|
|
|
|
|
}
|
|
|
|
|
if (transferlength == -1)
|
|
|
|
|
return HandleHugePayload();
|
2022-08-06 00:34:53 +00:00
|
|
|
|
cpm.msgsize = hdrsize + transferlength;
|
2021-07-05 08:03:45 +00:00
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-19 21:55:20 +00:00
|
|
|
|
static char *SynchronizeStream(void) {
|
2021-04-21 02:14:21 +00:00
|
|
|
|
int64_t cl;
|
2021-07-05 08:03:45 +00:00
|
|
|
|
if (HasHeader(kHttpTransferEncoding) &&
|
2021-07-08 04:44:27 +00:00
|
|
|
|
!HeaderEqualCase(kHttpTransferEncoding, "identity")) {
|
|
|
|
|
if (HeaderEqualCase(kHttpTransferEncoding, "chunked")) {
|
2021-07-05 08:03:45 +00:00
|
|
|
|
return SynchronizeChunked();
|
|
|
|
|
} else {
|
|
|
|
|
return HandleTransferRefused();
|
|
|
|
|
}
|
|
|
|
|
} else if (HasHeader(kHttpContentLength)) {
|
2021-05-03 19:09:35 +00:00
|
|
|
|
if ((cl = ParseContentLength(HeaderData(kHttpContentLength),
|
2021-07-05 08:03:45 +00:00
|
|
|
|
HeaderLength(kHttpContentLength))) != -1) {
|
|
|
|
|
payloadlength = cl;
|
|
|
|
|
return SynchronizeLength();
|
|
|
|
|
} else {
|
2021-05-03 19:09:35 +00:00
|
|
|
|
return HandleBadContentLength();
|
2021-04-21 02:14:21 +00:00
|
|
|
|
}
|
2022-08-06 00:34:53 +00:00
|
|
|
|
} else if (cpm.msg.method == kHttpPost || cpm.msg.method == kHttpPut) {
|
2021-05-03 19:09:35 +00:00
|
|
|
|
return HandleLengthRequired();
|
|
|
|
|
} else {
|
2022-08-06 00:34:53 +00:00
|
|
|
|
cpm.msgsize = hdrsize;
|
2021-07-05 08:03:45 +00:00
|
|
|
|
payloadlength = 0;
|
|
|
|
|
return NULL;
|
2021-04-21 02:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void ParseRequestParameters(void) {
|
2021-04-23 17:45:19 +00:00
|
|
|
|
uint32_t ip;
|
2022-09-20 02:23:24 +00:00
|
|
|
|
FreeLater(ParseUrl(inbuf.p + cpm.msg.uri.a, cpm.msg.uri.b - cpm.msg.uri.a,
|
|
|
|
|
&url, kUrlPlus | kUrlLatin1));
|
2021-04-21 02:14:21 +00:00
|
|
|
|
if (!url.host.p) {
|
2022-09-17 08:37:33 +00:00
|
|
|
|
if (HasHeader(kHttpXForwardedHost) && //
|
2022-10-17 18:02:04 +00:00
|
|
|
|
!GetRemoteAddr(&ip, 0) && IsTrustedIp(ip)) {
|
2021-04-23 17:45:19 +00:00
|
|
|
|
FreeLater(ParseHost(HeaderData(kHttpXForwardedHost),
|
|
|
|
|
HeaderLength(kHttpXForwardedHost), &url));
|
|
|
|
|
} else if (HasHeader(kHttpHost)) {
|
|
|
|
|
FreeLater(
|
|
|
|
|
ParseHost(HeaderData(kHttpHost), HeaderLength(kHttpHost), &url));
|
2021-06-24 19:31:26 +00:00
|
|
|
|
} else {
|
|
|
|
|
FreeLater(ParseHost(DescribeServer(), -1, &url));
|
2021-04-23 17:45:19 +00:00
|
|
|
|
}
|
2021-04-21 02:14:21 +00:00
|
|
|
|
} else if (!url.path.n) {
|
|
|
|
|
url.path.p = "/";
|
|
|
|
|
url.path.n = 1;
|
|
|
|
|
}
|
2021-06-24 19:31:26 +00:00
|
|
|
|
if (!url.scheme.n) {
|
2022-05-29 15:14:55 +00:00
|
|
|
|
if (usingssl) {
|
2021-06-24 19:31:26 +00:00
|
|
|
|
url.scheme.p = "https";
|
|
|
|
|
url.scheme.n = 5;
|
|
|
|
|
} else {
|
|
|
|
|
url.scheme.p = "http";
|
|
|
|
|
url.scheme.n = 4;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-04-21 02:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-05-03 19:09:35 +00:00
|
|
|
|
static bool HasAtMostThisElement(int h, const char *s) {
|
|
|
|
|
size_t i, n;
|
2021-06-24 19:31:26 +00:00
|
|
|
|
struct HttpHeader *x;
|
2021-05-03 19:09:35 +00:00
|
|
|
|
if (HasHeader(h)) {
|
|
|
|
|
n = strlen(s);
|
2021-07-05 08:03:45 +00:00
|
|
|
|
if (!SlicesEqualCase(s, n, HeaderData(h), HeaderLength(h))) {
|
2021-05-03 19:09:35 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
2022-08-06 00:34:53 +00:00
|
|
|
|
for (i = 0; i < cpm.msg.xheaders.n; ++i) {
|
|
|
|
|
x = cpm.msg.xheaders.p + i;
|
2021-05-03 19:09:35 +00:00
|
|
|
|
if (GetHttpHeader(inbuf.p + x->k.a, x->k.b - x->k.a) == h &&
|
|
|
|
|
!SlicesEqualCase(inbuf.p + x->v.a, x->v.b - x->v.a, s, n)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-03-25 09:21:13 +00:00
|
|
|
|
}
|
2021-05-03 19:09:35 +00:00
|
|
|
|
return true;
|
2021-04-21 02:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-04-23 17:45:19 +00:00
|
|
|
|
static char *HandleRequest(void) {
|
2021-04-21 02:14:21 +00:00
|
|
|
|
char *p;
|
2022-08-06 00:34:53 +00:00
|
|
|
|
if (cpm.msg.version == 11) {
|
2021-05-03 19:09:35 +00:00
|
|
|
|
LockInc(&shared->c.http11);
|
2022-08-06 00:34:53 +00:00
|
|
|
|
} else if (cpm.msg.version < 10) {
|
2021-05-03 19:09:35 +00:00
|
|
|
|
LockInc(&shared->c.http09);
|
2022-08-06 00:34:53 +00:00
|
|
|
|
} else if (cpm.msg.version == 10) {
|
2021-05-03 19:09:35 +00:00
|
|
|
|
LockInc(&shared->c.http10);
|
2021-04-23 17:45:19 +00:00
|
|
|
|
} else {
|
2021-05-03 19:09:35 +00:00
|
|
|
|
return HandleVersionNotSupported();
|
2021-04-21 02:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
if ((p = SynchronizeStream()))
|
|
|
|
|
return p;
|
2021-07-05 08:03:45 +00:00
|
|
|
|
if (logbodies)
|
|
|
|
|
LogBody("received", inbuf.p + hdrsize, payloadlength);
|
2022-08-06 00:34:53 +00:00
|
|
|
|
if (cpm.msg.version < 11 || HeaderEqualCase(kHttpConnection, "close")) {
|
2021-03-25 09:21:13 +00:00
|
|
|
|
connectionclose = true;
|
|
|
|
|
}
|
2022-08-06 00:34:53 +00:00
|
|
|
|
if (cpm.msg.method == kHttpOptions &&
|
|
|
|
|
SlicesEqual(inbuf.p + cpm.msg.uri.a, cpm.msg.uri.b - cpm.msg.uri.a, "*",
|
|
|
|
|
1)) {
|
2021-04-23 17:45:19 +00:00
|
|
|
|
return ServeServerOptions();
|
|
|
|
|
}
|
2022-08-06 00:34:53 +00:00
|
|
|
|
if (cpm.msg.method == kHttpConnect) {
|
2021-05-03 19:09:35 +00:00
|
|
|
|
return HandleConnectRefused();
|
2021-04-21 02:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
if (!HasAtMostThisElement(kHttpExpect, "100-continue")) {
|
2021-05-03 19:09:35 +00:00
|
|
|
|
return HandleExpectFailed();
|
2021-04-18 18:34:59 +00:00
|
|
|
|
}
|
2021-04-21 02:14:21 +00:00
|
|
|
|
ParseRequestParameters();
|
2021-06-24 19:31:26 +00:00
|
|
|
|
if (!url.host.n || !url.path.n || url.path.p[0] != '/' ||
|
2021-04-21 02:14:21 +00:00
|
|
|
|
!IsAcceptablePath(url.path.p, url.path.n) ||
|
|
|
|
|
!IsAcceptableHost(url.host.p, url.host.n) ||
|
|
|
|
|
!IsAcceptablePort(url.port.p, url.port.n)) {
|
2021-07-05 21:03:50 +00:00
|
|
|
|
free(url.params.p);
|
2021-05-03 19:09:35 +00:00
|
|
|
|
LockInc(&shared->c.urisrefused);
|
2021-05-17 01:22:39 +00:00
|
|
|
|
return ServeFailure(400, "Bad URI");
|
2021-04-23 17:45:19 +00:00
|
|
|
|
}
|
2024-02-22 22:12:18 +00:00
|
|
|
|
char method[9] = {0};
|
|
|
|
|
WRITE64LE(method, cpm.msg.method);
|
|
|
|
|
INFOF("(req) received %s HTTP%02d %s %s %`'.*s %`'.*s", DescribeClient(),
|
|
|
|
|
cpm.msg.version, method, FreeLater(EncodeUrl(&url, 0)),
|
2022-08-06 00:34:53 +00:00
|
|
|
|
HeaderLength(kHttpReferer), HeaderData(kHttpReferer),
|
|
|
|
|
HeaderLength(kHttpUserAgent), HeaderData(kHttpUserAgent));
|
2021-07-05 08:03:45 +00:00
|
|
|
|
if (HasHeader(kHttpContentType) &&
|
|
|
|
|
IsMimeType(HeaderData(kHttpContentType), HeaderLength(kHttpContentType),
|
|
|
|
|
"application/x-www-form-urlencoded")) {
|
|
|
|
|
FreeLater(ParseParams(inbuf.p + hdrsize, payloadlength, &url.params));
|
|
|
|
|
}
|
|
|
|
|
FreeLater(url.params.p);
|
2021-06-24 19:31:26 +00:00
|
|
|
|
#ifndef STATIC
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
if (hasonhttprequest)
|
|
|
|
|
return LuaOnHttpRequest();
|
2021-06-24 19:31:26 +00:00
|
|
|
|
#endif
|
2021-04-25 00:09:01 +00:00
|
|
|
|
return Route(url.host.p, url.host.n, url.path.p, url.path.n);
|
2021-03-25 09:21:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-05-03 19:09:35 +00:00
|
|
|
|
static char *Route(const char *host, size_t hostlen, const char *path,
|
|
|
|
|
size_t pathlen) {
|
|
|
|
|
char *p;
|
2021-10-25 21:04:57 +00:00
|
|
|
|
// reset the redirect loop check, as it can only be looping inside
|
|
|
|
|
// this function (as it always serves something); otherwise
|
|
|
|
|
// successful RoutePath and Route may fail with "508 loop detected"
|
2022-08-06 00:34:53 +00:00
|
|
|
|
cpm.loops.n = 0;
|
2021-05-03 19:09:35 +00:00
|
|
|
|
if (hostlen && (p = RouteHost(host, hostlen, path, pathlen))) {
|
|
|
|
|
return p;
|
|
|
|
|
}
|
|
|
|
|
if (SlicesEqual(path, pathlen, "/", 1)) {
|
|
|
|
|
if ((p = ServeIndex("/", 1)))
|
|
|
|
|
return p;
|
|
|
|
|
return ServeListing();
|
|
|
|
|
} else if ((p = RoutePath(path, pathlen))) {
|
|
|
|
|
return p;
|
|
|
|
|
} else if (SlicesEqual(path, pathlen, "/statusz", 8)) {
|
|
|
|
|
return ServeStatusz();
|
|
|
|
|
} else {
|
|
|
|
|
LockInc(&shared->c.notfounds);
|
2023-07-02 02:47:59 +00:00
|
|
|
|
return ServeErrorWithPath(404, "Not Found", path, pathlen);
|
2021-05-03 19:09:35 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *RoutePath(const char *path, size_t pathlen) {
|
|
|
|
|
int m;
|
|
|
|
|
long r;
|
|
|
|
|
struct Asset *a;
|
2021-08-22 22:01:52 +00:00
|
|
|
|
DEBUGF("(srvr) RoutePath(%`'.*s)", pathlen, path);
|
2021-05-03 19:09:35 +00:00
|
|
|
|
if ((a = GetAsset(path, pathlen))) {
|
2022-03-08 02:13:49 +00:00
|
|
|
|
// only allow "read other" permissions for security
|
|
|
|
|
// and consistency with handling of "external" files
|
|
|
|
|
// in this and other webservers
|
2021-05-03 19:09:35 +00:00
|
|
|
|
if ((m = GetMode(a)) & 0004) {
|
|
|
|
|
if (!S_ISDIR(m)) {
|
|
|
|
|
return HandleAsset(a, path, pathlen);
|
|
|
|
|
} else {
|
|
|
|
|
return HandleFolder(path, pathlen);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
LockInc(&shared->c.forbiddens);
|
2021-08-22 22:01:52 +00:00
|
|
|
|
WARNF("(srvr) asset %`'.*s %#o isn't readable", pathlen, path, m);
|
2023-07-02 02:47:59 +00:00
|
|
|
|
return ServeErrorWithPath(403, "Forbidden", path, pathlen);
|
2021-05-03 19:09:35 +00:00
|
|
|
|
}
|
|
|
|
|
} else if ((r = FindRedirect(path, pathlen)) != -1) {
|
|
|
|
|
return HandleRedirect(redirects.p + r);
|
|
|
|
|
} else {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *RouteHost(const char *host, size_t hostlen, const char *path,
|
|
|
|
|
size_t pathlen) {
|
|
|
|
|
size_t hn, hm;
|
|
|
|
|
char *hp, *p, b[96];
|
|
|
|
|
if (hostlen) {
|
|
|
|
|
hn = 1 + hostlen + url.path.n;
|
|
|
|
|
hm = 3 + 1 + hn;
|
|
|
|
|
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 (!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;
|
|
|
|
|
} else {
|
|
|
|
|
mempcpy(mempcpy(mempcpy(hp + 1, "www.", 4), host, hostlen), path,
|
|
|
|
|
pathlen);
|
|
|
|
|
if ((p = RoutePath(hp, hn + 4)))
|
|
|
|
|
return p;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline bool IsLua(struct Asset *a) {
|
|
|
|
|
size_t n;
|
|
|
|
|
const char *p;
|
2021-05-14 12:36:58 +00:00
|
|
|
|
if (a->file && a->file->path.n >= 4 &&
|
|
|
|
|
READ32LE(a->file->path.s + a->file->path.n - 4) ==
|
|
|
|
|
('.' | 'l' << 8 | 'u' << 16 | 'a' << 24)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2023-06-17 11:20:16 +00:00
|
|
|
|
p = ZIP_CFILE_NAME(zmap + a->cf);
|
|
|
|
|
n = ZIP_CFILE_NAMESIZE(zmap + a->cf);
|
2021-05-03 19:09:35 +00:00
|
|
|
|
return n > 4 &&
|
|
|
|
|
READ32LE(p + n - 4) == ('.' | 'l' << 8 | 'u' << 16 | 'a' << 24);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *HandleAsset(struct Asset *a, const char *path, size_t pathlen) {
|
2022-06-15 05:01:13 +00:00
|
|
|
|
char *p;
|
2021-05-03 19:09:35 +00:00
|
|
|
|
#ifndef STATIC
|
|
|
|
|
if (IsLua(a))
|
|
|
|
|
return ServeLua(a, path, pathlen);
|
|
|
|
|
#endif
|
2022-08-06 00:34:53 +00:00
|
|
|
|
if (cpm.msg.method == kHttpGet || cpm.msg.method == kHttpHead) {
|
2021-05-03 19:09:35 +00:00
|
|
|
|
LockInc(&shared->c.staticrequests);
|
2022-06-15 05:01:13 +00:00
|
|
|
|
p = ServeAsset(a, path, pathlen);
|
2022-08-06 00:34:53 +00:00
|
|
|
|
if (!cpm.gotxcontenttypeoptions) {
|
2022-06-15 05:01:13 +00:00
|
|
|
|
p = stpcpy(p, "X-Content-Type-Options: nosniff\r\n");
|
|
|
|
|
}
|
|
|
|
|
return p;
|
2021-05-03 19:09:35 +00:00
|
|
|
|
} else {
|
|
|
|
|
return BadMethod();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const char *GetContentType(struct Asset *a, const char *path, size_t n) {
|
|
|
|
|
const char *r;
|
2022-08-23 05:02:58 +00:00
|
|
|
|
if (a->file && (r = GetContentTypeExt(a->file->path.s, a->file->path.n))) {
|
2021-05-03 19:09:35 +00:00
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
return firstnonnull(
|
2022-08-23 05:02:58 +00:00
|
|
|
|
GetContentTypeExt(path, n),
|
2023-06-17 11:20:16 +00:00
|
|
|
|
firstnonnull(GetContentTypeExt(ZIP_CFILE_NAME(zmap + a->cf),
|
|
|
|
|
ZIP_CFILE_NAMESIZE(zmap + a->cf)),
|
2021-05-03 19:09:35 +00:00
|
|
|
|
a->istext ? "text/plain" : "application/octet-stream"));
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-05 14:25:39 +00:00
|
|
|
|
static bool IsNotModified(struct Asset *a) {
|
2022-08-06 00:34:53 +00:00
|
|
|
|
if (cpm.msg.version < 10)
|
|
|
|
|
return false;
|
2021-05-05 14:25:39 +00:00
|
|
|
|
if (!HasHeader(kHttpIfModifiedSince))
|
|
|
|
|
return false;
|
2022-08-22 05:03:30 +00:00
|
|
|
|
return a->lastmodified <=
|
2021-05-05 14:25:39 +00:00
|
|
|
|
ParseHttpDateTime(HeaderData(kHttpIfModifiedSince),
|
|
|
|
|
HeaderLength(kHttpIfModifiedSince));
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-03 19:09:35 +00:00
|
|
|
|
static char *ServeAsset(struct Asset *a, const char *path, size_t pathlen) {
|
|
|
|
|
char *p;
|
|
|
|
|
const char *ct;
|
|
|
|
|
ct = GetContentType(a, path, pathlen);
|
|
|
|
|
if (IsNotModified(a)) {
|
|
|
|
|
LockInc(&shared->c.notmodifieds);
|
|
|
|
|
p = SetStatus(304, "Not Modified");
|
|
|
|
|
} else {
|
|
|
|
|
if (!a->file) {
|
2023-06-17 11:20:16 +00:00
|
|
|
|
cpm.content = (char *)ZIP_LFILE_CONTENT(zmap + a->lf);
|
|
|
|
|
cpm.contentlength = GetZipCfileCompressedSize(zmap + a->cf);
|
2021-05-03 19:09:35 +00:00
|
|
|
|
} else if ((p = OpenAsset(a))) {
|
|
|
|
|
return p;
|
|
|
|
|
}
|
|
|
|
|
if (IsCompressed(a)) {
|
|
|
|
|
if (ClientAcceptsGzip()) {
|
|
|
|
|
p = ServeAssetPrecompressed(a);
|
|
|
|
|
} else {
|
|
|
|
|
p = ServeAssetDecompressed(a);
|
|
|
|
|
}
|
2022-08-06 00:34:53 +00:00
|
|
|
|
} else if (cpm.msg.version >= 11 && HasHeader(kHttpRange)) {
|
2021-05-03 19:09:35 +00:00
|
|
|
|
p = ServeAssetRange(a);
|
|
|
|
|
} else if (!a->file) {
|
|
|
|
|
LockInc(&shared->c.identityresponses);
|
2021-08-22 22:01:52 +00:00
|
|
|
|
DEBUGF("(zip) ServeAssetZipIdentity(%`'s)", ct);
|
2022-08-06 00:34:53 +00:00
|
|
|
|
if (Verify(cpm.content, cpm.contentlength,
|
2023-06-17 11:20:16 +00:00
|
|
|
|
ZIP_LFILE_CRC32(zmap + a->lf))) {
|
2021-05-03 19:09:35 +00:00
|
|
|
|
p = SetStatus(200, "OK");
|
|
|
|
|
} else {
|
|
|
|
|
return ServeError(500, "Internal Server Error");
|
|
|
|
|
}
|
2022-08-06 00:34:53 +00:00
|
|
|
|
} else if (!IsTiny() && cpm.msg.method != kHttpHead && !IsSslCompressed() &&
|
2022-12-18 10:22:58 +00:00
|
|
|
|
ClientAcceptsGzip() && !ShouldAvoidGzip() &&
|
2022-10-17 18:02:04 +00:00
|
|
|
|
!(a->file &&
|
|
|
|
|
IsNoCompressExt(a->file->path.s, a->file->path.n)) &&
|
2023-08-14 03:31:27 +00:00
|
|
|
|
((cpm.contentlength >= 100 && startswithi(ct, "text/")) ||
|
2022-08-06 00:34:53 +00:00
|
|
|
|
(cpm.contentlength >= 1000 &&
|
|
|
|
|
MeasureEntropy(cpm.content, 1000) < 7))) {
|
2022-11-02 16:42:52 +00:00
|
|
|
|
VERBOSEF("serving compressed asset");
|
2021-05-03 19:09:35 +00:00
|
|
|
|
p = ServeAssetCompressed(a);
|
|
|
|
|
} else {
|
|
|
|
|
p = ServeAssetIdentity(a, ct);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
p = AppendContentType(p, ct);
|
|
|
|
|
p = stpcpy(p, "Vary: Accept-Encoding\r\n");
|
|
|
|
|
p = AppendHeader(p, "Last-Modified", a->lastmodifiedstr);
|
2022-08-06 00:34:53 +00:00
|
|
|
|
if (cpm.msg.version >= 11) {
|
|
|
|
|
if (!cpm.gotcachecontrol) {
|
2023-02-24 06:24:40 +00:00
|
|
|
|
p = AppendCache(p, cacheseconds, cachedirective);
|
2022-06-15 05:01:13 +00:00
|
|
|
|
}
|
2021-05-03 19:09:35 +00:00
|
|
|
|
if (!IsCompressed(a)) {
|
|
|
|
|
p = stpcpy(p, "Accept-Ranges: bytes\r\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return p;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *SetStatus(unsigned code, const char *reason) {
|
2022-08-06 00:34:53 +00:00
|
|
|
|
if (cpm.msg.version == 10) {
|
2021-06-24 19:31:26 +00:00
|
|
|
|
if (code == 307)
|
|
|
|
|
code = 302;
|
|
|
|
|
if (code == 308)
|
|
|
|
|
code = 301;
|
|
|
|
|
}
|
2022-08-06 00:34:53 +00:00
|
|
|
|
cpm.statuscode = code;
|
|
|
|
|
cpm.hascontenttype = false;
|
2023-05-18 03:46:27 +00:00
|
|
|
|
// reset, as the headers are reset.
|
|
|
|
|
// istext is `true`, as the default content type
|
|
|
|
|
// is text/html, which will be set later
|
|
|
|
|
cpm.istext = true;
|
2022-08-06 00:34:53 +00:00
|
|
|
|
cpm.gotxcontenttypeoptions = 0;
|
|
|
|
|
cpm.gotcachecontrol = 0;
|
|
|
|
|
cpm.referrerpolicy = 0;
|
|
|
|
|
cpm.branded = 0;
|
2021-05-03 19:09:35 +00:00
|
|
|
|
stpcpy(hdrbuf.p, "HTTP/1.0 000 ");
|
2022-08-06 00:34:53 +00:00
|
|
|
|
hdrbuf.p[7] += cpm.msg.version & 1;
|
2021-05-03 19:09:35 +00:00
|
|
|
|
hdrbuf.p[9] += code / 100;
|
|
|
|
|
hdrbuf.p[10] += code / 10 % 10;
|
|
|
|
|
hdrbuf.p[11] += code % 10;
|
2021-08-22 22:01:52 +00:00
|
|
|
|
VERBOSEF("(rsp) %d %s", code, reason);
|
2021-05-03 19:09:35 +00:00
|
|
|
|
return AppendCrlf(stpcpy(hdrbuf.p + 13, reason));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline bool MustNotIncludeMessageBody(void) { /* RFC2616 § 4.4 */
|
2022-08-06 00:34:53 +00:00
|
|
|
|
return cpm.msg.method == kHttpHead ||
|
|
|
|
|
(100 <= cpm.statuscode && cpm.statuscode <= 199) ||
|
|
|
|
|
cpm.statuscode == 204 || cpm.statuscode == 304;
|
2021-05-03 19:09:35 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-07-12 06:17:47 +00:00
|
|
|
|
static bool TransmitResponse(char *p) {
|
2021-03-25 09:21:13 +00:00
|
|
|
|
int iovlen;
|
2021-07-12 06:17:47 +00:00
|
|
|
|
struct iovec iov[4];
|
2021-03-25 09:21:13 +00:00
|
|
|
|
long actualcontentlength;
|
2022-08-06 00:34:53 +00:00
|
|
|
|
if (cpm.msg.version >= 10) {
|
|
|
|
|
actualcontentlength = cpm.contentlength;
|
|
|
|
|
if (cpm.gzipped) {
|
2021-07-12 06:17:47 +00:00
|
|
|
|
actualcontentlength += sizeof(kGzipHeader) + sizeof(gzip_footer);
|
|
|
|
|
p = stpcpy(p, "Content-Encoding: gzip\r\n");
|
|
|
|
|
}
|
|
|
|
|
p = AppendContentLength(p, actualcontentlength);
|
|
|
|
|
p = AppendCrlf(p);
|
|
|
|
|
CHECK_LE(p - hdrbuf.p, hdrbuf.n);
|
|
|
|
|
if (logmessages) {
|
|
|
|
|
LogMessage("sending", hdrbuf.p, p - hdrbuf.p);
|
|
|
|
|
}
|
|
|
|
|
iov[0].iov_base = hdrbuf.p;
|
|
|
|
|
iov[0].iov_len = p - hdrbuf.p;
|
|
|
|
|
iovlen = 1;
|
|
|
|
|
if (!MustNotIncludeMessageBody()) {
|
2022-08-06 00:34:53 +00:00
|
|
|
|
if (cpm.gzipped) {
|
2023-09-02 03:49:13 +00:00
|
|
|
|
iov[iovlen].iov_base = (void *)kGzipHeader;
|
2021-07-12 06:17:47 +00:00
|
|
|
|
iov[iovlen].iov_len = sizeof(kGzipHeader);
|
|
|
|
|
++iovlen;
|
|
|
|
|
}
|
2022-08-06 00:34:53 +00:00
|
|
|
|
iov[iovlen].iov_base = cpm.content;
|
|
|
|
|
iov[iovlen].iov_len = cpm.contentlength;
|
2021-07-12 06:17:47 +00:00
|
|
|
|
++iovlen;
|
2022-08-06 00:34:53 +00:00
|
|
|
|
if (cpm.gzipped) {
|
2021-07-12 06:17:47 +00:00
|
|
|
|
iov[iovlen].iov_base = gzip_footer;
|
|
|
|
|
iov[iovlen].iov_len = sizeof(gzip_footer);
|
|
|
|
|
++iovlen;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2022-08-06 00:34:53 +00:00
|
|
|
|
iov[0].iov_base = cpm.content;
|
|
|
|
|
iov[0].iov_len = cpm.contentlength;
|
2021-07-12 06:17:47 +00:00
|
|
|
|
iovlen = 1;
|
|
|
|
|
}
|
|
|
|
|
Send(iov, iovlen);
|
|
|
|
|
LockInc(&shared->c.messageshandled);
|
|
|
|
|
++messageshandled;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool StreamResponse(char *p) {
|
|
|
|
|
int rc;
|
|
|
|
|
struct iovec iov[6];
|
|
|
|
|
char *s, chunkbuf[23];
|
|
|
|
|
assert(!MustNotIncludeMessageBody());
|
2022-08-06 00:34:53 +00:00
|
|
|
|
if (cpm.msg.version >= 11) {
|
2021-07-12 06:17:47 +00:00
|
|
|
|
p = stpcpy(p, "Transfer-Encoding: chunked\r\n");
|
|
|
|
|
} else {
|
|
|
|
|
assert(connectionclose);
|
|
|
|
|
}
|
|
|
|
|
p = AppendCrlf(p);
|
|
|
|
|
CHECK_LE(p - hdrbuf.p, hdrbuf.n);
|
|
|
|
|
if (logmessages) {
|
|
|
|
|
LogMessage("sending", hdrbuf.p, p - hdrbuf.p);
|
|
|
|
|
}
|
2021-09-28 05:58:51 +00:00
|
|
|
|
bzero(iov, sizeof(iov));
|
2022-08-06 00:34:53 +00:00
|
|
|
|
if (cpm.msg.version >= 10) {
|
2021-07-12 06:17:47 +00:00
|
|
|
|
iov[0].iov_base = hdrbuf.p;
|
|
|
|
|
iov[0].iov_len = p - hdrbuf.p;
|
|
|
|
|
}
|
2022-08-06 00:34:53 +00:00
|
|
|
|
if (cpm.msg.version >= 11) {
|
2021-07-12 06:17:47 +00:00
|
|
|
|
iov[5].iov_base = "\r\n";
|
|
|
|
|
iov[5].iov_len = 2;
|
|
|
|
|
}
|
|
|
|
|
for (;;) {
|
|
|
|
|
iov[2].iov_base = 0;
|
|
|
|
|
iov[2].iov_len = 0;
|
|
|
|
|
iov[3].iov_base = 0;
|
|
|
|
|
iov[3].iov_len = 0;
|
|
|
|
|
iov[4].iov_base = 0;
|
|
|
|
|
iov[4].iov_len = 0;
|
2022-08-06 00:34:53 +00:00
|
|
|
|
if ((rc = cpm.generator(iov + 2)) <= 0)
|
|
|
|
|
break;
|
|
|
|
|
if (cpm.msg.version >= 11) {
|
2021-07-12 06:17:47 +00:00
|
|
|
|
s = chunkbuf;
|
|
|
|
|
s += uint64toarray_radix16(rc, s);
|
|
|
|
|
s = AppendCrlf(s);
|
|
|
|
|
iov[1].iov_base = chunkbuf;
|
|
|
|
|
iov[1].iov_len = s - chunkbuf;
|
|
|
|
|
}
|
|
|
|
|
if (Send(iov, 6) == -1)
|
|
|
|
|
break;
|
|
|
|
|
iov[0].iov_base = 0;
|
|
|
|
|
iov[0].iov_len = 0;
|
|
|
|
|
}
|
|
|
|
|
if (rc != -1) {
|
2022-08-06 00:34:53 +00:00
|
|
|
|
if (cpm.msg.version >= 11) {
|
2021-07-12 06:17:47 +00:00
|
|
|
|
iov[0].iov_base = "0\r\n\r\n";
|
|
|
|
|
iov[0].iov_len = 5;
|
|
|
|
|
Send(iov, 1);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
connectionclose = true;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-23 04:04:08 +00:00
|
|
|
|
static bool HandleMessageActual(void) {
|
2021-07-12 06:17:47 +00:00
|
|
|
|
int rc;
|
2022-07-19 03:17:14 +00:00
|
|
|
|
long reqtime, contime;
|
2021-07-12 06:17:47 +00:00
|
|
|
|
char *p;
|
2022-08-06 02:24:05 +00:00
|
|
|
|
struct timespec now;
|
2024-06-04 12:41:53 +00:00
|
|
|
|
if ((rc = ParseHttpMessage(&cpm.msg, inbuf.p, amtread, inbuf.n)) != -1) {
|
2021-03-25 09:21:13 +00:00
|
|
|
|
if (!rc)
|
|
|
|
|
return false;
|
2021-03-27 14:29:55 +00:00
|
|
|
|
hdrsize = rc;
|
2022-09-17 08:37:33 +00:00
|
|
|
|
if (logmessages) {
|
|
|
|
|
LogMessage("received", inbuf.p, hdrsize);
|
|
|
|
|
}
|
2021-04-23 17:45:19 +00:00
|
|
|
|
p = HandleRequest();
|
2021-03-25 09:21:13 +00:00
|
|
|
|
} else {
|
2021-05-03 19:09:35 +00:00
|
|
|
|
LockInc(&shared->c.badmessages);
|
2021-04-02 01:51:12 +00:00
|
|
|
|
connectionclose = true;
|
2021-08-09 14:00:23 +00:00
|
|
|
|
if ((p = DumpHexc(inbuf.p, MIN(amtread, 256), 0))) {
|
2021-09-04 04:14:26 +00:00
|
|
|
|
INFOF("(clnt) %s sent garbage %s", DescribeClient(), p);
|
2021-08-09 14:00:23 +00:00
|
|
|
|
}
|
2021-07-12 06:17:47 +00:00
|
|
|
|
return true;
|
2021-03-25 09:21:13 +00:00
|
|
|
|
}
|
2022-08-06 00:34:53 +00:00
|
|
|
|
if (!cpm.msgsize) {
|
2021-03-25 09:21:13 +00:00
|
|
|
|
amtread = 0;
|
|
|
|
|
connectionclose = true;
|
2021-05-03 19:09:35 +00:00
|
|
|
|
LockInc(&shared->c.synchronizationfailures);
|
2021-08-22 22:01:52 +00:00
|
|
|
|
DEBUGF("(clnt) could not synchronize message stream");
|
2021-04-23 17:45:19 +00:00
|
|
|
|
}
|
2022-08-06 00:34:53 +00:00
|
|
|
|
if (cpm.msg.version >= 10) {
|
2024-12-02 22:05:38 +00:00
|
|
|
|
unassert(!pthread_mutex_lock(&shared->datetime_mu));
|
2021-04-24 20:58:34 +00:00
|
|
|
|
p = AppendCrlf(stpcpy(stpcpy(p, "Date: "), shared->currentdate));
|
2024-12-02 22:05:38 +00:00
|
|
|
|
unassert(!pthread_mutex_unlock(&shared->datetime_mu));
|
2022-08-06 00:34:53 +00:00
|
|
|
|
if (!cpm.branded)
|
|
|
|
|
p = stpcpy(p, serverheader);
|
2021-04-23 17:45:19 +00:00
|
|
|
|
if (extrahdrs)
|
|
|
|
|
p = stpcpy(p, extrahdrs);
|
2021-03-25 09:21:13 +00:00
|
|
|
|
if (connectionclose) {
|
2021-04-21 02:14:21 +00:00
|
|
|
|
p = stpcpy(p, "Connection: close\r\n");
|
2022-08-06 00:34:53 +00:00
|
|
|
|
} else if (timeout.tv_sec < 0 && cpm.msg.version >= 11) {
|
2021-04-21 02:14:21 +00:00
|
|
|
|
p = stpcpy(p, "Connection: keep-alive\r\n");
|
2021-03-25 09:21:13 +00:00
|
|
|
|
}
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
}
|
2022-03-05 02:44:39 +00:00
|
|
|
|
// keep content-type update *before* referrerpolicy
|
|
|
|
|
// https://datatracker.ietf.org/doc/html/rfc2616#section-7.2.1
|
2022-08-06 00:34:53 +00:00
|
|
|
|
if (!cpm.hascontenttype && cpm.contentlength > 0) {
|
2022-03-05 02:44:39 +00:00
|
|
|
|
p = AppendContentType(p, "text/html");
|
|
|
|
|
}
|
2022-08-06 00:34:53 +00:00
|
|
|
|
if (cpm.referrerpolicy) {
|
2021-08-04 05:42:17 +00:00
|
|
|
|
p = stpcpy(p, "Referrer-Policy: ");
|
2022-08-06 00:34:53 +00:00
|
|
|
|
p = stpcpy(p, cpm.referrerpolicy);
|
2021-08-04 05:42:17 +00:00
|
|
|
|
p = stpcpy(p, "\r\n");
|
|
|
|
|
}
|
2022-07-19 03:17:14 +00:00
|
|
|
|
if (loglatency || LOGGABLE(kLogDebug) || hasonloglatency) {
|
2022-11-06 02:49:41 +00:00
|
|
|
|
now = timespec_real();
|
|
|
|
|
reqtime = timespec_tomicros(timespec_sub(now, startrequest));
|
|
|
|
|
contime = timespec_tomicros(timespec_sub(now, startconnection));
|
2022-07-19 03:17:14 +00:00
|
|
|
|
if (hasonloglatency)
|
|
|
|
|
LuaOnLogLatency(reqtime, contime);
|
|
|
|
|
if (loglatency || LOGGABLE(kLogDebug))
|
|
|
|
|
LOGF(kLogDebug, "(stat) %`'.*s latency r: %,ldµs c: %,ldµs",
|
2022-08-06 00:34:53 +00:00
|
|
|
|
cpm.msg.uri.b - cpm.msg.uri.a, inbuf.p + cpm.msg.uri.a, reqtime,
|
|
|
|
|
contime);
|
2021-08-09 21:45:52 +00:00
|
|
|
|
}
|
2022-08-06 00:34:53 +00:00
|
|
|
|
if (!cpm.generator) {
|
2021-07-12 06:17:47 +00:00
|
|
|
|
return TransmitResponse(p);
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
} else {
|
2021-07-12 06:17:47 +00:00
|
|
|
|
return StreamResponse(p);
|
2020-10-06 06:11:49 +00:00
|
|
|
|
}
|
2020-09-07 04:39:00 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-09 21:45:52 +00:00
|
|
|
|
static bool HandleMessage(void) {
|
|
|
|
|
bool r;
|
|
|
|
|
ishandlingrequest = true;
|
2022-03-23 04:04:08 +00:00
|
|
|
|
r = HandleMessageActual();
|
2021-08-09 21:45:52 +00:00
|
|
|
|
ishandlingrequest = false;
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-25 09:21:13 +00:00
|
|
|
|
static void InitRequest(void) {
|
2022-08-06 00:34:53 +00:00
|
|
|
|
assert(!cpm.outbuf);
|
|
|
|
|
bzero(&cpm, sizeof(cpm));
|
2021-03-25 09:21:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-09 14:00:23 +00:00
|
|
|
|
static bool IsSsl(unsigned char c) {
|
|
|
|
|
if (c == 22)
|
|
|
|
|
return true;
|
|
|
|
|
if (!(c & 128))
|
|
|
|
|
return false;
|
|
|
|
|
/* RHEL5 sends SSLv2 hello but supports TLS */
|
2021-08-22 22:01:52 +00:00
|
|
|
|
DEBUGF("(ssl) %s SSLv2 hello D:", DescribeClient());
|
2021-08-09 14:00:23 +00:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-23 17:45:19 +00:00
|
|
|
|
static void HandleMessages(void) {
|
2021-06-24 19:31:26 +00:00
|
|
|
|
bool once;
|
2020-10-06 06:11:49 +00:00
|
|
|
|
ssize_t rc;
|
2021-03-25 09:21:13 +00:00
|
|
|
|
size_t got;
|
2023-09-02 03:49:13 +00:00
|
|
|
|
(void)once;
|
2021-06-24 19:31:26 +00:00
|
|
|
|
for (once = false;;) {
|
2021-03-25 09:21:13 +00:00
|
|
|
|
InitRequest();
|
2022-11-06 02:49:41 +00:00
|
|
|
|
startread = timespec_real();
|
2021-03-25 09:21:13 +00:00
|
|
|
|
for (;;) {
|
2022-08-06 00:34:53 +00:00
|
|
|
|
if (!cpm.msg.i && amtread) {
|
2022-11-06 02:49:41 +00:00
|
|
|
|
startrequest = timespec_real();
|
2021-04-23 17:45:19 +00:00
|
|
|
|
if (HandleMessage())
|
|
|
|
|
break;
|
|
|
|
|
}
|
2021-06-24 19:31:26 +00:00
|
|
|
|
if ((rc = reader(client, inbuf.p + amtread, inbuf.n - amtread)) != -1) {
|
2022-11-06 02:49:41 +00:00
|
|
|
|
startrequest = timespec_real();
|
2021-03-25 09:21:13 +00:00
|
|
|
|
got = rc;
|
|
|
|
|
amtread += got;
|
|
|
|
|
if (amtread) {
|
2021-07-12 06:17:47 +00:00
|
|
|
|
#ifndef UNSECURE
|
2021-06-24 19:31:26 +00:00
|
|
|
|
if (!once) {
|
|
|
|
|
once = true;
|
2022-05-18 23:41:29 +00:00
|
|
|
|
if (!unsecure) {
|
|
|
|
|
if (IsSsl(inbuf.p[0])) {
|
|
|
|
|
if (TlsSetup()) {
|
|
|
|
|
continue;
|
|
|
|
|
} else {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2022-05-29 15:14:55 +00:00
|
|
|
|
} else if (requiressl) {
|
|
|
|
|
INFOF("(clnt) %s didn't send an ssl hello", DescribeClient());
|
|
|
|
|
return;
|
2021-06-24 19:31:26 +00:00
|
|
|
|
} else {
|
2022-05-18 23:41:29 +00:00
|
|
|
|
WipeServingKeys();
|
2021-06-24 19:31:26 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-07-12 06:17:47 +00:00
|
|
|
|
#endif
|
2021-08-22 22:01:52 +00:00
|
|
|
|
DEBUGF("(stat) %s read %,zd bytes", DescribeClient(), got);
|
2021-04-23 17:45:19 +00:00
|
|
|
|
if (HandleMessage()) {
|
2021-03-25 09:21:13 +00:00
|
|
|
|
break;
|
|
|
|
|
} else if (got) {
|
2021-05-03 19:09:35 +00:00
|
|
|
|
HandleFrag(got);
|
2021-03-25 09:21:13 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!got) {
|
2021-06-24 19:31:26 +00:00
|
|
|
|
NotifyClose();
|
2021-03-25 09:21:13 +00:00
|
|
|
|
LogClose("disconnect");
|
|
|
|
|
return;
|
|
|
|
|
}
|
2021-04-23 17:45:19 +00:00
|
|
|
|
} else if (errno == EINTR) {
|
2021-05-03 19:09:35 +00:00
|
|
|
|
LockInc(&shared->c.readinterrupts);
|
2022-03-19 10:37:00 +00:00
|
|
|
|
errno = 0;
|
2021-04-23 17:45:19 +00:00
|
|
|
|
} else if (errno == EAGAIN) {
|
2021-05-03 19:09:35 +00:00
|
|
|
|
LockInc(&shared->c.readtimeouts);
|
2021-04-23 17:45:19 +00:00
|
|
|
|
if (amtread)
|
|
|
|
|
SendTimeout();
|
2021-06-24 19:31:26 +00:00
|
|
|
|
NotifyClose();
|
2022-07-08 14:14:50 +00:00
|
|
|
|
LogClose("read timeout");
|
2021-04-23 17:45:19 +00:00
|
|
|
|
return;
|
2021-03-25 09:21:13 +00:00
|
|
|
|
} else if (errno == ECONNRESET) {
|
2021-05-03 19:09:35 +00:00
|
|
|
|
LockInc(&shared->c.readresets);
|
2022-07-08 14:14:50 +00:00
|
|
|
|
LogClose("read reset");
|
2021-03-25 09:21:13 +00:00
|
|
|
|
return;
|
2021-04-23 17:45:19 +00:00
|
|
|
|
} else {
|
2021-05-03 19:09:35 +00:00
|
|
|
|
LockInc(&shared->c.readerrors);
|
2022-07-08 14:14:50 +00:00
|
|
|
|
if (errno == EBADF) { // don't warn on close/bad fd
|
|
|
|
|
LogClose("read badf");
|
|
|
|
|
} else {
|
|
|
|
|
WARNF("(clnt) %s read error: %m", DescribeClient());
|
|
|
|
|
}
|
2021-03-25 09:21:13 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (killed || (terminated && !amtread) ||
|
2022-08-06 02:24:05 +00:00
|
|
|
|
(meltdown &&
|
2022-11-06 02:49:41 +00:00
|
|
|
|
(!amtread || timespec_cmp(timespec_sub(timespec_real(), startread),
|
|
|
|
|
(struct timespec){1}) >= 0))) {
|
2021-04-23 17:45:19 +00:00
|
|
|
|
if (amtread) {
|
2021-05-03 19:09:35 +00:00
|
|
|
|
LockInc(&shared->c.dropped);
|
2021-04-23 17:45:19 +00:00
|
|
|
|
SendServiceUnavailable();
|
|
|
|
|
}
|
2021-06-24 19:31:26 +00:00
|
|
|
|
NotifyClose();
|
2021-03-25 09:21:13 +00:00
|
|
|
|
LogClose(DescribeClose());
|
|
|
|
|
return;
|
|
|
|
|
}
|
2021-05-02 18:50:43 +00:00
|
|
|
|
if (invalidated) {
|
|
|
|
|
HandleReload();
|
|
|
|
|
}
|
2021-03-25 09:21:13 +00:00
|
|
|
|
}
|
2022-08-06 00:34:53 +00:00
|
|
|
|
if (cpm.msgsize == amtread) {
|
2021-04-23 17:45:19 +00:00
|
|
|
|
amtread = 0;
|
2021-06-24 19:31:26 +00:00
|
|
|
|
if (killed) {
|
|
|
|
|
LogClose(DescribeClose());
|
|
|
|
|
return;
|
|
|
|
|
} else if (connectionclose || terminated || meltdown) {
|
|
|
|
|
NotifyClose();
|
2021-04-23 17:45:19 +00:00
|
|
|
|
LogClose(DescribeClose());
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2022-08-06 00:34:53 +00:00
|
|
|
|
CHECK_LT(cpm.msgsize, amtread);
|
2021-05-03 19:09:35 +00:00
|
|
|
|
LockInc(&shared->c.pipelinedrequests);
|
2022-08-06 00:34:53 +00:00
|
|
|
|
DEBUGF("(stat) %,ld pipelinedrequest bytes", amtread - cpm.msgsize);
|
|
|
|
|
memmove(inbuf.p, inbuf.p + cpm.msgsize, amtread - cpm.msgsize);
|
|
|
|
|
amtread -= cpm.msgsize;
|
2021-06-24 19:31:26 +00:00
|
|
|
|
if (killed) {
|
|
|
|
|
LogClose(DescribeClose());
|
|
|
|
|
return;
|
|
|
|
|
} else if (connectionclose) {
|
|
|
|
|
NotifyClose();
|
2021-04-23 17:45:19 +00:00
|
|
|
|
LogClose(DescribeClose());
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-10-06 06:11:49 +00:00
|
|
|
|
}
|
2021-04-18 18:34:59 +00:00
|
|
|
|
CollectGarbage();
|
2021-05-02 18:50:43 +00:00
|
|
|
|
if (invalidated) {
|
|
|
|
|
HandleReload();
|
|
|
|
|
}
|
2020-10-06 06:11:49 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-24 19:31:26 +00:00
|
|
|
|
static void CloseServerFds(void) {
|
|
|
|
|
size_t i;
|
|
|
|
|
for (i = 0; i < servers.n; ++i) {
|
|
|
|
|
close(servers.p[i].fd);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-17 03:29:08 +00:00
|
|
|
|
static int ExitWorker(void) {
|
2022-04-18 15:54:42 +00:00
|
|
|
|
if (IsModeDbg() && !sandboxed) {
|
2022-04-17 03:29:08 +00:00
|
|
|
|
isexitingworker = true;
|
|
|
|
|
return eintr();
|
|
|
|
|
}
|
2023-11-11 02:37:00 +00:00
|
|
|
|
LuaDestroy();
|
2022-04-18 07:01:26 +00:00
|
|
|
|
_Exit(0);
|
2022-04-17 03:29:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-07-23 03:44:24 +00:00
|
|
|
|
static void UnveilRedbean(void) {
|
|
|
|
|
size_t i;
|
|
|
|
|
for (i = 0; i < stagedirs.n; ++i) {
|
|
|
|
|
unveil(stagedirs.p[i].s, "r");
|
|
|
|
|
}
|
|
|
|
|
unveil(0, 0);
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-18 15:54:42 +00:00
|
|
|
|
static int EnableSandbox(void) {
|
2022-08-11 18:27:25 +00:00
|
|
|
|
__pledge_mode = PLEDGE_PENALTY_RETURN_EPERM | PLEDGE_STDERR_LOGGING;
|
2022-04-18 15:54:42 +00:00
|
|
|
|
switch (sandboxed) {
|
|
|
|
|
case 0:
|
|
|
|
|
return 0;
|
2022-07-09 12:49:19 +00:00
|
|
|
|
case 1: // -S
|
2022-04-18 15:54:42 +00:00
|
|
|
|
DEBUGF("(stat) applying '%s' sandbox policy", "online");
|
2022-07-23 03:44:24 +00:00
|
|
|
|
UnveilRedbean();
|
2022-08-07 23:18:33 +00:00
|
|
|
|
return pledge("stdio rpath inet dns id", 0);
|
2022-07-09 12:49:19 +00:00
|
|
|
|
case 2: // -SS
|
2022-04-18 15:54:42 +00:00
|
|
|
|
DEBUGF("(stat) applying '%s' sandbox policy", "offline");
|
2022-07-23 03:44:24 +00:00
|
|
|
|
UnveilRedbean();
|
2022-08-07 23:18:33 +00:00
|
|
|
|
return pledge("stdio rpath id", 0);
|
2022-07-09 12:49:19 +00:00
|
|
|
|
default: // -SSS
|
|
|
|
|
DEBUGF("(stat) applying '%s' sandbox policy", "contained");
|
2022-07-23 03:44:24 +00:00
|
|
|
|
UnveilRedbean();
|
2022-07-09 12:49:19 +00:00
|
|
|
|
return pledge("stdio", 0);
|
2022-04-18 15:54:42 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-17 03:29:08 +00:00
|
|
|
|
static int HandleConnection(size_t i) {
|
2022-10-17 18:02:04 +00:00
|
|
|
|
uint32_t ip;
|
|
|
|
|
int pid, tok, rc = 0;
|
2020-10-06 06:11:49 +00:00
|
|
|
|
clientaddrsize = sizeof(clientaddr);
|
2022-10-11 00:52:41 +00:00
|
|
|
|
if ((client = accept4(servers.p[i].fd, (struct sockaddr *)&clientaddr,
|
|
|
|
|
&clientaddrsize, SOCK_CLOEXEC)) != -1) {
|
2022-10-17 18:02:04 +00:00
|
|
|
|
LockInc(&shared->c.accepts);
|
|
|
|
|
GetClientAddr(&ip, 0);
|
|
|
|
|
if (tokenbucket.cidr && tokenbucket.reject >= 0) {
|
2022-10-19 20:10:00 +00:00
|
|
|
|
if (!IsTrustedIp(ip)) {
|
2022-10-17 18:02:04 +00:00
|
|
|
|
tok = AcquireToken(tokenbucket.b, ip, tokenbucket.cidr);
|
|
|
|
|
if (tok <= tokenbucket.ban && tokenbucket.ban >= 0) {
|
2022-10-19 20:10:00 +00:00
|
|
|
|
WARNF("(token) banning %hhu.%hhu.%hhu.%hhu who only has %d tokens",
|
2022-10-17 18:02:04 +00:00
|
|
|
|
ip >> 24, ip >> 16, ip >> 8, ip, tok);
|
|
|
|
|
LockInc(&shared->c.bans);
|
|
|
|
|
Blackhole(ip);
|
|
|
|
|
close(client);
|
|
|
|
|
return 0;
|
|
|
|
|
} else if (tok <= tokenbucket.ignore && tokenbucket.ignore >= 0) {
|
2022-10-19 20:10:00 +00:00
|
|
|
|
DEBUGF("(token) ignoring %hhu.%hhu.%hhu.%hhu who only has %d tokens",
|
|
|
|
|
ip >> 24, ip >> 16, ip >> 8, ip, tok);
|
2022-10-17 18:02:04 +00:00
|
|
|
|
LockInc(&shared->c.ignores);
|
|
|
|
|
close(client);
|
|
|
|
|
return 0;
|
|
|
|
|
} else if (tok < tokenbucket.reject) {
|
2022-10-19 20:10:00 +00:00
|
|
|
|
WARNF("(token) rejecting %hhu.%hhu.%hhu.%hhu who only has %d tokens",
|
2022-10-17 18:02:04 +00:00
|
|
|
|
ip >> 24, ip >> 16, ip >> 8, ip, tok);
|
|
|
|
|
LockInc(&shared->c.rejects);
|
|
|
|
|
SendTooManyRequests();
|
|
|
|
|
close(client);
|
|
|
|
|
return 0;
|
2022-10-19 20:10:00 +00:00
|
|
|
|
} else {
|
|
|
|
|
DEBUGF("(token) %hhu.%hhu.%hhu.%hhu has %d tokens", ip >> 24,
|
|
|
|
|
ip >> 16, ip >> 8, ip, tok - 1);
|
2022-10-17 18:02:04 +00:00
|
|
|
|
}
|
|
|
|
|
} else {
|
2022-10-19 20:10:00 +00:00
|
|
|
|
DEBUGF("(token) won't acquire token for trusted ip %hhu.%hhu.%hhu.%hhu",
|
|
|
|
|
ip >> 24, ip >> 16, ip >> 8, ip);
|
2022-10-17 18:02:04 +00:00
|
|
|
|
}
|
2022-10-19 20:10:00 +00:00
|
|
|
|
} else {
|
|
|
|
|
DEBUGF("(token) can't acquire accept() token for client");
|
2022-10-17 18:02:04 +00:00
|
|
|
|
}
|
2022-11-06 02:49:41 +00:00
|
|
|
|
startconnection = timespec_real();
|
2024-12-02 22:05:38 +00:00
|
|
|
|
if (UNLIKELY(maxworkers) &&
|
|
|
|
|
atomic_load_explicit(&shared->workers, memory_order_relaxed) >=
|
|
|
|
|
maxworkers) {
|
2022-08-05 22:42:17 +00:00
|
|
|
|
EnterMeltdownMode();
|
|
|
|
|
SendServiceUnavailable();
|
|
|
|
|
close(client);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2022-04-18 15:54:42 +00:00
|
|
|
|
VERBOSEF("(srvr) accept %s via %s", DescribeClient(), DescribeServer());
|
2021-04-23 17:45:19 +00:00
|
|
|
|
messageshandled = 0;
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
if (hasonclientconnection && LuaOnClientConnection()) {
|
|
|
|
|
close(client);
|
2022-04-17 03:29:08 +00:00
|
|
|
|
return 0;
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
}
|
2021-03-25 09:21:13 +00:00
|
|
|
|
if (uniprocess) {
|
|
|
|
|
pid = -1;
|
|
|
|
|
connectionclose = true;
|
|
|
|
|
} else {
|
|
|
|
|
switch ((pid = fork())) {
|
|
|
|
|
case 0:
|
2024-12-17 04:51:27 +00:00
|
|
|
|
lua_repl_wock();
|
|
|
|
|
lua_repl_lock();
|
2021-03-25 09:21:13 +00:00
|
|
|
|
meltdown = false;
|
2022-04-18 15:54:42 +00:00
|
|
|
|
__isworker = true;
|
2021-03-25 09:21:13 +00:00
|
|
|
|
connectionclose = false;
|
2022-04-29 13:06:23 +00:00
|
|
|
|
if (!IsTiny() && systrace) {
|
2022-06-12 16:37:17 +00:00
|
|
|
|
kStartTsc = rdtsc();
|
2021-04-24 20:58:34 +00:00
|
|
|
|
}
|
2022-04-29 13:06:23 +00:00
|
|
|
|
TRACE_BEGIN;
|
2022-04-23 01:55:28 +00:00
|
|
|
|
if (sandboxed) {
|
|
|
|
|
CHECK_NE(-1, EnableSandbox());
|
|
|
|
|
}
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
if (hasonworkerstart) {
|
|
|
|
|
CallSimpleHook("OnWorkerStart");
|
|
|
|
|
}
|
2021-03-25 09:21:13 +00:00
|
|
|
|
break;
|
|
|
|
|
case -1:
|
2021-05-03 19:09:35 +00:00
|
|
|
|
HandleForkFailure();
|
2022-04-17 03:29:08 +00:00
|
|
|
|
return 0;
|
2021-03-25 09:21:13 +00:00
|
|
|
|
default:
|
2022-05-14 11:33:58 +00:00
|
|
|
|
LockInc(&shared->workers);
|
2021-03-25 09:21:13 +00:00
|
|
|
|
close(client);
|
2021-06-24 19:31:26 +00:00
|
|
|
|
ReseedRng(&rng, "parent");
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
if (hasonprocesscreate) {
|
|
|
|
|
LuaOnProcessCreate(pid);
|
|
|
|
|
}
|
2022-04-17 03:29:08 +00:00
|
|
|
|
return 0;
|
2021-03-25 09:21:13 +00:00
|
|
|
|
}
|
2020-10-06 06:11:49 +00:00
|
|
|
|
}
|
2022-03-21 15:25:33 +00:00
|
|
|
|
if (!pid && !IsWindows()) {
|
|
|
|
|
CloseServerFds();
|
|
|
|
|
}
|
2021-04-23 17:45:19 +00:00
|
|
|
|
HandleMessages();
|
2022-11-06 02:49:41 +00:00
|
|
|
|
DEBUGF("(stat) %s closing after %,ldµs", DescribeClient(),
|
|
|
|
|
timespec_tomicros(timespec_sub(timespec_real(), startconnection)));
|
2021-04-18 18:34:59 +00:00
|
|
|
|
if (!pid) {
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
if (hasonworkerstop) {
|
|
|
|
|
CallSimpleHook("OnWorkerStop");
|
|
|
|
|
}
|
2022-04-17 03:29:08 +00:00
|
|
|
|
rc = ExitWorker();
|
2021-04-18 18:34:59 +00:00
|
|
|
|
} else {
|
2021-06-24 19:31:26 +00:00
|
|
|
|
close(client);
|
|
|
|
|
oldin.p = 0;
|
|
|
|
|
oldin.n = 0;
|
|
|
|
|
if (inbuf.c) {
|
|
|
|
|
inbuf.p -= inbuf.c;
|
|
|
|
|
inbuf.n += inbuf.c;
|
|
|
|
|
inbuf.c = 0;
|
|
|
|
|
}
|
|
|
|
|
#ifndef UNSECURE
|
2022-05-29 15:14:55 +00:00
|
|
|
|
if (usingssl) {
|
|
|
|
|
usingssl = false;
|
2021-06-24 19:31:26 +00:00
|
|
|
|
reader = read;
|
|
|
|
|
writer = WritevAll;
|
|
|
|
|
mbedtls_ssl_session_reset(&ssl);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2021-04-18 18:34:59 +00:00
|
|
|
|
}
|
2022-04-17 03:29:08 +00:00
|
|
|
|
CollectGarbage();
|
2021-04-23 17:45:19 +00:00
|
|
|
|
} else {
|
2022-04-17 03:29:08 +00:00
|
|
|
|
if (errno == EINTR || errno == EAGAIN) {
|
|
|
|
|
LockInc(&shared->c.acceptinterrupts);
|
|
|
|
|
} else if (errno == ENFILE) {
|
|
|
|
|
LockInc(&shared->c.enfiles);
|
2022-05-18 23:41:29 +00:00
|
|
|
|
LogAcceptError("enfile: too many open files");
|
2022-04-17 03:29:08 +00:00
|
|
|
|
meltdown = true;
|
|
|
|
|
} else if (errno == EMFILE) {
|
|
|
|
|
LockInc(&shared->c.emfiles);
|
2022-05-18 23:41:29 +00:00
|
|
|
|
LogAcceptError("emfile: ran out of open file quota");
|
2022-04-17 03:29:08 +00:00
|
|
|
|
meltdown = true;
|
|
|
|
|
} else if (errno == ENOMEM) {
|
|
|
|
|
LockInc(&shared->c.enomems);
|
2022-05-18 23:41:29 +00:00
|
|
|
|
LogAcceptError("enomem: ran out of memory");
|
2022-04-17 03:29:08 +00:00
|
|
|
|
meltdown = true;
|
|
|
|
|
} else if (errno == ENOBUFS) {
|
|
|
|
|
LockInc(&shared->c.enobufs);
|
2022-05-18 23:41:29 +00:00
|
|
|
|
LogAcceptError("enobuf: ran out of buffer");
|
2022-04-17 03:29:08 +00:00
|
|
|
|
meltdown = true;
|
|
|
|
|
} else if (errno == ENONET) {
|
|
|
|
|
LockInc(&shared->c.enonets);
|
2022-05-18 23:41:29 +00:00
|
|
|
|
LogAcceptError("enonet: network gone");
|
2022-04-17 03:29:08 +00:00
|
|
|
|
polls[i].fd = -polls[i].fd;
|
|
|
|
|
} else if (errno == ENETDOWN) {
|
|
|
|
|
LockInc(&shared->c.enetdowns);
|
2022-05-18 23:41:29 +00:00
|
|
|
|
LogAcceptError("enetdown: network down");
|
2022-04-17 03:29:08 +00:00
|
|
|
|
polls[i].fd = -polls[i].fd;
|
|
|
|
|
} else if (errno == ECONNABORTED) {
|
2022-05-18 23:41:29 +00:00
|
|
|
|
LockInc(&shared->c.accepterrors);
|
2022-04-17 03:29:08 +00:00
|
|
|
|
LockInc(&shared->c.acceptresets);
|
2023-10-13 14:43:47 +00:00
|
|
|
|
WARNF("(srvr) %s accept error: %s", DescribeServer(),
|
2022-05-18 23:41:29 +00:00
|
|
|
|
"acceptreset: connection reset before accept");
|
2022-04-17 03:29:08 +00:00
|
|
|
|
} else if (errno == ENETUNREACH || errno == EHOSTUNREACH ||
|
|
|
|
|
errno == EOPNOTSUPP || errno == ENOPROTOOPT || errno == EPROTO) {
|
|
|
|
|
LockInc(&shared->c.accepterrors);
|
2022-05-18 23:41:29 +00:00
|
|
|
|
LockInc(&shared->c.acceptflakes);
|
2022-05-17 18:38:35 +00:00
|
|
|
|
WARNF("(srvr) accept error: %s ephemeral accept error: %m",
|
|
|
|
|
DescribeServer());
|
2022-04-17 03:29:08 +00:00
|
|
|
|
} else {
|
2023-10-13 14:43:47 +00:00
|
|
|
|
WARNF("(srvr) %s accept error: %m", DescribeServer());
|
2022-04-17 03:29:08 +00:00
|
|
|
|
}
|
|
|
|
|
errno = 0;
|
2020-10-06 06:11:49 +00:00
|
|
|
|
}
|
2022-04-17 03:29:08 +00:00
|
|
|
|
return rc;
|
2020-10-06 06:11:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-05-25 18:31:08 +00:00
|
|
|
|
static void MakeExecutableModifiable(void) {
|
2023-06-03 15:12:13 +00:00
|
|
|
|
#ifdef __x86_64__
|
2022-05-18 23:41:29 +00:00
|
|
|
|
int ft;
|
2022-10-11 03:31:25 +00:00
|
|
|
|
if (!(SUPPORT_VECTOR & (_HOSTMETAL | _HOSTWINDOWS | _HOSTXNU)))
|
|
|
|
|
return;
|
2022-04-24 16:59:22 +00:00
|
|
|
|
if (IsWindows())
|
|
|
|
|
return; // TODO
|
|
|
|
|
if (IsOpenbsd())
|
|
|
|
|
return; // TODO
|
|
|
|
|
if (IsNetbsd())
|
|
|
|
|
return; // TODO
|
2024-03-03 00:57:56 +00:00
|
|
|
|
if (endswith(zpath, ".dbg"))
|
|
|
|
|
return;
|
2022-05-25 18:31:08 +00:00
|
|
|
|
close(zfd);
|
2022-11-02 05:36:03 +00:00
|
|
|
|
ft = ftrace_enabled(0);
|
2023-08-14 03:31:27 +00:00
|
|
|
|
if ((zfd = __open_executable()) == -1) {
|
2022-06-27 04:16:13 +00:00
|
|
|
|
WARNF("(srvr) can't open executable for modification: %m");
|
2022-05-25 18:31:08 +00:00
|
|
|
|
}
|
|
|
|
|
if (ft > 0) {
|
|
|
|
|
__ftrace = 0;
|
|
|
|
|
ftrace_install();
|
2022-11-02 05:36:03 +00:00
|
|
|
|
ftrace_enabled(ft);
|
2021-04-18 18:34:59 +00:00
|
|
|
|
}
|
2023-06-03 15:12:13 +00:00
|
|
|
|
#else
|
|
|
|
|
// TODO
|
|
|
|
|
#endif
|
2021-04-18 18:34:59 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-04-23 01:55:28 +00:00
|
|
|
|
static int HandleReadline(void) {
|
|
|
|
|
int status;
|
2022-04-26 04:16:05 +00:00
|
|
|
|
lua_State *L = GL;
|
2022-04-23 01:55:28 +00:00
|
|
|
|
for (;;) {
|
2022-04-26 04:16:05 +00:00
|
|
|
|
status = lua_loadline(L);
|
2022-04-23 01:55:28 +00:00
|
|
|
|
if (status < 0) {
|
|
|
|
|
if (status == -1) {
|
|
|
|
|
OnTerm(SIGHUP); // eof
|
2022-05-14 11:33:58 +00:00
|
|
|
|
VERBOSEF("(repl) eof");
|
2022-04-23 01:55:28 +00:00
|
|
|
|
return -1;
|
|
|
|
|
} else if (errno == EINTR) {
|
|
|
|
|
errno = 0;
|
2022-05-14 11:33:58 +00:00
|
|
|
|
VERBOSEF("(repl) interrupt");
|
2022-05-14 18:47:16 +00:00
|
|
|
|
shutdownsig = SIGINT;
|
|
|
|
|
OnInt(SIGINT);
|
|
|
|
|
kill(0, SIGINT);
|
2022-04-24 16:59:22 +00:00
|
|
|
|
return -1;
|
2022-04-23 01:55:28 +00:00
|
|
|
|
} else if (errno == EAGAIN) {
|
|
|
|
|
errno = 0;
|
|
|
|
|
return 0;
|
|
|
|
|
} else {
|
2022-06-27 04:16:13 +00:00
|
|
|
|
WARNF("(srvr) unexpected terminal error %d% m", status);
|
2022-05-19 23:57:49 +00:00
|
|
|
|
errno = 0;
|
|
|
|
|
return 0;
|
2022-04-23 01:55:28 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2022-06-26 01:17:31 +00:00
|
|
|
|
DisableRawMode();
|
2022-06-27 20:01:58 +00:00
|
|
|
|
lua_repl_lock();
|
2022-04-23 01:55:28 +00:00
|
|
|
|
if (status == LUA_OK) {
|
2022-04-26 04:16:05 +00:00
|
|
|
|
status = lua_runchunk(L, 0, LUA_MULTRET);
|
2022-04-23 01:55:28 +00:00
|
|
|
|
}
|
|
|
|
|
if (status == LUA_OK) {
|
2022-04-26 04:16:05 +00:00
|
|
|
|
LuaPrint(L);
|
2022-04-23 01:55:28 +00:00
|
|
|
|
} else {
|
2022-04-26 04:16:05 +00:00
|
|
|
|
lua_report(L, status);
|
2022-04-23 01:55:28 +00:00
|
|
|
|
}
|
2022-06-27 20:01:58 +00:00
|
|
|
|
lua_repl_unlock();
|
2022-06-26 01:17:31 +00:00
|
|
|
|
EnableRawMode();
|
2022-04-23 01:55:28 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int HandlePoll(int ms) {
|
|
|
|
|
int rc, nfds;
|
|
|
|
|
size_t pollid, serverid;
|
|
|
|
|
if ((nfds = poll(polls, 1 + servers.n, ms)) != -1) {
|
|
|
|
|
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].fd) {
|
|
|
|
|
// handle listen socket
|
2022-06-27 20:01:58 +00:00
|
|
|
|
lua_repl_lock();
|
2022-04-23 01:55:28 +00:00
|
|
|
|
serverid = pollid - 1;
|
|
|
|
|
assert(0 <= serverid && serverid < servers.n);
|
|
|
|
|
serveraddr = &servers.p[serverid].addr;
|
|
|
|
|
ishandlingconnection = true;
|
|
|
|
|
rc = HandleConnection(serverid);
|
|
|
|
|
ishandlingconnection = false;
|
2022-06-27 20:01:58 +00:00
|
|
|
|
lua_repl_unlock();
|
2022-04-23 01:55:28 +00:00
|
|
|
|
if (rc == -1)
|
|
|
|
|
return -1;
|
2022-04-24 16:59:22 +00:00
|
|
|
|
#ifndef STATIC
|
2022-04-23 01:55:28 +00:00
|
|
|
|
} else {
|
|
|
|
|
// handle standard input
|
|
|
|
|
rc = HandleReadline();
|
|
|
|
|
if (rc == -1)
|
|
|
|
|
return rc;
|
2022-04-24 16:59:22 +00:00
|
|
|
|
#endif
|
2022-04-23 01:55:28 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2022-04-24 16:59:22 +00:00
|
|
|
|
#ifndef STATIC
|
2023-10-04 05:34:45 +00:00
|
|
|
|
} else if (__ttyconf.replmode) {
|
2022-04-23 01:55:28 +00:00
|
|
|
|
// handle refresh repl line
|
2023-08-15 13:06:43 +00:00
|
|
|
|
rc = HandleReadline();
|
|
|
|
|
if (rc < 0)
|
|
|
|
|
return rc;
|
2022-04-24 16:59:22 +00:00
|
|
|
|
#endif
|
2022-04-23 01:55:28 +00:00
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (errno == EINTR || errno == EAGAIN) {
|
|
|
|
|
LockInc(&shared->c.pollinterrupts);
|
|
|
|
|
} else if (errno == ENOMEM) {
|
|
|
|
|
LockInc(&shared->c.enomems);
|
2022-05-17 18:38:35 +00:00
|
|
|
|
WARNF("(srvr) poll error: ran out of memory");
|
2022-04-23 01:55:28 +00:00
|
|
|
|
meltdown = true;
|
|
|
|
|
} else {
|
|
|
|
|
DIEF("(srvr) poll error: %m");
|
|
|
|
|
}
|
|
|
|
|
errno = 0;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-24 19:31:26 +00:00
|
|
|
|
static void Listen(void) {
|
|
|
|
|
char ipbuf[16];
|
|
|
|
|
size_t i, j, n;
|
2022-10-17 18:02:04 +00:00
|
|
|
|
uint32_t ip, port, addrsize, *ifp;
|
2022-07-08 14:17:25 +00:00
|
|
|
|
bool hasonserverlisten = IsHookDefined("OnServerListen");
|
2021-06-24 19:31:26 +00:00
|
|
|
|
if (!ports.n) {
|
|
|
|
|
ProgramPort(8080);
|
|
|
|
|
}
|
|
|
|
|
if (!ips.n) {
|
2022-10-17 18:02:04 +00:00
|
|
|
|
if (interfaces && *interfaces) {
|
|
|
|
|
for (ifp = interfaces; *ifp; ++ifp) {
|
2021-06-24 19:31:26 +00:00
|
|
|
|
sprintf(ipbuf, "%hhu.%hhu.%hhu.%hhu", *ifp >> 24, *ifp >> 16, *ifp >> 8,
|
|
|
|
|
*ifp);
|
|
|
|
|
ProgramAddr(ipbuf);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
ProgramAddr("0.0.0.0");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
servers.p = malloc(ips.n * ports.n * sizeof(*servers.p));
|
|
|
|
|
for (n = i = 0; i < ips.n; ++i) {
|
|
|
|
|
for (j = 0; j < ports.n; ++j, ++n) {
|
2021-09-28 05:58:51 +00:00
|
|
|
|
bzero(servers.p + n, sizeof(*servers.p));
|
2021-06-24 19:31:26 +00:00
|
|
|
|
servers.p[n].addr.sin_family = AF_INET;
|
|
|
|
|
servers.p[n].addr.sin_port = htons(ports.p[j]);
|
|
|
|
|
servers.p[n].addr.sin_addr.s_addr = htonl(ips.p[i]);
|
2021-08-14 13:17:56 +00:00
|
|
|
|
if ((servers.p[n].fd = GoodSocket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC,
|
|
|
|
|
IPPROTO_TCP, true, &timeout)) == -1) {
|
2021-08-22 22:01:52 +00:00
|
|
|
|
DIEF("(srvr) socket: %m");
|
2021-06-24 19:31:26 +00:00
|
|
|
|
}
|
2022-07-08 14:17:25 +00:00
|
|
|
|
if (hasonserverlisten &&
|
|
|
|
|
LuaOnServerListen(servers.p[n].fd, ips.p[i], ports.p[j])) {
|
2022-07-09 19:16:44 +00:00
|
|
|
|
close(servers.p[n].fd);
|
2022-07-08 14:17:25 +00:00
|
|
|
|
n--; // skip this server instance
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-11 00:52:41 +00:00
|
|
|
|
if (bind(servers.p[n].fd, (struct sockaddr *)&servers.p[n].addr,
|
2021-06-24 19:31:26 +00:00
|
|
|
|
sizeof(servers.p[n].addr)) == -1) {
|
2021-11-13 00:34:18 +00:00
|
|
|
|
DIEF("(srvr) bind error: %m: %hhu.%hhu.%hhu.%hhu:%hu", ips.p[i] >> 24,
|
|
|
|
|
ips.p[i] >> 16, ips.p[i] >> 8, ips.p[i], ports.p[j]);
|
2021-06-24 19:31:26 +00:00
|
|
|
|
}
|
|
|
|
|
if (listen(servers.p[n].fd, 10) == -1) {
|
2021-10-25 21:44:04 +00:00
|
|
|
|
DIEF("(srvr) listen error: %m");
|
2021-06-24 19:31:26 +00:00
|
|
|
|
}
|
|
|
|
|
addrsize = sizeof(servers.p[n].addr);
|
2022-10-11 00:52:41 +00:00
|
|
|
|
if (getsockname(servers.p[n].fd, (struct sockaddr *)&servers.p[n].addr,
|
|
|
|
|
&addrsize) == -1) {
|
2021-10-25 21:44:04 +00:00
|
|
|
|
DIEF("(srvr) getsockname error: %m");
|
2021-06-24 19:31:26 +00:00
|
|
|
|
}
|
|
|
|
|
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;
|
2021-09-07 18:40:11 +00:00
|
|
|
|
INFOF("(srvr) listen http://%hhu.%hhu.%hhu.%hhu:%d", ip >> 24, ip >> 16,
|
|
|
|
|
ip >> 8, ip, port);
|
2021-06-24 19:31:26 +00:00
|
|
|
|
if (printport && !ports.p[j]) {
|
2022-04-18 15:54:42 +00:00
|
|
|
|
printf("%d\r\n", port);
|
2021-06-24 19:31:26 +00:00
|
|
|
|
fflush(stdout);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-07-09 19:16:44 +00:00
|
|
|
|
// shrink allocated memory in case some of the sockets were skipped
|
2022-07-10 00:26:23 +00:00
|
|
|
|
if (n < ips.n * ports.n)
|
|
|
|
|
servers.p = realloc(servers.p, n * sizeof(*servers.p));
|
2021-06-24 19:31:26 +00:00
|
|
|
|
servers.n = n;
|
2022-04-17 03:29:08 +00:00
|
|
|
|
polls = malloc((1 + n) * sizeof(*polls));
|
|
|
|
|
polls[0].fd = -1;
|
|
|
|
|
polls[0].events = POLLIN;
|
|
|
|
|
polls[0].revents = 0;
|
2021-06-24 19:31:26 +00:00
|
|
|
|
for (i = 0; i < n; ++i) {
|
2022-04-17 03:29:08 +00:00
|
|
|
|
polls[1 + i].fd = servers.p[i].fd;
|
|
|
|
|
polls[1 + i].events = POLLIN;
|
|
|
|
|
polls[1 + i].revents = 0;
|
2021-06-24 19:31:26 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
static void HandleShutdown(void) {
|
|
|
|
|
CloseServerFds();
|
2022-04-13 05:11:00 +00:00
|
|
|
|
INFOF("(srvr) received %s", strsignal(shutdownsig));
|
2022-04-17 03:29:08 +00:00
|
|
|
|
if (shutdownsig != SIGINT && shutdownsig != SIGQUIT) {
|
2022-04-13 05:11:00 +00:00
|
|
|
|
if (!killed)
|
|
|
|
|
terminated = false;
|
|
|
|
|
INFOF("(srvr) killing process group");
|
|
|
|
|
KillGroup();
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
}
|
|
|
|
|
WaitAll();
|
2022-07-24 01:58:31 +00:00
|
|
|
|
INFOF("(srvr) shutdown complete");
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-04-17 03:29:08 +00:00
|
|
|
|
// this function coroutines with linenoise
|
2022-08-15 03:16:44 +00:00
|
|
|
|
int EventLoop(int ms) {
|
2022-08-06 02:24:05 +00:00
|
|
|
|
struct timespec t;
|
2022-05-14 11:33:58 +00:00
|
|
|
|
DEBUGF("(repl) event loop");
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
while (!terminated) {
|
2022-04-17 03:29:08 +00:00
|
|
|
|
errno = 0;
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
if (zombied) {
|
2022-06-27 20:01:58 +00:00
|
|
|
|
lua_repl_lock();
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
ReapZombies();
|
2022-06-27 20:01:58 +00:00
|
|
|
|
lua_repl_unlock();
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
} else if (invalidated) {
|
2022-06-27 20:01:58 +00:00
|
|
|
|
lua_repl_lock();
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
HandleReload();
|
2022-06-27 20:01:58 +00:00
|
|
|
|
lua_repl_unlock();
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
} else if (meltdown) {
|
2022-06-27 20:01:58 +00:00
|
|
|
|
lua_repl_lock();
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
EnterMeltdownMode();
|
2022-06-27 20:01:58 +00:00
|
|
|
|
lua_repl_unlock();
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
meltdown = false;
|
2022-11-06 02:49:41 +00:00
|
|
|
|
} else if (timespec_cmp(timespec_sub((t = timespec_real()), lastheartbeat),
|
|
|
|
|
heartbeatinterval) >= 0) {
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
lastheartbeat = t;
|
|
|
|
|
HandleHeartbeat();
|
2022-04-23 01:55:28 +00:00
|
|
|
|
} else if (HandlePoll(ms) == -1) {
|
|
|
|
|
break;
|
2022-04-17 03:29:08 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2022-04-23 01:55:28 +00:00
|
|
|
|
return -1;
|
2022-04-17 03:29:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void ReplEventLoop(void) {
|
2022-04-26 04:16:05 +00:00
|
|
|
|
lua_State *L = GL;
|
2022-04-23 01:55:28 +00:00
|
|
|
|
DEBUGF("ReplEventLoop()");
|
2022-04-17 06:46:16 +00:00
|
|
|
|
polls[0].fd = 0;
|
2022-04-24 16:59:22 +00:00
|
|
|
|
lua_repl_completions_callback = HandleCompletions;
|
2023-07-09 12:11:25 +00:00
|
|
|
|
lua_initrepl(L);
|
2022-06-26 01:17:31 +00:00
|
|
|
|
EnableRawMode();
|
2023-10-13 15:30:18 +00:00
|
|
|
|
EventLoop(-1);
|
2022-06-26 01:17:31 +00:00
|
|
|
|
DisableRawMode();
|
2022-04-23 01:55:28 +00:00
|
|
|
|
lua_freerepl();
|
2022-04-26 04:16:05 +00:00
|
|
|
|
lua_settop(L, 0); // clear stack
|
2022-04-23 01:55:28 +00:00
|
|
|
|
polls[0].fd = -1;
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-12 13:43:59 +00:00
|
|
|
|
static void InstallSignalHandler(int sig, void *handler) {
|
|
|
|
|
struct sigaction sa = {.sa_sigaction = handler};
|
2023-06-03 14:50:29 +00:00
|
|
|
|
if (sigaction(sig, &sa, 0) == -1)
|
|
|
|
|
WARNF("(srvr) failed to set signal handler #%d: %m", sig);
|
2022-05-12 13:43:59 +00:00
|
|
|
|
}
|
|
|
|
|
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
static void SigInit(void) {
|
2022-05-12 13:43:59 +00:00
|
|
|
|
InstallSignalHandler(SIGINT, OnInt);
|
|
|
|
|
InstallSignalHandler(SIGHUP, OnHup);
|
|
|
|
|
InstallSignalHandler(SIGTERM, OnTerm);
|
|
|
|
|
InstallSignalHandler(SIGCHLD, OnChld);
|
|
|
|
|
InstallSignalHandler(SIGUSR1, OnUsr1);
|
|
|
|
|
InstallSignalHandler(SIGUSR2, OnUsr2);
|
|
|
|
|
InstallSignalHandler(SIGPIPE, SIG_IGN);
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void TlsInit(void) {
|
2021-06-24 19:31:26 +00:00
|
|
|
|
#ifndef UNSECURE
|
2021-07-19 21:55:20 +00:00
|
|
|
|
int suite;
|
2022-05-18 23:41:29 +00:00
|
|
|
|
if (unsecure)
|
|
|
|
|
return;
|
2022-03-15 00:11:05 +00:00
|
|
|
|
|
2023-07-07 17:00:49 +00:00
|
|
|
|
if (suiteb && !mbedtls_aes_uses_hardware()) {
|
|
|
|
|
WARNF("(srvr) requested suiteb crypto, but hardware aes not present");
|
2022-05-19 07:34:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-03-15 00:11:05 +00:00
|
|
|
|
if (!sslinitialized) {
|
|
|
|
|
InitializeRng(&rng);
|
|
|
|
|
InitializeRng(&rngcli);
|
|
|
|
|
suite = suiteb ? MBEDTLS_SSL_PRESET_SUITEB : MBEDTLS_SSL_PRESET_SUITEC;
|
|
|
|
|
mbedtls_ssl_config_defaults(&conf, MBEDTLS_SSL_IS_SERVER,
|
|
|
|
|
MBEDTLS_SSL_TRANSPORT_STREAM, suite);
|
|
|
|
|
mbedtls_ssl_config_defaults(&confcli, MBEDTLS_SSL_IS_CLIENT,
|
|
|
|
|
MBEDTLS_SSL_TRANSPORT_STREAM, suite);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// the following setting can be re-applied even when SSL/TLS is initialized
|
2021-08-09 14:00:23 +00:00
|
|
|
|
if (suites.n) {
|
|
|
|
|
mbedtls_ssl_conf_ciphersuites(&conf, suites.p);
|
|
|
|
|
mbedtls_ssl_conf_ciphersuites(&confcli, suites.p);
|
|
|
|
|
}
|
|
|
|
|
if (psks.n) {
|
|
|
|
|
mbedtls_ssl_conf_psk_cb(&conf, TlsRoutePsk, 0);
|
|
|
|
|
DCHECK_EQ(0,
|
|
|
|
|
mbedtls_ssl_conf_psk(&confcli, psks.p[0].key, psks.p[0].key_len,
|
|
|
|
|
psks.p[0].identity, psks.p[0].identity_len));
|
|
|
|
|
}
|
2021-07-19 21:55:20 +00:00
|
|
|
|
if (sslticketlifetime > 0) {
|
|
|
|
|
mbedtls_ssl_ticket_setup(&ssltick, mbedtls_ctr_drbg_random, &rng,
|
|
|
|
|
MBEDTLS_CIPHER_AES_256_GCM, sslticketlifetime);
|
|
|
|
|
mbedtls_ssl_conf_session_tickets_cb(&conf, mbedtls_ssl_ticket_write,
|
|
|
|
|
mbedtls_ssl_ticket_parse, &ssltick);
|
|
|
|
|
}
|
2022-03-15 00:11:05 +00:00
|
|
|
|
|
|
|
|
|
if (sslinitialized)
|
|
|
|
|
return;
|
|
|
|
|
sslinitialized = true;
|
|
|
|
|
|
2021-07-12 06:17:47 +00:00
|
|
|
|
LoadCertificates();
|
2021-07-19 21:55:20 +00:00
|
|
|
|
mbedtls_ssl_conf_sni(&conf, TlsRoute, 0);
|
2021-06-24 19:31:26 +00:00
|
|
|
|
mbedtls_ssl_conf_dbg(&conf, TlsDebug, 0);
|
2021-07-08 04:44:27 +00:00
|
|
|
|
mbedtls_ssl_conf_dbg(&confcli, TlsDebug, 0);
|
2021-06-24 19:31:26 +00:00
|
|
|
|
mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &rng);
|
2021-07-08 04:44:27 +00:00
|
|
|
|
mbedtls_ssl_conf_rng(&confcli, mbedtls_ctr_drbg_random, &rngcli);
|
2021-07-19 21:55:20 +00:00
|
|
|
|
if (sslclientverify) {
|
2022-03-18 09:33:37 +00:00
|
|
|
|
mbedtls_ssl_conf_ca_chain(&conf, GetSslRoots(), 0);
|
2021-07-19 21:55:20 +00:00
|
|
|
|
mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_REQUIRED);
|
|
|
|
|
}
|
|
|
|
|
if (sslfetchverify) {
|
2022-03-18 09:33:37 +00:00
|
|
|
|
mbedtls_ssl_conf_ca_chain(&confcli, GetSslRoots(), 0);
|
2021-07-19 21:55:20 +00:00
|
|
|
|
mbedtls_ssl_conf_authmode(&confcli, MBEDTLS_SSL_VERIFY_REQUIRED);
|
|
|
|
|
} else {
|
|
|
|
|
mbedtls_ssl_conf_authmode(&confcli, MBEDTLS_SSL_VERIFY_NONE);
|
|
|
|
|
}
|
2021-07-09 04:54:21 +00:00
|
|
|
|
mbedtls_ssl_set_bio(&ssl, &g_bio, TlsSend, 0, TlsRecv);
|
2021-08-09 14:00:23 +00:00
|
|
|
|
conf.disable_compression = confcli.disable_compression = true;
|
2023-09-02 03:49:13 +00:00
|
|
|
|
DCHECK_EQ(0, mbedtls_ssl_conf_alpn_protocols(&conf, (void *)kAlpn));
|
|
|
|
|
DCHECK_EQ(0, mbedtls_ssl_conf_alpn_protocols(&confcli, (void *)kAlpn));
|
2021-07-12 06:17:47 +00:00
|
|
|
|
DCHECK_EQ(0, mbedtls_ssl_setup(&ssl, &conf));
|
|
|
|
|
DCHECK_EQ(0, mbedtls_ssl_setup(&sslcli, &confcli));
|
2021-06-24 19:31:26 +00:00
|
|
|
|
#endif
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void TlsDestroy(void) {
|
|
|
|
|
#ifndef UNSECURE
|
2022-05-18 23:41:29 +00:00
|
|
|
|
if (unsecure)
|
|
|
|
|
return;
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
mbedtls_ssl_free(&ssl);
|
|
|
|
|
mbedtls_ssl_free(&sslcli);
|
|
|
|
|
mbedtls_ctr_drbg_free(&rng);
|
|
|
|
|
mbedtls_ctr_drbg_free(&rngcli);
|
|
|
|
|
mbedtls_ssl_config_free(&conf);
|
|
|
|
|
mbedtls_ssl_config_free(&confcli);
|
2021-07-12 06:17:47 +00:00
|
|
|
|
mbedtls_ssl_ticket_free(&ssltick);
|
2022-03-18 09:33:37 +00:00
|
|
|
|
CertsDestroy();
|
|
|
|
|
PsksDestroy();
|
2021-08-09 14:00:23 +00:00
|
|
|
|
Free(&suites.p), suites.n = 0;
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-15 00:19:31 +00:00
|
|
|
|
static void GetOpts(int argc, char *argv[]) {
|
|
|
|
|
int opt;
|
2023-04-25 08:52:13 +00:00
|
|
|
|
bool got_e_arg = false;
|
2022-03-15 00:19:31 +00:00
|
|
|
|
bool storeasset = false;
|
2022-11-03 16:32:12 +00:00
|
|
|
|
// only generate ecp cert under blinkenlights (rsa is slow)
|
2023-01-18 08:56:09 +00:00
|
|
|
|
norsagen = IsGenuineBlink();
|
2022-04-18 07:01:26 +00:00
|
|
|
|
while ((opt = getopt(argc, argv, GETOPTS)) != -1) {
|
2022-03-15 00:19:31 +00:00
|
|
|
|
switch (opt) {
|
2022-04-18 15:54:42 +00:00
|
|
|
|
CASE('S', ++sandboxed);
|
2022-03-15 00:19:31 +00:00
|
|
|
|
CASE('v', ++__log_level);
|
|
|
|
|
CASE('s', --__log_level);
|
2022-05-18 23:41:29 +00:00
|
|
|
|
CASE('X', unsecure = true);
|
2022-05-29 15:14:55 +00:00
|
|
|
|
CASE('%', norsagen = true);
|
2022-04-18 07:01:26 +00:00
|
|
|
|
CASE('Z', systrace = true);
|
2022-03-15 00:19:31 +00:00
|
|
|
|
CASE('b', logbodies = true);
|
|
|
|
|
CASE('z', printport = true);
|
|
|
|
|
CASE('d', daemonize = true);
|
|
|
|
|
CASE('a', logrusage = true);
|
2022-05-29 15:14:55 +00:00
|
|
|
|
CASE('J', requiressl = true);
|
2022-03-15 00:19:31 +00:00
|
|
|
|
CASE('u', uniprocess = true);
|
|
|
|
|
CASE('g', loglatency = true);
|
|
|
|
|
CASE('m', logmessages = true);
|
2022-07-17 13:11:13 +00:00
|
|
|
|
CASE('w', launchbrowser = strdup(optarg));
|
2022-03-15 00:19:31 +00:00
|
|
|
|
CASE('l', ProgramAddr(optarg));
|
|
|
|
|
CASE('H', ProgramHeader(optarg));
|
|
|
|
|
CASE('L', ProgramLogPath(optarg));
|
|
|
|
|
CASE('P', ProgramPidPath(optarg));
|
|
|
|
|
CASE('D', ProgramDirectory(optarg));
|
|
|
|
|
CASE('U', ProgramUid(atoi(optarg)));
|
|
|
|
|
CASE('G', ProgramGid(atoi(optarg)));
|
|
|
|
|
CASE('p', ProgramPort(ParseInt(optarg)));
|
|
|
|
|
CASE('R', ProgramRedirectArg(0, optarg));
|
2023-03-06 06:57:22 +00:00
|
|
|
|
case 'c':; // accept "num" or "num,directive"
|
2023-02-24 06:24:40 +00:00
|
|
|
|
char *p;
|
|
|
|
|
long ret = strtol(optarg, &p, 0);
|
2023-03-06 06:57:22 +00:00
|
|
|
|
ProgramCache(ret, *p ? p + 1 : NULL); // skip separator, if any
|
2023-02-24 06:24:40 +00:00
|
|
|
|
break;
|
2023-03-06 06:57:22 +00:00
|
|
|
|
CASE('r', ProgramRedirectArg(307, optarg));
|
|
|
|
|
CASE('t', ProgramTimeout(ParseInt(optarg)));
|
|
|
|
|
CASE('h', PrintUsage(1, EXIT_SUCCESS));
|
|
|
|
|
CASE('M', ProgramMaxPayloadSize(ParseInt(optarg)));
|
2022-05-29 15:14:55 +00:00
|
|
|
|
#if !IsTiny()
|
2022-04-29 13:06:23 +00:00
|
|
|
|
case 'f':
|
|
|
|
|
funtrace = true;
|
|
|
|
|
if (ftrace_install() == -1) {
|
2022-06-27 04:16:13 +00:00
|
|
|
|
WARNF("(srvr) ftrace failed to install %m");
|
2022-04-29 13:06:23 +00:00
|
|
|
|
}
|
|
|
|
|
break;
|
2022-07-09 12:49:19 +00:00
|
|
|
|
#endif
|
|
|
|
|
#ifndef STATIC
|
|
|
|
|
CASE('F', LuaEvalFile(optarg));
|
|
|
|
|
CASE('*', selfmodifiable = true);
|
|
|
|
|
CASE('i', interpretermode = true);
|
|
|
|
|
CASE('E', leakcrashreports = true);
|
2023-04-25 08:52:13 +00:00
|
|
|
|
case 'e':
|
|
|
|
|
got_e_arg = true;
|
|
|
|
|
LuaEvalCode(optarg);
|
|
|
|
|
break;
|
2022-08-05 22:04:13 +00:00
|
|
|
|
case 'A':
|
|
|
|
|
if (!storeasset) {
|
|
|
|
|
storeasset = true;
|
|
|
|
|
MakeExecutableModifiable();
|
|
|
|
|
}
|
|
|
|
|
StorePath(optarg);
|
|
|
|
|
break;
|
2022-07-09 12:49:19 +00:00
|
|
|
|
#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
|
2022-03-15 00:19:31 +00:00
|
|
|
|
default:
|
2022-04-18 15:54:42 +00:00
|
|
|
|
PrintUsage(2, EX_USAGE);
|
2022-03-15 00:19:31 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// if storing asset(s) is requested, don't need to continue
|
|
|
|
|
if (storeasset)
|
|
|
|
|
exit(0);
|
2023-04-25 08:52:13 +00:00
|
|
|
|
// we don't want to drop into a repl after using -e in -i mode
|
|
|
|
|
if (interpretermode && got_e_arg)
|
|
|
|
|
exit(0);
|
2022-03-15 00:19:31 +00:00
|
|
|
|
}
|
|
|
|
|
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
void RedBean(int argc, char *argv[]) {
|
2022-07-24 01:58:31 +00:00
|
|
|
|
char ibuf[21];
|
|
|
|
|
int fd;
|
2023-11-20 03:02:30 +00:00
|
|
|
|
// 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;
|
2022-04-28 16:42:36 +00:00
|
|
|
|
if (IsLinux()) {
|
2022-07-23 19:06:41 +00:00
|
|
|
|
// disable weird linux capabilities
|
|
|
|
|
for (int e = errno, i = 0;; ++i) {
|
|
|
|
|
if (prctl(PR_CAPBSET_DROP, i) == -1) {
|
|
|
|
|
errno = e;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-04-28 16:42:36 +00:00
|
|
|
|
// disable sneak privilege since we don't use them
|
|
|
|
|
// seccomp will fail later if this fails
|
|
|
|
|
prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
|
|
|
|
|
}
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
reader = read;
|
|
|
|
|
writer = WritevAll;
|
2022-11-06 02:49:41 +00:00
|
|
|
|
gmtoff = GetGmtOffset((lastrefresh = startserver = timespec_real()).tv_sec);
|
2022-05-14 11:33:58 +00:00
|
|
|
|
mainpid = getpid();
|
2022-08-06 02:24:05 +00:00
|
|
|
|
heartbeatinterval.tv_sec = 5;
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
CHECK_GT(CLK_TCK, 0);
|
|
|
|
|
CHECK_NE(MAP_FAILED,
|
2024-07-07 19:24:25 +00:00
|
|
|
|
(shared = mmap(NULL, ROUNDUP(sizeof(struct Shared), getgransize()),
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS,
|
|
|
|
|
-1, 0)));
|
2024-12-02 22:05:38 +00:00
|
|
|
|
pthread_mutexattr_t attr;
|
|
|
|
|
unassert(!pthread_mutexattr_init(&attr));
|
|
|
|
|
unassert(!pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED));
|
|
|
|
|
unassert(!pthread_mutex_init(&shared->datetime_mu, &attr));
|
|
|
|
|
unassert(!pthread_mutex_init(&shared->server_mu, &attr));
|
|
|
|
|
unassert(!pthread_mutex_init(&shared->children_mu, &attr));
|
|
|
|
|
unassert(!pthread_mutex_init(&shared->lastmeltdown_mu, &attr));
|
|
|
|
|
unassert(!pthread_mutexattr_destroy(&attr));
|
2022-07-24 01:58:31 +00:00
|
|
|
|
if (daemonize) {
|
|
|
|
|
for (int i = 0; i < 256; ++i) {
|
2022-08-05 21:57:17 +00:00
|
|
|
|
close(i);
|
2022-07-24 01:58:31 +00:00
|
|
|
|
}
|
|
|
|
|
open("/dev/null", O_RDONLY);
|
|
|
|
|
open("/dev/null", O_WRONLY);
|
2022-08-05 21:57:17 +00:00
|
|
|
|
open("/dev/null", O_WRONLY);
|
2022-07-24 01:58:31 +00:00
|
|
|
|
}
|
2022-04-26 04:16:05 +00:00
|
|
|
|
zpath = GetProgramExecutableName();
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
CHECK_NE(-1, (zfd = open(zpath, O_RDONLY)));
|
|
|
|
|
CHECK_NE(-1, fstat(zfd, &zst));
|
|
|
|
|
OpenZip(true);
|
|
|
|
|
SetDefaults();
|
2022-10-17 18:02:04 +00:00
|
|
|
|
// this can fail with EPERM if we're running under pledge()
|
|
|
|
|
if (!interpretermode && !(interfaces = GetHostIps())) {
|
|
|
|
|
WARNF("(srvr) failed to query system network interface addresses: %m");
|
|
|
|
|
}
|
2023-06-03 14:50:29 +00:00
|
|
|
|
LuaStart();
|
|
|
|
|
GetOpts(argc, argv);
|
2022-07-09 12:49:19 +00:00
|
|
|
|
#ifndef STATIC
|
2022-07-09 08:18:55 +00:00
|
|
|
|
if (selfmodifiable) {
|
|
|
|
|
MakeExecutableModifiable();
|
|
|
|
|
}
|
2022-07-09 12:49:19 +00:00
|
|
|
|
#endif
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
LuaInit();
|
|
|
|
|
oldloglevel = __log_level;
|
2022-05-14 11:33:58 +00:00
|
|
|
|
if (uniprocess) {
|
|
|
|
|
shared->workers = 1;
|
|
|
|
|
}
|
2022-07-24 01:58:31 +00:00
|
|
|
|
if (daemonize) {
|
|
|
|
|
if (!logpath)
|
|
|
|
|
ProgramLogPath("/dev/null");
|
|
|
|
|
dup2(2, 1);
|
|
|
|
|
}
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
SigInit();
|
|
|
|
|
Listen();
|
|
|
|
|
TlsInit();
|
2021-06-24 19:31:26 +00:00
|
|
|
|
if (launchbrowser) {
|
|
|
|
|
LaunchBrowser(launchbrowser);
|
2021-02-27 18:47:19 +00:00
|
|
|
|
}
|
2021-05-03 08:21:50 +00:00
|
|
|
|
if (daemonize) {
|
|
|
|
|
Daemonize();
|
|
|
|
|
}
|
2022-07-24 01:58:31 +00:00
|
|
|
|
if (pidpath) {
|
2023-10-12 04:45:27 +00:00
|
|
|
|
fd = open(pidpath, O_CREAT | O_WRONLY | O_TRUNC, 0644);
|
2022-07-24 01:58:31 +00:00
|
|
|
|
WRITE(fd, ibuf, FormatInt32(ibuf, getpid()) - ibuf);
|
|
|
|
|
close(fd);
|
|
|
|
|
}
|
|
|
|
|
ChangeUser();
|
2022-11-06 02:49:41 +00:00
|
|
|
|
UpdateCurrentDate(timespec_real());
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
CollectGarbage();
|
2021-03-25 09:21:13 +00:00
|
|
|
|
hdrbuf.n = 4 * 1024;
|
2021-05-03 08:21:50 +00:00
|
|
|
|
hdrbuf.p = xmalloc(hdrbuf.n);
|
2022-03-18 09:33:37 +00:00
|
|
|
|
inbuf_actual.n = maxpayloadsize;
|
|
|
|
|
inbuf_actual.p = xmalloc(inbuf_actual.n);
|
|
|
|
|
inbuf = inbuf_actual;
|
2021-08-09 21:45:52 +00:00
|
|
|
|
isinitialized = true;
|
Make improvements to redbean
The following Lua APIs have been added:
- IsDaemon() → bool
- ProgramPidPath(str)
The following Lua hooks have been added:
- OnClientConnection(ip:int,port:int,serverip:int,serverport:int) → bool
- OnProcessCreate(pid:int,ip:int,port:int,serverip:int,serverport:int)
- OnProcessDestroy(pid:int)
- OnServerStart()
- OnServerStop()
- OnWorkerStart()
- OnWorkerStop()
redbean now does a better job at applying gzip on the fly from the local
filesystem, using a streaming chunked api with constant memory, which is
useful for doing things like serving a 4gb text file off NFS, and having
it start transmitting in milliseconds. redbean will also compute entropy
on the beginnings of files to determine if compression is profitable.
This change pays off technical debts relating to memory, such as relying
on exit() to free() allocations. That's now mostly fixed so it should be
easier now to spot memory leaks in malloc traces.
This change also fixes bugs and makes improvements to our SSL support.
Uniprocess mode failed handshakes are no longer an issue. Token Alpn is
offered so curl -v looks less weird. Hybrid SSL certificate loading is
now smarter about naming conflicts. Self-signed CA root anchors will no
longer be delivered to the client during the handshake.
2021-07-10 22:02:03 +00:00
|
|
|
|
CallSimpleHookIfDefined("OnServerStart");
|
2022-04-17 03:29:08 +00:00
|
|
|
|
#ifdef STATIC
|
2022-11-06 02:49:41 +00:00
|
|
|
|
EventLoop(timespec_tomillis(heartbeatinterval));
|
2022-04-17 03:29:08 +00:00
|
|
|
|
#else
|
2022-04-24 16:59:22 +00:00
|
|
|
|
if (daemonize || uniprocess || !linenoiseIsTerminal()) {
|
2022-11-06 02:49:41 +00:00
|
|
|
|
EventLoop(timespec_tomillis(heartbeatinterval));
|
2022-04-17 03:29:08 +00:00
|
|
|
|
} else {
|
2022-04-23 01:55:28 +00:00
|
|
|
|
ReplEventLoop();
|
2022-04-17 03:29:08 +00:00
|
|
|
|
}
|
|
|
|
|
#endif
|
2022-06-26 01:17:31 +00:00
|
|
|
|
if (!isexitingworker) {
|
2022-07-24 01:58:31 +00:00
|
|
|
|
HandleShutdown();
|
|
|
|
|
CallSimpleHookIfDefined("OnServerStop");
|
2022-05-14 11:33:58 +00:00
|
|
|
|
}
|
2022-07-24 01:58:31 +00:00
|
|
|
|
if (!IsTiny()) {
|
|
|
|
|
LuaDestroy();
|
|
|
|
|
TlsDestroy();
|
|
|
|
|
MemDestroy();
|
2022-06-11 04:51:46 +00:00
|
|
|
|
}
|
2020-10-06 06:11:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int main(int argc, char *argv[]) {
|
2023-10-03 15:14:01 +00:00
|
|
|
|
lua_progname = "redbean";
|
|
|
|
|
|
Make improvements
- Every unit test now passes on Apple Silicon. The final piece of this
puzzle was porting our POSIX threads cancelation support, since that
works differently on ARM64 XNU vs. AMD64. Our semaphore support on
Apple Silicon is also superior now compared to AMD64, thanks to the
grand central dispatch library which lets *NSYNC locks go faster.
- The Cosmopolitan runtime is now more stable, particularly on Windows.
To do this, thread local storage is mandatory at all runtime levels,
and the innermost packages of the C library is no longer being built
using ASAN. TLS is being bootstrapped with a 128-byte TIB during the
process startup phase, and then later on the runtime re-allocates it
either statically or dynamically to support code using _Thread_local.
fork() and execve() now do a better job cooperating with threads. We
can now check how much stack memory is left in the process or thread
when functions like kprintf() / execve() etc. call alloca(), so that
ENOMEM can be raised, reduce a buffer size, or just print a warning.
- POSIX signal emulation is now implemented the same way kernels do it
with pthread_kill() and raise(). Any thread can interrupt any other
thread, regardless of what it's doing. If it's blocked on read/write
then the killer thread will cancel its i/o operation so that EINTR can
be returned in the mark thread immediately. If it's doing a tight CPU
bound operation, then that's also interrupted by the signal delivery.
Signal delivery works now by suspending a thread and pushing context
data structures onto its stack, and redirecting its execution to a
trampoline function, which calls SetThreadContext(GetCurrentThread())
when it's done.
- We're now doing a better job managing locks and handles. On NetBSD we
now close semaphore file descriptors in forked children. Semaphores on
Windows can now be canceled immediately, which means mutexes/condition
variables will now go faster. Apple Silicon semaphores can be canceled
too. We're now using Apple's pthread_yield() funciton. Apple _nocancel
syscalls are now used on XNU when appropriate to ensure pthread_cancel
requests aren't lost. The MbedTLS library has been updated to support
POSIX thread cancelations. See tool/build/runitd.c for an example of
how it can be used for production multi-threaded tls servers. Handles
on Windows now leak less often across processes. All i/o operations on
Windows are now overlapped, which means file pointers can no longer be
inherited across dup() and fork() for the time being.
- We now spawn a thread on Windows to deliver SIGCHLD and wakeup wait4()
which means, for example, that posix_spawn() now goes 3x faster. POSIX
spawn is also now more correct. Like Musl, it's now able to report the
failure code of execve() via a pipe although our approach favors using
shared memory to do that on systems that have a true vfork() function.
- We now spawn a thread to deliver SIGALRM to threads when setitimer()
is used. This enables the most precise wakeups the OS makes possible.
- The Cosmopolitan runtime now uses less memory. On NetBSD for example,
it turned out the kernel would actually commit the PT_GNU_STACK size
which caused RSS to be 6mb for every process. Now it's down to ~4kb.
On Apple Silicon, we reduce the mandatory upstream thread size to the
smallest possible size to reduce the memory overhead of Cosmo threads.
The examples directory has a program called greenbean which can spawn
a web server on Linux with 10,000 worker threads and have the memory
usage of the process be ~77mb. The 1024 byte overhead of POSIX-style
thread-local storage is now optional; it won't be allocated until the
pthread_setspecific/getspecific functions are called. On Windows, the
threads that get spawned which are internal to the libc implementation
use reserve rather than commit memory, which shaves a few hundred kb.
- sigaltstack() is now supported on Windows, however it's currently not
able to be used to handle stack overflows, since crash signals are
still generated by WIN32. However the crash handler will still switch
to the alt stack, which is helpful in environments with tiny threads.
- Test binaries are now smaller. Many of the mandatory dependencies of
the test runner have been removed. This ensures many programs can do a
better job only linking the the thing they're testing. This caused the
test binaries for LIBC_FMT for example, to decrease from 200kb to 50kb
- long double is no longer used in the implementation details of libc,
except in the APIs that define it. The old code that used long double
for time (instead of struct timespec) has now been thoroughly removed.
- ShowCrashReports() is now much tinier in MODE=tiny. Instead of doing
backtraces itself, it'll just print a command you can run on the shell
using our new `cosmoaddr2line` program to view the backtrace.
- Crash report signal handling now works in a much better way. Instead
of terminating the process, it now relies on SA_RESETHAND so that the
default SIG_IGN behavior can terminate the process if necessary.
- Our pledge() functionality has now been fully ported to AARCH64 Linux.
2023-09-19 03:44:45 +00:00
|
|
|
|
#if !IsTiny()
|
2023-06-04 09:57:17 +00:00
|
|
|
|
ShowCrashReports();
|
|
|
|
|
#endif
|
2023-10-03 15:14:01 +00:00
|
|
|
|
|
2024-08-17 13:45:35 +00:00
|
|
|
|
// just in case
|
|
|
|
|
setlocale(LC_ALL, "C.UTF-8");
|
|
|
|
|
|
2022-05-12 18:01:58 +00:00
|
|
|
|
LoadZipArgs(&argc, &argv);
|
2021-05-02 18:50:43 +00:00
|
|
|
|
RedBean(argc, argv);
|
2022-07-09 12:49:19 +00:00
|
|
|
|
|
|
|
|
|
// try to detect memory leaks upon:
|
|
|
|
|
// 1. main process exit
|
|
|
|
|
// 2. unwound worker exit
|
2022-03-18 09:33:37 +00:00
|
|
|
|
if (IsModeDbg()) {
|
2022-07-09 12:49:19 +00:00
|
|
|
|
if (isexitingworker) {
|
2022-07-10 11:01:17 +00:00
|
|
|
|
linenoiseDisableRawMode();
|
|
|
|
|
linenoiseHistoryFree();
|
2022-07-09 12:49:19 +00:00
|
|
|
|
}
|
2022-03-18 09:33:37 +00:00
|
|
|
|
CheckForMemoryLeaks();
|
|
|
|
|
}
|
2022-07-09 12:49:19 +00:00
|
|
|
|
|
2020-09-07 04:39:00 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|