GNUnet  0.11.x
plugin_rest_config.c
Go to the documentation of this file.
1 /*
2  This file is part of GNUnet.
3  Copyright (C) 2012-2018 GNUnet e.V.
4 
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.
9 
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.
14 
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/>.
17 
18  SPDX-License-Identifier: AGPL3.0-or-later
19  */
27 #include "platform.h"
28 #include "gnunet_rest_plugin.h"
29 #include <gnunet_rest_lib.h>
30 #include <gnunet_util_lib.h>
31 #include <jansson.h>
32 
33 #define GNUNET_REST_API_NS_CONFIG "/config"
34 
38 struct Plugin
39 {
40  const struct GNUNET_CONFIGURATION_Handle *cfg;
41 };
42 
44 
45 struct RequestHandle
46 {
50  struct RequestHandle *next;
51 
55  struct RequestHandle *prev;
56 
60  struct GNUNET_REST_RequestHandle *rest_handle;
61 
66 
70  void *proc_cls;
71 
75  int response_code;
76 
80  char *url;
81 };
82 
87 
92 
93 
94 
100 static void
102 {
103  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
104  if (NULL != handle->url)
105  GNUNET_free (handle->url);
106  GNUNET_CONTAINER_DLL_remove (requests_head,
107  requests_tail,
108  handle);
109  GNUNET_free (handle);
110 }
111 
112 
119 static void
120 do_error (void *cls)
121 {
122  struct RequestHandle *handle = cls;
123  struct MHD_Response *resp;
124 
125  resp = GNUNET_REST_create_response (NULL);
126  handle->proc (handle->proc_cls, resp, handle->response_code);
127  cleanup_handle (handle);
128 }
129 
130 
131 static void
132 add_sections (void *cls,
133  const char *section,
134  const char *option,
135  const char *value)
136 {
137  json_t *sections_obj = cls;
138  json_t *sec_obj;
139 
140  sec_obj = json_object_get (sections_obj, section);
141  if (NULL != sec_obj)
142  {
143  json_object_set_new (sec_obj, option, json_string (value));
144  return;
145  }
146  sec_obj = json_object ();
147  json_object_set_new (sec_obj, option, json_string (value));
148  json_object_set_new (sections_obj, section, sec_obj);
149 }
150 
151 
152 static void
154  const char *section,
155  const char *option,
156  const char *value)
157 {
158  json_t *section_obj = cls;
159 
160  json_object_set_new (section_obj, option, json_string (value));
161 }
162 
163 
169 static void
171  const char *url,
172  void *cls)
173 {
174  struct MHD_Response *resp;
175  struct RequestHandle *handle = cls;
176  const char *section;
177  char *response;
178  json_t *result;
179 
180  if (strlen (GNUNET_REST_API_NS_CONFIG) > strlen (handle->url))
181  {
182  handle->response_code = MHD_HTTP_BAD_REQUEST;
184  return;
185  }
186  if (strlen (GNUNET_REST_API_NS_CONFIG) == strlen (handle->url))
187  {
188  result = json_object ();
190  }
191  else
192  {
193  result = json_object ();
194  section = &handle->url[strlen (GNUNET_REST_API_NS_CONFIG) + 1];
196  section,
198  result);
199  }
200  response = json_dumps (result, 0);
201  resp = GNUNET_REST_create_response (response);
202  MHD_add_response_header (resp, "Content-Type", "application/json");
203  handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
204  cleanup_handle (handle);
205  GNUNET_free (response);
206  json_decref (result);
207 }
208 
209 
212  const char *section,
213  const char *option,
214  json_t *value)
215 {
216  if (json_is_string (value))
217  GNUNET_CONFIGURATION_set_value_string (config, section, option,
218  json_string_value (value));
219  else if (json_is_number (value))
220  GNUNET_CONFIGURATION_set_value_number (config, section, option,
221  json_integer_value (value));
222  else if (json_is_null (value))
223  GNUNET_CONFIGURATION_set_value_string (config, section, option, NULL);
224  else if (json_is_true (value))
225  GNUNET_CONFIGURATION_set_value_string (config, section, option, "yes");
226  else if (json_is_false (value))
227  GNUNET_CONFIGURATION_set_value_string (config, section, option, "no");
228  else
229  return NULL;
230  return config; // for error handling (0 -> success, 1 -> error)
231 }
232 
233 
239 static void
241  const char *url,
242  void *cls)
243 {
244  struct RequestHandle *handle = cls;
245  char term_data[handle->rest_handle->data_size + 1];
247 
248  json_error_t err;
249  json_t *data_json;
250  const char *section;
251  const char *option;
252  json_t *sec_obj;
253  json_t *value;
254  char *cfg_fn;
255 
256  // invalid url
257  if (strlen (GNUNET_REST_API_NS_CONFIG) > strlen (handle->url))
258  {
259  handle->response_code = MHD_HTTP_BAD_REQUEST;
261  return;
262  }
263 
264  // extract data from handle
265  term_data[handle->rest_handle->data_size] = '\0';
266  GNUNET_memcpy (term_data,
267  handle->rest_handle->data,
268  handle->rest_handle->data_size);
269  data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
270 
271  if (NULL == data_json)
272  {
274  "Unable to parse JSON Object from %s\n",
275  term_data);
277  return;
278  }
279 
280  // POST /config => {<section> : {<option> : <value>}}
281  if (strlen (GNUNET_REST_API_NS_CONFIG) == strlen (handle->url)) // POST /config
282  {
283  // iterate over sections
284  json_object_foreach (data_json, section, sec_obj)
285  {
286  // iterate over options
287  json_object_foreach (sec_obj, option, value)
288  {
289  out = set_value (out, section, option, value);
290  if (NULL == out)
291  {
292  handle->response_code = MHD_HTTP_BAD_REQUEST;
294  json_decref (data_json);
295  return;
296  }
297  }
298  }
299  }
300  else // POST /config/<section> => {<option> : <value>}
301  {
302  // extract the "<section>" part from the url
303  section = &handle->url[strlen (GNUNET_REST_API_NS_CONFIG) + 1];
304  // iterate over options
305  json_object_foreach (data_json, option, value)
306  {
307  out = set_value (out, section, option, value);
308  if (NULL == out)
309  {
310  handle->response_code = MHD_HTTP_BAD_REQUEST;
312  json_decref (data_json);
313  return;
314  }
315  }
316  }
317  json_decref (data_json);
318 
319 
320  // get cfg file path
321  cfg_fn = NULL;
322  const char *xdg = getenv ("XDG_CONFIG_HOME");
323  if (NULL != xdg)
324  GNUNET_asprintf (&cfg_fn,
325  "%s%s%s",
326  xdg,
329  else
330  cfg_fn = GNUNET_strdup (GNUNET_OS_project_data_get ()->user_config_file);
331 
332  GNUNET_CONFIGURATION_write (out, cfg_fn);
333  cfg = out;
334  handle->proc (handle->proc_cls,
336  MHD_HTTP_OK);
337  cleanup_handle (handle);
338 }
339 
340 
346 static void
348  const char *url,
349  void *cls)
350 {
351  struct MHD_Response *resp;
352  struct RequestHandle *handle = cls;
353 
354  resp = GNUNET_REST_create_response (NULL);
355  MHD_add_response_header (resp,
356  "Access-Control-Allow-Methods",
357  MHD_HTTP_METHOD_GET);
358  handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
359  cleanup_handle (handle);
360 }
361 
362 
374 static enum GNUNET_GenericReturnValue
377  void *proc_cls)
378 {
379  static const struct GNUNET_REST_RequestHandler handlers[] = {
380  { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_CONFIG, &get_cont },
381  { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_CONFIG, &set_cont },
382  { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_CONFIG, &options_cont },
384  };
385  struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
387 
388  handle->proc_cls = proc_cls;
389  handle->proc = proc;
390  handle->rest_handle = conndata_handle;
391  handle->url = GNUNET_strdup (conndata_handle->url);
392  if (handle->url[strlen (handle->url) - 1] == '/')
393  handle->url[strlen (handle->url) - 1] = '\0';
394  GNUNET_CONTAINER_DLL_insert (requests_head,
395  requests_tail,
396  handle);
397  if (GNUNET_NO ==
398  GNUNET_REST_handle_request (conndata_handle, handlers, &err, handle))
399  {
400  cleanup_handle (handle);
401  return GNUNET_NO;
402  }
403  return GNUNET_YES;
404 }
405 
406 
413 void *
415 {
416  static struct Plugin plugin;
417 
418  cfg = cls;
419  struct GNUNET_REST_Plugin *api;
420 
421  memset (&plugin, 0, sizeof(struct Plugin));
422  plugin.cfg = cfg;
423  api = GNUNET_new (struct GNUNET_REST_Plugin);
424  api->cls = &plugin;
427  GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("CONFIG REST API initialized\n"));
428  return api;
429 }
430 
431 
438 void *
440 {
441  struct GNUNET_REST_Plugin *api = cls;
442  struct Plugin *plugin;
443 
444  while (NULL != requests_head)
445  cleanup_handle (requests_head);
446  plugin = api->cls;
447  plugin->cfg = NULL;
448  GNUNET_free (api);
449  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "CONFIG REST plugin is finished\n");
450  return NULL;
451 }
452 
453 
454 /* end of plugin_rest_config.c */
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
void(* GNUNET_REST_ResultProcessor)(void *cls, struct MHD_Response *resp, int status)
Iterator called on obtained result for a REST result.
#define GNUNET_REST_API_NS_CONFIG
void GNUNET_CONFIGURATION_iterate_section_values(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, GNUNET_CONFIGURATION_Iterator iter, void *iter_cls)
Iterate over values of a section in the configuration.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
int GNUNET_CONFIGURATION_write(struct GNUNET_CONFIGURATION_Handle *cfg, const char *filename)
Write configuration file.
static struct RequestHandle * requests_head
DLL.
void * cls
The closure of the plugin.
size_t data_size
The POST data size.
void GNUNET_CONFIGURATION_iterate(const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_CONFIGURATION_Iterator iter, void *iter_cls)
Iterate over all options in the configuration.
GNUNET_REST_ResultProcessor proc
The plugin result processor.
static char * config_file
Set to the name of the config file used.
Definition: gnunet-arm.c:84
const struct GNUNET_CONFIGURATION_Handle * cfg
Our configuration.
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
struct returned by the initialization function of the plugin
void GNUNET_CONFIGURATION_set_value_number(struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, unsigned long long number)
Set a configuration value that should be a number.
GNUNET_GenericReturnValue
Named constants for return values.
Definition: gnunet_common.h:83
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
void * proc_cls
The closure of the result processor.
#define GNUNET_REST_HANDLER_END
struct GNUNET_BLOCK_PluginFunctions * api
Plugin API.
Definition: block.c:47
The request handle.
#define _(String)
GNU gettext support macro.
Definition: platform.h:184
static char * section
Name of the section.
Definition: gnunet-config.c:33
static enum GNUNET_GenericReturnValue rest_config_process_request(struct GNUNET_REST_RequestHandle *conndata_handle, GNUNET_REST_ResultProcessor proc, void *proc_cls)
Function processing the REST call.
static struct RequestHandle * requests_tail
DLL.
int GNUNET_asprintf(char **buf, const char *format,...)
Like asprintf, just portable.
static char * value
Value of the record to add/remove.
const char * url
The url as string.
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_now(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run as soon as possible.
Definition: scheduler.c:1296
#define DIR_SEPARATOR_STR
Definition: platform.h:171
char * name
Plugin name.
static char * option
Name of the option.
Definition: gnunet-config.c:38
static void do_error(void *cls)
Task run on shutdown.
static const struct GNUNET_CONFIGURATION_Handle * config
static void get_cont(struct GNUNET_REST_RequestHandle *con_handle, const char *url, void *cls)
Handle rest request.
static struct GNUNET_DNS_Handle * handle
Handle to transport service.
static int result
Global testing status.
void GNUNET_CONFIGURATION_set_value_string(struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, const char *value)
Set a configuration value that should be a string.
int GNUNET_REST_handle_request(struct GNUNET_REST_RequestHandle *conn, const struct GNUNET_REST_RequestHandler *handlers, struct GNUNET_REST_RequestHandlerError *err, void *cls)
Definition: rest.c:77
static void add_section_contents(void *cls, const char *section, const char *option, const char *value)
struct GNUNET_REST_RequestHandle * rest_handle
Rest connection.
int response_code
Response code.
static char * plugin
Solver plugin name as string.
const char * data
The POST data.
struct RequestHandle * next
DLL.
void * libgnunet_plugin_rest_config_init(void *cls)
Entry point for the plugin.
char * getenv()
struct RequestHandle * prev
DLL.
struct GNUNET_CONFIGURATION_Handle * GNUNET_CONFIGURATION_dup(const struct GNUNET_CONFIGURATION_Handle *cfg)
Duplicate an existing configuration object.
static void set_cont(struct GNUNET_REST_RequestHandle *con_handle, const char *url, void *cls)
Handle REST POST request.
configuration data
Definition: configuration.c:84
Handle for a plugin.
Definition: block.c:37
struct MHD_Response * GNUNET_REST_create_response(const char *data)
Create REST MHD response.
Definition: rest.c:57
#define GNUNET_log(kind,...)
const struct GNUNET_OS_ProjectData * GNUNET_OS_project_data_get(void)
static struct MHD_Response * response
Our canonical response.
static void add_sections(void *cls, const char *section, const char *option, const char *value)
void * libgnunet_plugin_rest_config_done(void *cls)
Exit point from the plugin.
struct GNUNET_CONFIGURATION_Handle * set_value(struct GNUNET_CONFIGURATION_Handle *config, const char *section, const char *option, json_t *value)
enum GNUNET_GenericReturnValue(* process_request)(struct GNUNET_REST_RequestHandle *handle, GNUNET_REST_ResultProcessor proc, void *proc_cls)
Function to process a REST call.
static void cleanup_handle(struct RequestHandle *handle)
Cleanup request handle.
static void options_cont(struct GNUNET_REST_RequestHandle *con_handle, const char *url, void *cls)
Handle rest request.
#define GNUNET_free(ptr)
Wrapper around free.
char * url
The url.