add test_http_client_io_simple default tip

Mon, 16 Feb 2026 18:45:17 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Mon, 16 Feb 2026 18:45:17 +0100
changeset 676
d43f1dd8b18e
parent 675
edacba8beedb

add test_http_client_io_simple

src/server/proxy/httpclient.c file | annotate | diff | comparison | revisions
--- a/src/server/proxy/httpclient.c	Mon Feb 16 17:43:14 2026 +0100
+++ b/src/server/proxy/httpclient.c	Mon Feb 16 18:45:17 2026 +0100
@@ -451,7 +451,7 @@
         
         // read the request buffer from sock and continue with client_send_request
         CxBuffer buf;
-        cxBufferInit(&buf, cxDefaultAllocator, NULL, len, CX_BUFFER_AUTO_EXTEND);
+        cxBufferInit(&buf, cxDefaultAllocator, NULL, len, CX_BUFFER_AUTO_EXTEND|CX_BUFFER_FREE_CONTENTS);
         char tmpbuf[1024];
         int writes = 1;
         while(client->req_buffer_pos < client->req_buffer_len && writes < 2000000) {
@@ -479,9 +479,129 @@
         close(fds[0]);
         close(fds[1]);
         http_client_free(client);
+        cxBufferDestroy(&buf);
+    }
+}
+
+typedef struct TestResponse {
+    int status;
+    char *msg;
+    CxBuffer *response;
+} TestResponse;
+
+static int test_response_start(HttpClient *client, int status, char *msg, void *userdata) {
+    TestResponse *test = userdata;
+    test->status = status;
+    test->msg = strdup(msg);
+    return 0;
+}
+
+static ssize_t test_response_body_write(HttpClient *client, void *buf, size_t size, void *userdata) {
+    TestResponse *test = userdata;
+    cxBufferWrite(buf, 1, size, test->response);
+    return size;
+}
+
+static CX_TEST(test_http_client_io_simple) {
+    CX_TEST_DO {
+        EventHandler dummy;
+        HttpClient *client = http_client_new(&dummy);
+        
+        int fds[2];
+        util_socketpair(fds);
+        util_socket_setnonblock(fds[0], 1);
+        util_socket_setnonblock(fds[1], 1);
+        client->socketfd = fds[0];
+        int sock = fds[1];
+        
+        // setup client
+        http_client_set_uri(client, "/test/uri/");
+        http_client_set_method(client, "GET");
+        http_client_add_request_header(client, cx_mutstr("Host"), cx_mutstr("localhost"));
+        http_client_add_request_header(client, cx_mutstr("Test1"), cx_mutstr("value1"));
+        http_client_add_request_header(client, cx_mutstr("Test2"), cx_mutstr("value2"));
+        create_req_buffer(client);
+        
+        size_t req_header_len = client->req_buffer_len;
+        
+        // response buffer
+        CxBuffer buf;
+        cxBufferInit(&buf, cxDefaultAllocator, NULL, 1024, CX_BUFFER_AUTO_EXTEND|CX_BUFFER_FREE_CONTENTS);
+        
+        TestResponse testr = { 0 };
+        testr.response = &buf;
+        client->response_start = test_response_start;
+        client->response_start_userdata = &testr;
+        client->response_body_write = test_response_body_write;
+        client->response_body_write_userdata = &testr;
+        
+        // test IO
+        Event event;
+        event.cookie = client;
+        int ret = client_io(&dummy, &event);
+        CX_TEST_ASSERT(!client->error);
+        CX_TEST_ASSERT(ret == 1);
+        
+        // do IO and read request until the header is processed
+        size_t req_header_pos = 0;
+        char req_buf[4];
+        while(req_header_pos < req_header_len) {
+            ssize_t r = read(sock, req_buf, 4);
+            if(r == 0) {
+                break;
+            }
+            CX_TEST_ASSERT(r > 0);
+            req_header_pos += r;
+            ret = client_io(&dummy, &event);
+            CX_TEST_ASSERT(!client->error);
+            CX_TEST_ASSERT(ret == 1);
+        }
+        CX_TEST_ASSERT(req_header_pos == req_header_len);
+        
+        char *response_str = 
+                "HTTP/1.1 200 OK\r\n"
+                "Host: localhost\r\n"
+                "Content-length: 13\r\n"
+                "\r\n"
+                "Hello World!\n";
+        size_t response_str_len = strlen(response_str);
+        size_t response_str_pos = 0;
+        
+        // send response and do IO
+        while(response_str_pos < response_str_len) {
+            size_t len = response_str_len - response_str_pos;
+            if(len > 3) {
+                //len = 3;
+            }
+            ssize_t w = write(sock, response_str + response_str_pos, len);
+            if(w == 0) {
+                break;
+            }
+            CX_TEST_ASSERT(w > 0);
+            response_str_pos += w;
+            
+            ret = client_io(&dummy, &event);
+            
+            CX_TEST_ASSERT(!client->error);
+            CX_TEST_ASSERT(ret == 1);
+        }
+        CX_TEST_ASSERT(response_str_pos == response_str_len);
+        CX_TEST_ASSERT(testr.status == 200);
+        CX_TEST_ASSERT(testr.msg);
+        CX_TEST_ASSERT(!strcmp(testr.msg, "OK"));
+        CX_TEST_ASSERT(testr.response->size == 13);
+        CX_TEST_ASSERT(!cx_strcmp(cx_strn(testr.response->space, testr.response->size), "Hello World!\n"));
+        
+        // cleanup
+        free(testr.msg);
+        close(fds[0]);
+        close(fds[1]);
+        http_client_free(client);
+        cxBufferDestroy(&buf);
     }
 }
 
 void http_client_add_tests(CxTestSuite *suite) {
     cx_test_register(suite, test_http_client_send_request);
+    cx_test_register(suite, test_http_client_io_simple);
 }

mercurial