2
0

Compare commits

...

4 Commits

Author SHA1 Message Date
2b4e6d3a4d [build] add .github workflow
Change-Id: I8377f42da3d28ae1d2593ac5ab9ba1c1f1d97074
2024-01-13 20:25:34 +01:00
d9e4b2e4d7 [tests] try to use shorter socket filenames
Change-Id: I7f59268078f2178910de3425a0b68a8e5113b071
2024-01-13 19:35:30 +01:00
643514a9c7 [core] recent g_module_open handles lib prefix and suffixes better; try that first
Change-Id: Ieecd1234e5cc81a11e43172d4563d43bca6658be
2024-01-13 18:55:49 +01:00
7c2d19ed24 [core] add proper error handling to li_module_load
Change-Id: I4b11b93cee06ea5d983712158b39b5a8542460e4
2024-01-13 18:55:49 +01:00
10 changed files with 225 additions and 20 deletions

50
.github/workflows/ci-alpine.yml vendored Normal file
View File

@ -0,0 +1,50 @@
name: "Checks (alpine, many platforms)"
on: [push, pull_request]
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref }}
cancel-in-progress: true
jobs:
linux-alpine:
runs-on: ubuntu-latest
name: linux-alpine-${{ matrix.platform }}
# abort if x86_64 fails
continue-on-error: ${{ matrix.platform != 'x86_64' }}
strategy:
fail-fast: true
matrix:
platform: ['x86_64','x86','armhf','armv7','aarch64','ppc64le','riscv64','s390x']
steps:
- uses: actions/checkout@v4
- uses: jirutka/setup-alpine@v1
with:
# riscv64 currently requires 'edge'
branch: edge
arch: ${{ matrix.platform }}
packages: >
build-base
meson
libev-dev
ragel
glib-dev
lua5.1-dev
zlib-dev
bzip2-dev
pkgconf
openssl-dev
gnutls-dev
libidn-dev
libunwind-dev
python3
py3-curl
- name: meson setup
shell: alpine.sh {0}
run: meson setup mesonbuilddir
- name: meson compile
shell: alpine.sh {0}
run: meson compile -C mesonbuilddir
- name: meson test
shell: alpine.sh {0}
run: meson test -C mesonbuilddir -v

67
.github/workflows/ci-linux.yml vendored Normal file
View File

