| 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; | ||
| 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 | ✗ | GATE_BREAK_IF_FAILED(ret); | |
| 531 | |||
| 532 | ✗ | if (hosts_succeeded == 0) | |
| 533 | { | ||
| 534 | ✗ | gate_microhost_log(self->host, GATE_MICROSERVICE_LOGTYPE_WARNING, 0, 0, &self->address, &msg_no_hosts); | |
| 535 | } | ||
| 536 | |||
| 537 | // load file-services configuration | ||
| 538 | ✗ | count = gate_arraylist_length(ptr_data->config.vdirs); | |
| 539 | ✗ | ptr_data->file_handlers_used = 0; | |
| 540 | ✗ | for (ndx = 0; ndx != count; ++ndx) | |
| 541 | { | ||
| 542 | ✗ | ptr_vdir = (webserver_config_vdir_t const*)gate_arraylist_get(ptr_data->config.vdirs, ndx); | |
| 543 | ✗ | if (!ptr_vdir) | |
| 544 | { | ||
| 545 | ✗ | continue; | |
| 546 | } | ||
| 547 | |||
| 548 | ✗ | ret = gate_httpserver_filehandler_config_init(&ptr_data->file_handlers[ptr_data->file_handlers_used], | |
| 549 | &ptr_vdir->webpath, | ||
| 550 | &ptr_vdir->filepath, | ||
| 551 | ✗ | ptr_vdir->webdav); | |
| 552 | ✗ | if (GATE_SUCCEEDED(ret)) | |
| 553 | { | ||
| 554 | ✗ | gate_microhost_log(self->host, GATE_MICROSERVICE_LOGTYPE_INFO, 0, 0, &self->address, &ptr_vdir->webpath); | |
| 555 | ✗ | ++ptr_data->file_handlers_used; | |
| 556 | } | ||
| 557 | else | ||
| 558 | { | ||
| 559 | ✗ | gate_microhost_log(self->host, GATE_MICROSERVICE_LOGTYPE_WARNING, ret, 0, &self->address, &ptr_vdir->webpath); | |
| 560 | } | ||
| 561 | } | ||
| 562 | |||
| 563 | // load http-handlers | ||
| 564 | /* | ||
| 565 | count = gate_arraylist_length(ptr_data->config.httphandlers); | ||
| 566 | ptr_data->http_handlers_used = 0; | ||
| 567 | for(ndx = 0; ndx != count; ++ndx) | ||
| 568 | { | ||
| 569 | webserver_config_httphandler_t const* const ptr_handler = (webserver_config_httphandler_t const*)(ptr_data->config.httphandlers, ndx); | ||
| 570 | if(!ptr_handler) | ||
| 571 | { | ||
| 572 | continue; | ||
| 573 | } | ||
| 574 | |||
| 575 | ret | ||
| 576 | } | ||
| 577 | */ | ||
| 578 | |||
| 579 | ✗ | count = gate_arraylist_length(ptr_data->config.webservices); | |
| 580 | ✗ | ptr_data->service_handlers_used = 0; | |
| 581 | ✗ | for (ndx = 0; ndx != count; ++ndx) | |
| 582 | { | ||
| 583 | ✗ | ptr_ws = (webserver_config_webservice_t const*)gate_arraylist_get(ptr_data->config.webservices, ndx); | |
| 584 | ✗ | if (!ptr_ws) | |
| 585 | { | ||
| 586 | ✗ | continue; | |
| 587 | } | ||
| 588 | |||
| 589 | ✗ | if (NULL == create_webservice_endpoint(&ptr_ws->service_address, &ptr_ws->service_method, &webservice_endpoint)) | |
| 590 | { | ||
| 591 | ✗ | continue; | |
| 592 | } | ||
| 593 | |||
| 594 | ✗ | ret = gate_httpserver_filehandler_config_init( | |
| 595 | ✗ | &ptr_data->service_handlers[ptr_data->service_handlers_used], | |
| 596 | &ptr_ws->webpath, | ||
| 597 | &webservice_endpoint, | ||
| 598 | false); | ||
| 599 | ✗ | if (GATE_SUCCEEDED(ret)) | |
| 600 | { | ||
| 601 | ✗ | ++ptr_data->service_handlers_used; | |
| 602 | } | ||
| 603 | |||
| 604 | ✗ | gate_string_release(&webservice_endpoint); | |
| 605 | } | ||
| 606 | |||
| 607 | ✗ | ret = gate_httpserver_start(server); | |
| 608 | ✗ | if (GATE_SUCCEEDED(ret)) | |
| 609 | { | ||
| 610 | ✗ | gate_microhost_log(self->host, GATE_MICROSERVICE_LOGTYPE_INFO, ret, 0, &self->address, &msg_http_start_succeeded); | |
| 611 | ✗ | count = gate_arraylist_length(ptr_data->config.http); | |
| 612 | ✗ | gate_microservice_base_set_condition_bits(self, (count == hosts_succeeded) | |
| 613 | ? GATE_MICROSERVICE_CONDITION_FULL_OPERATIONAL | ||
| 614 | : GATE_MICROSERVICE_CONDITION_PARTIAL_OPERATIONAL | ||
| 615 | ); | ||
| 616 | } | ||
| 617 | else | ||
| 618 | { | ||
| 619 | ✗ | gate_microhost_log(self->host, GATE_MICROSERVICE_LOGTYPE_ERROR, ret, 0, &self->address, &msg_http_start_failed); | |
| 620 | ✗ | gate_microservice_base_set_condition_bits(self, GATE_MICROSERVICE_CONDITION_INIT_ERROR); | |
| 621 | } | ||
| 622 | ✗ | GATE_BREAK_IF_FAILED(ret); | |
| 623 | } while (0); | ||
| 624 | |||
| 625 | ✗ | gate_microservice_base_clear_condition_bits(self, GATE_MICROSERVICE_CONDITION_INITIALIZING); | |
| 626 | |||
| 627 | |||
| 628 | ✗ | if (GATE_FAILED(ret)) | |
| 629 | { | ||
| 630 | ✗ | release_all_file_handler_configs(&ptr_data->file_handlers[0], &ptr_data->file_handlers_used); | |
| 631 | } | ||
| 632 | |||
| 633 | ✗ | return ret; | |
| 634 | } | ||
| 635 | ✗ | static gate_result_t webserver_on_stop(gate_microservice_base_t* self) | |
| 636 | { | ||
| 637 | ✗ | gate_result_t ret = GATE_RESULT_OK; | |
| 638 | ✗ | gate_webserver_data_t* webserver_data = (gate_webserver_data_t*)self->data_ptr; | |
| 639 | do | ||
| 640 | { | ||
| 641 | ✗ | gate_httpserver_remove_all_hosts(&webserver_data->server); | |
| 642 | ✗ | gate_httpserver_stop(&webserver_data->server); | |
| 643 | ✗ | release_all_file_handler_configs(&webserver_data->file_handlers[0], &webserver_data->file_handlers_used); | |
| 644 | ✗ | release_all_file_handler_configs(&webserver_data->service_handlers[0], &webserver_data->service_handlers_used); | |
| 645 | } while (0); | ||
| 646 | ✗ | return ret; | |
| 647 | } | ||
| 648 | |||
| 649 | ✗ | static void webserver_on_release(gate_microservice_base_t* self) | |
| 650 | { | ||
| 651 | ✗ | gate_webserver_data_t* ptr_data = (gate_webserver_data_t*)self->data_ptr; | |
| 652 | |||
| 653 | ✗ | webserver_on_stop(self); | |
| 654 | |||
| 655 | ✗ | gate_httpserver_destroy(&ptr_data->server); | |
| 656 | ✗ | gate_struct_release(&ptr_data->config.struct_base); | |
| 657 | ✗ | } | |
| 658 | |||
| 659 | ✗ | static gate_result_t webserver_on_message_received(gate_microservice_base_t* self, | |
| 660 | gate_string_t const* source, gate_string_t const* destination, | ||
| 661 | gate_string_t const* msg_id, gate_string_t const* message) | ||
| 662 | { | ||
| 663 | ✗ | gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED; | |
| 664 | GATE_UNUSED_ARG(self); | ||
| 665 | GATE_UNUSED_ARG(source); | ||
| 666 | GATE_UNUSED_ARG(destination); | ||
| 667 | GATE_UNUSED_ARG(msg_id); | ||
| 668 | GATE_UNUSED_ARG(message); | ||
| 669 | ✗ | return ret; | |
| 670 | } | ||
| 671 | ✗ | static gate_result_t webserver_on_object_received(gate_microservice_base_t* self, | |
| 672 | gate_string_t const* source, gate_string_t const* destination, | ||
| 673 | gate_string_t const* obj_id, gate_object_t* obj) | ||
| 674 | { | ||
| 675 | ✗ | gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED; | |
| 676 | GATE_UNUSED_ARG(self); | ||
| 677 | GATE_UNUSED_ARG(source); | ||
| 678 | GATE_UNUSED_ARG(destination); | ||
| 679 | GATE_UNUSED_ARG(obj_id); | ||
| 680 | GATE_UNUSED_ARG(obj); | ||
| 681 | ✗ | return ret; | |
| 682 | } | ||
| 683 | ✗ | static gate_result_t webserver_on_invoke(gate_microservice_base_t* self, gate_string_t const* method, | |
| 684 | gate_struct_t const* request, gate_struct_t* response) | ||
| 685 | { | ||
| 686 | ✗ | gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED; | |
| 687 | GATE_UNUSED_ARG(self); | ||
| 688 | GATE_UNUSED_ARG(method); | ||
| 689 | GATE_UNUSED_ARG(request); | ||
| 690 | GATE_UNUSED_ARG(response); | ||
| 691 | ✗ | return ret; | |
| 692 | } | ||
| 693 | |||
| 694 | ✗ | gate_microservice_t* gate_microservice_webserver_create(void) | |
| 695 | { | ||
| 696 | ✗ | gate_microservice_t* ret = NULL; | |
| 697 | ✗ | gate_microservice_base_t* webserver_service = NULL; | |
| 698 | ✗ | gate_webserver_data_t* webserver_data = NULL; | |
| 699 | gate_result_t result; | ||
| 700 | |||
| 701 | do | ||
| 702 | { | ||
| 703 | ✗ | webserver_service = gate_microservice_base_create(sizeof(gate_webserver_data_t), NULL); | |
| 704 | ✗ | if (NULL == webserver_service) | |
| 705 | { | ||
| 706 | ✗ | break; | |
| 707 | } | ||
| 708 | |||
| 709 | ✗ | webserver_service->on_release = &webserver_on_release; | |
| 710 | ✗ | webserver_service->on_start = &webserver_on_start; | |
| 711 | ✗ | webserver_service->on_stop = &webserver_on_stop; | |
| 712 | ✗ | webserver_service->on_message_received = &webserver_on_message_received; | |
| 713 | ✗ | webserver_service->on_object_received = &webserver_on_object_received; | |
| 714 | ✗ | webserver_service->on_invoke = &webserver_on_invoke; | |
| 715 | |||
| 716 | /* init webserver internal data */ | ||
| 717 | ✗ | webserver_data = (gate_webserver_data_t*)webserver_service->data_ptr; | |
| 718 | |||
| 719 | ✗ | webserver_config_ctor(&webserver_data->config.struct_base, NULL); | |
| 720 | |||
| 721 | ✗ | gate_property_create_object(&webserver_service->parameters); | |
| 722 | ✗ | gate_property_import(&webserver_service->parameters, GATE_TYPE_STRUCT, &webserver_data->config.struct_base); | |
| 723 | ✗ | webserver_service->ptr_parameters = &webserver_data->config.struct_base; | |
| 724 | |||
| 725 | ✗ | result = gate_httpserver_create(&webserver_data->server); | |
| 726 | ✗ | GATE_BREAK_IF_FAILED(result); | |
| 727 | |||
| 728 | ✗ | ret = (gate_microservice_t*)webserver_service; | |
| 729 | ✗ | webserver_service = NULL; | |
| 730 | |||
| 731 | } while (0); | ||
| 732 | |||
| 733 | ✗ | if (webserver_service != NULL) | |
| 734 | { | ||
| 735 | ✗ | gate_object_release(webserver_service); | |
| 736 | } | ||
| 737 | ✗ | return ret; | |
| 738 | } | ||
| 739 | |||
| 740 |