diff -r fea7c3d74cc6 -r d794871da099 src/server/safs/proxy.c --- 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 #include +#include +#include #include #include @@ -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 ? + 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);