@ -0,0 +1,67 @@
name: "Checks (Ubuntu: gcc+clang)"
on: [push, pull_request]
concurrency:
group: ${{github.workflow}}-${{github.head_ref}}
cancel-in-progress: true
jobs:
linux-build-docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: |
pkgs=(
ruby
ruby-nokogiri
ruby-kramdown
libxml2-utils
)
sudo apt-get install "${pkgs[@]}"
- name: Build docs
run: |
mkdir -p out
ruby doc/compile.rb out
cp doc/*.css doc/*.js out
- uses: actions/upload-artifact@v4
with:
name: lighttpd2-docs
path: out
linux-ubuntu:
runs-on: ubuntu-latest
name: linux-ubuntu-${{ matrix.compiler }}
strategy:
matrix:
compiler: ['gcc', 'clang']
steps:
- uses: actions/checkout@v4
- if: ${{ matrix.compiler == 'clang' }}
uses: egor-tensin/setup-clang@v1
- name: Install dependencies
run: |
pkgs=(
meson
libev-dev
ragel
libglib2.0-dev
liblua5.1-dev
zlib1g-dev
libbz2-dev
pkg-config
libssl-dev
libgnutls28-dev
libidn-dev
libunwind8-dev
python3
python3-pycurl
)
sudo apt-get install "${pkgs[@]}"
- name: meson setup
run: meson setup mesonbuilddir
- name: meson compile
run: meson compile -C mesonbuilddir
- name: meson test
run: meson test -C mesonbuilddir -v

52
.github/workflows/ci-macos.yml vendored Normal file
View File

@ -0,0 +1,52 @@
name: "Checks (macOS)"
on: [push, pull_request]
concurrency:
group: ${{github.workflow}}-${{github.head_ref}}
cancel-in-progress: true
jobs:
macOS:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: |
pkgs=(
meson
libev
ragel
glib
lua@5.1
zlib
bzip2
openssl@3
gnutls
libidn
python3
python-pycurl
md5sha1sum
)
brew install "${pkgs[@]}"
- name: meson setup
run: meson setup -D unwind=false mesonbuilddir
- name: meson compile
run: meson compile -C mesonbuilddir
- name: prepare environment for tests
run: |
sudo ifconfig lo0 alias 127.0.0.2 up
# try to create a tmpdir with a short relative path (for shorter unix socket paths)
NEWTMPDIR=~/tmp
ln -sf "${TMPDIR}" "${NEWTMPDIR}"
echo "TMPDIR=$NEWTMPDIR" >> "$GITHUB_ENV"
echo "PATH=$(brew --prefix python)/libexec/bin:$PATH" >> "$GITHUB_ENV"
if [ ! -f $(brew --prefix python)/libexec/bin/python3 ]; then
# the brew path only provides "python", not "python3"...
ln -s python $(brew --prefix python)/libexec/bin/python3
fi
- name: meson test
run: |
meson test -C mesonbuilddir -v

View File

@ -17,11 +17,16 @@
/** see li_module_load */
#define MODULE_DEPENDS(mods, name) do { \
if (!li_module_load(mods, name)) { \
ERROR(mods->main, "Couldn't load dependency '%s'", name); \
GError *err = NULL; \
if (!li_module_load(mods, name, &err)) { \
ERROR(mods->main, "Couldn't load dependency '%s': %s", name, err->message); \
g_error_free(err); \
return FALSE; \
} } while(0)
#define LI_MODULES_ERROR li_modules_error_quark()
LI_API GQuark li_modules_error_quark(void);
typedef struct liModule liModule;
typedef struct liModules liModules;
@ -58,7 +63,7 @@ LI_API void li_modules_free(liModules *mods);
* returns NULL if it couldn't load the module.
*
* You should release modules after you used them with li_module_release or li_module_release_name */
LI_API liModule* li_module_load(liModules *mods, const gchar* name);
LI_API liModule* li_module_load(liModules *mods, const gchar* name, GError **error);
/* find module by name */
LI_API liModule *li_module_lookup(liModules *mods, const gchar *name);

View File

