src/server/proxy/httpclient.c

Fri, 06 Feb 2026 19:37:41 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Fri, 06 Feb 2026 19:37:41 +0100
changeset 666
c99e0b352e36
parent 665
b8d5b797d090
permissions
-rw-r--r--

add non-blocking http client connect

662
70fdf948b642 refactor HttpParser to support parsing of Http responses
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff changeset
1 /*
665
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
3 *
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
4 * Copyright 2026 Olaf Wintermann. All rights reserved.
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
5 *
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
6 * Redistribution and use in source and binary forms, with or without
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
7 * modification, are permitted provided that the following conditions are met:
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
8 *
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
9 * 1. Redistributions of source code must retain the above copyright
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
10 * notice, this list of conditions and the following disclaimer.
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
11 *
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
12 * 2. Redistributions in binary form must reproduce the above copyright
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
13 * notice, this list of conditions and the following disclaimer in the
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
14 * documentation and/or other materials provided with the distribution.
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
15 *
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
26 * POSSIBILITY OF SUCH DAMAGE.
662
70fdf948b642 refactor HttpParser to support parsing of Http responses
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff changeset
27 */
70fdf948b642 refactor HttpParser to support parsing of Http responses
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
diff changeset
28
665
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
29 #include "httpclient.h"
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
30
666
c99e0b352e36 add non-blocking http client connect
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 665
diff changeset
31 #include <cx/buffer.h>
c99e0b352e36 add non-blocking http client connect
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 665
diff changeset
32
c99e0b352e36 add non-blocking http client connect
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 665
diff changeset
33 static int client_connected(EventHandler *ev, Event *event);
c99e0b352e36 add non-blocking http client connect
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 665
diff changeset
34
665
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
35 HttpClient* http_client_new(EventHandler *ev) {
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
36 CxMempool *mp = cxMempoolCreate(32, CX_MEMPOOL_TYPE_PURE);
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
37 if(!mp) {
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
38 return NULL;
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
39 }
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
40
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
41 HttpClient *client = malloc(sizeof(HttpClient));
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
42 HeaderArray *req_headers = header_array_create();
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
43 HeaderArray *resp_headers = header_array_create();
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
44 if(!client || !req_headers || !resp_headers) {
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
45 free(client);
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
46 header_array_free(req_headers);
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
47 header_array_free(resp_headers);
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
48 cxMempoolFree(mp);
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
49 return NULL;
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
50 }
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
51
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
52 memset(client, 0, sizeof(HttpClient));
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
53 client->request_headers = req_headers;
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
54 client->response_headers = resp_headers;
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
55
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
56 return client;
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
57 }
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
58
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
59 int http_client_set_addr(HttpClient *client, const struct sockaddr *addr, socklen_t addrlen) {
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
60 free(client->addr);
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
61 client->addr = NULL;
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
62 client->addrlen = 0;
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
63
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
64 void *newaddr = malloc(addrlen);
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
65 if(!newaddr) {
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
66 return 1;
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
67 }
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
68 memcpy(newaddr, addr, addrlen);
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
69 client->addr = newaddr;
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
70 client->addrlen = addrlen;
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
71
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
72 return 0;
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
73 }
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
74
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
75 int http_client_add_request_header(HttpClient *client, cxmutstr name, cxmutstr value) {
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
76 return header_array_add(client->request_headers, name, value);
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
77 }
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
78
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
79 int http_client_add_request_header_copy(HttpClient *client, cxstring name, cxstring value) {
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
80 cxmutstr n = cx_strdup_a(client->mp->allocator, name);
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
81 cxmutstr v = cx_strdup_a(client->mp->allocator, value);
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
82
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
83 int err = 1;
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
84 if(n.ptr && v.ptr) {
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
85 err = http_client_add_request_header(client, n, v);
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
86 }
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
87 if(err) {
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
88 cxFree(client->mp->allocator, n.ptr);
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
89 cxFree(client->mp->allocator, v.ptr);
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
90 }
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
91 return err;
b8d5b797d090 add first http client code
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 662
diff changeset
92 }
666
c99e0b352e36 add non-blocking http client connect
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 665
diff changeset
93
c99e0b352e36 add non-blocking http client connect
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 665
diff changeset
94 int http_client_start(HttpClient *client) {
c99e0b352e36 add non-blocking http client connect
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 665
diff changeset
95 int socketfd = socket(AF_INET, SOCK_STREAM, 0);
c99e0b352e36 add non-blocking http client connect
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 665
diff changeset
96 if(socketfd < 0) {
c99e0b352e36 add non-blocking http client connect
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 665
diff changeset
97 return 1;
c99e0b352e36 add non-blocking http client connect
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 665
diff changeset
98 }
c99e0b352e36 add non-blocking http client connect
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 665
diff changeset
99
c99e0b352e36 add non-blocking http client connect
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 665
diff changeset
100 int flags;
c99e0b352e36 add non-blocking http client connect
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 665
diff changeset
101 if ((flags = fcntl(socketfd, F_GETFL, 0)) == -1) {
c99e0b352e36 add non-blocking http client connect
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 665
diff changeset
102 flags = 0;
c99e0b352e36 add non-blocking http client connect
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 665
diff changeset
103 }
c99e0b352e36 add non-blocking http client connect
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 665
diff changeset
104 if (fcntl(socketfd, F_SETFL, flags | O_NONBLOCK) != 0) {
c99e0b352e36 add non-blocking http client connect
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 665
diff changeset
105 close(socketfd);
c99e0b352e36 add non-blocking http client connect
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 665
diff changeset
106 return 1;
c99e0b352e36 add non-blocking http client connect
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 665
diff changeset
107 }
c99e0b352e36 add non-blocking http client connect
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 665
diff changeset
108
c99e0b352e36 add non-blocking http client connect
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 665
diff changeset
109 client->writeev.cookie = client;
c99e0b352e36 add non-blocking http client connect
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 665
diff changeset
110 client->writeev.fn = client_connected;
c99e0b352e36 add non-blocking http client connect
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 665
diff changeset
111
c99e0b352e36 add non-blocking http client connect
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 665
diff changeset
112 int ret = ev_pollout(client->ev, socketfd, &client->writeev);
c99e0b352e36 add non-blocking http client connect
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 665
diff changeset
113 if(ret) {
c99e0b352e36 add non-blocking http client connect
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 665
diff changeset
114 close(socketfd);
c99e0b352e36 add non-blocking http client connect
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 665
diff changeset
115 }
c99e0b352e36 add non-blocking http client connect
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 665
diff changeset
116 return 1;
c99e0b352e36 add non-blocking http client connect
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 665
diff changeset
117 }
c99e0b352e36 add non-blocking http client connect
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 665
diff changeset
118
c99e0b352e36 add non-blocking http client connect
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 665
diff changeset
119 static int create_req_buffer(HttpClient *client) {
c99e0b352e36 add non-blocking http client connect
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 665
diff changeset
120 CxBuffer buf;
c99e0b352e36 add non-blocking http client connect
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 665
diff changeset
121 if(cxBufferInit(&buf, cxDefaultAllocator, NULL, 1024, CX_BUFFER_AUTO_EXTEND)) {
c99e0b352e36 add non-blocking http client connect
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 665
diff changeset
122 return 1;
c99e0b352e36 add non-blocking http client connect
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 665
diff changeset
123 }
c99e0b352e36 add non-blocking http client connect
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 665
diff changeset
124
c99e0b352e36 add non-blocking http client connect
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 665
diff changeset
125
c99e0b352e36 add non-blocking http client connect
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 665
diff changeset
126
c99e0b352e36 add non-blocking http client connect
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 665
diff changeset
127 return 0;
c99e0b352e36 add non-blocking http client connect
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 665
diff changeset
128 }
c99e0b352e36 add non-blocking http client connect
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 665
diff changeset
129
c99e0b352e36 add non-blocking http client connect
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 665
diff changeset
130 static int client_connected(EventHandler *ev, Event *event) {
c99e0b352e36 add non-blocking http client connect
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 665
diff changeset
131 HttpClient *client = event->cookie;
c99e0b352e36 add non-blocking http client connect
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 665
diff changeset
132 if(create_req_buffer(client)) {
c99e0b352e36 add non-blocking http client connect
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 665
diff changeset
133 // TODO: set error
c99e0b352e36 add non-blocking http client connect
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 665
diff changeset
134 return 0; // end
c99e0b352e36 add non-blocking http client connect
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 665
diff changeset
135 }
c99e0b352e36 add non-blocking http client connect
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 665
diff changeset
136
c99e0b352e36 add non-blocking http client connect
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 665
diff changeset
137
c99e0b352e36 add non-blocking http client connect
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 665
diff changeset
138 return 1;
c99e0b352e36 add non-blocking http client connect
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 665
diff changeset
139 }
c99e0b352e36 add non-blocking http client connect
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 665
diff changeset
140
c99e0b352e36 add non-blocking http client connect
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 665
diff changeset
141

mercurial