implement reverse_proxy_service location and url parameters

Sun, 22 Feb 2026 13:19:12 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Sun, 22 Feb 2026 13:19:12 +0100
changeset 699
d794871da099
parent 698
fea7c3d74cc6
child 700
658f4c02b4c5

implement reverse_proxy_service location and url parameters

src/server/safs/proxy.c file | annotate | diff | comparison | revisions
--- a/src/server/safs/proxy.c	Sun Feb 22 11:18:47 2026 +0100
+++ b/src/server/safs/proxy.c	Sun Feb 22 13:19:12 2026 +0100
@@ -30,6 +30,8 @@
 
 #include <sys/socket.h>
 #include <arpa/inet.h>
+#include <sys/types.h>
+#include <netdb.h>
 #include <ctype.h>
 #include <string.h>
 
@@ -142,16 +144,84 @@
     const char *uri = pblock_findkeyval(pb_key_uri, rq->reqpb);
     const char *query = pblock_findkeyval(pb_key_query, rq->reqpb);
     
+    const char *location = pblock_findval("location", param);
+    if(location) {
+        cxstring loc = cx_str(location);
+        if(cx_strprefix(uri, loc)) {
+            if(loc.length > 0 && loc.ptr[loc.length-1] == '/') {
+                uri += loc.length - 1;
+            } else {
+                uri += loc.length;
+            }
+            if(uri[0] == '\0') {
+                uri = "/";
+            }
+        } else {
+            // location does not match
+            return REQ_NOACTION;
+        }
+    }
+    
+    const char *server_url = pblock_findval("proxy-url", rq->vars);
+    if(!server_url) {
+        server_url = pblock_findval("url", param);
+        if(!server_url) {
+            log_ereport(LOG_MISCONFIG, "reverse-proxy: missing server url");
+            return REQ_ABORTED;
+        }
+    }
+    WSUri srv_url;
+    if(!util_parse_uri(server_url, &srv_url)) {
+        log_ereport(LOG_MISCONFIG, "reverse-proxy: invalid server url: %s", server_url);
+        return REQ_ABORTED;
+    }
+    
+    char srvport[16];
+    snprintf(srvport, 16, "%d", (int)srv_url.port);
+    
+    char srvhost_static[256];
+    char *srvhost;
+    if(srv_url.hostlen < 255) {
+        memcpy(srvhost_static, srv_url.host, srv_url.hostlen);
+        srvhost_static[srv_url.hostlen] = 0;
+        srvhost = srvhost_static;
+    } else {
+        srvhost = pool_malloc(sn->pool, srv_url.hostlen + 1);
+        if(!srvhost) {
+            return REQ_ABORTED;
+        }
+        memcpy(srvhost, srv_url.host, srv_url.hostlen);
+        srvhost[srv_url.hostlen] = 0;
+    }
+    
+    // build the new uri using <srv_url.path><uri>?<query>
+    if(srv_url.pathlen > 0 && srv_url.path[srv_url.pathlen-1] == '/') {
+        srv_url.pathlen--;
+    }
+    
     cxmutstr new_uri = CX_NULLSTR;
     size_t uri_len = strlen(uri);
     size_t query_len = query ? strlen(query) : 0;
-    size_t new_uri_alloc = ((uri_len + query_len) * 3) + 2;
+    size_t new_uri_alloc = ((uri_len + query_len) * 3) + 2 + srv_url.pathlen;
     new_uri.ptr = pool_malloc(sn->pool, new_uri_alloc);
-    new_uri.length = util_uri_escape_s(new_uri.ptr, new_uri_alloc, uri);
+    if(!new_uri.ptr) {
+        return REQ_ABORTED;
+    }
+    
+    char *s = new_uri.ptr;
+    size_t s_len = new_uri_alloc;
+    if(srv_url.pathlen > 0) {
+        memcpy(s, srv_url.path, srv_url.pathlen);
+        s += srv_url.pathlen;
+        new_uri.length = srv_url.pathlen;
+        s_len -= srv_url.pathlen;
+    }
+    
+    new_uri.length += util_uri_escape_s(s, s_len, uri);
     if(new_uri.length > 0 && query_len > 0) {
         new_uri.ptr[new_uri.length] = '?';
         memcpy(new_uri.ptr + new_uri.length + 1, query, query_len + 1);
-        new_uri.length = new_uri.length + 1 + query_len;
+        new_uri.length += query_len + 1;
     }
     
     // remove some response headers, that were previously set by ObjectType
@@ -190,6 +260,24 @@
         return REQ_ABORTED;
     }
     
+    // set server address
+    struct addrinfo hints = { 0 };
+    hints.ai_family = AF_UNSPEC;
+    hints.ai_socktype = SOCK_STREAM;
+    struct addrinfo *srv_addr;
+    if(getaddrinfo(srvhost, srvport, &hints, &srv_addr)) {
+        http_client_free(client);
+        log_ereport(LOG_FAILURE, "reverse-proxy: getaddr failed for address %s: %s", srvhost, strerror(errno));
+        return REQ_ABORTED;
+    }
+    
+    int ret = http_client_set_addr(client, srv_addr->ai_addr, srv_addr->ai_addrlen);
+    freeaddrinfo(srv_addr);
+    if(ret) {
+        http_client_free(client);
+        return REQ_ABORTED;
+    }
+    
     // test address
     struct sockaddr_in address;
     inet_pton(AF_INET, "127.0.0.1", &address.sin_addr);

mercurial