Hi everyone! I was wondering if someone with a better understanding of httpd and mod_proxy could review my module idea and prototype implementation and warn me of any unforeseen pitfalls looming ahead before I commit to implementing this fully.
Following is a short text on my motivation and I've attached the 62 lines of prototype code. I fully understand if no one's in the mood to have a look at this and apologize for having wasted some of your time. Otherwise: Thank you for reading on. Wanting to switch to mod_proxy_http for deploying backend applications (and opening the way for WebSockets through mod_proxy_wstunnel) I'm missing the process management provided by mod_fastcgi [1]. While fully understanding that one can be of the opinion that process management is best kept out of httpd, I personally like the convenience and more importantly clarity offered by having the complete command, arguments and environment required to run the backend application in the httpd configuration. Authentication, URL rewriting and whatelse will already be setup there, anyways. So I took a shot at seeing if I could implement a module to do just that. My current idea/prototype: 1. Register a hook to run before mod_proxy.c:proxy_handler and have a look at the request filename and handler to see if they start with "proxy:spawn://". 2. Use everything after that and until a pipe character as the command to spawn. No process management in that module, yet, of course, but that could easily be lifted from mod_fastcgi or mod_fcgid. As done in those implementations the process manager will create a AF_UNIX socket and pass its file descriptor to the spawned process. 3. Rewrite the request filename/handler to "unix://uds_path|rest" form using the AF_UNIX socket from the process manager as well as the proxy configuration included in the filename/handler after the pipe. Then let httpd/mod_proxy continue onward. Repository with code and httpd.conf for testing this is at [2]. Thanks in advance and regards Florian [1] https://fastcgi-archives.github.io/mod_fastcgi.html#FastCgiServer [2] https://github.com/wagnerflo/mod_proxy_spawn
#include "http_core.h" #include "mod_proxy.h" static int start_process(request_rec* r, const char* name, char** uds_path) { ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0, r, "start_process(\"%s\", ...)", name); *uds_path = "..."; return OK; } static int proxy_spawn_handler(request_rec* r) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "proxy_handler({ filename=\"%s\", handler=\"%s\", ... })", r->filename, r->handler); char** url; // forced proxy handler by SetHandler if (!r->proxyreq && r->handler && strncmp(r->handler, "proxy:", 6) == 0) url = (char**) &r->handler; // filename rewritten by proxy_trans else if (strncmp(r->filename, "proxy:", 6) == 0) url = &r->filename; else return DECLINED; if (ap_cstr_casecmpn(*url + 6, "spawn://", 8) != 0) return DECLINED; char* name = *url + 14; char* real = ap_strchr_c(name, '|'); if (real == NULL) { return HTTP_INTERNAL_SERVER_ERROR; } char* uds_path; if (start_process(r, apr_pstrndup(r->pool, name, real - name), &uds_path)) { return HTTP_INTERNAL_SERVER_ERROR; } *url = apr_pstrcat(r->pool, "proxy:unix://", uds_path, real, NULL); ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "rewrite proxy url to %s", *url); return DECLINED; } static void register_hooks(apr_pool_t* pool) { // make sure we get called before proxy_handler static const char* const aszSucc[] = { "mod_proxy.c", NULL }; ap_hook_handler(proxy_spawn_handler, NULL, aszSucc, APR_HOOK_FIRST); } AP_DECLARE_MODULE(proxy_spawn) = { STANDARD20_MODULE_STUFF, NULL, NULL, NULL, NULL, NULL, register_hooks };