setup HttpClient in proxy SAF

Fri, 13 Feb 2026 12:16:09 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Fri, 13 Feb 2026 12:16:09 +0100
changeset 669
ccdc97fd8204
parent 668
0a7d1e9ca6b8
child 670
73987de73246

setup HttpClient in proxy SAF

src/server/proxy/httpclient.c file | annotate | diff | comparison | revisions
src/server/proxy/httpclient.h file | annotate | diff | comparison | revisions
src/server/safs/proxy.c file | annotate | diff | comparison | revisions
src/server/safs/proxy.h file | annotate | diff | comparison | revisions
src/server/test/main.c file | annotate | diff | comparison | revisions
--- a/src/server/proxy/httpclient.c	Thu Feb 12 16:02:09 2026 +0100
+++ b/src/server/proxy/httpclient.c	Fri Feb 13 12:16:09 2026 +0100
@@ -29,6 +29,8 @@
 #include "httpclient.h"
 
 #include <cx/buffer.h>
+#include <stdlib.h>
+#include <string.h>
 
 static int client_connected(EventHandler *ev, Event *event);
 
@@ -56,6 +58,15 @@
     return client;
 }
 
+void http_client_free(HttpClient *client) {
+    cxMempoolFree(client->mp);
+    header_array_free(client->request_headers);
+    free(client->addr);
+    free(client->method);
+    free(client->uri);
+    free(client);
+}
+
 int http_client_set_addr(HttpClient *client, const struct sockaddr *addr, socklen_t addrlen) {
    free(client->addr);
    client->addr = NULL;
@@ -72,6 +83,39 @@
    return 0;
 }
 
+int http_client_set_method(HttpClient *client, const char *method) {
+    return http_client_set_method_len(client, method, method ? strlen(method) : 0);
+}
+
+int http_client_set_uri(HttpClient *client, const char *uri) {
+    return http_client_set_uri_len(client, uri, uri ? strlen(uri) : 0);
+}
+
+static int client_set_str(char **ptr, const char *str, size_t len) {
+    free(*ptr);
+    if(str) {
+        char *newvalue = malloc(len+1);
+        if(!newvalue) {
+            *ptr = NULL;
+            return 1;
+        }
+        memcpy(newvalue, str, len);
+        newvalue[len] = 0;
+        *ptr = newvalue;
+    } else {
+        *ptr = NULL;
+        return 0;
+    }
+}
+
+int http_client_set_method_len(HttpClient *client, const char *method, size_t len) {
+    return client_set_str(&client->method, method, len);
+}
+
+int http_client_set_uri_len(HttpClient *client, const char *uri, size_t len) {
+    return client_set_str(&client->uri, uri, len);
+}
+
 int http_client_add_request_header(HttpClient *client, cxmutstr name, cxmutstr value) {
     return header_array_add(client->request_headers, name, value);
 }
@@ -113,7 +157,7 @@
     if(ret) {
         close(socketfd);
     }
