2 This file is part of GNUnet.
3 Copyright (C) 2012-2018 GNUnet e.V.
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
21 * @author Martin Schanzenbach
22 * @file gns/plugin_rest_config.c
23 * @brief REST plugin for configuration
28 #include "gnunet_rest_plugin.h"
29 #include <gnunet_rest_lib.h>
30 #include <gnunet_util_lib.h>
33 #define GNUNET_REST_API_NS_CONFIG "/config"
36 * @brief struct returned by the initialization function of the plugin
40 const struct GNUNET_CONFIGURATION_Handle *cfg;
43 const struct GNUNET_CONFIGURATION_Handle *cfg;
48 * Handle to rest request
50 struct GNUNET_REST_RequestHandle *rest_handle;
53 * The plugin result processor
55 GNUNET_REST_ResultProcessor proc;
58 * The closure of the result processor
75 * Cleanup request handle.
77 * @param handle Handle to clean up
80 cleanup_handle (struct RequestHandle *handle)
82 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
83 if (NULL != handle->url)
84 GNUNET_free (handle->url);
90 * Task run on shutdown. Cleans up everything.
93 * @param tc scheduler context
98 struct RequestHandle *handle = cls;
99 struct MHD_Response *resp;
101 resp = GNUNET_REST_create_response (NULL);
102 handle->proc (handle->proc_cls, resp, handle->response_code);
103 cleanup_handle (handle);
108 add_sections (void *cls,
113 json_t *sections_obj = cls;
116 sec_obj = json_object_get (sections_obj, section);
119 json_object_set_new (sec_obj, option, json_string (value));
122 sec_obj = json_object ();
123 json_object_set_new (sec_obj, option, json_string (value));
124 json_object_set_new (sections_obj, section, sec_obj);
129 add_section_contents (void *cls,
134 json_t *section_obj = cls;
136 json_object_set_new (section_obj, option, json_string (value));
141 * Handle rest request
143 * @param handle the lookup handle
146 get_cont (struct GNUNET_REST_RequestHandle *con_handle,
150 struct MHD_Response *resp;
151 struct RequestHandle *handle = cls;
156 if (strlen (GNUNET_REST_API_NS_CONFIG) > strlen (handle->url))
158 handle->response_code = MHD_HTTP_BAD_REQUEST;
159 GNUNET_SCHEDULER_add_now (&do_error, handle);
162 if (strlen (GNUNET_REST_API_NS_CONFIG) == strlen (handle->url))
164 result = json_object ();
165 GNUNET_CONFIGURATION_iterate (cfg, &add_sections, result);
169 result = json_object ();
170 section = &handle->url[strlen (GNUNET_REST_API_NS_CONFIG) + 1];
171 GNUNET_CONFIGURATION_iterate_section_values (cfg,
173 &add_section_contents,
176 response = json_dumps (result, 0);
177 resp = GNUNET_REST_create_response (response);
178 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
179 cleanup_handle (handle);
180 GNUNET_free (response);
181 json_decref (result);
185 struct GNUNET_CONFIGURATION_Handle *
186 set_value (struct GNUNET_CONFIGURATION_Handle *config,
191 if (json_is_string (value))
192 GNUNET_CONFIGURATION_set_value_string (config, section, option,
193 json_string_value (value));
194 else if (json_is_number (value))
195 GNUNET_CONFIGURATION_set_value_number (config, section, option,
196 json_integer_value (value));
197 else if (json_is_null (value))
198 GNUNET_CONFIGURATION_set_value_string (config, section, option, NULL);
199 else if (json_is_true (value))
200 GNUNET_CONFIGURATION_set_value_string (config, section, option, "yes");
201 else if (json_is_false (value))
202 GNUNET_CONFIGURATION_set_value_string (config, section, option, "no");
205 return config; // for error handling (0 -> success, 1 -> error)
210 * Handle REST POST request
212 * @param handle the lookup handle
215 set_cont (struct GNUNET_REST_RequestHandle *con_handle,
219 struct RequestHandle *handle = cls;
220 char term_data[handle->rest_handle->data_size + 1];
221 struct GNUNET_CONFIGURATION_Handle *out = GNUNET_CONFIGURATION_dup (cfg);
232 if (strlen (GNUNET_REST_API_NS_CONFIG) > strlen (handle->url))
234 handle->response_code = MHD_HTTP_BAD_REQUEST;
235 GNUNET_SCHEDULER_add_now (&do_error, handle);
239 // extract data from handle
240 term_data[handle->rest_handle->data_size] = '\0';
241 GNUNET_memcpy (term_data,
242 handle->rest_handle->data,
243 handle->rest_handle->data_size);
244 data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
246 if (NULL == data_json)
248 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
249 "Unable to parse JSON Object from %s\n",
251 GNUNET_SCHEDULER_add_now (&do_error, handle);
255 // POST /config => {<section> : {<option> : <value>}}
256 if (strlen (GNUNET_REST_API_NS_CONFIG) == strlen (handle->url)) // POST /config
258 // iterate over sections
259 json_object_foreach (data_json, section, sec_obj)
261 // iterate over options
262 json_object_foreach (sec_obj, option, value)
264 out = set_value (out, section, option, value);
267 handle->response_code = MHD_HTTP_BAD_REQUEST;
268 GNUNET_SCHEDULER_add_now (&do_error, handle);
269 json_decref (data_json);
275 else // POST /config/<section> => {<option> : <value>}
277 // extract the "<section>" part from the url
278 section = &handle->url[strlen (GNUNET_REST_API_NS_CONFIG) + 1];
279 // iterate over options
280 json_object_foreach (data_json, option, value)
282 out = set_value (out, section, option, value);
285 handle->response_code = MHD_HTTP_BAD_REQUEST;
286 GNUNET_SCHEDULER_add_now (&do_error, handle);
287 json_decref (data_json);
292 json_decref (data_json);
297 const char *xdg = getenv ("XDG_CONFIG_HOME");
299 GNUNET_asprintf (&cfg_fn,
303 GNUNET_OS_project_data_get ()->config_file);
305 cfg_fn = GNUNET_strdup (GNUNET_OS_project_data_get ()->user_config_file);
307 GNUNET_CONFIGURATION_write (out, cfg_fn);
309 handle->proc (handle->proc_cls,
310 GNUNET_REST_create_response (NULL),
312 cleanup_handle (handle);
317 * Handle rest request
319 * @param handle the lookup handle
322 options_cont (struct GNUNET_REST_RequestHandle *con_handle,
326 struct MHD_Response *resp;
327 struct RequestHandle *handle = cls;
329 resp = GNUNET_REST_create_response (NULL);
330 MHD_add_response_header (resp,
331 "Access-Control-Allow-Methods",
332 MHD_HTTP_METHOD_GET);
333 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
334 cleanup_handle (handle);
339 * Function processing the REST call
341 * @param method HTTP method
342 * @param url URL of the HTTP request
343 * @param data body of the HTTP request (optional)
344 * @param data_size length of the body
345 * @param proc callback function for the result
346 * @param proc_cls closure for @a proc
347 * @return #GNUNET_OK if request accepted
350 rest_config_process_request (struct GNUNET_REST_RequestHandle *conndata_handle,
351 GNUNET_REST_ResultProcessor proc,
354 static const struct GNUNET_REST_RequestHandler handlers[] = {
355 { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_CONFIG, &get_cont },
356 { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_CONFIG, &set_cont },
357 { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_CONFIG, &options_cont },
358 GNUNET_REST_HANDLER_END
360 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
361 struct GNUNET_REST_RequestHandlerError err;
363 handle->proc_cls = proc_cls;
365 handle->rest_handle = conndata_handle;
366 handle->url = GNUNET_strdup (conndata_handle->url);
367 if (handle->url[strlen (handle->url) - 1] == '/')
368 handle->url[strlen (handle->url) - 1] = '\0';
371 GNUNET_REST_handle_request (conndata_handle, handlers, &err, handle))
373 handle->response_code = err.error_code;
374 GNUNET_SCHEDULER_add_now (&do_error, handle);
380 * Entry point for the plugin.
382 * @param cls the "struct GNUNET_NAMESTORE_PluginEnvironment*"
383 * @return NULL on error, otherwise the plugin context
386 libgnunet_plugin_rest_config_init (void *cls)
388 static struct Plugin plugin;
391 struct GNUNET_REST_Plugin *api;
393 if (NULL != plugin.cfg)
394 return NULL; /* can only initialize once! */
395 memset (&plugin, 0, sizeof(struct Plugin));
397 api = GNUNET_new (struct GNUNET_REST_Plugin);
399 api->name = GNUNET_REST_API_NS_CONFIG;
400 api->process_request = &rest_config_process_request;
401 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("CONFIG REST API initialized\n"));
407 * Exit point from the plugin.
409 * @param cls the plugin context (as returned by "init")
410 * @return always NULL
413 libgnunet_plugin_rest_config_done (void *cls)
415 struct GNUNET_REST_Plugin *api = cls;
416 struct Plugin *plugin = api->cls;
420 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "CONFIG REST plugin is finished\n");
425 /* end of plugin_rest_config.c */