From 8024fea889d334c4b0650a0fb129673e696581f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Gro=C3=9Fmann?= Date: Fri, 20 Mar 2026 18:21:30 +0100 Subject: [PATCH 1/3] feat: lazy UFS session lifecycle via http_get_ufs() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace eager per-connection UFS session creation in socket_thread() with lazy initialization through http_get_ufs(). The session is created on first access and cached in httpc->ufs for the connection lifetime. Key changes: - New http_get_ufs() accessor (httpgufs.c) with HTTPX vector at 0x120 - Remove ufsnew() from socket_thread() — session created on demand - Close UFS file handle in httpdone.c between requests (Keep-Alive prep) - Clear ACEE on UFS session in httprese.c between requests (security) - httpopen.c and httpget.c use http_get_ufs() instead of direct access Fixes #32 --- include/httpcgi.h | 5 +++++ include/httpd.h | 6 ++++++ src/httpd.c | 6 +----- src/httpdone.c | 5 +++++ src/httpget.c | 2 +- src/httpgufs.c | 21 +++++++++++++++++++++ src/httpopen.c | 27 +++++++++++++++------------ src/httprese.c | 5 +++++ src/httpx.c | 1 + 9 files changed, 60 insertions(+), 18 deletions(-) create mode 100644 src/httpgufs.c diff --git a/include/httpcgi.h b/include/httpcgi.h index 225f277..1b67ca3 100644 --- a/include/httpcgi.h +++ b/include/httpcgi.h @@ -298,6 +298,8 @@ struct httpx { HTTPCP *xlate_cp037; /* 114 CP037 codepage pair */ HTTPCP *xlate_1047; /* 118 IBM-1047 codepage pair */ HTTPCP *xlate_legacy; /* 11C legacy hybrid codepage pair */ + UFS * (*http_get_ufs)(HTTPC *); + /* 120 get/create UFS handle */ }; /* Eye-catcher for HTTPD pointer identification (ABI constant) */ @@ -522,4 +524,7 @@ struct httpx { #define http_xlate(buf,len,tbl) \ ((httpx->http_xlate)((buf),(len),(tbl))) +#define http_get_ufs(httpc) \ + ((httpx->http_get_ufs)((httpc))) + #endif /* HTTPCGI_H */ diff --git a/include/httpd.h b/include/httpd.h index 3f351f4..60302a4 100644 --- a/include/httpd.h +++ b/include/httpd.h @@ -430,6 +430,8 @@ struct httpx { HTTPCP *xlate_cp037; /* 114 CP037 codepage pair */ HTTPCP *xlate_1047; /* 118 IBM-1047 codepage pair */ HTTPCP *xlate_legacy; /* 11C legacy hybrid codepage pair */ + UFS * (*http_get_ufs)(HTTPC *); + /* 120 get/create UFS handle */ }; extern int http_in(HTTPC*) asm("HTTPIN"); @@ -489,6 +491,7 @@ extern HTTPCGI *http_find_cgi(HTTPD *httpd, const char *path) asm("HTT extern HTTPCGI *http_add_cgi(HTTPD *httpd, const char *pgm, const char *path, int login) asm("HTTPACGI"); extern int http_process_cgi(HTTPC *httpc, HTTPCGI *cgi) asm("HTTPPCGI"); extern unsigned char *http_xlate(unsigned char *, int, const unsigned char *) asm("HTTPXLAT"); +extern UFS *http_get_ufs(HTTPC *) asm("HTTPGUFS"); extern double httpsecs(double *psecs) asm("HTTPSECS"); extern int httpcred(HTTPC *httpc) asm("HTTPCRED"); extern int httpd048(HTTPD *httpd) asm("HTTPD048"); @@ -719,6 +722,9 @@ extern int http_gets(HTTPC *httpc, UCHAR *buf, unsigned max) asm("HTT #define http_xlate(buf,len,tbl) \ ((httpx->http_xlate)((buf),(len),(tbl))) +#define http_get_ufs(httpc) \ + ((httpx->http_get_ufs)((httpc))) + #endif /* ifndef HTTPX_H */ #endif diff --git a/src/httpd.c b/src/httpd.c index 2bce719..238879c 100644 --- a/src/httpd.c +++ b/src/httpd.c @@ -671,11 +671,7 @@ socket_thread(void *arg1, void *arg2) httpc->port = a->sin_port; httpc->state = CSTATE_IN; httpsecs(&httpc->start); - if (httpd->ufs) { - /* create UFS handle */ - httpc->ufs = ufsnew(); - crt->crtufs = httpc->ufs; - } + /* UFS session created lazily by http_get_ufs() */ mgr = httpd->mgr; if (mgr) { diff --git a/src/httpdone.c b/src/httpdone.c index b795c28..b2e9ca5 100644 --- a/src/httpdone.c +++ b/src/httpdone.c @@ -16,6 +16,11 @@ httpdone(HTTPC *httpc) httpc->fp = NULL; } + if (httpc->ufp) { + /* close UFS file handle */ + ufs_fclose(&httpc->ufp); + } + httpsecs(&httpc->end); quit: diff --git a/src/httpget.c b/src/httpget.c index c0413b1..74b7d7c 100644 --- a/src/httpget.c +++ b/src/httpget.c @@ -76,7 +76,7 @@ httpget(HTTPC *httpc) __asm__("DC\tH'0'"); } - if (httpc->ufs) { + if (http_get_ufs(httpc)) { /* try to open path asis */ mime = http_mime(path); fp = http_open(httpc, path, mime); diff --git a/src/httpgufs.c b/src/httpgufs.c new file mode 100644 index 0000000..5129b3c --- /dev/null +++ b/src/httpgufs.c @@ -0,0 +1,21 @@ +/* HTTPGUFS.C +** Get or create per-client UFS session (lazy init) +*/ +#define HTTP_PRIVATE +#include "httpd.h" + +__asm__("\n&FUNC SETC 'HTTPGUFS'"); + +#undef http_get_ufs +UFS * +http_get_ufs(HTTPC *httpc) +{ + if (!httpc->ufs && httpc->httpd->ufssys) { + httpc->ufs = ufsnew(); + if (httpc->ufs) { + CLIBCRT *crt = __crtget(); + if (crt) crt->crtufs = httpc->ufs; + } + } + return httpc->ufs; +} diff --git a/src/httpopen.c b/src/httpopen.c index 2bb81bc..a0c4969 100644 --- a/src/httpopen.c +++ b/src/httpopen.c @@ -97,18 +97,21 @@ http_open(HTTPC *httpc, const UCHAR *path, const HTTPM *mime) } - if (httpc->ufs) { - UCHAR ufspath[256]; - const char *dr = httpc->httpd->docroot; - if (dr[0] && http_cmpn(buf, "/DD:", 4) != 0) { - /* prepend document root to UFS path */ - snprintf((char *)ufspath, sizeof(ufspath), "%s%s", dr, buf); - httpc->ufp = ufs_fopen(httpc->ufs, ufspath, mode); - } else { - httpc->ufp = ufs_fopen(httpc->ufs, buf, mode); - } - if (httpc->ufp) { - goto quit; /* success, return NULL to caller */ + { + UFS *ufs = http_get_ufs(httpc); + if (ufs) { + UCHAR ufspath[256]; + const char *dr = httpc->httpd->docroot; + if (dr[0] && http_cmpn(buf, "/DD:", 4) != 0) { + /* prepend document root to UFS path */ + snprintf((char *)ufspath, sizeof(ufspath), "%s%s", dr, buf); + httpc->ufp = ufs_fopen(ufs, ufspath, mode); + } else { + httpc->ufp = ufs_fopen(ufs, buf, mode); + } + if (httpc->ufp) { + goto quit; /* success, return NULL to caller */ + } } } diff --git a/src/httprese.c b/src/httprese.c index 2973786..d1b6db0 100644 --- a/src/httprese.c +++ b/src/httprese.c @@ -35,6 +35,11 @@ httprese(HTTPC *httpc) httpc->end = 0.0; memset(httpc->buf, 0, CBUFSIZE); + /* clear ACEE on UFS session between requests */ + if (httpc->ufs) { + ufs_set_acee(httpc->ufs, NULL); + } + /* if this is was HTTP1.1 or higher client then we ** *could* transition to CSTATE_IN. We'll leave that ** for another time. diff --git a/src/httpx.c b/src/httpx.c index e002fdd..f72101c 100644 --- a/src/httpx.c +++ b/src/httpx.c @@ -77,6 +77,7 @@ static HTTPX vect = { &http_cp037, /* 114 CP037 codepage pair */ &http_cp1047, /* 118 IBM-1047 codepage pair */ &http_legacy, /* 11C legacy hybrid codepage pair */ + http_get_ufs, /* 120 http_get_ufs() */ }; HTTPX *httpx = &vect; From cd9a788ceb1ac78ac6bd4ed6b016ef200897ac88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Gro=C3=9Fmann?= Date: Fri, 20 Mar 2026 19:27:59 +0100 Subject: [PATCH 2/3] fix: remove server-level UFS session from startup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The server-level httpd->ufs session created in httpconf.c is no longer needed — per-client sessions are created lazily by http_get_ufs(). Only the ufssys stub handle remains as UFS availability indicator. This eliminates the persistent UFSD session that existed for the entire server lifetime, reducing resource usage to zero sessions when no clients need UFS access. Fixes #32 --- src/httpconf.c | 18 +++--------------- src/httpd.c | 4 +--- 2 files changed, 4 insertions(+), 18 deletions(-) diff --git a/src/httpconf.c b/src/httpconf.c index 1debf18..6b6e19b 100644 --- a/src/httpconf.c +++ b/src/httpconf.c @@ -514,10 +514,8 @@ process_httpd(lua_State *L, HTTPD *httpd) static int process_httpd_ufs(lua_State *L, HTTPD *httpd) { - CLIBCRT *crt = __crtget(); int rc = 0; int i; - UFS *ufs; lua_getfield(L,-1,"ufs"); i = (int) lua_tointeger(L, -1); @@ -525,7 +523,8 @@ process_httpd_ufs(lua_State *L, HTTPD *httpd) if (i<=0) goto quit; - /* Stub system handle — signals UFS availability to FTPD */ + /* Stub system handle — signals UFS availability to FTPD and + ** http_get_ufs(). Per-client sessions are created lazily. */ httpd->ufssys = ufs_sys_new(); if (!httpd->ufssys) { wtof("HTTPD044W Unable to initialize file system"); @@ -534,18 +533,7 @@ process_httpd_ufs(lua_State *L, HTTPD *httpd) if (httpd->ftpd) httpd->ftpd->sys = httpd->ufssys; - /* Open server-level UFS session to UFSD STC */ - httpd->ufs = ufs = ufsnew(); - if (!ufs) { - wtof("HTTPD044W Unable to open UFSD session"); - ufs_sys_term(&httpd->ufssys); - httpd->ufssys = NULL; - goto quit; - } - - wtof("HTTPD046I UFS session opened via UFSD subsystem"); - - if (crt) crt->crtufs = ufs; + wtof("HTTPD046I UFS available via UFSD subsystem"); /* Read document root prefix (optional) */ lua_getfield(L, -1, "docroot"); diff --git a/src/httpd.c b/src/httpd.c index 238879c..37682a9 100644 --- a/src/httpd.c +++ b/src/httpd.c @@ -318,9 +318,7 @@ terminate(void) array_free(&httpd->httpcgi); } - if (httpd->ufs) { - ufsfree(&httpd->ufs); - } + /* httpd->ufs removed — per-client sessions freed in httpclos.c */ if (httpd->ufssys) { wtof("HTTPD047I Terminating File System"); From 4c434527a193c05863f4f34b32d315e584e3cf95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Gro=C3=9Fmann?= Date: Fri, 20 Mar 2026 19:52:00 +0100 Subject: [PATCH 3/3] fix: remove obsolete UFS session WTO messages from startup/shutdown HTTPD046I and HTTPD047I referred to the server-level UFS session which no longer exists. The ufssys stub handle is purely internal. Fixes #32 --- src/httpconf.c | 2 -- src/httpd.c | 1 - 2 files changed, 3 deletions(-) diff --git a/src/httpconf.c b/src/httpconf.c index 6b6e19b..7e09c85 100644 --- a/src/httpconf.c +++ b/src/httpconf.c @@ -533,8 +533,6 @@ process_httpd_ufs(lua_State *L, HTTPD *httpd) if (httpd->ftpd) httpd->ftpd->sys = httpd->ufssys; - wtof("HTTPD046I UFS available via UFSD subsystem"); - /* Read document root prefix (optional) */ lua_getfield(L, -1, "docroot"); { diff --git a/src/httpd.c b/src/httpd.c index 37682a9..6f3e48b 100644 --- a/src/httpd.c +++ b/src/httpd.c @@ -321,7 +321,6 @@ terminate(void) /* httpd->ufs removed — per-client sessions freed in httpclos.c */ if (httpd->ufssys) { - wtof("HTTPD047I Terminating File System"); ufs_sys_term(&httpd->ufssys); httpd->ufssys = NULL; }