From 2d348197792f76992339b4950820fecd75cb23cf Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Mon, 3 May 2021 11:52:24 -0700 Subject: [PATCH] Escape LaunchBrowser path This also fix a bug where CTRL-C'ing redbean on Linux would kill the browser process. It furthermore fixes a regression with the APE self repair process that happened in a recent change. See #158 --- tool/net/demo/.init.lua | 7 +++- tool/net/redbean.c | 82 +++++++++++++++++++++++++++++------------ 2 files changed, 64 insertions(+), 25 deletions(-) diff --git a/tool/net/demo/.init.lua b/tool/net/demo/.init.lua index 077d60f7..bed6b40f 100644 --- a/tool/net/demo/.init.lua +++ b/tool/net/demo/.init.lua @@ -1,7 +1,10 @@ -- /.init.lua is loaded at startup in redbean's main process - HidePath('/usr/share/zoneinfo/') +-- open a browser tab using explorer/open/xdg-open +-- LaunchBrowser('/tool/net/demo/index.html') + +-- this intercepts all requests if it's defined function OnHttpRequest() if HasParam('magic') then Write('

\r\n') @@ -11,7 +14,7 @@ function OnHttpRequest() Write(EscapeHtml(LoadAsset('/.init.lua'))) Write('\r\n') else - Route() + Route() -- this asks redbean to do the default thing end SetHeader('Server', 'redbean!') end diff --git a/tool/net/redbean.c b/tool/net/redbean.c index 447ead86..ffcc4898 100644 --- a/tool/net/redbean.c +++ b/tool/net/redbean.c @@ -19,8 +19,10 @@ #include "libc/bits/popcnt.h" #include "libc/bits/safemacros.internal.h" #include "libc/calls/calls.h" +#include "libc/calls/sigbits.h" #include "libc/calls/struct/itimerval.h" #include "libc/calls/struct/rusage.h" +#include "libc/calls/struct/sigaction.h" #include "libc/calls/struct/stat.h" #include "libc/errno.h" #include "libc/fmt/conv.h" @@ -33,6 +35,7 @@ #include "libc/nexgen32e/bsr.h" #include "libc/nexgen32e/crc32.h" #include "libc/runtime/clktck.h" +#include "libc/runtime/gc.internal.h" #include "libc/runtime/runtime.h" #include "libc/sock/sock.h" #include "libc/stdio/stdio.h" @@ -2003,26 +2006,61 @@ static char *GetBasicAuthorization(size_t *z) { } } -static void LaunchBrowser(const char *path) { - char openbrowsercommand[255]; - char *prog; +static const char *GetSystemUrlLauncherCommand(void) { if (IsWindows()) { - prog = "explorer"; + return "explorer"; } else if (IsXnu()) { - prog = "open"; + return "open"; } else { - prog = "xdg-open"; + return "xdg-open"; } - struct in_addr addr = serveraddr.sin_addr; - if (addr.s_addr == INADDR_ANY) addr.s_addr = htonl(INADDR_LOOPBACK); - const char *pathname = path; - if (path == NULL) { - pathname = "/"; +} + +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; + path = firstnonnull(path, "/"); + addr = serveraddr.sin_addr; + if (!addr.s_addr) addr.s_addr = htonl(INADDR_LOOPBACK); + if (*path != '/') path = gc(xasprintf("/%s", path)); + if ((prog = commandv(GetSystemUrlLauncherCommand(), gc(malloc(PATH_MAX))))) { + u = gc(xasprintf("http://%s:%d%s", inet_ntoa(addr), + ntohs(serveraddr.sin_port), gc(EscapePath(path, -1, 0)))); + DEBUGF("opening browser with command %s %s\n", prog, u); + 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) { + setpgid(getpid(), getpid()); + sigaction(SIGINT, &saveint, 0); + sigaction(SIGQUIT, &savequit, 0); + sigprocmask(SIG_SETMASK, &savemask, 0); + execv(prog, (char *const[]){prog, u, 0}); + _exit(127); + } + while (wait4(pid, &ws, 0, 0) == -1) { + CHECK_EQ(EINTR, errno); + } + sigaction(SIGINT, &saveint, 0); + sigaction(SIGQUIT, &savequit, 0); + sigprocmask(SIG_SETMASK, &savemask, 0); + if (!(WIFEXITED(ws) && WEXITSTATUS(ws) == 0)) { + WARNF("%s failed with %d", GetSystemUrlLauncherCommand(), + WIFEXITED(ws) ? WEXITSTATUS(ws) : 128 + WEXITSTATUS(ws)); + } + } else { + WARNF("can't launch browser because %s isn't installed", + GetSystemUrlLauncherCommand()); } - snprintf(openbrowsercommand, sizeof(openbrowsercommand), "%s http://%s:%d%s", - prog, inet_ntoa(addr), ntohs(serveraddr.sin_port), pathname); - DEBUGF("Opening browser with command %s\n", openbrowsercommand); - system(openbrowsercommand); } static char *BadMethod(void) { @@ -3555,8 +3593,7 @@ static void LuaSetIntField(lua_State *L, const char *k, lua_Integer v) { } static int LuaLaunchBrowser(lua_State *L) { - const char *p = luaL_optstring(L, 1, "/"); - LaunchBrowser(p); + LaunchBrowser(luaL_optstring(L, 1, "/")); return 1; } @@ -4530,6 +4567,7 @@ static void TuneSockets(void) { } static void RestoreApe(void) { + int fd; char *p; size_t n; struct Asset *a; @@ -4538,16 +4576,14 @@ static void RestoreApe(void) { if (IsOpenbsd()) return; /* TODO */ if (IsNetbsd()) return; /* TODO */ if (endswith(zpath, ".com.dbg")) return; - close(OpenExecutable()); + fd = OpenExecutable(); if ((a = GetAssetZip("/.ape", 5)) && (p = LoadAsset(a, &n))) { - mprotect(ape_rom_vaddr, PAGESIZE, PROT_READ | PROT_WRITE); - memcpy(ape_rom_vaddr, p, MIN(n, PAGESIZE)); - msync(ape_rom_vaddr, PAGESIZE, MS_ASYNC); - mprotect(ape_rom_vaddr, PAGESIZE, PROT_NONE); + write(fd, p, n); free(p); } else { - LOGF("/.ape not found"); + WARNF("/.ape not found"); } + close(fd); } void RedBean(int argc, char *argv[]) {