From 91d4ce9f14668a5a04b51158b1921e83d51ba9a0 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Thu, 22 Jul 2021 10:12:58 +0200 Subject: initial codebase --- serve.c | 203 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 203 insertions(+) create mode 100644 serve.c (limited to 'serve.c') diff --git a/serve.c b/serve.c new file mode 100644 index 0000000..dd61da1 --- /dev/null +++ b/serve.c @@ -0,0 +1,203 @@ +/** + * part of Hydrilla + * Serving data queries over HTTP using libmicrohttpd. + * + * Copyright (C) 2021 Wojtek Kosior + * Redistribution terms are gathered in the `copyright' file. + * + * This file is based on Christian Grothoff's public comain code from + * `doc/examples/logging.c' in libmicrohttpd source tree. + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "scriptbase.h" + +#define PORT 10111 + +#define ARRLEN(array) (sizeof(array) / sizeof(*array)) + +static struct MHD_Response *default_response, *error_response, + *not_found_response; + +static struct { + struct MHD_Response **response; + const char *const text; +} static_responses[] = { + {&default_response, "Nothing to see here"}, + {&error_response, "Error occured"}, + {¬_found_response, "Not found"} +}; + +static int add_CORS_header(struct MHD_Response *response) +{ + return -1 * (MHD_add_response_header(response, + "Access-Control-Allow-Origin", + "*") == MHD_NO); +} + +typedef char *(*request_handler_t)(const char *queried, + struct scriptbase *base); + +static struct { + const char *path; + request_handler_t request_handler; +} resources[] = { + {"/script", get_script_json}, + {"/bag", get_bag_json}, + {"/pattern", get_pattern_json}, + {"/query", get_page_query_json} +}; + +struct request_handling { + struct scriptbase *base; + request_handler_t handler; + char *json_response; + int error_number; +}; + +static int handle_query_argument(void *cls, enum MHD_ValueKind kind, + const char *key, const char *value) +{ + struct request_handling *handling = cls; + + if (strcmp(key, "n")) { + fprintf(stderr, "Unknown argument: \"%s\" = \"%s\"\n", + key, value); + return MHD_YES; + } + + errno = 0; + + handling->json_response = handling->handler(value, handling->base); + + handling->error_number = errno; + + return MHD_NO; +} + +static int answer_with(struct MHD_Connection *connection, + request_handler_t handler, struct scriptbase *base) +{ + struct request_handling handling = {base, handler, NULL, EINVAL}; + struct MHD_Response *response; + int retval; + + MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND, + handle_query_argument, &handling); + + if (!handling.json_response) { + if (handling.error_number) + goto send_error; + goto send_not_found; + } + + response = MHD_create_response_from_buffer + (strlen(handling.json_response), handling.json_response, + MHD_RESPMEM_MUST_FREE); + if (!response || add_CORS_header(response)) + goto send_error; + + retval = MHD_queue_response(connection, MHD_HTTP_OK, response); + MHD_destroy_response(response); + + return retval; + +send_not_found: + return MHD_queue_response(connection, MHD_HTTP_NOT_FOUND, + not_found_response); + +send_error: + free(handling.json_response); + return MHD_queue_response(connection, MHD_HTTP_INTERNAL_SERVER_ERROR, + error_response); +} + +static int answer(void *data, + struct MHD_Connection *connection, + const char *url, + const char *method, + const char *version, + const char *upload_data, + size_t *upload_data_size, + void **ptr) +{ + static int aptr; + int i; + struct scriptbase *base = data; + + printf("New %s request for %s using version %s\n", method, url, version); + + if (strcmp(method, "GET")) + return MHD_NO; + + if (&aptr != *ptr) { + /* do never respond on first call */ + *ptr = &aptr; + return MHD_YES; + } + *ptr = NULL; /* reset when done */ + + for (i = 0; i < ARRLEN(resources); i++) { + if (strcmp(resources[i].path, url)) + continue; + + return answer_with(connection, resources[i].request_handler, + base); + } + + return MHD_queue_response(connection, MHD_HTTP_OK, default_response); +} + +int getchar(void); + +int serve_scriptbase(struct scriptbase *base) +{ + int i; + struct MHD_Daemon *daemon; + int retval = -1; + + if (init_url_lookup_regex()) + return -1; + + for (i = 0; i < ARRLEN(static_responses); i++) { + *static_responses[i].response = MHD_create_response_from_buffer + (strlen(static_responses[i].text), + (char*) static_responses[i].text, + MHD_RESPMEM_PERSISTENT); + + if (!*static_responses[i].response || + add_CORS_header(*static_responses[i].response)) + goto free_resources; + } + + daemon = MHD_start_daemon(MHD_USE_INTERNAL_POLLING_THREAD, PORT, NULL, + NULL, &answer, (void*) base, MHD_OPTION_END); + if (!daemon) + goto free_resources; + + getchar(); + MHD_stop_daemon(daemon); + + retval = 0; + +free_resources: + for (i = 0; i < ARRLEN(static_responses); i++) { + if (*static_responses[i].response) + MHD_destroy_response(*static_responses[i].response); + *static_responses[i].response = NULL; + } + + destroy_url_lookup_regex(); + + return retval; +} -- cgit v1.2.3