1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 #include "proxy.h"
30
31 #include <sys/socket.h>
32 #include <arpa/inet.h>
33 #include <ctype.h>
34 #include <string.h>
35
36 #include "../util/pblock.h"
37 #include "../proxy/httpclient.h"
38
39
40 static cxstring get_uri_from_clfreq(
const char *clfreq) {
41 cxstring uri = {
NULL,
0 };
42
43 const char *begin =
NULL;
44 const char *str = clfreq;
45 for(;*str !=
'\0';str++) {
46 if(*str <
33) {
47 if(begin) {
48 str++;
49 break;
50 }
51 }
else {
52 if(!begin) {
53 begin = str;
54 }
55 }
56 }
57
58 begin =
NULL;
59 for(;*str !=
'\0';str++) {
60 if(*str >
32) {
61 if(!begin) {
62 begin = str;
63 }
64 }
else {
65 if(begin) {
66 break;
67 }
68 }
69 }
70
71 if(begin && *str !=
'\0') {
72 return cx_strn(begin, str-begin);
73 }
74
75 return uri;
76
77 }
78
79 typedef struct ProxyRequest {
80 Session *sn;
81 Request *rq;
82
83
84
85
86
87
88 pblock *request_header_rewrite;
89
90
91
92
93
94
95 pblock *response_header_rewrite;
96
97
98
99
100 int response_started;
101 } ProxyRequest;
102
103 static int proxy_response_start(HttpClient *client,
int status,
char *message,
void *userdata) {
104 ProxyRequest *proxy = userdata;
105
106 HeaderArray *headers = client->response_headers;
107 while(headers) {
108 for(
int i=
0;i<headers->len;i++) {
109 cxmutstr name = headers->headers[i].name;
110 cxmutstr value = headers->headers[i].value;
111
112 for(
int c=
0;c<name.length;c++) {
113 name.ptr[c] = tolower(name.ptr[c]);
114 }
115
116 name.ptr[name.length] =
0;
117
118 char *rewrite = pblock_findval(name.ptr, proxy->response_header_rewrite);
119 if(rewrite) {
120 value = cx_mutstr(rewrite);
121 if(value.length ==
0) {
122
123 continue;
124 }
125 }
126
127
128 pblock_nvlinsert(name.ptr, name.length, value.ptr, value.length, proxy->rq->srvhdrs);
129 }
130 headers = headers->next;
131 }
132
133 protocol_status(proxy->sn, proxy->rq, status, message);
134 protocol_start_response(proxy->sn, proxy->rq);
135 proxy->response_started =
1;
136
137 return 0;
138 }
139
140 static void proxy_response_finished(HttpClient *client,
void *userdata) {
141 ProxyRequest *proxy = userdata;
142
143 int ret =
REQ_PROCEED;
144 if(!proxy->response_started) {
145 protocol_status(proxy->sn, proxy->rq,
502,
NULL);
146 ret =
REQ_ABORTED;
147 }
148
149 http_client_free(client);
150
151 nsapi_function_return(proxy->sn, proxy->rq, ret);
152 }
153
154 static ssize_t proxy_request_read(HttpClient *client,
void *buf,
size_t nbytes,
void *userdata) {
155 ProxyRequest *proxy = userdata;
156 int ret = netbuf_getbytes(proxy->sn->inbuf, buf, nbytes);
157 if(ret ==
NETBUF_EOF) {
158 ret =
0;
159 }
160
161 return ret;
162 }
163
164 static ssize_t proxy_response_write(HttpClient *client,
void *buf,
size_t nbytes,
void *userdata) {
165 ProxyRequest *proxy = userdata;
166 ssize_t ret = net_write(proxy->sn->csd, buf, nbytes);
167
168 return ret;
169 }
170
171 int http_reverse_proxy_service(pblock *param, Session *sn, Request *rq) {
172 EventHandler *ev = sn->ev;
173 const char *method = pblock_findkeyval(pb_key_method, rq->reqpb);
174 const char *clfreq = pblock_findkeyval(pb_key_clf_request, rq->reqpb);
175
176 cxstring uri = get_uri_from_clfreq(clfreq);
177 if(uri.length ==
0) {
178 return REQ_ABORTED;
179 }
180
181
182
183 pblock_removekey(pb_key_content_type, rq->srvhdrs);
184
185 ProxyRequest *proxy = pool_malloc(sn->pool,
sizeof(ProxyRequest));
186 proxy->sn = sn;
187 proxy->rq = rq;
188 proxy->request_header_rewrite = pblock_create_pool(sn->pool,
16);
189 proxy->response_header_rewrite = pblock_create_pool(sn->pool,
16);
190 proxy->response_started =
0;
191
192
193
194 pblock_nvinsert(
"host",
"", proxy->request_header_rewrite);
195 pblock_nvinsert(
"connection",
"", proxy->request_header_rewrite);
196 pblock_nvinsert(
"transfer-encoding",
"", proxy->request_header_rewrite);
197 pblock_nvinsert(
"content-length",
"", proxy->request_header_rewrite);
198 pblock_nvinsert(
"server",
"", proxy->response_header_rewrite);
199 pblock_nvinsert(
"connection",
"", proxy->response_header_rewrite);
200
201
202 HttpClient *client = http_client_new(ev);
203 if(!client) {
204 return REQ_ABORTED;
205 }
206
207 if(http_client_set_method(client, method)) {
208 http_client_free(client);
209 return REQ_ABORTED;
210 }
211
212 if(http_client_set_uri_len(client, uri.ptr, uri.length)) {
213 http_client_free(client);
214 return REQ_ABORTED;
215 }
216
217
218 struct sockaddr_in address;
219 inet_pton(
AF_INET,
"127.0.0.1", &address.sin_addr);
220 address.sin_family =
AF_INET;
221 address.sin_port = htons(
8080);
222 http_client_set_addr(client, (
struct sockaddr*)&address,
sizeof(address));
223 http_client_add_request_header(client, cx_mutstr(
"host"), cx_mutstr(
"localhost:8080"));
224
225
226 CxIterator i = pblock_iterator(rq->headers);
227 cx_foreach(pb_entry*, entry, i) {
228 cxmutstr header_value;
229 char *rewrite_header = pblock_findval(entry->param->name, proxy->request_header_rewrite);
230 if(rewrite_header) {
231 if(!strcmp(entry->param->name,
"transfer-encoding")) {
232 if(!strcmp(entry->param->value,
"chunked")) {
233
234 if(http_client_enable_chunked_transfer_encoding(client)) {
235 http_client_free(client);
236 return REQ_ABORTED;
237 }
238 continue;
239 }
240 }
else if(!strcmp(entry->param->name,
"content-length")) {
241 long long contentlength;
242 if(!cx_strtoll(cx_str(entry->param->value), &contentlength,
10)) {
243 if(http_client_set_content_length(client, contentlength)) {
244 http_client_free(client);
245 return REQ_ABORTED;
246 }
247 }
else {
248
249 protocol_status(sn, rq,
400,
NULL);
250 http_client_free(client);
251 return REQ_ABORTED;
252 }
253 continue;
254 }
else {
255
256 header_value = cx_mutstr(rewrite_header);
257 if(header_value.length ==
0) {
258 continue;
259 }
260 }
261 }
else {
262 header_value = cx_mutstr(entry->param->value);
263 }
264
265 if(http_client_add_request_header(client, cx_mutstr(entry->param->name), header_value)) {
266 http_client_free(client);
267 return REQ_ABORTED;
268 }
269 }
270
271 client->request_body_read = proxy_request_read;
272 client->request_body_read_userdata = proxy;
273 client->response_start = proxy_response_start;
274 client->response_start_userdata = proxy;
275 client->response_body_write = proxy_response_write;
276 client->response_body_write_userdata = proxy;
277
278
279 if(http_client_start(client)) {
280
281 http_client_free(client);
282 return REQ_ABORTED;
283 }
284
285 return REQ_PROCESSING;
286 }
287
288
289
290
291
292 static CX_TEST(test_safs_proxy_get_uri_from_clfreq) {
293 CX_TEST_DO {
294 cxstring ret;
295
296 ret = get_uri_from_clfreq(
"GET /uri HTTP/1.1");
297 CX_TEST_ASSERT(!cx_strcmp(ret,
"/uri"));
298 ret = get_uri_from_clfreq(
"G / HTTP/1.1");
299 CX_TEST_ASSERT(!cx_strcmp(ret,
"/"));
300 ret = get_uri_from_clfreq(
"POST /test%20/path HTTP/1.1");
301 CX_TEST_ASSERT(!cx_strcmp(ret,
"/test%20/path"));
302 ret = get_uri_from_clfreq(
" GET /leading_space HTTP/1.1");
303 CX_TEST_ASSERT(!cx_strcmp(ret,
"/leading_space"));
304 ret = get_uri_from_clfreq(
" PROPFIND /space2 HTTP/1.1");
305 CX_TEST_ASSERT(!cx_strcmp(ret,
"/space2"));
306 ret = get_uri_from_clfreq(
"HEAD /trailing_space HTTP/1.1");
307 CX_TEST_ASSERT(!cx_strcmp(ret,
"/trailing_space"));
308 ret = get_uri_from_clfreq(
" GET /space3 HTTP/1.1 ");
309 CX_TEST_ASSERT(!cx_strcmp(ret,
"/space3"));
310
311
312 ret = get_uri_from_clfreq(
"");
313 CX_TEST_ASSERT(ret.ptr ==
NULL);
314 ret = get_uri_from_clfreq(
" ");
315 CX_TEST_ASSERT(ret.ptr ==
NULL);
316 ret = get_uri_from_clfreq(
"GET");
317 CX_TEST_ASSERT(ret.ptr ==
NULL);
318 ret = get_uri_from_clfreq(
"GET /path");
319 CX_TEST_ASSERT(ret.ptr ==
NULL);
320 ret = get_uri_from_clfreq(
" /path2/ ");
321 CX_TEST_ASSERT(ret.ptr ==
NULL);
322 }
323 }
324
325 void http_reverse_proxy_add_tests(CxTestSuite *suite) {
326 cx_test_register(suite, test_safs_proxy_get_uri_from_clfreq);
327 }
328