-    return 1;
+    return ret;
 }
 
 static int create_req_buffer(HttpClient *client) {
--- a/src/server/proxy/httpclient.h	Thu Feb 12 16:02:09 2026 +0100
+++ b/src/server/proxy/httpclient.h	Fri Feb 13 12:16:09 2026 +0100
@@ -100,8 +100,18 @@
 
 HttpClient* http_client_new(EventHandler *ev);
 
+void http_client_free(HttpClient *client);
+
 int http_client_set_addr(HttpClient *client, const struct sockaddr *addr, socklen_t addrlen);
 
+int http_client_set_method(HttpClient *client, const char *method);
+
+int http_client_set_uri(HttpClient *client, const char *uri);
+
+int http_client_set_method_len(HttpClient *client, const char *method, size_t len);
+
+int http_client_set_uri_len(HttpClient *client, const char *uri, size_t len);
+
 /*
  * Adds a request header
  * 
--- a/src/server/safs/proxy.c	Thu Feb 12 16:02:09 2026 +0100
+++ b/src/server/safs/proxy.c	Fri Feb 13 12:16:09 2026 +0100
@@ -32,12 +32,124 @@
 
 #include "../proxy/httpclient.h"
 
+static cxstring get_uri_from_clfreq(const char *clfreq) {
+    cxstring uri = { NULL, 0 };
+    
+    const char *begin = NULL;
+    const char *str = clfreq;
+    for(;*str != '\0';str++) {
+        if(*str < 33) {
+            if(begin) {
+                str++;
+                break;
+            }
+        } else {
+            if(!begin) {
+                begin = str;
+            }
+        }
+    }
+    
+    begin = NULL;
+    for(;*str != '\0';str++) {
+        if(*str > 32) {
+            if(!begin) {
+                begin = str;
+            }
+        } else {
+            if(begin) {
+                break;
+            }
+        }
+    }
+    
+    if(begin && *str != '\0') {
+        return cx_strn(begin, str-begin);
+    }
+    
+    return uri;
+    
+}
+
 int http_reverse_proxy_service(pblock *param, Session *sn, Request *rq) {
     EventHandler *ev = sn->ev;
+    const char *method = pblock_findkeyval(pb_key_method, rq->reqpb);
+    const char *clfreq = pblock_findkeyval(pb_key_clf_request, rq->reqpb);
     
+    cxstring uri = get_uri_from_clfreq(clfreq);
+    if(uri.length == 0) {
+        return REQ_ABORTED;
+    }
+    
+    // setup HttpClient
     HttpClient *client = http_client_new(ev);
+    if(!client) {
+        return REQ_ABORTED;
+    }
     
+    if(http_client_set_method(client, method)) {
+        http_client_free(client);
+        return REQ_ABORTED;
+    }
     
+    if(http_client_set_uri_len(client, uri.ptr, uri.length)) {
+        http_client_free(client);
+        return REQ_ABORTED;
+    }
+    
+    // add request headers to the client
+    CxIterator i = pblock_iterator(rq->headers);
+    cx_foreach(pb_entry*, entry, i) {
+        // TODO: don't pass all headers
+        if(http_client_add_request_header(client, cx_mutstr(entry->param->name), cx_mutstr(entry->param->value))) {
+            http_client_free(client);
+            return REQ_ABORTED;
+        }
+    }
+    
+    if(http_client_start(client)) {
+        http_client_free(client);
+        return REQ_ABORTED;
+    }
     
     return REQ_PROCESSING;
 }
+
+
+
+static CX_TEST(test_safs_proxy_get_uri_from_clfreq) {
+    CX_TEST_DO {
+        cxstring ret;
+        
+        ret = get_uri_from_clfreq("GET /uri HTTP/1.1");
+        CX_TEST_ASSERT(!cx_strcmp(ret, "/uri"));
+        ret = get_uri_from_clfreq("GET / HTTP/1.1");
+        CX_TEST_ASSERT(!cx_strcmp(ret, "/"));
+        ret = get_uri_from_clfreq("GET   /test%20/path HTTP/1.1");
+        CX_TEST_ASSERT(!cx_strcmp(ret, "/test%20/path"));
+        ret = get_uri_from_clfreq("   GET /leading_space HTTP/1.1");
+        CX_TEST_ASSERT(!cx_strcmp(ret, "/leading_space"));
+        ret = get_uri_from_clfreq("   GET   /space2 HTTP/1.1");
+        CX_TEST_ASSERT(!cx_strcmp(ret, "/space2"));
+        ret = get_uri_from_clfreq("GET /trailing_space     HTTP/1.1");
+        CX_TEST_ASSERT(!cx_strcmp(ret, "/trailing_space"));
+        ret = get_uri_from_clfreq("   GET   /space3     HTTP/1.1   ");
+        CX_TEST_ASSERT(!cx_strcmp(ret, "/space3"));
+        
+        // fail test
+        ret = get_uri_from_clfreq("");
+        CX_TEST_ASSERT(ret.ptr == NULL);
+        ret = get_uri_from_clfreq("  ");
+        CX_TEST_ASSERT(ret.ptr == NULL);
+        ret = get_uri_from_clfreq("GET");
+        CX_TEST_ASSERT(ret.ptr == NULL);
+        ret = get_uri_from_clfreq("GET /path");
+        CX_TEST_ASSERT(ret.ptr == NULL);
+        ret = get_uri_from_clfreq(" /path2/ ");
+        CX_TEST_ASSERT(ret.ptr == NULL);
+    }
+}
+
+void http_reverse_proxy_add_tests(CxTestSuite *suite) {
+    cx_test_register(suite, test_safs_proxy_get_uri_from_clfreq);
+}
--- a/src/server/safs/proxy.h	Thu Feb 12 16:02:09 2026 +0100
+++ b/src/server/safs/proxy.h	Fri Feb 13 12:16:09 2026 +0100
@@ -30,12 +30,16 @@
 #define SAF_PROXY_H
 
 #include "../public/nsapi.h"
+#include <cx/test.h>
 
 #ifdef __cplusplus
 extern "C" {
 #endif
+    
+int http_reverse_proxy_service(pblock *param, Session *sn, Request *rq);
 
-int http_reverse_proxy_service(pblock *param, Session *sn, Request *rq);
+
+void http_reverse_proxy_add_tests(CxTestSuite *suite);
 
 
 #ifdef __cplusplus
--- a/src/server/test/main.c	Thu Feb 12 16:02:09 2026 +0100
+++ b/src/server/test/main.c	Fri Feb 13 12:16:09 2026 +0100
@@ -39,6 +39,7 @@
 #include "../util/plist.h"
 #include "../util/date.h"
 #include "../daemon/vfs.h"
+#include "../safs/proxy.h"
 
 #include "test.h"
 
@@ -191,6 +192,9 @@
     cx_test_register(suite, test_webdav_proppatch);
     cx_test_register(suite, test_webdav_put);
     
+    // saf tests
+    http_reverse_proxy_add_tests(suite);
+    
     // plugin tests
 #ifdef ENABLE_POSTGRESQL
     register_pg_tests(argc, argv, suite);

mercurial