@ -230,6 +230,7 @@ gboolean li_plugins_load_module(liServer *srv, const gchar *name) {
liPlugins *ps = &srv->plugins;
server_module *sm;
const gchar* modname = name ? name : "core";
GError *err = NULL;
sm = g_hash_table_lookup(ps->module_refs, modname);
if (sm) return TRUE; /* already loaded */
@ -240,9 +241,11 @@ gboolean li_plugins_load_module(liServer *srv, const gchar *name) {
sm = server_module_new(srv, modname);
g_hash_table_insert(ps->module_refs, sm->name, sm);
if (name) {
mod = li_module_load(ps->modules, name);
mod = li_module_load(ps->modules, name, &err);
if (!mod) {
ERROR(srv, "Couldn't load dependency '%s': %s", name, err->message);
g_error_free(err);
_server_module_release(sm);
return FALSE;
}

View File

@ -2,6 +2,10 @@
#include <lighttpd/module.h>
#include <lighttpd/utils.h>
GQuark li_modules_error_quark(void) {
return g_quark_from_string("li-modules-error-quark");
}
liModules *li_modules_new(gpointer main, const gchar *module_dir, gboolean module_resident) {
liModules *m = g_slice_new(liModules);
@ -48,7 +52,7 @@ void li_modules_free(liModules* mods) {
}
liModule* li_module_load(liModules *mods, const gchar* name) {
liModule* li_module_load(liModules *mods, const gchar* name, GError **err) {
liModule *mod;
liModuleInitCB m_init;
GString *m_init_str, *m_free_str;
@ -65,15 +69,23 @@ liModule* li_module_load(liModules *mods, const gchar* name) {
mod = g_slice_new0(liModule);
mod->name = g_string_new(name);
mod->refcount = 1;
mod->path = g_module_build_path(mods->module_dir, name);
mod->path = g_strconcat(mods->module_dir, G_DIR_SEPARATOR_S, name, NULL);
mod->module = g_module_open(mod->path, G_MODULE_BIND_LAZY);
if (!mod->module) {
g_string_free(mod->name, TRUE);
if (err) g_set_error(err, LI_MODULES_ERROR, 1, "%s", g_module_error());
g_free(mod->path);
g_slice_free(liModule, mod);
return NULL;
mod->path = g_module_build_path(mods->module_dir, name);
mod->module = g_module_open(mod->path, G_MODULE_BIND_LAZY);
if (!mod->module) {
g_string_free(mod->name, TRUE);
g_free(mod->path);
g_slice_free(liModule, mod);
return NULL;
}
}
/* temporary strings for mod_xyz_init and mod_xyz_free */
@ -86,6 +98,12 @@ liModule* li_module_load(liModules *mods, const gchar* name) {
|| !g_module_symbol(mod->module, m_free_str->str, (gpointer *)&mod->free)
|| m_init == NULL || mod->free == NULL) {
g_set_error(err, LI_MODULES_ERROR, 1,
"li_module_load: couldn't load %s or %s from %s",
m_init_str->str,
m_free_str->str,
mod->path);
/* mod_init or mod_free couldn't be located, something went wrong */
g_string_free(m_init_str, TRUE);
g_string_free(m_free_str, TRUE);
@ -97,6 +115,11 @@ liModule* li_module_load(liModules *mods, const gchar* name) {
/* call mod_xyz_init */
if (!m_init(mods, mod)) {
g_set_error(err, LI_MODULES_ERROR, 1,
"li_module_load: calling %s from %s failed",
m_init_str->str,
mod->path);
g_string_free(m_init_str, TRUE);
g_string_free(m_free_str, TRUE);
g_free(mod->path);

View File

@ -1238,6 +1238,7 @@ static gboolean core_workers_cpu_affinity(liServer *srv, liPlugin* p, liValue *v
}
static gboolean core_module_load(liServer *srv, liPlugin* p, liValue *val, gpointer userdata) {
GError *err = NULL;
UNUSED(p); UNUSED(userdata);
if (!g_module_supported()) {
@ -1272,8 +1273,9 @@ static gboolean core_module_load(liServer *srv, liPlugin* p, liValue *val, gpoin
continue;
}
if (!li_module_load(srv->modules, name->str)) {
ERROR(srv, "could not load module '%s': %s", name->str, g_module_error());
if (!li_module_load(srv->modules, name->str, &err)) {
ERROR(srv, "could not load module '%s': %s", name->str, err->message);
g_error_free(err);
return FALSE;
}

View File

@ -62,6 +62,15 @@ class Service:
self.proc: typing.Optional[subprocess.Popen] = None
self.failed = False
def bind_unix_socket(self, *, sockfile: str, backlog: int = 8) -> socket.socket:
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
rel_sockfile = os.path.relpath(sockfile)
if len(rel_sockfile) < len(sockfile):
sockfile = rel_sockfile
sock.bind(sockfile)
sock.listen(8)
return sock
def fork(self, *args: str, inp: typing.Union[tuple[()], FileWithFd, None] = ()) -> None:
arguments = list(args) # convert tuple to list
stdin: typing.Optional[FileWithFd]
@ -245,9 +254,7 @@ class FastCGI(Service):
def prepare_service(self) -> None:
assert self.tests
self.tests.install_dir(os.path.join("tmp", "sockets"))
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sock.bind(os.path.relpath(self.sockfile))
sock.listen(8)
sock = self.bind_unix_socket(sockfile=self.sockfile)
self.fork(*self.binary, inp=sock)
def cleanup_service(self) -> None:

View File

@ -21,9 +21,7 @@ class Memcached(Service):
def prepare_service(self) -> None:
assert self.tests
self.tests.install_dir(os.path.join("tmp", "sockets"))
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sock.bind(os.path.relpath(self.sockfile))
sock.listen(8)
sock = self.bind_unix_socket(sockfile=self.sockfile)
self.fork(*self.binary, inp=sock)
def cleanup_service(self) -> None:

View File

@ -20,9 +20,7 @@ class SCGI(Service):
def prepare_service(self) -> None:
assert self.tests
self.tests.install_dir(os.path.join("tmp", "sockets"))
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sock.bind(os.path.relpath(self.sockfile))
sock.listen(8)
sock = self.bind_unix_socket(sockfile=self.sockfile)
self.fork(*self.binary, inp=sock)
def cleanup_service(self) -> None: