Line |
Branch |
Exec |
Source |
1 |
|
|
/* GATE PROJECT LICENSE: |
2 |
|
|
+----------------------------------------------------------------------------+ |
3 |
|
|
| Copyright(c) 2018-2025, Stefan Meislinger | |
4 |
|
|
| All rights reserved. | |
5 |
|
|
| | |
6 |
|
|
| Redistribution and use in source and binary forms, with or without | |
7 |
|
|
| modification, are permitted provided that the following conditions are met:| |
8 |
|
|
| | |
9 |
|
|
| 1. Redistributions of source code must retain the above copyright notice, | |
10 |
|
|
| this list of conditions and the following disclaimer. | |
11 |
|
|
| 2. Redistributions in binary form must reproduce the above copyright | |
12 |
|
|
| notice, this list of conditions and the following disclaimer in the | |
13 |
|
|
| documentation and/or other materials provided with the distribution. | |
14 |
|
|
| | |
15 |
|
|
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"| |
16 |
|
|
| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
17 |
|
|
| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
18 |
|
|
| ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | |
19 |
|
|
| LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
20 |
|
|
| CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
21 |
|
|
| SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
22 |
|
|
| INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
23 |
|
|
| CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
24 |
|
|
| ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | |
25 |
|
|
| THE POSSIBILITY OF SUCH DAMAGE. | |
26 |
|
|
+----------------------------------------------------------------------------+ |
27 |
|
|
*/ |
28 |
|
|
|
29 |
|
|
#include "gate/tech/microservices/webserver_service.h" |
30 |
|
|
#include "gate/results.h" |
31 |
|
|
#include "gate/net/httpservers.h" |
32 |
|
|
#include "gate/times.h" |
33 |
|
|
|
34 |
|
|
#define WEBSERVER_CONFIG_NAME GATE_STRUCT_ROOT_NAME GATE_STRUCT_SEPARATOR WEBSERVER_ROOT_NAME GATE_STRUCT_SEPARATOR "config" |
35 |
|
|
|
36 |
|
|
#define WEBSERVER_CONFIG_VDIR_NAME WEBSERVER_CONFIG_NAME GATE_STRUCT_SEPARATOR "vdir" |
37 |
|
|
#define WEBSERVER_CONFIG_HTTPHANDLER_NAME WEBSERVER_CONFIG_NAME GATE_STRUCT_SEPARATOR "httphandler" |
38 |
|
|
|
39 |
|
|
|
40 |
|
|
static gate_struct_item_t const webservice_request_members[] = |
41 |
|
|
{ |
42 |
|
|
GATE_STRUCT_ITEM(gate_microservice_webservice_request_t, GATE_TYPE_STRING, verb), |
43 |
|
|
GATE_STRUCT_ITEM(gate_microservice_webservice_request_t, GATE_TYPE_STRING, path), |
44 |
|
|
GATE_STRUCT_ITEM(gate_microservice_webservice_request_t, GATE_TYPE_BLOB, content), |
45 |
|
|
GATE_STRUCT_ITEM(gate_microservice_webservice_request_t, GATE_TYPE_STRING, content_type), |
46 |
|
|
}; |
47 |
|
|
|
48 |
|
|
static gate_struct_descriptor_t const webservice_request_descriptor = |
49 |
|
|
{ |
50 |
|
|
WEBSERVER_WEBSERVICE_REQUEST, |
51 |
|
|
webservice_request_members, |
52 |
|
|
sizeof(webservice_request_members) / sizeof(webservice_request_members[0]), |
53 |
|
|
sizeof(gate_microservice_webservice_request_t) |
54 |
|
|
}; |
55 |
|
|
|
56 |
|
✗ |
gate_result_t gate_microservice_webservice_request_ctor(void* target, void const* src) |
57 |
|
|
{ |
58 |
|
|
gate_result_t ret; |
59 |
|
✗ |
gate_microservice_webservice_request_t const* ptr_src = (gate_microservice_webservice_request_t const*)src; |
60 |
|
✗ |
gate_microservice_webservice_request_t* ptr_dst = (gate_microservice_webservice_request_t*)target; |
61 |
|
|
|
62 |
|
✗ |
if (src == NULL) |
63 |
|
|
{ |
64 |
|
✗ |
ret = gate_struct_init(&ptr_dst->struct_base, &webservice_request_descriptor); |
65 |
|
|
} |
66 |
|
|
else |
67 |
|
|
{ |
68 |
|
✗ |
gate_mem_clear(ptr_dst, sizeof(gate_microservice_webservice_request_t)); |
69 |
|
✗ |
ret = gate_struct_copy(&ptr_dst->struct_base, &ptr_src->struct_base); |
70 |
|
|
} |
71 |
|
✗ |
return ret; |
72 |
|
|
} |
73 |
|
|
|
74 |
|
|
|
75 |
|
|
|
76 |
|
|
static gate_struct_item_t const webservice_response_members[] = |
77 |
|
|
{ |
78 |
|
|
GATE_STRUCT_ITEM(gate_microservice_webservice_response_t, GATE_TYPE_UI32, status_code), |
79 |
|
|
GATE_STRUCT_ITEM(gate_microservice_webservice_response_t, GATE_TYPE_BLOB, content), |
80 |
|
|
GATE_STRUCT_ITEM(gate_microservice_webservice_response_t, GATE_TYPE_STRING, content_type), |
81 |
|
|
}; |
82 |
|
|
|
83 |
|
|
static gate_struct_descriptor_t const webservice_response_descriptor = |
84 |
|
|
{ |
85 |
|
|
WEBSERVER_WEBSERVICE_RESPONSE, |
86 |
|
|
webservice_response_members, |
87 |
|
|
sizeof(webservice_response_members) / sizeof(webservice_response_members[0]), |
88 |
|
|
sizeof(gate_microservice_webservice_response_t) |
89 |
|
|
}; |
90 |
|
|
|
91 |
|
✗ |
gate_result_t gate_microservice_webservice_response_ctor(void* target, void const* src) |
92 |
|
|
{ |
93 |
|
|
gate_result_t ret; |
94 |
|
✗ |
gate_microservice_webservice_response_t const* ptr_src = (gate_microservice_webservice_response_t const*)src; |
95 |
|
✗ |
gate_microservice_webservice_response_t* ptr_dst = (gate_microservice_webservice_response_t*)target; |
96 |
|
|
|
97 |
|
✗ |
if (src == NULL) |
98 |
|
|
{ |
99 |
|
✗ |
ret = gate_struct_init(&ptr_dst->struct_base, &webservice_response_descriptor); |
100 |
|
|
} |
101 |
|
|
else |
102 |
|
|
{ |
103 |
|
✗ |
gate_mem_clear(ptr_dst, sizeof(gate_microservice_webservice_response_t)); |
104 |
|
✗ |
ret = gate_struct_copy(&ptr_dst->struct_base, &ptr_src->struct_base); |
105 |
|
|
} |
106 |
|
✗ |
return ret; |
107 |
|
|
} |
108 |
|
|
|
109 |
|
|
|
110 |
|
|
|
111 |
|
|
typedef struct webserver_config_vdir_class |
112 |
|
|
{ |
113 |
|
|
gate_struct_t struct_base; |
114 |
|
|
|
115 |
|
|
gate_string_t webpath; |
116 |
|
|
gate_string_t filepath; |
117 |
|
|
gate_bool_t webdav; |
118 |
|
|
} webserver_config_vdir_t; |
119 |
|
|
|
120 |
|
|
static gate_struct_item_t const webserver_config_vdir_members[] = |
121 |
|
|
{ |
122 |
|
|
GATE_STRUCT_ITEM(webserver_config_vdir_t, GATE_TYPE_STRING, webpath), |
123 |
|
|
GATE_STRUCT_ITEM(webserver_config_vdir_t, GATE_TYPE_STRING, filepath), |
124 |
|
|
GATE_STRUCT_ITEM(webserver_config_vdir_t, GATE_TYPE_BOOL, webdav), |
125 |
|
|
}; |
126 |
|
|
|
127 |
|
|
static gate_struct_descriptor_t const webserver_config_vdir_descriptor = |
128 |
|
|
{ |
129 |
|
|
WEBSERVER_CONFIG_VDIR_NAME, |
130 |
|
|
webserver_config_vdir_members, |
131 |
|
|
sizeof(webserver_config_vdir_members) / sizeof(webserver_config_vdir_members[0]), |
132 |
|
|
sizeof(webserver_config_vdir_t) |
133 |
|
|
}; |
134 |
|
|
|
135 |
|
✗ |
static gate_result_t webserver_config_vdir_ctor(void* target, void const* src) |
136 |
|
|
{ |
137 |
|
|
gate_result_t ret; |
138 |
|
✗ |
webserver_config_vdir_t const* ptr_src = (webserver_config_vdir_t const*)src; |
139 |
|
✗ |
webserver_config_vdir_t* ptr_dst = (webserver_config_vdir_t*)target; |
140 |
|
|
|
141 |
|
✗ |
if (src == NULL) |
142 |
|
|
{ |
143 |
|
✗ |
ret = gate_struct_init(&ptr_dst->struct_base, &webserver_config_vdir_descriptor); |
144 |
|
|
} |
145 |
|
|
else |
146 |
|
|
{ |
147 |
|
✗ |
gate_mem_clear(ptr_dst, sizeof(webserver_config_vdir_t)); |
148 |
|
✗ |
ret = gate_struct_copy(&ptr_dst->struct_base, &ptr_src->struct_base); |
149 |
|
|
} |
150 |
|
✗ |
return ret; |
151 |
|
|
} |
152 |
|
|
|
153 |
|
|
|
154 |
|
|
typedef struct webserver_config_httphandler_class |
155 |
|
|
{ |
156 |
|
|
gate_struct_t struct_base; |
157 |
|
|
|
158 |
|
|
gate_string_t webpath; |
159 |
|
|
gate_string_t handlername; |
160 |
|
|
} webserver_config_httphandler_t; |
161 |
|
|
|
162 |
|
|
static gate_struct_item_t const webserver_config_httphandler_members[] = |
163 |
|
|
{ |
164 |
|
|
GATE_STRUCT_ITEM(webserver_config_httphandler_t, GATE_TYPE_STRING, webpath), |
165 |
|
|
GATE_STRUCT_ITEM(webserver_config_httphandler_t, GATE_TYPE_STRING, handlername), |
166 |
|
|
}; |
167 |
|
|
|
168 |
|
|
static gate_struct_descriptor_t const webserver_config_httphandler_descriptor = |
169 |
|
|
{ |
170 |
|
|
WEBSERVER_CONFIG_HTTPHANDLER_NAME, |
171 |
|
|
webserver_config_httphandler_members, |
172 |
|
|
sizeof(webserver_config_httphandler_members) / sizeof(webserver_config_httphandler_members[0]), |
173 |
|
|
sizeof(webserver_config_httphandler_t) |
174 |
|
|
}; |
175 |
|
|
|
176 |
|
✗ |
static gate_result_t webserver_config_httphandler_ctor(void* target, void const* src) |
177 |
|
|
{ |
178 |
|
|
gate_result_t ret; |
179 |
|
✗ |
webserver_config_httphandler_t const* ptr_src = (webserver_config_httphandler_t const*)src; |
180 |
|
✗ |
webserver_config_httphandler_t* ptr_dst = (webserver_config_httphandler_t*)target; |
181 |
|
|
|
182 |
|
✗ |
if (src == NULL) |
183 |
|
|
{ |
184 |
|
✗ |
ret = gate_struct_init(&ptr_dst->struct_base, &webserver_config_httphandler_descriptor); |
185 |
|
|
} |
186 |
|
|
else |
187 |
|
|
{ |
188 |
|
✗ |
gate_mem_clear(ptr_dst, sizeof(webserver_config_httphandler_t)); |
189 |
|
✗ |
ret = gate_struct_copy(&ptr_dst->struct_base, &ptr_src->struct_base); |
190 |
|
|
} |
191 |
|
✗ |
return ret; |
192 |
|
|
} |
193 |
|
|
|
194 |
|
|
|
195 |
|
|
|
196 |
|
|
typedef struct webserver_config_webservice_class |
197 |
|
|
{ |
198 |
|
|
gate_struct_t struct_base; |
199 |
|
|
|
200 |
|
|
gate_string_t webpath; |
201 |
|
|
gate_string_t service_address; |
202 |
|
|
gate_string_t service_method; |
203 |
|
|
} webserver_config_webservice_t; |
204 |
|
|
|
205 |
|
|
static gate_struct_item_t const webserver_config_webservice_members[] = |
206 |
|
|
{ |
207 |
|
|
GATE_STRUCT_ITEM(webserver_config_webservice_t, GATE_TYPE_STRING, webpath), |
208 |
|
|
GATE_STRUCT_ITEM(webserver_config_webservice_t, GATE_TYPE_STRING, service_address), |
209 |
|
|
GATE_STRUCT_ITEM(webserver_config_webservice_t, GATE_TYPE_STRING, service_method), |
210 |
|
|
}; |
211 |
|
|
|
212 |
|
|
static gate_struct_descriptor_t const webserver_config_webservice_descriptor = |
213 |
|
|
{ |
214 |
|
|
WEBSERVER_CONFIG_VDIR_NAME, |
215 |
|
|
webserver_config_webservice_members, |
216 |
|
|
sizeof(webserver_config_webservice_members) / sizeof(webserver_config_webservice_members[0]), |
217 |
|
|
sizeof(webserver_config_webservice_t) |
218 |
|
|
}; |
219 |
|
|
|
220 |
|
✗ |
static gate_result_t webserver_config_webservice_ctor(void* target, void const* src) |
221 |
|
|
{ |
222 |
|
|
gate_result_t ret; |
223 |
|
✗ |
webserver_config_webservice_t const* ptr_src = (webserver_config_webservice_t const*)src; |
224 |
|
✗ |
webserver_config_webservice_t* ptr_dst = (webserver_config_webservice_t*)target; |
225 |
|
|
|
226 |
|
✗ |
if (src == NULL) |
227 |
|
|
{ |
228 |
|
✗ |
ret = gate_struct_init(&ptr_dst->struct_base, &webserver_config_webservice_descriptor); |
229 |
|
|
} |
230 |
|
|
else |
231 |
|
|
{ |
232 |
|
✗ |
gate_mem_clear(ptr_dst, sizeof(webserver_config_webservice_t)); |
233 |
|
✗ |
ret = gate_struct_copy(&ptr_dst->struct_base, &ptr_src->struct_base); |
234 |
|
|
} |
235 |
|
✗ |
return ret; |
236 |
|
|
} |
237 |
|
|
|
238 |
|
|
|
239 |
|
|
|
240 |
|
|
|
241 |
|
|
typedef struct webserver_config_class |
242 |
|
|
{ |
243 |
|
|
gate_struct_t struct_base; |
244 |
|
|
|
245 |
|
|
gate_arraylist_t http; |
246 |
|
|
gate_arraylist_t https; |
247 |
|
|
gate_uint32_t idletimeout; |
248 |
|
|
gate_arraylist_t vdirs; |
249 |
|
|
gate_arraylist_t httphandlers; |
250 |
|
|
gate_arraylist_t webservices; |
251 |
|
|
} webserver_config_t; |
252 |
|
|
|
253 |
|
|
static gate_struct_item_t const webserver_config_members[] = |
254 |
|
|
{ |
255 |
|
|
GATE_STRUCT_ITEM(webserver_config_t, GATE_TYPE_ARRAYLIST_STRING, http), |
256 |
|
|
GATE_STRUCT_ITEM(webserver_config_t, GATE_TYPE_ARRAYLIST_STRING, https), |
257 |
|
|
GATE_STRUCT_ITEM(webserver_config_t, GATE_TYPE_UI32, idletimeout), |
258 |
|
|
GATE_STRUCT_ITEM(webserver_config_t, GATE_TYPE_ARRAYLIST_STRUCT, vdirs), |
259 |
|
|
GATE_STRUCT_ITEM(webserver_config_t, GATE_TYPE_ARRAYLIST_STRUCT, httphandlers), |
260 |
|
|
GATE_STRUCT_ITEM(webserver_config_t, GATE_TYPE_ARRAYLIST_STRUCT, webservices) |
261 |
|
|
}; |
262 |
|
|
|
263 |
|
|
static gate_struct_descriptor_t const webserver_config_descriptor = |
264 |
|
|
{ |
265 |
|
|
WEBSERVER_CONFIG_NAME, |
266 |
|
|
webserver_config_members, |
267 |
|
|
sizeof(webserver_config_members) / sizeof(webserver_config_members[0]), |
268 |
|
|
sizeof(webserver_config_t) |
269 |
|
|
}; |
270 |
|
|
|
271 |
|
✗ |
static gate_result_t webserver_config_ctor(void* target, void const* src) |
272 |
|
|
{ |
273 |
|
|
gate_result_t ret; |
274 |
|
✗ |
webserver_config_t const* ptr_src = (webserver_config_t const*)src; |
275 |
|
✗ |
webserver_config_t* ptr_target = (webserver_config_t*)target; |
276 |
|
|
|
277 |
|
|
do |
278 |
|
|
{ |
279 |
|
✗ |
gate_mem_clear(ptr_target, sizeof(webserver_config_t)); |
280 |
|
✗ |
if (src) |
281 |
|
|
{ |
282 |
|
✗ |
ret = gate_struct_copy(&ptr_target->struct_base, &ptr_src->struct_base); |
283 |
|
|
} |
284 |
|
|
else |
285 |
|
|
{ |
286 |
|
✗ |
ret = gate_struct_init(&ptr_target->struct_base, &webserver_config_descriptor); |
287 |
|
✗ |
GATE_BREAK_IF_FAILED(ret); |
288 |
|
|
|
289 |
|
✗ |
ptr_target->vdirs = gate_arraylist_create(sizeof(webserver_config_vdir_t), NULL, 0, |
290 |
|
|
&webserver_config_vdir_ctor, &gate_struct_destructor); |
291 |
|
✗ |
if (NULL == ptr_target->vdirs) |
292 |
|
|
{ |
293 |
|
✗ |
gate_struct_destructor(ptr_target); |
294 |
|
✗ |
ret = GATE_RESULT_OUTOFMEMORY; |
295 |
|
✗ |
break; |
296 |
|
|
} |
297 |
|
|
|
298 |
|
✗ |
ptr_target->httphandlers = gate_arraylist_create(sizeof(webserver_config_httphandler_t), NULL, 0, |
299 |
|
|
&webserver_config_httphandler_ctor, &gate_struct_destructor); |
300 |
|
✗ |
if (NULL == ptr_target->httphandlers) |
301 |
|
|
{ |
302 |
|
✗ |
gate_struct_destructor(ptr_target); |
303 |
|
✗ |
ret = GATE_RESULT_OUTOFMEMORY; |
304 |
|
✗ |
break; |
305 |
|
|
} |
306 |
|
|
|
307 |
|
✗ |
ptr_target->webservices = gate_arraylist_create(sizeof(webserver_config_webservice_t), NULL, 0, |
308 |
|
|
&webserver_config_webservice_ctor, &gate_struct_destructor); |
309 |
|
✗ |
if (NULL == ptr_target->webservices) |
310 |
|
|
{ |
311 |
|
✗ |
gate_struct_destructor(ptr_target); |
312 |
|
✗ |
ret = GATE_RESULT_OUTOFMEMORY; |
313 |
|
✗ |
break; |
314 |
|
|
} |
315 |
|
|
} |
316 |
|
|
} while (0); |
317 |
|
|
|
318 |
|
✗ |
return ret; |
319 |
|
|
} |
320 |
|
|
|
321 |
|
|
|
322 |
|
|
|
323 |
|
|
|
324 |
|
|
|
325 |
|
|
|
326 |
|
|
|
327 |
|
|
|
328 |
|
|
typedef struct webserver_data_class |
329 |
|
|
{ |
330 |
|
|
gate_httpserver_t server; |
331 |
|
|
gate_httpserver_host_id_t hosts[64]; |
332 |
|
|
gate_size_t hosts_usesd; |
333 |
|
|
gate_httpserver_filehandler_config_t file_handlers[16]; |
334 |
|
|
gate_size_t file_handlers_used; |
335 |
|
|
gate_httpserver_handler_t* http_handlers[64]; |
336 |
|
|
gate_size_t http_handlers_used; |
337 |
|
|
gate_httpserver_filehandler_config_t service_handlers[16]; |
338 |
|
|
gate_size_t service_handlers_used; |
339 |
|
|
|
340 |
|
|
webserver_config_t config; |
341 |
|
|
} gate_webserver_data_t; |
342 |
|
|
|
343 |
|
|
|
344 |
|
✗ |
static gate_string_t* create_webservice_endpoint(gate_string_t const* ptr_address, gate_string_t const* ptr_method, gate_string_t* ptr_endpoint) |
345 |
|
|
{ |
346 |
|
✗ |
gate_string_t* ret = NULL; |
347 |
|
|
gate_strbuilder_t builder; |
348 |
|
✗ |
gate_strbuilder_create(&builder, gate_string_length(ptr_address) + gate_string_length(ptr_method) + 4); |
349 |
|
✗ |
gate_strbuilder_append_string(&builder, ptr_address); |
350 |
|
✗ |
gate_strbuilder_append_chars(&builder, 1, '/'); |
351 |
|
✗ |
gate_strbuilder_append_string(&builder, ptr_method); |
352 |
|
✗ |
ret = gate_strbuilder_to_string(&builder, ptr_endpoint); |
353 |
|
✗ |
gate_strbuilder_release(&builder); |
354 |
|
✗ |
return ret; |
355 |
|
|
} |
356 |
|
|
|
357 |
|
✗ |
static gate_bool_t parse_service_endpoint(gate_string_t const* endpoint, gate_string_t* service_address, gate_string_t* service_endpoint) |
358 |
|
|
{ |
359 |
|
|
gate_size_t pos; |
360 |
|
✗ |
pos = gate_string_char_pos_last(endpoint, '/'); |
361 |
|
✗ |
if (pos != GATE_STR_NPOS) |
362 |
|
|
{ |
363 |
|
✗ |
gate_string_substr(service_address, endpoint, 0, pos); |
364 |
|
✗ |
gate_string_substr(service_endpoint, endpoint, pos + 1, GATE_STR_NPOS); |
365 |
|
✗ |
return true; |
366 |
|
|
} |
367 |
|
✗ |
return false; |
368 |
|
|
} |
369 |
|
|
|
370 |
|
✗ |
static gate_result_t webserver_on_request(gate_httpserver_t* server, |
371 |
|
|
gate_httpserver_host_id_t host_id, |
372 |
|
|
gate_http_request_t const* request, |
373 |
|
|
gate_httpserver_response_t* response, |
374 |
|
|
void* userparam) |
375 |
|
|
{ |
376 |
|
✗ |
gate_result_t ret = GATE_RESULT_NOMATCH; |
377 |
|
✗ |
gate_microservice_base_t* ptr_service = (gate_microservice_base_t*)userparam; |
378 |
|
✗ |
gate_webserver_data_t* ptr_data = (gate_webserver_data_t*)ptr_service->data_ptr; |
379 |
|
|
gate_size_t ndx; |
380 |
|
✗ |
gate_string_t service_address = GATE_STRING_INIT_EMPTY; |
381 |
|
✗ |
gate_string_t service_method = GATE_STRING_INIT_EMPTY; |
382 |
|
|
gate_microservice_webservice_request_t webrequest; |
383 |
|
|
gate_microservice_webservice_response_t webresponse; |
384 |
|
|
|
385 |
|
|
GATE_UNUSED_ARG(server); |
386 |
|
|
|
387 |
|
|
do |
388 |
|
|
{ |
389 |
|
|
/* check if we have a file-handler for the given request */ |
390 |
|
✗ |
for (ndx = 0; ndx != ptr_data->file_handlers_used; ++ndx) |
391 |
|
|
{ |
392 |
|
✗ |
ret = gate_httpserver_filehandler_process(&ptr_data->file_handlers[ndx], request, response); |
393 |
|
✗ |
if (GATE_SUCCEEDED(ret)) |
394 |
|
|
{ |
395 |
|
✗ |
break; |
396 |
|
|
} |
397 |
|
|
} |
398 |
|
✗ |
if (GATE_SUCCEEDED(ret)) |
399 |
|
|
{ |
400 |
|
|
/* file-handler has processed the request, we are done */ |
401 |
|
✗ |
break; |
402 |
|
|
} |
403 |
|
|
|
404 |
|
✗ |
for (ndx = 0; ndx != ptr_data->service_handlers_used; ++ndx) |
405 |
|
|
{ |
406 |
|
✗ |
if (gate_string_starts_with(&request->path, &ptr_data->service_handlers[ndx].http_request_root_path)) |
407 |
|
|
{ |
408 |
|
✗ |
if (parse_service_endpoint(&ptr_data->service_handlers[ndx].filesystem_root_path, &service_address, &service_method)) |
409 |
|
|
{ |
410 |
|
|
do |
411 |
|
|
{ |
412 |
|
✗ |
ret = gate_microservice_webservice_request_ctor(&webrequest, NULL); |
413 |
|
✗ |
GATE_BREAK_IF_FAILED(ret); |
414 |
|
✗ |
ret = gate_microservice_webservice_response_ctor(&webresponse, NULL); |
415 |
|
✗ |
if (GATE_FAILED(ret)) |
416 |
|
|
{ |
417 |
|
✗ |
gate_struct_release(&webrequest.struct_base); |
418 |
|
✗ |
break; |
419 |
|
|
} |
420 |
|
✗ |
ret = gate_microhost_remote_invoke(ptr_service->host, &service_address, &service_method, &webrequest.struct_base, &webresponse.struct_base); |
421 |
|
|
|
422 |
|
✗ |
gate_httpserver_response_set_status(response, 200); |
423 |
|
✗ |
gate_httpserver_response_send_headers(response); |
424 |
|
✗ |
gate_stream_write(response, (char const*)webresponse.content.data, webresponse.content.length, NULL); |
425 |
|
✗ |
gate_stream_flush(response); |
426 |
|
|
|
427 |
|
✗ |
gate_struct_release(&webresponse.struct_base); |
428 |
|
✗ |
gate_struct_release(&webrequest.struct_base); |
429 |
|
|
|
430 |
|
|
} while (0); |
431 |
|
✗ |
gate_string_release(&service_address); |
432 |
|
✗ |
gate_string_release(&service_method); |
433 |
|
|
} |
434 |
|
|
else |
435 |
|
|
{ |
436 |
|
✗ |
ret = GATE_RESULT_FAILED; |
437 |
|
|
} |
438 |
|
✗ |
break; |
439 |
|
|
} |
440 |
|
|
} |
441 |
|
|
|
442 |
|
✗ |
if (GATE_SUCCEEDED(ret)) |
443 |
|
|
{ |
444 |
|
|
/* file-handler has processed the request, we are done */ |
445 |
|
✗ |
break; |
446 |
|
|
} |
447 |
|
|
|
448 |
|
|
} while (0); |
449 |
|
|
|
450 |
|
|
|
451 |
|
|
|
452 |
|
✗ |
if (GATE_FAILED(ret)) |
453 |
|
|
{ |
454 |
|
✗ |
if (!gate_httpserver_response_are_headers_sent(response)) |
455 |
|
|
{ |
456 |
|
✗ |
gate_httpserver_response_set_status(response, ret == GATE_RESULT_NOMATCH ? 404 : 501); |
457 |
|
✗ |
gate_httpserver_response_send_headers(response); |
458 |
|
|
} |
459 |
|
✗ |
gate_stream_flush(response); |
460 |
|
✗ |
ret = GATE_RESULT_OK; |
461 |
|
|
} |
462 |
|
|
|
463 |
|
✗ |
return ret; |
464 |
|
|
} |
465 |
|
|
|
466 |
|
✗ |
static void release_all_file_handler_configs(gate_httpserver_filehandler_config_t* cfgs, gate_size_t* count) |
467 |
|
|
{ |
468 |
|
|
gate_size_t ndx; |
469 |
|
✗ |
for (ndx = 0; ndx != *count; ++ndx) |
470 |
|
|
{ |
471 |
|
✗ |
gate_httpserver_filehandler_config_release(&cfgs[ndx]); |
472 |
|
|
} |
473 |
|
✗ |
*count = 0; |
474 |
|
✗ |
} |
475 |
|
|
|
476 |
|
✗ |
static gate_result_t webserver_on_start(gate_microservice_base_t* self) |
477 |
|
|
{ |
478 |
|
|
static gate_string_t const msg_add_host_failed = GATE_STRING_INIT_STATIC("Failed to add host"); |
479 |
|
|
static gate_string_t const msg_add_host_success = GATE_STRING_INIT_STATIC("Webservice host successfully added"); |
480 |
|
|
static gate_string_t const msg_no_hosts = GATE_STRING_INIT_STATIC("Webservice contains no configured hosts"); |
481 |
|
|
static gate_string_t const msg_http_start_failed = GATE_STRING_INIT_STATIC("Failed to start webservice"); |
482 |
|
|
static gate_string_t const msg_http_start_succeeded = GATE_STRING_INIT_STATIC("Webservice successfully started"); |
483 |
|
✗ |
gate_result_t ret = GATE_RESULT_FAILED; |
484 |
|
✗ |
gate_webserver_data_t* ptr_data = (gate_webserver_data_t*)self->data_ptr; |
485 |
|
✗ |
gate_httpserver_t* server = &ptr_data->server; |
486 |
|
|
gate_httpserver_config_t http_config; |
487 |
|
|
gate_httpserver_host_id_t http_host_id; |
488 |
|
|
gate_size_t ndx; |
489 |
|
|
gate_size_t count; |
490 |
|
|
gate_string_t const* ptr_str; |
491 |
|
|
webserver_config_vdir_t const* ptr_vdir; |
492 |
|
|
webserver_config_webservice_t const* ptr_ws; |
493 |
|
✗ |
gate_size_t hosts_succeeded = 0; |
494 |
|
|
gate_int16_t socket_family; |
495 |
|
|
gate_string_t webservice_endpoint; |
496 |
|
|
|
497 |
|
|
do |
498 |
|
|
{ |
499 |
|
✗ |
gate_microservice_base_set_condition_bits(self, GATE_MICROSERVICE_CONDITION_INITIALIZING); |
500 |
|
|
|
501 |
|
|
/* export parameters from property storage to native config struct */ |
502 |
|
✗ |
gate_property_export(&self->parameters, GATE_TYPE_STRUCT, &ptr_data->config.struct_base); |
503 |
|
|
|
504 |
|
|
// load HTTP server bindings |
505 |
|
✗ |
count = gate_arraylist_length(ptr_data->config.http); |
506 |
|
✗ |
ret = GATE_RESULT_OK; |
507 |
|
✗ |
for (ndx = 0; ndx != count; ++ndx) |
508 |
|
|
{ |
509 |
|
✗ |
ptr_str = (gate_string_t const*)gate_arraylist_get(ptr_data->config.http, ndx); |
510 |
|
|
|
511 |
|
✗ |
gate_httpserver_config_init(&http_config); |
512 |
|
|
|
513 |
|
✗ |
ret = gate_socket_parse_address(ptr_str, &http_config.address, &http_config.port, &socket_family); |
514 |
|
✗ |
GATE_BREAK_IF_FAILED(ret); |
515 |
|
✗ |
http_config.max_connections = 32; |
516 |
|
✗ |
http_config.secure = false; |
517 |
|
|
|
518 |
|
✗ |
ret = gate_httpserver_add_host(server, &http_config, &webserver_on_request, self, &http_host_id); |
519 |
|
✗ |
gate_httpserver_config_destroy(&http_config); |
520 |
|
✗ |
if (GATE_SUCCEEDED(ret)) |
521 |
|
|
{ |
522 |
|
✗ |
gate_microhost_log(self->host, GATE_MICROSERVICE_LOGTYPE_INFO, 0, 0, &self->address, &msg_add_host_success); |
523 |
|
✗ |
++hosts_succeeded; |
524 |
|
|
} |
525 |
|
|
else |
526 |
|
|
{ |
527 |
|
✗ |
gate_microhost_log(self->host, GATE_MICROSERVICE_LOGTYPE_WARNING, ret, 0, &self->address, &msg_add_host_failed); |
528 |
|
|
} |
529 |
|
|
} |
530 |
|
|
|
531 |
|
✗ |
if (hosts_succeeded == 0) |
532 |
|
|
{ |
533 |
|
✗ |
gate_microhost_log(self->host, GATE_MICROSERVICE_LOGTYPE_WARNING, 0, 0, &self->address, &msg_no_hosts); |
534 |
|
|
} |
535 |
|
|
|
536 |
|
|
// load file-services configuration |
537 |
|
✗ |
count = gate_arraylist_length(ptr_data->config.vdirs); |
538 |
|
✗ |
ptr_data->file_handlers_used = 0; |
539 |
|
✗ |
for (ndx = 0; ndx != count; ++ndx) |
540 |
|
|
{ |
541 |
|
✗ |
ptr_vdir = (webserver_config_vdir_t const*)gate_arraylist_get(ptr_data->config.vdirs, ndx); |
542 |
|
✗ |
if (!ptr_vdir) |
543 |
|
|
{ |
544 |
|
✗ |
continue; |
545 |
|
|
} |
546 |
|
|
|
547 |
|
✗ |
ret = gate_httpserver_filehandler_config_init(&ptr_data->file_handlers[ptr_data->file_handlers_used], |
548 |
|
|
&ptr_vdir->webpath, |
549 |
|
|
&ptr_vdir->filepath, |
550 |
|
✗ |
ptr_vdir->webdav); |
551 |
|
✗ |
if (GATE_SUCCEEDED(ret)) |
552 |
|
|
{ |
553 |
|
✗ |
gate_microhost_log(self->host, GATE_MICROSERVICE_LOGTYPE_INFO, 0, 0, &self->address, &ptr_vdir->webpath); |
554 |
|
✗ |
++ptr_data->file_handlers_used; |
555 |
|
|
} |
556 |
|
|
else |
557 |
|
|
{ |
558 |
|
✗ |
gate_microhost_log(self->host, GATE_MICROSERVICE_LOGTYPE_WARNING, ret, 0, &self->address, &ptr_vdir->webpath); |
559 |
|
|
} |
560 |
|
|
} |
561 |
|
|
|
562 |
|
|
// load http-handlers |
563 |
|
|
/* |
564 |
|
|
count = gate_arraylist_length(ptr_data->config.httphandlers); |
565 |
|
|
ptr_data->http_handlers_used = 0; |
566 |
|
|
for(ndx = 0; ndx != count; ++ndx) |
567 |
|
|
{ |
568 |
|
|
webserver_config_httphandler_t const* const ptr_handler = (webserver_config_httphandler_t const*)(ptr_data->config.httphandlers, ndx); |
569 |
|
|
if(!ptr_handler) |
570 |
|
|
{ |
571 |
|
|
continue; |
572 |
|
|
} |
573 |
|
|
|
574 |
|
|
ret |
575 |
|
|
} |
576 |
|
|
*/ |
577 |
|
|
|
578 |
|
✗ |
count = gate_arraylist_length(ptr_data->config.webservices); |
579 |
|
✗ |
ptr_data->service_handlers_used = 0; |
580 |
|
✗ |
for (ndx = 0; ndx != count; ++ndx) |
581 |
|
|
{ |
582 |
|
✗ |
ptr_ws = (webserver_config_webservice_t const*)gate_arraylist_get(ptr_data->config.webservices, ndx); |
583 |
|
✗ |
if (!ptr_ws) |
584 |
|
|
{ |
585 |
|
✗ |
continue; |
586 |
|
|
} |
587 |
|
|
|
588 |
|
✗ |
if (NULL == create_webservice_endpoint(&ptr_ws->service_address, &ptr_ws->service_method, &webservice_endpoint)) |
589 |
|
|
{ |
590 |
|
✗ |
continue; |
591 |
|
|
} |
592 |
|
|
|
593 |
|
✗ |
ret = gate_httpserver_filehandler_config_init( |
594 |
|
✗ |
&ptr_data->service_handlers[ptr_data->service_handlers_used], |
595 |
|
|
&ptr_ws->webpath, |
596 |
|
|
&webservice_endpoint, |
597 |
|
|
false); |
598 |
|
✗ |
if (GATE_SUCCEEDED(ret)) |
599 |
|
|
{ |
600 |
|
✗ |
++ptr_data->service_handlers_used; |
601 |
|
|
} |
602 |
|
|
|
603 |
|
✗ |
gate_string_release(&webservice_endpoint); |
604 |
|
|
} |
605 |
|
|
|
606 |
|
✗ |
ret = gate_httpserver_start(server); |
607 |
|
✗ |
if (GATE_SUCCEEDED(ret)) |
608 |
|
|
{ |
609 |
|
✗ |
gate_microhost_log(self->host, GATE_MICROSERVICE_LOGTYPE_INFO, ret, 0, &self->address, &msg_http_start_succeeded); |
610 |
|
✗ |
count = gate_arraylist_length(ptr_data->config.http); |
611 |
|
✗ |
gate_microservice_base_set_condition_bits(self, (count == hosts_succeeded) |
612 |
|
|
? GATE_MICROSERVICE_CONDITION_FULL_OPERATIONAL |
613 |
|
|
: GATE_MICROSERVICE_CONDITION_PARTIAL_OPERATIONAL |
614 |
|
|
); |
615 |
|
|
} |
616 |
|
|
else |
617 |
|
|
{ |
618 |
|
✗ |
gate_microhost_log(self->host, GATE_MICROSERVICE_LOGTYPE_ERROR, ret, 0, &self->address, &msg_http_start_failed); |
619 |
|
✗ |
gate_microservice_base_set_condition_bits(self, GATE_MICROSERVICE_CONDITION_INIT_ERROR); |
620 |
|
|
} |
621 |
|
✗ |
GATE_BREAK_IF_FAILED(ret); |
622 |
|
|
} while (0); |
623 |
|
|
|
624 |
|
✗ |
gate_microservice_base_clear_condition_bits(self, GATE_MICROSERVICE_CONDITION_INITIALIZING); |
625 |
|
|
|
626 |
|
|
|
627 |
|
✗ |
if (GATE_FAILED(ret)) |
628 |
|
|
{ |
629 |
|
✗ |
release_all_file_handler_configs(&ptr_data->file_handlers[0], &ptr_data->file_handlers_used); |
630 |
|
|
} |
631 |
|
|
|
632 |
|
✗ |
return ret; |
633 |
|
|
} |
634 |
|
✗ |
static gate_result_t webserver_on_stop(gate_microservice_base_t* self) |
635 |
|
|
{ |
636 |
|
✗ |
gate_result_t ret = GATE_RESULT_OK; |
637 |
|
✗ |
gate_webserver_data_t* webserver_data = (gate_webserver_data_t*)self->data_ptr; |
638 |
|
|
do |
639 |
|
|
{ |
640 |
|
✗ |
gate_httpserver_remove_all_hosts(&webserver_data->server); |
641 |
|
✗ |
gate_httpserver_stop(&webserver_data->server); |
642 |
|
✗ |
release_all_file_handler_configs(&webserver_data->file_handlers[0], &webserver_data->file_handlers_used); |
643 |
|
✗ |
release_all_file_handler_configs(&webserver_data->service_handlers[0], &webserver_data->service_handlers_used); |
644 |
|
|
} while (0); |
645 |
|
✗ |
return ret; |
646 |
|
|
} |
647 |
|
|
|
648 |
|
✗ |
static void webserver_on_release(gate_microservice_base_t* self) |
649 |
|
|
{ |
650 |
|
✗ |
gate_webserver_data_t* ptr_data = (gate_webserver_data_t*)self->data_ptr; |
651 |
|
|
|
652 |
|
✗ |
webserver_on_stop(self); |
653 |
|
|
|
654 |
|
✗ |
gate_httpserver_destroy(&ptr_data->server); |
655 |
|
✗ |
gate_struct_release(&ptr_data->config.struct_base); |
656 |
|
✗ |
} |
657 |
|
|
|
658 |
|
✗ |
static gate_result_t webserver_on_message_received(gate_microservice_base_t* self, |
659 |
|
|
gate_string_t const* source, gate_string_t const* destination, |
660 |
|
|
gate_string_t const* msg_id, gate_string_t const* message) |
661 |
|
|
{ |
662 |
|
✗ |
gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED; |
663 |
|
|
GATE_UNUSED_ARG(self); |
664 |
|
|
GATE_UNUSED_ARG(source); |
665 |
|
|
GATE_UNUSED_ARG(destination); |
666 |
|
|
GATE_UNUSED_ARG(msg_id); |
667 |
|
|
GATE_UNUSED_ARG(message); |
668 |
|
✗ |
return ret; |
669 |
|
|
} |
670 |
|
✗ |
static gate_result_t webserver_on_object_received(gate_microservice_base_t* self, |
671 |
|
|
gate_string_t const* source, gate_string_t const* destination, |
672 |
|
|
gate_string_t const* obj_id, gate_object_t* obj) |
673 |
|
|
{ |
674 |
|
✗ |
gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED; |
675 |
|
|
GATE_UNUSED_ARG(self); |
676 |
|
|
GATE_UNUSED_ARG(source); |
677 |
|
|
GATE_UNUSED_ARG(destination); |
678 |
|
|
GATE_UNUSED_ARG(obj_id); |
679 |
|
|
GATE_UNUSED_ARG(obj); |
680 |
|
✗ |
return ret; |
681 |
|
|
} |
682 |
|
✗ |
static gate_result_t webserver_on_invoke(gate_microservice_base_t* self, gate_string_t const* method, |
683 |
|
|
gate_struct_t const* request, gate_struct_t* response) |
684 |
|
|
{ |
685 |
|
✗ |
gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED; |
686 |
|
|
GATE_UNUSED_ARG(self); |
687 |
|
|
GATE_UNUSED_ARG(method); |
688 |
|
|
GATE_UNUSED_ARG(request); |
689 |
|
|
GATE_UNUSED_ARG(response); |
690 |
|
✗ |
return ret; |
691 |
|
|
} |
692 |
|
|
|
693 |
|
✗ |
gate_microservice_t* gate_microservice_webserver_create() |
694 |
|
|
{ |
695 |
|
✗ |
gate_microservice_t* ret = NULL; |
696 |
|
✗ |
gate_microservice_base_t* webserver_service = NULL; |
697 |
|
✗ |
gate_webserver_data_t* webserver_data = NULL; |
698 |
|
|
gate_result_t result; |
699 |
|
|
|
700 |
|
|
do |
701 |
|
|
{ |
702 |
|
✗ |
webserver_service = gate_microservice_base_create(sizeof(gate_webserver_data_t), NULL); |
703 |
|
✗ |
if (NULL == webserver_service) |
704 |
|
|
{ |
705 |
|
✗ |
break; |
706 |
|
|
} |
707 |
|
|
|
708 |
|
✗ |
webserver_service->on_release = &webserver_on_release; |
709 |
|
✗ |
webserver_service->on_start = &webserver_on_start; |
710 |
|
✗ |
webserver_service->on_stop = &webserver_on_stop; |
711 |
|
✗ |
webserver_service->on_message_received = &webserver_on_message_received; |
712 |
|
✗ |
webserver_service->on_object_received = &webserver_on_object_received; |
713 |
|
✗ |
webserver_service->on_invoke = &webserver_on_invoke; |
714 |
|
|
|
715 |
|
|
/* init webserver internal data */ |
716 |
|
✗ |
webserver_data = (gate_webserver_data_t*)webserver_service->data_ptr; |
717 |
|
|
|
718 |
|
✗ |
webserver_config_ctor(&webserver_data->config.struct_base, NULL); |
719 |
|
|
|
720 |
|
✗ |
gate_property_create_object(&webserver_service->parameters); |
721 |
|
✗ |
gate_property_import(&webserver_service->parameters, GATE_TYPE_STRUCT, &webserver_data->config.struct_base); |
722 |
|
✗ |
webserver_service->ptr_parameters = &webserver_data->config.struct_base; |
723 |
|
|
|
724 |
|
✗ |
result = gate_httpserver_create(&webserver_data->server); |
725 |
|
✗ |
GATE_BREAK_IF_FAILED(result); |
726 |
|
|
|
727 |
|
✗ |
ret = (gate_microservice_t*)webserver_service; |
728 |
|
✗ |
webserver_service = NULL; |
729 |
|
|
|
730 |
|
|
} while (0); |
731 |
|
|
|
732 |
|
✗ |
if (webserver_service != NULL) |
733 |
|
|
{ |
734 |
|
✗ |
gate_object_release(webserver_service); |
735 |
|
|
} |
736 |
|
✗ |
return ret; |
737 |
|
|
} |
738 |
|
|
|
739 |
|
|
|