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 net 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-05-14 11:33:58 +00:00
|
|
|
|
#include "libc/calls/ioctl.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"
|
2022-06-23 20:01:01 +00:00
|
|
|
|
#include "libc/dce.h"
|
2021-06-24 19:31:26 +00:00
|
|
|
|
#include "libc/dns/dns.h"
|
|
|
|
|
#include "libc/dns/hoststxt.h"
|
2023-06-10 01:02:06 +00:00
|
|
|
|
#include "libc/dos.internal.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"
|
2022-08-12 12:17:06 +00:00
|
|
|
|
#include "libc/intrin/atomic.h"
|
2022-10-17 18:02:04 +00:00
|
|
|
|
#include "libc/intrin/bits.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.internal.h"
|
2022-08-12 12:17:06 +00:00
|
|
|
|
#include "libc/intrin/safemacros.internal.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.internal.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"
|
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-23 01:55:28 +00:00
|
|
|
|
#include "libc/nexgen32e/nt2sysv.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"
|
2022-04-23 01:55:28 +00:00
|
|
|
|
#include "libc/nt/thread.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"
|
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"
|
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"
|
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"
|
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-07-10 11:01:17 +00:00
|
|
|
|
#include "libc/thread/spawn.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.internal.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"
|
2020-10-06 06:11:49 +00:00
|
|
|
|
#include "third_party/zlib/zlib.h"
|
2022-05-12 18:01:58 +00:00
|
|
|
|
#include "tool/args/args.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
|
|
|
|
|
2021-10-14 00:27:13 +00:00
|
|
|
|
STATIC_STACK_SIZE(0x40000);
|
2023-06-17 14:55:35 +00:00
|
|
|
|
|
2023-06-10 16:15:19 +00:00
|
|
|
|
STATIC_YOINK("zipos");
|
2023-06-17 14:55:35 +00:00
|
|
|
|
|
|
|
|
|
#ifndef TINY
|
|
|
|
|
STATIC_YOINK("blink_linux_aarch64"); // for raspberry pi
|
|
|
|
|
STATIC_YOINK("blink_xnu_aarch64"); // is apple silicon
|
|
|
|
|
#endif
|
|
|
|
|
|
2022-06-23 20:01:01 +00:00
|
|
|
|
#if !IsTiny()
|
2023-05-14 16:32:15 +00:00
|
|
|
|
#ifdef __x86_64__
|
2022-06-23 20:01:01 +00:00
|
|
|
|
STATIC_YOINK("ShowCrashReportsEarly");
|
|
|
|
|
#endif
|
2023-05-14 16:32:15 +00:00
|
|
|
|
#endif
|
2021-10-14 00:27:13 +00:00
|
|
|
|
|
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
|
|
|
|
|
* contains your assets. All you need to do is download the redbean.com
|
|
|
|
|
* program below, change the filename to .zip, add your content in a zip
|
|
|
|
|
* editing tool, and then change the extension back to .com.
|
|
|
|
|
*
|
|
|
|
|
* 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
|
|
|
|
|
|
2022-11-02 16:52:54 +00:00
|
|
|
|
#define VERSION 0x020200
|
2021-03-25 09:21:13 +00:00
|
|
|
|
#define HASH_LOAD_FACTOR /* 1. / */ 4
|
2022-05-14 11:33:58 +00:00
|
|
|
|
#define MONITOR_MICROS 150000
|
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)
|
2023-05-14 16:32:15 +00:00
|
|
|
|
#define LockInc(P) (*(_Atomic(typeof(*(P))) *)(P))++
|
|
|
|
|
#define LockDec(P) (*(_Atomic(typeof(*(P))) *)(P))--
|
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))
|
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;
|
|
|
|
|
} * 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;
|
|
|
|
|
} * p;
|
|
|
|
|
} 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;
|
|
|
|
|
} * p;
|
|
|
|
|
} 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;
|
|
|
|
|
} * p;
|
|
|
|
|
} 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;
|
2020-10-06 06:11:49 +00:00
|
|
|
|
} * p;
|
|
|
|
|
} 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;
|
|
|
|
|
} * file;
|
2020-10-06 06:11:49 +00:00
|
|
|
|
} * p;
|
|
|
|
|
} 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;
|
|
|
|
|
} * 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 {
|
2021-04-18 18:34:59 +00:00
|
|
|
|
int workers;
|
2022-08-06 02:24:05 +00:00
|
|
|
|
struct timespec nowish;
|
|
|
|
|
struct timespec lastreindex;
|
|
|
|
|
struct timespec lastmeltdown;
|
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 {
|
|
|
|
|
#define C(x) long x;
|
|
|
|
|
#include "tool/net/counters.inc"
|
|
|
|
|
#undef C
|
|
|
|
|
} c;
|
2022-09-08 18:54:56 +00:00
|
|
|
|
pthread_spinlock_t montermlock;
|
2021-03-29 08:22:49 +00:00
|
|
|
|
} * shared;
|
|
|
|
|
|
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;
|
2022-04-23 01:55:28 +00:00
|
|
|
|
static bool isterminal;
|
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;
|
2021-03-25 09:21:13 +00:00
|
|
|
|
static bool checkedmethod;
|
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;
|
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-04-23 17:45:19 +00:00
|
|
|
|
static bool loggednetworkorigin;
|
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;
|
2022-11-11 05:52:47 +00:00
|
|
|
|
static atomic_int terminatemonitor;
|
2020-10-06 06:11:49 +00:00
|
|
|
|
|
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;
|
2022-06-26 01:17:31 +00:00
|
|
|
|
static char *replstack;
|
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;
|
2021-03-29 08:22:49 +00:00
|
|
|
|
static const char *brand;
|
2022-06-26 01:17:31 +00:00
|
|
|
|
static char *monitorstack;
|
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;
|
2022-04-17 03:29:08 +00:00
|
|
|
|
static const char *histpath;
|
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-02-24 06:24:40 +00:00
|
|
|
|
static const char *cachedirective;
|
2022-05-14 11:33:58 +00:00
|
|
|
|
static const char *monitortty;
|
2020-10-06 06:11:49 +00:00
|
|
|
|
static const char *serverheader;
|
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-07-10 11:01:17 +00:00
|
|
|
|
static struct spawn replth;
|
|
|
|
|
static struct spawn monitorth;
|
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) {
|
2020-10-06 06:11:49 +00:00
|
|
|
|
int c, m, l, r, z;
|
|
|
|
|
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) {
|
|
|
|
|
m = (l + r) >> 1;
|
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),
|
2022-09-13 06:10:38 +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",
|
2022-09-13 06:10:38 +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)",
|
2022-09-13 06:10:38 +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",
|
2022-09-13 06:10:38 +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",
|
2022-09-13 06:10:38 +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};
|
|
|
|
|
if ((rc = getaddrinfo(addr, "0", &hint, &ai)) != EAI_SUCCESS) {
|
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
|
|
|
|
}
|
|
|
|
|
ip = ntohl(ai->ai_addr4->sin_addr.s_addr);
|
|
|
|
|
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;
|
|
|
|
|
const char *s;
|
|
|
|
|
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) {
|
|
|
|
|
char str[40];
|
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-02-24 06:24:40 +00:00
|
|
|
|
if (s) cachedirective = s;
|
2021-03-29 08:22:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-03-25 09:21:13 +00:00
|
|
|
|
static void SetDefaults(void) {
|
2022-09-13 06:10:38 +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-05-27 01:29:00 +00:00
|
|
|
|
static void UpdateLuaPath(const char *s) {
|
|
|
|
|
#ifndef STATIC
|
|
|
|
|
lua_State *L = GL;
|
|
|
|
|
int n = lua_gettop(L);
|
|
|
|
|
lua_getglobal(L, "package");
|
|
|
|
|
if (lua_istable(L, -1)) {
|
|
|
|
|
lua_getfield(L, -1, "path");
|
|
|
|
|
lua_pushstring(L, _gc(xasprintf("%s;%s/.lua/?.lua;%s/.lua/?/init.lua",
|
|
|
|
|
luaL_optstring(L, -1, ""), s, s)));
|
|
|
|
|
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) {
|
|
|
|
|
char *p, *v, *h;
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
2021-08-22 22:01:52 +00:00
|
|
|
|
static void LogLuaError(char *hook, char *err) {
|
|
|
|
|
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) {
|
2022-09-13 06:10:38 +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) {
|
2022-05-14 11:33:58 +00:00
|
|
|
|
int workers;
|
2022-05-18 23:41:29 +00:00
|
|
|
|
workers = atomic_fetch_sub(&shared->workers, 1) - 1;
|
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);
|
2022-11-06 02:49:41 +00:00
|
|
|
|
rusage_add(&shared->children, ru);
|
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);
|
|
|
|
|
v[1].iov_base = buf;
|
|
|
|
|
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 iovec v[2];
|
|
|
|
|
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;
|
|
|
|
|
ssize_t s;
|
|
|
|
|
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;
|
2021-07-12 06:17:47 +00:00
|
|
|
|
struct TlsBio *bio = ctx;
|
2021-07-08 04:44:27 +00:00
|
|
|
|
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) {
|
|
|
|
|
size_t i;
|
|
|
|
|
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),
|
2022-09-13 06:10:38 +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),
|
2022-09-13 06:10:38 +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",
|
2022-09-13 06:10:38 +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",
|
2022-09-13 06:10:38 +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",
|
2022-09-13 06:10:38 +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(),
|
2022-09-13 06:10:38 +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) {
|
|
|
|
|
int r;
|
|
|
|
|
const char *s;
|
|
|
|
|
bool isduplicate;
|
|
|
|
|
size_t i, j, k, nsan;
|
|
|
|
|
struct HostsTxt *htxt;
|
|
|
|
|
struct mbedtls_san *san;
|
|
|
|
|
const mbedtls_x509_name *xname;
|
|
|
|
|
char *name, *subject, *issuer, notbefore[16], notafter[16], hbuf[256];
|
|
|
|
|
san = 0;
|
|
|
|
|
nsan = 0;
|
|
|
|
|
name = 0;
|
|
|
|
|
htxt = GetHostsTxt();
|
|
|
|
|
strcpy(hbuf, "localhost");
|
|
|
|
|
gethostname(hbuf, sizeof(hbuf));
|
|
|
|
|
for (i = 0; i < htxt->entries.i; ++i) {
|
|
|
|
|
for (j = 0; j < ips.n; ++j) {
|
2023-03-06 06:57:22 +00:00
|
|
|
|
if (IsLoopbackIp(ips.p[j])) continue;
|
2021-06-24 19:31:26 +00:00
|
|
|
|
if (ips.p[j] == READ32BE(htxt->entries.p[i].ip)) {
|
|
|
|
|
isduplicate = false;
|
|
|
|
|
s = htxt->strings.p + htxt->entries.p[i].name;
|
|
|
|
|
if (!name) name = s;
|
|
|
|
|
for (k = 0; k < nsan; ++k) {
|
|
|
|
|
if (san[k].tag == MBEDTLS_X509_SAN_DNS_NAME &&
|
|
|
|
|
!strcasecmp(s, san[k].val)) {
|
|
|
|
|
isduplicate = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!isduplicate) {
|
2022-06-11 04:51:46 +00:00
|
|
|
|
san = realloc(san, (nsan += 2) * sizeof(*san));
|
|
|
|
|
san[nsan - 2].tag = MBEDTLS_X509_SAN_DNS_NAME;
|
|
|
|
|
san[nsan - 2].val = s;
|
2021-06-24 19:31:26 +00:00
|
|
|
|
san[nsan - 1].tag = MBEDTLS_X509_SAN_DNS_NAME;
|
2022-09-13 06:10:38 +00:00
|
|
|
|
san[nsan - 1].val = _gc(xasprintf("*.%s", s));
|
2021-06-24 19:31:26 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for (i = 0; i < ips.n; ++i) {
|
2023-03-06 06:57:22 +00:00
|
|
|
|
if (IsLoopbackIp(ips.p[i])) continue;
|
2021-06-24 19:31:26 +00:00
|
|
|
|
san = realloc(san, ++nsan * sizeof(*san));
|
|
|
|
|
san[nsan - 1].tag = MBEDTLS_X509_SAN_IP_ADDRESS;
|
|
|
|
|
san[nsan - 1].ip4 = ips.p[i];
|
|
|
|
|
}
|
|
|
|
|
ChooseCertificateLifetime(notbefore, notafter);
|
|
|
|
|
subject = xasprintf("CN=%s", name ? name : hbuf);
|
|
|
|
|
if (ca) {
|
|
|
|
|
issuer = calloc(1, 1000);
|
|
|
|
|
CHECK_GT(mbedtls_x509_dn_gets(issuer, 1000, &ca->cert->subject), 0);
|
|
|
|
|
} else {
|
|
|
|
|
issuer = strdup(subject);
|
|
|
|
|
}
|
|
|
|
|
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",
|
2022-09-13 06:10:38 +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-04-23 17:45:19 +00:00
|
|
|
|
shared->nowish = now;
|
2021-03-25 09:21:13 +00:00
|
|
|
|
gmtime_r(&t, &tm);
|
2021-04-23 17:45:19 +00:00
|
|
|
|
FormatHttpDateTime(shared->currentdate, &tm);
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
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);
|
2022-09-13 06:10:38 +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 {
|
|
|
|
|
i = (hash + (step * (step + 1)) >> 1) & (m - 1);
|
|
|
|
|
++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;
|
2021-05-03 19:09:35 +00:00
|
|
|
|
struct stat st;
|
2023-06-17 11:20:16 +00:00
|
|
|
|
uint8_t *m, *d, *p;
|
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) {
|
|
|
|
|
i = (hash + (step * (step + 1)) >> 1) & (assets.n - 1);
|
|
|
|
|
if (!assets.p[i].hash) 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) {
|
|
|
|
|
char *path2;
|
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);
|
2022-09-13 06:10:38 +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");
|
|
|
|
|
}
|
2022-09-13 06:10:38 +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);
|
2022-08-06 02:24:05 +00:00
|
|
|
|
return AppendExpires(p, shared->nowish.tv_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) {
|
2021-04-21 02:14:21 +00:00
|
|
|
|
int mode;
|
2021-03-25 09:21:13 +00:00
|
|
|
|
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) {
|
2021-04-21 02:14:21 +00:00
|
|
|
|
p = AppendContentType(p, "text/html; charset=ISO-8859-1");
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-12 07:42:14 +00:00
|
|
|
|
static char *ServeErrorImpl(unsigned code, const char *reason,
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-02 02:47:59 +00:00
|
|
|
|
static char *ServeErrorWithPath(unsigned code, const char *reason,
|
|
|
|
|
const char *path, size_t pathlen) {
|
|
|
|
|
ERRORF("(srvr) server error: %d %s %`'.*s", code, reason,
|
|
|
|
|
pathlen, path);
|
|
|
|
|
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) {
|
2021-09-07 18:40:11 +00:00
|
|
|
|
ERRORF("(srvr) failure: %d %s %s HTTP%02d %.*s %`'.*s %`'.*s %`'.*s %`'.*s",
|
2022-08-06 00:34:53 +00:00
|
|
|
|
code, reason, DescribeClient(), cpm.msg.version,
|
|
|
|
|
cpm.msg.xmethod.b - cpm.msg.xmethod.a, inbuf.p + cpm.msg.xmethod.a,
|
|
|
|
|
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);
|
2022-05-14 18:47:16 +00:00
|
|
|
|
if (__replmode) {
|
|
|
|
|
sa.sa_flags = SA_RESETHAND;
|
|
|
|
|
sa.sa_handler = OnLuaServerPageCtrlc;
|
|
|
|
|
sigemptyset(&sa.sa_mask);
|
|
|
|
|
sigaction(SIGINT, &sa, &saold);
|
|
|
|
|
}
|
|
|
|
|
status = LuaCallWithTrace(L, 0, 0, co);
|
|
|
|
|
if (__replmode) {
|
|
|
|
|
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;
|
|
|
|
|
void *res;
|
2021-07-19 21:55:20 +00:00
|
|
|
|
int level;
|
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
|
|
|
|
i = 0;
|
|
|
|
|
if (!dg.t) {
|
|
|
|
|
v[0].iov_base = kGzipHeader;
|
|
|
|
|
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;
|
2021-04-21 02:14:21 +00:00
|
|
|
|
uint32_t crc;
|
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
|
|
|
|
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;
|
|
|
|
|
void *res;
|
|
|
|
|
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
|
|
|
|
uint32_t crc;
|
|
|
|
|
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) {
|
2021-03-29 09:39:20 +00:00
|
|
|
|
char *p1, *p2;
|
|
|
|
|
size_t n1, n2;
|
2021-05-14 12:36:58 +00:00
|
|
|
|
p1 = ZIP_CFILE_NAME(zcf);
|
|
|
|
|
n1 = ZIP_CFILE_NAMESIZE(zcf);
|
2021-04-18 18:34:59 +00:00
|
|
|
|
p2 = xmalloc(1 + n1 + 1);
|
2021-03-29 09:39:20 +00:00
|
|
|
|
n2 = 1 + n1 + 1;
|
|
|
|
|
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()) {
|
2021-05-03 18:52:24 +00:00
|
|
|
|
return "explorer";
|
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) {
|
|
|
|
|
int pid, ws;
|
|
|
|
|
struct in_addr addr;
|
|
|
|
|
const char *u, *prog;
|
|
|
|
|
sigset_t chldmask, savemask;
|
|
|
|
|
struct sigaction ignore, saveint, savequit;
|
2022-03-05 01:41:19 +00:00
|
|
|
|
uint16_t port = 80;
|
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);
|
2022-09-13 06:10:38 +00:00
|
|
|
|
if (*path != '/') path = _gc(xasprintf("/%s", path));
|
|
|
|
|
if ((prog = commandv(GetSystemUrlLauncherCommand(), _gc(malloc(PATH_MAX)),
|
2022-04-28 16:42:36 +00:00
|
|
|
|
PATH_MAX))) {
|
2022-09-13 06:10:38 +00:00
|
|
|
|
u = _gc(xasprintf("http://%s:%d%s", inet_ntoa(addr), port, path));
|
2021-10-25 21:44:04 +00:00
|
|
|
|
DEBUGF("(srvr) opening browser with command %`'s %s", prog, u);
|
2021-05-03 18:52:24 +00:00
|
|
|
|
ignore.sa_flags = 0;
|
|
|
|
|
ignore.sa_handler = SIG_IGN;
|
|
|
|
|
sigemptyset(&ignore.sa_mask);
|
|
|
|
|
sigaction(SIGINT, &ignore, &saveint);
|
|
|
|
|
sigaction(SIGQUIT, &ignore, &savequit);
|
|
|
|
|
sigemptyset(&chldmask);
|
|
|
|
|
sigaddset(&chldmask, SIGCHLD);
|
|
|
|
|
sigprocmask(SIG_BLOCK, &chldmask, &savemask);
|
|
|
|
|
CHECK_NE(-1, (pid = fork()));
|
|
|
|
|
if (!pid) {
|
2022-04-20 16:56:53 +00:00
|
|
|
|
setpgrp(); // ctrl-c'ing redbean shouldn't kill browser
|
2021-05-03 18:52:24 +00:00
|
|
|
|
sigaction(SIGINT, &saveint, 0);
|
|
|
|
|
sigaction(SIGQUIT, &savequit, 0);
|
|
|
|
|
sigprocmask(SIG_SETMASK, &savemask, 0);
|
|
|
|
|
execv(prog, (char *const[]){prog, u, 0});
|
2022-03-23 04:04:08 +00:00
|
|
|
|
_Exit(127);
|
2021-05-03 18:52:24 +00:00
|
|
|
|
}
|
|
|
|
|
while (wait4(pid, &ws, 0, 0) == -1) {
|
|
|
|
|
CHECK_EQ(EINTR, errno);
|
2022-03-19 10:37:00 +00:00
|
|
|
|
errno = 0;
|
2021-05-03 18:52:24 +00:00
|
|
|
|
}
|
|
|
|
|
sigaction(SIGINT, &saveint, 0);
|
|
|
|
|
sigaction(SIGQUIT, &savequit, 0);
|
|
|
|
|
sigprocmask(SIG_SETMASK, &savemask, 0);
|
|
|
|
|
if (!(WIFEXITED(ws) && WEXITSTATUS(ws) == 0)) {
|
2021-10-25 21:44:04 +00:00
|
|
|
|
WARNF("(srvr) command %`'s exited with %d", GetSystemUrlLauncherCommand(),
|
2021-05-03 18:52:24 +00:00
|
|
|
|
WIFEXITED(ws) ? WEXITSTATUS(ws) : 128 + WEXITSTATUS(ws));
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2021-10-25 21:44:04 +00:00
|
|
|
|
WARNF("(srvr) can't launch browser because %`'s isn't installed",
|
2021-05-03 18:52:24 +00:00
|
|
|
|
GetSystemUrlLauncherCommand());
|
2021-05-03 17:55:21 +00:00
|
|
|
|
}
|
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) {
|
2022-09-13 06:10:38 +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;
|
|
|
|
|
const char *and;
|
|
|
|
|
struct rusage ru;
|
|
|
|
|
char *p, *q, *path;
|
2021-08-14 13:17:56 +00:00
|
|
|
|
struct timespec lastmod;
|
2021-07-04 19:21:29 +00:00
|
|
|
|
char rb[8], tb[20], *rp[6];
|
2021-04-25 00:09:01 +00:00
|
|
|
|
size_t i, n, pathlen, rn[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\
|
|
|
|
|
");
|
2021-05-03 19:09:35 +00:00
|
|
|
|
if (shared->c.connectionshandled) {
|
2022-08-06 00:34:53 +00:00
|
|
|
|
appends(&cpm.outbuf, "says your redbean<br>\r\n");
|
|
|
|
|
AppendResourceReport(&cpm.outbuf, &shared->children, "<br>\r\n");
|
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");
|
2021-05-03 19:09:35 +00:00
|
|
|
|
x = shared->c.messageshandled;
|
2022-08-06 00:34:53 +00:00
|
|
|
|
appendf(&cpm.outbuf, "%,ld message%s handled<br>\r\n", x, x == 1 ? "" : "s");
|
2021-05-03 19:09:35 +00:00
|
|
|
|
x = shared->c.connectionshandled;
|
2022-08-06 00:34:53 +00:00
|
|
|
|
appendf(&cpm.outbuf, "%,ld connection%s handled<br>\r\n", x,
|
|
|
|
|
x == 1 ? "" : "s");
|
2021-04-25 00:09:01 +00:00
|
|
|
|
x = shared->workers;
|
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) {
|
|
|
|
|
const long *c;
|
|
|
|
|
const char *s;
|
|
|
|
|
for (c = (const long *)&shared->c, s = kCounterNames; *s;
|
|
|
|
|
++c, s += strlen(s) + 1) {
|
|
|
|
|
AppendLong1(s, *c);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
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);
|
2022-08-06 02:24:05 +00:00
|
|
|
|
AppendLong1("nowish", shared->nowish.tv_sec);
|
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);
|
|
|
|
|
AppendLong1("lastmeltdown", shared->lastmeltdown.tv_sec);
|
2021-04-25 00:09:01 +00:00
|
|
|
|
AppendLong1("workers", shared->workers);
|
|
|
|
|
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();
|
2021-04-25 00:09:01 +00:00
|
|
|
|
AppendRusage("server", &shared->server);
|
|
|
|
|
AppendRusage("children", &shared->children);
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
2021-04-25 00:09:01 +00:00
|
|
|
|
static char *GetLuaResponse(void) {
|
2022-08-06 00:34:53 +00:00
|
|
|
|
return cpm.luaheaderp ? cpm.luaheaderp : SetStatus(200, "OK");
|
2021-04-21 02:14:21 +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);
|
|
|
|
|
effectivepath.p = s;
|
|
|
|
|
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) {
|
|
|
|
|
size_t loclen;
|
|
|
|
|
const char *location, *eval;
|
|
|
|
|
int code;
|
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);
|
2022-09-13 06:10:38 +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);
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-15 00:19:31 +00:00
|
|
|
|
static void StoreAsset(char *path, size_t pathlen, char *data, size_t datalen,
|
2022-03-18 09:33:37 +00:00
|
|
|
|
int mode) {
|
2021-05-03 20:06:43 +00:00
|
|
|
|
int64_t ft;
|
2022-03-15 00:19:31 +00:00
|
|
|
|
int i;
|
2021-05-03 20:06:43 +00:00
|
|
|
|
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];
|
|
|
|
|
uint8_t *cdir, 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;
|
Introduce --strace flag for system call tracing
This is similar to the --ftrace (c function call trace) flag, except
it's less noisy since it only logs system calls to stderr. Having this
flag is valuable because (1) system call tracing tells us a lot about
the behavior of complex programs and (2) it's usually very hard to get
system call tracing on various operating systems, e.g. strace, ktrace,
dtruss, truss, nttrace, etc. Especially on Apple platforms where even
with the special boot trick, debuggers still aren't guaranteed to work.
make -j8 o//examples
o//examples/hello.com --strace
This is enabled by default in MODE=, MODE=opt, and MODE=dbg. In MODE=dbg
extra information will be printed.
make -j8 MODE=dbg o/dbg/examples
o/dbg/examples/hello.com --strace |& less
This change also changes:
- Rename IsText() → _istext()
- Rename IsUtf8() → _isutf8()
- Fix madvise() on Windows NT
- Fix empty string case of inet_ntop()
- vfork() wrapper now saves and restores errno
- Update xsigaction() to yoink syscall support
2022-03-19 01:07:28 +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);
|
2021-05-14 12:36:58 +00:00
|
|
|
|
p = WRITE32LE(p, MIN(uselen, 0xffffffff));
|
|
|
|
|
p = WRITE32LE(p, MIN(datalen, 0xffffffff));
|
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;
|
|
|
|
|
v[1].iov_base = path;
|
|
|
|
|
// file data
|
2021-08-25 12:43:26 +00:00
|
|
|
|
v[3].iov_len = uselen;
|
|
|
|
|
v[3].iov_base = 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);
|
2021-05-14 12:36:58 +00:00
|
|
|
|
p = WRITE32LE(p, MIN(uselen, 0xffffffff));
|
|
|
|
|
p = WRITE32LE(p, MIN(datalen, 0xffffffff));
|
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);
|
2021-05-14 12:36:58 +00:00
|
|
|
|
p = WRITE32LE(p, MIN(zsize, 0xffffffff));
|
|
|
|
|
v[7].iov_len = pathlen;
|
|
|
|
|
v[7].iov_base = path;
|
|
|
|
|
// 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
|
|
|
|
|
v[12].iov_base = GetZipCdirComment(zcdir);
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void StoreFile(char *path) {
|
|
|
|
|
char *p;
|
2022-03-21 10:20:09 +00:00
|
|
|
|
size_t plen, tlen;
|
2022-03-15 00:19:31 +00:00
|
|
|
|
struct stat st;
|
2022-03-21 10:20:09 +00:00
|
|
|
|
char *target = path;
|
2022-09-13 06:10:38 +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;
|
2022-09-13 06:10:38 +00:00
|
|
|
|
if (!isdirectory(dirpath) && !_endswith(dirpath, "/"))
|
2022-03-21 10:20:09 +00:00
|
|
|
|
return StoreFile(dirpath);
|
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;
|
2022-09-13 06:10:38 +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),
|
2022-09-13 06:10:38 +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) {
|
2022-08-06 02:24:05 +00:00
|
|
|
|
lua_pushinteger(L, shared->nowish.tv_sec);
|
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");
|
2022-08-06 00:34:53 +00:00
|
|
|
|
if (cpm.msg.method) {
|
|
|
|
|
lua_pushstring(L, kHttpMethod[cpm.msg.method]);
|
2021-04-25 00:09:01 +00:00
|
|
|
|
} else {
|
2022-08-06 00:34:53 +00:00
|
|
|
|
lua_pushlstring(L, inbuf.p + cpm.msg.xmethod.a,
|
|
|
|
|
cpm.msg.xmethod.b - cpm.msg.xmethod.a);
|
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 {
|
2022-09-13 06:10:38 +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);
|
|
|
|
|
} else if ((p = GetBasicAuthorization(&n))) {
|
|
|
|
|
if (!(q = memchr(p, ':', n))) q = p + n;
|
|
|
|
|
lua_pushlstring(L, p, q - p);
|
|
|
|
|
free(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);
|
|
|
|
|
} else if ((p = GetBasicAuthorization(&n))) {
|
|
|
|
|
if ((q = memchr(p, ':', n))) {
|
|
|
|
|
lua_pushlstring(L, q + 1, p + n - (q + 1));
|
|
|
|
|
} else {
|
|
|
|
|
lua_pushnil(L);
|
|
|
|
|
}
|
|
|
|
|
free(p);
|
|
|
|
|
} 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;
|
2021-03-25 09:21:13 +00:00
|
|
|
|
ssize_t rc;
|
2021-04-25 00:09:01 +00:00
|
|
|
|
char *p, *q;
|
2021-03-28 07:10:17 +00:00
|
|
|
|
const char *key, *val, *eval;
|
|
|
|
|
size_t i, 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");
|
2022-09-13 06:10:38 +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,
|
2022-09-13 06:10:38 +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 {
|
|
|
|
|
expires = lua_tostring(L, -1);
|
|
|
|
|
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) {
|
|
|
|
|
samesite = 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) {
|
|
|
|
|
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) {
|
|
|
|
|
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(
|
2022-09-13 06:10:38 +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;
|
|
|
|
|
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);
|
2022-09-13 06:10:38 +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
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
wontreturn static void Replenisher(void) {
|
|
|
|
|
struct timespec ts;
|
2022-10-19 20:10:00 +00:00
|
|
|
|
VERBOSEF("(token) replenish worker started");
|
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));
|
|
|
|
|
if ((blackhole.fd = socket(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 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
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
tokenbucket.b = _mapshared(ROUNDUP(1ul << cidr, FRAMESIZE));
|
|
|
|
|
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();
|
|
|
|
|
_npassert(pid != -1);
|
|
|
|
|
if (!pid) Replenisher();
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-23 05:02:58 +00:00
|
|
|
|
static const char *GetContentTypeExt(const char *path, size_t n) {
|
|
|
|
|
char *r, *e;
|
|
|
|
|
int top;
|
|
|
|
|
lua_State *L = GL;
|
|
|
|
|
if ((r = FindContentType(path, n))) return r;
|
|
|
|
|
|
|
|
|
|
// extract the last .; use the entire path if none is present
|
|
|
|
|
if (e = strrchr(path, '.')) path = e + 1;
|
|
|
|
|
top = lua_gettop(L);
|
|
|
|
|
lua_pushlightuserdata(L, (void *)&ctIdx); // push address as unique key
|
|
|
|
|
CHECK_EQ(lua_gettable(L, LUA_REGISTRYINDEX), LUA_TTABLE);
|
|
|
|
|
|
|
|
|
|
lua_pushstring(L, path);
|
|
|
|
|
if (lua_gettable(L, -2) == LUA_TSTRING)
|
|
|
|
|
r = FreeLater(strdup(lua_tostring(L, -1)));
|
|
|
|
|
lua_settop(L, top);
|
|
|
|
|
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;
|
2021-04-23 17:45:19 +00:00
|
|
|
|
effectivepath.p = path;
|
|
|
|
|
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}, //
|
|
|
|
|
{"Decimate", LuaDecimate}, //
|
|
|
|
|
{"DecodeBase64", LuaDecodeBase64}, //
|
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}, //
|
2022-06-26 01:17:31 +00:00
|
|
|
|
{"EncodeBase64", LuaEncodeBase64}, //
|
|
|
|
|
{"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}, //
|
|
|
|
|
{"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}, //
|
|
|
|
|
{"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);
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-06 21:12:11 +00:00
|
|
|
|
static char *GetDefaultLuaPath(void) {
|
|
|
|
|
char *s;
|
|
|
|
|
size_t i;
|
|
|
|
|
for (s = 0, i = 0; i < stagedirs.n; ++i) {
|
|
|
|
|
appendf(&s, "%s/.lua/?.lua;%s/.lua/?/init.lua;", stagedirs.p[i].s,
|
|
|
|
|
stagedirs.p[i].s);
|
|
|
|
|
}
|
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
|
|
|
|
appends(&s, "/zip/.lua/?.lua;/zip/.lua/?/init.lua");
|
2021-08-06 21:12:11 +00:00
|
|
|
|
return 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();
|
2021-08-06 21:12:11 +00:00
|
|
|
|
g_lua_path_default = GetDefaultLuaPath();
|
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) {
|
|
|
|
|
m = (l + r) >> 1;
|
|
|
|
|
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;
|
|
|
|
|
const char *s;
|
|
|
|
|
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;
|
|
|
|
|
lua_initrepl(GL, "redbean");
|
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);
|
|
|
|
|
free(g_lua_path_default);
|
|
|
|
|
#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);
|
|
|
|
|
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");
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void LuaReload(void) {
|
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
|
|
|
|
}
|
|
|
|
|
#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)",
|
|
|
|
|
DescribeClient(), reason, amtread, messageshandled, shared->workers);
|
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);
|
2021-06-24 19:31:26 +00:00
|
|
|
|
iov.iov_base = s;
|
|
|
|
|
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) {
|
2022-11-06 02:49:41 +00:00
|
|
|
|
if (timespec_cmp(timespec_sub(timespec_real(), shared->lastmeltdown),
|
|
|
|
|
(struct timespec){1}) < 0) {
|
2022-08-06 02:24:05 +00:00
|
|
|
|
return;
|
2022-11-06 02:49:41 +00:00
|
|
|
|
}
|
2022-06-27 04:16:13 +00:00
|
|
|
|
WARNF("(srvr) server is melting down (%,d workers)", shared->workers);
|
2021-05-03 19:09:35 +00:00
|
|
|
|
LOGIFNEG1(kill(0, SIGUSR2));
|
2022-11-06 02:49:41 +00:00
|
|
|
|
shared->lastmeltdown = timespec_real();
|
2021-05-03 19:09:35 +00:00
|
|
|
|
++shared->c.meltdowns;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
Reindex();
|
|
|
|
|
LuaReload();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void HandleHeartbeat(void) {
|
2021-06-24 19:31:26 +00:00
|
|
|
|
size_t i;
|
|
|
|
|
sigset_t mask;
|
2022-11-06 02:49:41 +00:00
|
|
|
|
UpdateCurrentDate(timespec_real());
|
2021-05-14 12:36:58 +00:00
|
|
|
|
Reindex();
|
2021-05-03 19:09:35 +00:00
|
|
|
|
getrusage(RUSAGE_SELF, &shared->server);
|
|
|
|
|
#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;
|
2022-03-21 14:34:19 +00:00
|
|
|
|
} else if ((st = _gc(malloc(sizeof(struct stat)))) &&
|
|
|
|
|
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
|
|
|
|
}
|
2021-09-04 04:14:26 +00:00
|
|
|
|
INFOF("(req) received %s HTTP%02d %.*s %s %`'.*s %`'.*s", DescribeClient(),
|
2022-08-06 00:34:53 +00:00
|
|
|
|
cpm.msg.version, cpm.msg.xmethod.b - cpm.msg.xmethod.a,
|
|
|
|
|
inbuf.p + cpm.msg.xmethod.a, FreeLater(EncodeUrl(&url, 0)),
|
|
|
|
|
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;
|
|
|
|
|
char *p;
|
|
|
|
|
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;
|
|
|
|
|
uint32_t crc;
|
|
|
|
|
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)) &&
|
2022-09-13 06:10:38 +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) {
|
2021-07-12 06:17:47 +00:00
|
|
|
|
iov[iovlen].iov_base = kGzipHeader;
|
|
|
|
|
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;
|
2022-08-06 00:34:53 +00:00
|
|
|
|
if ((rc = ParseHttpMessage(&cpm.msg, inbuf.p, amtread)) != -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) {
|
2021-04-24 20:58:34 +00:00
|
|
|
|
p = AppendCrlf(stpcpy(stpcpy(p, "Date: "), shared->currentdate));
|
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) {
|
2022-05-29 15:14:55 +00:00
|
|
|
|
char *p;
|
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;
|
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();
|
|
|
|
|
invalidated = false;
|
|
|
|
|
}
|
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();
|
|
|
|
|
invalidated = false;
|
|
|
|
|
}
|
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();
|
|
|
|
|
}
|
2022-05-14 11:33:58 +00:00
|
|
|
|
if (monitortty) {
|
|
|
|
|
terminatemonitor = true;
|
2022-07-10 11:01:17 +00:00
|
|
|
|
_join(&monitorth);
|
2022-05-14 11:33:58 +00:00
|
|
|
|
}
|
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-07-10 11:01:17 +00:00
|
|
|
|
static int MemoryMonitor(void *arg, int tid) {
|
2022-05-14 11:33:58 +00:00
|
|
|
|
static struct termios oldterm;
|
|
|
|
|
static int tty;
|
|
|
|
|
sigset_t ss;
|
|
|
|
|
bool done, ok;
|
|
|
|
|
size_t intervals;
|
|
|
|
|
struct winsize ws;
|
|
|
|
|
unsigned char rez;
|
|
|
|
|
struct termios term;
|
|
|
|
|
char *b, *addr, title[128];
|
|
|
|
|
struct MemoryInterval *mi, *mi2;
|
|
|
|
|
long i, j, k, n, x, y, pi, gen, pages;
|
|
|
|
|
int rc, id, color, color2, workers;
|
2022-05-18 23:41:29 +00:00
|
|
|
|
id = atomic_load_explicit(&shared->workers, memory_order_relaxed);
|
2022-05-14 11:33:58 +00:00
|
|
|
|
DEBUGF("(memv) started for pid %d on tid %d", getpid(), gettid());
|
|
|
|
|
|
|
|
|
|
sigemptyset(&ss);
|
|
|
|
|
sigaddset(&ss, SIGHUP);
|
|
|
|
|
sigaddset(&ss, SIGINT);
|
|
|
|
|
sigaddset(&ss, SIGQUIT);
|
|
|
|
|
sigaddset(&ss, SIGTERM);
|
|
|
|
|
sigaddset(&ss, SIGPIPE);
|
|
|
|
|
sigaddset(&ss, SIGUSR1);
|
|
|
|
|
sigaddset(&ss, SIGUSR2);
|
|
|
|
|
sigprocmask(SIG_BLOCK, &ss, 0);
|
|
|
|
|
|
2022-09-08 18:54:56 +00:00
|
|
|
|
pthread_spin_lock(&shared->montermlock);
|
2022-05-14 11:33:58 +00:00
|
|
|
|
if (!id) {
|
|
|
|
|
if ((tty = open(monitortty, O_RDWR | O_NOCTTY)) != -1) {
|
2023-06-15 00:02:57 +00:00
|
|
|
|
tcgetattr(tty, &oldterm);
|
2022-05-14 11:33:58 +00:00
|
|
|
|
term = oldterm;
|
|
|
|
|
term.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
|
|
|
|
|
term.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
|
|
|
|
|
term.c_oflag |= OPOST | ONLCR;
|
|
|
|
|
term.c_iflag |= IUTF8;
|
|
|
|
|
term.c_cflag |= CS8;
|
|
|
|
|
term.c_cc[VMIN] = 1;
|
|
|
|
|
term.c_cc[VTIME] = 0;
|
2023-06-15 00:02:57 +00:00
|
|
|
|
tcsetattr(tty, TCSANOW, &term);
|
2022-05-14 11:33:58 +00:00
|
|
|
|
WRITE(tty, "\e[?25l", 6);
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-09-08 18:54:56 +00:00
|
|
|
|
pthread_spin_unlock(&shared->montermlock);
|
2022-05-14 11:33:58 +00:00
|
|
|
|
|
|
|
|
|
if (tty != -1) {
|
2022-05-19 23:57:49 +00:00
|
|
|
|
for (gen = 0, mi = 0, b = 0; !terminatemonitor;) {
|
2022-05-18 23:41:29 +00:00
|
|
|
|
workers = atomic_load_explicit(&shared->workers, memory_order_relaxed);
|
2022-05-14 11:33:58 +00:00
|
|
|
|
if (id) id = MAX(1, MIN(id, workers));
|
|
|
|
|
if (!id && workers) {
|
|
|
|
|
usleep(50000);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
++gen;
|
2022-05-18 23:41:29 +00:00
|
|
|
|
intervals = atomic_load_explicit(&_mmi.i, memory_order_relaxed);
|
2022-05-14 11:33:58 +00:00
|
|
|
|
if ((mi2 = realloc(mi, (intervals += 3) * sizeof(*mi)))) {
|
|
|
|
|
mi = mi2;
|
2023-05-19 02:05:08 +00:00
|
|
|
|
mi[0].x = (intptr_t)__executable_start >> 16;
|
|
|
|
|
mi[0].size = _etext - __executable_start;
|
2022-05-20 11:01:50 +00:00
|
|
|
|
mi[0].flags = 0;
|
2022-05-14 11:33:58 +00:00
|
|
|
|
mi[1].x = (intptr_t)_etext >> 16;
|
|
|
|
|
mi[1].size = _edata - _etext;
|
2022-05-20 11:01:50 +00:00
|
|
|
|
mi[1].flags = 0;
|
2022-05-14 11:33:58 +00:00
|
|
|
|
mi[2].x = (intptr_t)_edata >> 16;
|
|
|
|
|
mi[2].size = _end - _edata;
|
2022-05-20 11:01:50 +00:00
|
|
|
|
mi[2].flags = 0;
|
2022-06-11 08:59:26 +00:00
|
|
|
|
__mmi_lock();
|
2022-05-14 11:33:58 +00:00
|
|
|
|
if (_mmi.i == intervals - 3) {
|
|
|
|
|
memcpy(mi + 3, _mmi.p, _mmi.i * sizeof(*mi));
|
|
|
|
|
ok = true;
|
|
|
|
|
} else {
|
|
|
|
|
ok = false;
|
|
|
|
|
}
|
2022-06-11 08:59:26 +00:00
|
|
|
|
__mmi_unlock();
|
2022-05-14 11:33:58 +00:00
|
|
|
|
if (!ok) {
|
2022-05-19 23:57:49 +00:00
|
|
|
|
VERBOSEF("(memv) retrying due to contention on mmap table");
|
2022-05-14 11:33:58 +00:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ws.ws_col = 80;
|
|
|
|
|
ws.ws_row = 40;
|
2023-06-15 00:02:57 +00:00
|
|
|
|
tcgetwinsize(tty, &ws);
|
2022-05-14 11:33:58 +00:00
|
|
|
|
|
|
|
|
|
appendr(&b, 0);
|
|
|
|
|
appends(&b, "\e[H\e[1m");
|
|
|
|
|
|
|
|
|
|
for (pi = k = x = y = i = 0; i < intervals; ++i) {
|
|
|
|
|
addr = (char *)((int64_t)((uint64_t)mi[i].x << 32) >> 16);
|
|
|
|
|
color = 0;
|
|
|
|
|
appendf(&b, "\e[0m%lx", addr);
|
|
|
|
|
pages = (mi[i].size + PAGESIZE - 1) / PAGESIZE;
|
|
|
|
|
for (j = 0; j < pages; ++j) {
|
|
|
|
|
rc = mincore(addr + j * PAGESIZE, PAGESIZE, &rez);
|
|
|
|
|
if (!rc) {
|
|
|
|
|
if (rez & 1) {
|
2022-05-20 11:01:50 +00:00
|
|
|
|
if (mi[i].flags & MAP_SHARED) {
|
|
|
|
|
color2 = 105;
|
|
|
|
|
} else {
|
|
|
|
|
color2 = 42;
|
|
|
|
|
}
|
2022-05-14 11:33:58 +00:00
|
|
|
|
} else {
|
|
|
|
|
color2 = 41;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
errno = 0;
|
|
|
|
|
color2 = 0;
|
|
|
|
|
}
|
|
|
|
|
if (color != color2) {
|
|
|
|
|
color = color2;
|
|
|
|
|
appendf(&b, "\e[%dm", color);
|
|
|
|
|
}
|
2022-05-20 11:01:50 +00:00
|
|
|
|
if (mi[i].flags & MAP_ANONYMOUS) {
|
|
|
|
|
appendw(&b, ' ');
|
|
|
|
|
} else {
|
|
|
|
|
appendw(&b, '/');
|
|
|
|
|
}
|
2022-05-14 11:33:58 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
appendf(&b,
|
|
|
|
|
"\e[0m ID=%d PID=%d WS=%dx%d WORKERS=%d MODE=" MODE
|
|
|
|
|
" GEN=%ld\e[J",
|
|
|
|
|
id, getpid(), ws.ws_col, ws.ws_row, workers, gen);
|
|
|
|
|
|
2022-09-08 18:54:56 +00:00
|
|
|
|
pthread_spin_lock(&shared->montermlock);
|
2022-05-14 11:33:58 +00:00
|
|
|
|
WRITE(tty, b, appendz(b).i);
|
|
|
|
|
appendr(&b, 0);
|
|
|
|
|
usleep(MONITOR_MICROS);
|
2022-09-08 18:54:56 +00:00
|
|
|
|
pthread_spin_unlock(&shared->montermlock);
|
2022-05-14 11:33:58 +00:00
|
|
|
|
} else {
|
|
|
|
|
// running out of memory temporarily is a real possibility here
|
|
|
|
|
// the right thing to do, is stand aside and let lua try to fix
|
|
|
|
|
WARNF("(memv) we require more vespene gas");
|
|
|
|
|
usleep(MONITOR_MICROS);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!id) {
|
|
|
|
|
appendr(&b, 0);
|
|
|
|
|
appends(&b, "\e[H\e[J\e[?25h");
|
|
|
|
|
WRITE(tty, b, appendz(b).i);
|
2023-06-15 00:02:57 +00:00
|
|
|
|
tcsetattr(tty, TCSANOW, &oldterm);
|
2022-05-14 11:33:58 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DEBUGF("(memv) exiting...");
|
|
|
|
|
close(tty);
|
|
|
|
|
free(mi);
|
|
|
|
|
free(b);
|
|
|
|
|
}
|
2022-05-19 23:57:49 +00:00
|
|
|
|
|
2022-05-14 11:33:58 +00:00
|
|
|
|
DEBUGF("(memv) done");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-19 23:57:49 +00:00
|
|
|
|
static void MonitorMemory(void) {
|
2022-07-10 11:01:17 +00:00
|
|
|
|
if (_spawn(MemoryMonitor, 0, &monitorth) == -1) {
|
|
|
|
|
WARNF("(memv) failed to start memory monitor %m");
|
2022-05-19 23:57:49 +00:00
|
|
|
|
}
|
2022-05-14 11:33:58 +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();
|
2022-08-05 22:42:17 +00:00
|
|
|
|
if (UNLIKELY(maxworkers) && shared->workers >= maxworkers) {
|
|
|
|
|
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:
|
2022-05-29 15:14:55 +00:00
|
|
|
|
if (!IsTiny() && monitortty) {
|
2022-05-14 11:33:58 +00:00
|
|
|
|
MonitorMemory();
|
|
|
|
|
}
|
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);
|
2022-05-17 18:38:35 +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 {
|
|
|
|
|
DIEF("(srvr) %s accept error: %m", DescribeServer());
|
|
|
|
|
}
|
|
|
|
|
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;
|
2021-04-18 18:34:59 +00:00
|
|
|
|
size_t n;
|
|
|
|
|
extern char ape_rom_vaddr[] __attribute__((__weak__));
|
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
|
2022-09-13 06:10:38 +00:00
|
|
|
|
if (_endswith(zpath, ".com.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-03-06 07:52:17 +00:00
|
|
|
|
if ((zfd = _OpenExecutable()) == -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
|
2022-04-23 01:55:28 +00:00
|
|
|
|
} else if (__replmode) {
|
|
|
|
|
// handle refresh repl line
|
|
|
|
|
if (!IsWindows()) {
|
|
|
|
|
rc = HandleReadline();
|
|
|
|
|
if (rc < 0) return rc;
|
|
|
|
|
} else {
|
2022-11-02 05:36:03 +00:00
|
|
|
|
strace_enabled(-1);
|
2022-04-23 01:55:28 +00:00
|
|
|
|
linenoiseRefreshLine(lua_repl_linenoise);
|
2022-11-02 05:36:03 +00:00
|
|
|
|
strace_enabled(+1);
|
2022-04-23 01:55:28 +00:00
|
|
|
|
}
|
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
|
|
|
|
invalidated = false;
|
|
|
|
|
} 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;
|
2022-04-26 04:16:05 +00:00
|
|
|
|
lua_initrepl(L, "redbean");
|
2022-06-26 01:17:31 +00:00
|
|
|
|
EnableRawMode();
|
2022-04-23 01:55:28 +00:00
|
|
|
|
EventLoop(100);
|
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-07-10 11:01:17 +00:00
|
|
|
|
static int WindowsReplThread(void *arg, int tid) {
|
2022-04-24 16:59:22 +00:00
|
|
|
|
int sig;
|
2022-04-26 04:16:05 +00:00
|
|
|
|
lua_State *L = GL;
|
2022-05-14 11:33:58 +00:00
|
|
|
|
DEBUGF("(repl) started windows thread");
|
2022-04-23 01:55:28 +00:00
|
|
|
|
lua_repl_blocking = true;
|
2022-04-24 16:59:22 +00:00
|
|
|
|
lua_repl_completions_callback = HandleCompletions;
|
2022-04-26 04:16:05 +00:00
|
|
|
|
lua_initrepl(L, "redbean");
|
2022-06-26 01:17:31 +00:00
|
|
|
|
EnableRawMode();
|
|
|
|
|
while (!terminated) {
|
2022-04-23 01:55:28 +00:00
|
|
|
|
if (HandleReadline() == -1) {
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
}
|
2022-06-26 01:17:31 +00:00
|
|
|
|
DisableRawMode();
|
2022-04-23 01:55:28 +00:00
|
|
|
|
lua_freerepl();
|
2022-06-27 20:01:58 +00:00
|
|
|
|
lua_repl_lock();
|
2022-04-26 04:16:05 +00:00
|
|
|
|
lua_settop(L, 0); // clear stack
|
2022-06-27 20:01:58 +00:00
|
|
|
|
lua_repl_unlock();
|
2022-04-24 16:59:22 +00:00
|
|
|
|
if ((sig = linenoiseGetInterrupt())) {
|
|
|
|
|
raise(sig);
|
|
|
|
|
}
|
2022-05-14 11:33:58 +00:00
|
|
|
|
DEBUGF("(repl) terminating windows thread");
|
2022-04-23 01:55:28 +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
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
|
|
2022-05-19 07:34:15 +00:00
|
|
|
|
if (suiteb && !X86_HAVE(AES)) {
|
2022-06-27 04:16:13 +00:00
|
|
|
|
WARNF("(srvr) requested suite b crypto, but aes-ni is 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;
|
2021-07-12 06:17:47 +00:00
|
|
|
|
DCHECK_EQ(0, mbedtls_ssl_conf_alpn_protocols(&conf, kAlpn));
|
|
|
|
|
DCHECK_EQ(0, mbedtls_ssl_conf_alpn_protocols(&confcli, kAlpn));
|
|
|
|
|
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()
|
2023-03-06 06:57:22 +00:00
|
|
|
|
CASE('W', monitortty = optarg);
|
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;
|
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,
|
|
|
|
|
(shared = mmap(NULL, ROUNDUP(sizeof(struct Shared), FRAMESIZE),
|
|
|
|
|
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS,
|
|
|
|
|
-1, 0)));
|
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) {
|
|
|
|
|
fd = open(pidpath, O_CREAT | O_WRONLY, 0644);
|
|
|
|
|
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-05-29 15:14:55 +00:00
|
|
|
|
if (!IsTiny()) {
|
|
|
|
|
if (monitortty && (daemonize || uniprocess)) {
|
|
|
|
|
monitortty = 0;
|
|
|
|
|
}
|
|
|
|
|
if (monitortty) {
|
|
|
|
|
MonitorMemory();
|
|
|
|
|
}
|
2022-05-14 11:33:58 +00:00
|
|
|
|
}
|
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-18 15:54:42 +00:00
|
|
|
|
GetHostsTxt(); // for effect
|
2022-04-23 01:55:28 +00:00
|
|
|
|
GetResolvConf(); // for effect
|
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-23 01:55:28 +00:00
|
|
|
|
} else if (IsWindows()) {
|
2022-07-10 11:01:17 +00:00
|
|
|
|
CHECK_NE(-1, _spawn(WindowsReplThread, 0, &replth));
|
2022-04-23 01:55:28 +00:00
|
|
|
|
EventLoop(100);
|
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) {
|
|
|
|
|
if (!IsTiny()) {
|
2022-07-10 11:01:17 +00:00
|
|
|
|
terminatemonitor = true;
|
|
|
|
|
_join(&monitorth);
|
2022-06-26 01:17:31 +00:00
|
|
|
|
}
|
|
|
|
|
#ifndef STATIC
|
2022-07-10 11:01:17 +00:00
|
|
|
|
_join(&replth);
|
2022-06-26 01:17:31 +00:00
|
|
|
|
#endif
|
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-06-04 09:57:17 +00:00
|
|
|
|
#if !IsTiny() && !defined(__x86_64__)
|
|
|
|
|
ShowCrashReports();
|
|
|
|
|
#endif
|
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) {
|
|
|
|
|
if (IsWindows()) {
|
|
|
|
|
// TODO(jart): Get windows worker leak detector working again.
|
|
|
|
|
return 0;
|
|
|
|
|
CloseServerFds();
|
|
|
|
|
}
|
2022-07-10 11:01:17 +00:00
|
|
|
|
_join(&replth);
|
|
|
|
|
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;
|
|
|
|
|
}
|