/* This file is part of GNUnet. Copyright (C) 2012-2018 GNUnet e.V. GNUnet is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . SPDX-License-Identifier: AGPL3.0-or-later */ /** * @author Martin Schanzenbach * @file gns/plugin_rest_config.c * @brief REST plugin for configuration * */ #include "platform.h" #include "gnunet_rest_plugin.h" #include #include #include #define GNUNET_REST_API_NS_CONFIG "/config" /** * @brief struct returned by the initialization function of the plugin */ struct Plugin { const struct GNUNET_CONFIGURATION_Handle *cfg; }; const struct GNUNET_CONFIGURATION_Handle *cfg; struct RequestHandle { /** * DLL */ struct RequestHandle *next; /** * DLL */ struct RequestHandle *prev; /** * Handle to rest request */ struct GNUNET_REST_RequestHandle *rest_handle; /** * The plugin result processor */ GNUNET_REST_ResultProcessor proc; /** * The closure of the result processor */ void *proc_cls; /** * HTTP response code */ int response_code; /** * The URL */ char *url; }; /** * DLL */ static struct RequestHandle *requests_head; /** * DLL */ static struct RequestHandle *requests_tail; /** * Cleanup request handle. * * @param handle Handle to clean up */ static void cleanup_handle (struct RequestHandle *handle) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n"); if (NULL != handle->url) GNUNET_free (handle->url); GNUNET_CONTAINER_DLL_remove (requests_head, requests_tail, handle); GNUNET_free (handle); } /** * Task run on shutdown. Cleans up everything. * * @param cls unused * @param tc scheduler context */ static void do_error (void *cls) { struct RequestHandle *handle = cls; struct MHD_Response *resp; resp = GNUNET_REST_create_response (NULL); handle->proc (handle->proc_cls, resp, handle->response_code); cleanup_handle (handle); } static void add_sections (void *cls, const char *section, const char *option, const char *value) { json_t *sections_obj = cls; json_t *sec_obj; sec_obj = json_object_get (sections_obj, section); if (NULL != sec_obj) { json_object_set_new (sec_obj, option, json_string (value)); return; } sec_obj = json_object (); json_object_set_new (sec_obj, option, json_string (value)); json_object_set_new (sections_obj, section, sec_obj); } static void add_section_contents (void *cls, const char *section, const char *option, const char *value) { json_t *section_obj = cls; json_object_set_new (section_obj, option, json_string (value)); } /** * Handle rest request * * @param handle the lookup handle */ static void get_cont (struct GNUNET_REST_RequestHandle *con_handle, const char *url, void *cls) { struct MHD_Response *resp; struct RequestHandle *handle = cls; const char *section; char *response; json_t *result; if (strlen (GNUNET_REST_API_NS_CONFIG) > strlen (handle->url)) { handle->response_code = MHD_HTTP_BAD_REQUEST; GNUNET_SCHEDULER_add_now (&do_error, handle); return; } if (strlen (GNUNET_REST_API_NS_CONFIG) == strlen (handle->url)) { result = json_object (); GNUNET_CONFIGURATION_iterate (cfg, &add_sections, result); } else { result = json_object (); section = &handle->url[strlen (GNUNET_REST_API_NS_CONFIG) + 1]; GNUNET_CONFIGURATION_iterate_section_values (cfg, section, &add_section_contents, result); } response = json_dumps (result, 0); resp = GNUNET_REST_create_response (response); MHD_add_response_header (resp, "Content-Type", "application/json"); handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); cleanup_handle (handle); GNUNET_free (response); json_decref (result); } struct GNUNET_CONFIGURATION_Handle * set_value (struct GNUNET_CONFIGURATION_Handle *config, const char *section, const char *option, json_t *value) { if (json_is_string (value)) GNUNET_CONFIGURATION_set_value_string (config, section, option, json_string_value (value)); else if (json_is_number (value)) GNUNET_CONFIGURATION_set_value_number (config, section, option, json_integer_value (value)); else if (json_is_null (value)) GNUNET_CONFIGURATION_set_value_string (config, section, option, NULL); else if (json_is_true (value)) GNUNET_CONFIGURATION_set_value_string (config, section, option, "yes"); else if (json_is_false (value)) GNUNET_CONFIGURATION_set_value_string (config, section, option, "no"); else return NULL; return config; // for error handling (0 -> success, 1 -> error) } /** * Handle REST POST request * * @param handle the lookup handle */ static void set_cont (struct GNUNET_REST_RequestHandle *con_handle, const char *url, void *cls) { struct RequestHandle *handle = cls; char term_data[handle->rest_handle->data_size + 1]; struct GNUNET_CONFIGURATION_Handle *out = GNUNET_CONFIGURATION_dup (cfg); json_error_t err; json_t *data_json; const char *section; const char *option; json_t *sec_obj; json_t *value; char *cfg_fn; // invalid url if (strlen (GNUNET_REST_API_NS_CONFIG) > strlen (handle->url)) { handle->response_code = MHD_HTTP_BAD_REQUEST; GNUNET_SCHEDULER_add_now (&do_error, handle); return; } // extract data from handle term_data[handle->rest_handle->data_size] = '\0'; GNUNET_memcpy (term_data, handle->rest_handle->data, handle->rest_handle->data_size); data_json = json_loads (term_data, JSON_DECODE_ANY, &err); if (NULL == data_json) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unable to parse JSON Object from %s\n", term_data); GNUNET_SCHEDULER_add_now (&do_error, handle); return; } // POST /config => {
: {