runtime: http_set_handler self-registers via dlsym

El programs that define `fn handle_request(method, path, body) -> String`
can now use http_serve directly without C-level glue. http_set_handler
falls back to dlsym(RTLD_DEFAULT, name) when the named handler isn't
already in the registry, picks up the El-compiled symbol, and registers
it transparently.

Closes the gap that made http_serve unusable from pure El. Verified
with a real El server on :17890 — POST /hello with body returned
{"method":"POST","path":"/hello","echo":"test body"} via curl.

dist/platform/elc rebuilt; .prev3 preserved.
This commit is contained in:
Will Anderson
2026-04-30 13:30:55 -05:00
parent 951b8d574b
commit 6bdd4a4ba9
3 changed files with 19 additions and 0 deletions
BIN
View File
Binary file not shown.
Vendored Executable
BIN
View File
Binary file not shown.
+19
View File
@@ -27,6 +27,7 @@
#include <sys/stat.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <dlfcn.h> /* dlsym for http_set_handler fallback */
#include <unistd.h>
#include <dirent.h>
#include <errno.h>
@@ -616,6 +617,24 @@ void http_set_handler(el_val_t name) {
pthread_mutex_lock(&_http_handler_mu);
free(_http_active_handler);
_http_active_handler = el_strdup(n ? n : "");
/* If the name is not yet in the registry, try dlsym lookup against
* the running binary's symbol table. Every El `fn name(...)` compiles
* to a global C symbol with that exact name, so El programs can self-
* register their own handlers just by calling http_set_handler("name"). */
if (n && *n) {
int found = 0;
for (size_t i = 0; i < _http_handler_count; i++) {
if (strcmp(_http_handlers[i].name, n) == 0) { found = 1; break; }
}
if (!found) {
void* sym = dlsym(RTLD_DEFAULT, n);
if (sym && _http_handler_count < sizeof(_http_handlers) / sizeof(_http_handlers[0])) {
_http_handlers[_http_handler_count].name = el_strdup(n);
_http_handlers[_http_handler_count].fn = (http_handler_fn)sym;
_http_handler_count++;
}
}
}
pthread_mutex_unlock(&_http_handler_mu);
}