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 GNUNET_REST_RequestHandle *rest_handle;
51 
56 
60  void *proc_cls;
61 
65  int response_code;
66 
70  char *url;
71 };
72 
73 
79 static void
81 {
82  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
83  if (NULL != handle->url)
84  GNUNET_free (handle->url);
85  GNUNET_free (handle);
86 }
87 
88 
95 static void
96 do_error (void *cls)
97 {
98  struct RequestHandle *handle = cls;
99  struct MHD_Response *resp;
100 
101  resp = GNUNET_REST_create_response (NULL);
102  handle->proc (handle->proc_cls, resp, handle->response_code);
103  cleanup_handle (handle);
104 }
105 
106 
107 static void
108 add_sections (void *cls,
109  const char *section,
110  const char *option,
111  const char *value)
112 {
113  json_t *sections_obj = cls;
114  json_t *sec_obj;
115 
116  sec_obj = json_object_get (sections_obj, section);
117  if (NULL != sec_obj)
118  {
119  json_object_set_new (sec_obj, option, json_string (value));
120  return;
121  }
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);
125 }
126 
127 
128 static void
130  const char *section,
131  const char *option,
132  const char *value)
133 {
134  json_t *section_obj = cls;
135 
136  json_object_set_new (section_obj, option, json_string (value));
137 }
138 
139 
145 static void
147  const char *url,
148  void *cls)
149 {
150  struct MHD_Response *resp;
151  struct RequestHandle *handle = cls;
152  const char *section;
153  char *response;
154  json_t *result;
155 
156  if (strlen (GNUNET_REST_API_NS_CONFIG) > strlen (handle->url))
157  {
158  handle->response_code = MHD_HTTP_BAD_REQUEST;
160  return;
161  }
162  if (strlen (GNUNET_REST_API_NS_CONFIG) == strlen (handle->url))
163  {
164  result = json_object ();
166  }
167  else
168  {
169  result = json_object ();
170  section = &handle->url[strlen (GNUNET_REST_API_NS_CONFIG) + 1];
172  section,
174  result);
175  }
176  response = json_dumps (result, 0);
177  resp = GNUNET_REST_create_response (response);
178  MHD_add_response_header (resp, "Content-Type", "application/json");
179  handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
180  cleanup_handle (handle);
181  GNUNET_free (response);
182  json_decref (result);
183 }
184 
185 
188  const char *section,
189  const char *option,
190  json_t *value)
191 {
192  if (json_is_string (value))
193  GNUNET_CONFIGURATION_set_value_string (config, section, option,
194  json_string_value (value));
195  else if (json_is_number (value))
196  GNUNET_CONFIGURATION_set_value_number (config, section, option,
197  json_integer_value (value));
198  else if (json_is_null (value))
199  GNUNET_CONFIGURATION_set_value_string (config, section, option, NULL);
200  else if (json_is_true (value))
201  GNUNET_CONFIGURATION_set_value_string (config, section, option, "yes");
202  else if (json_is_false (value))
203  GNUNET_CONFIGURATION_set_value_string (config, section, option, "no");
204  else
205  return NULL;
206  return config; // for error handling (0 -> success, 1 -> error)
207 }
208 
209 
215 static void
217  const char *url,
218  void *cls)
219 {
220  struct RequestHandle *handle = cls;
221  char term_data[handle->rest_handle->data_size + 1];
223 
224  json_error_t err;
225  json_t *data_json;
226  const char *section;
227  const char *option;
228  json_t *sec_obj;
229  json_t *value;
230  char *cfg_fn;
231 
232  // invalid url
233  if (strlen (GNUNET_REST_API_NS_CONFIG) > strlen (handle->url))
234  {
235  handle->response_code = MHD_HTTP_BAD_REQUEST;
237  return;
238  }
239 
240  // extract data from handle
241  term_data[handle->rest_handle->data_size] = '\0';
242  GNUNET_memcpy (term_data,
243  handle->rest_handle->data,
244  handle->rest_handle->data_size);
245  data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
246 
247  if (NULL == data_json)
248  {
250  "Unable to parse JSON Object from %s\n",
251  term_data);
253  return;
254  }
255 
256  // POST /config => {<section> : {<option> : <value>}}
257  if (strlen (GNUNET_REST_API_NS_CONFIG) == strlen (handle->url)) // POST /config
258  {
259  // iterate over sections
260  json_object_foreach (data_json, section, sec_obj)
261  {
262  // iterate over options
263  json_object_foreach (sec_obj, option, value)
264  {
265  out = set_value (out, section, option, value);
266  if (NULL == out)
267  {
268  handle->response_code = MHD_HTTP_BAD_REQUEST;
270  json_decref (data_json);
271  return;
272  }
273  }
274  }
275  }
276  else // POST /config/<section> => {<option> : <value>}
277  {
278  // extract the "<section>" part from the url
279  section = &handle->url[strlen (GNUNET_REST_API_NS_CONFIG) + 1];
280  // iterate over options
281  json_object_foreach (data_json, option, value)
282  {
283  out = set_value (out, section, option, value);
284  if (NULL == out)
285  {
286  handle->response_code = MHD_HTTP_BAD_REQUEST;
288  json_decref (data_json);
289  return;
290  }
291  }
292  }
293  json_decref (data_json);
294 
295 
296  // get cfg file path
297  cfg_fn = NULL;
298  const char *xdg = getenv ("XDG_CONFIG_HOME");
299  if (NULL != xdg)
300  GNUNET_asprintf (&cfg_fn,
301  "%s%s%s",
302  xdg,
305  else
306  cfg_fn = GNUNET_strdup (GNUNET_OS_project_data_get ()->user_config_file);
307 
308  GNUNET_CONFIGURATION_write (out, cfg_fn);
309  cfg = out;
310  handle->proc (handle->proc_cls,
312  MHD_HTTP_OK);
313  cleanup_handle (handle);
314 }
315 
316 
322 static void
324  const char *url,
325  void *cls)
326 {
327  struct MHD_Response *resp;
328  struct RequestHandle *handle = cls;
329 
330  resp = GNUNET_REST_create_response (NULL);
331  MHD_add_response_header (resp,
332  "Access-Control-Allow-Methods",
333  MHD_HTTP_METHOD_GET);
334  handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
335  cleanup_handle (handle);
336 }
337 
338 
350 static void
353  void *proc_cls)
354 {
355  static const struct GNUNET_REST_RequestHandler handlers[] = {
356  { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_CONFIG, &get_cont },
357  { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_CONFIG, &set_cont },
358  { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_CONFIG, &options_cont },
360  };
361  struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
363 
364  handle->proc_cls = proc_cls;
365  handle->proc = proc;
366  handle->rest_handle = conndata_handle;
367  handle->url = GNUNET_strdup (conndata_handle->url);
368  if (handle->url[strlen (handle->url) - 1] == '/')
369  handle->url[strlen (handle->url) - 1] = '\0';
370 
371  if (GNUNET_NO ==
372  GNUNET_REST_handle_request (conndata_handle, handlers, &err, handle))
373  {
374  handle->response_code = err.error_code;
376  }
377 }
378 
379 
386 void *
388 {
389  static struct Plugin plugin;
390 
391  cfg = cls;
392  struct GNUNET_REST_Plugin *api;
393 
394  if (NULL != plugin.cfg)
395  return NULL; /* can only initialize once! */
396  memset (&plugin, 0, sizeof(struct Plugin));
397  plugin.cfg = cfg;
398  api = GNUNET_new (struct GNUNET_REST_Plugin);
399  api->cls = &plugin;
402  GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("CONFIG REST API initialized\n"));
403  return api;
404 }
405 
406 
413 void *
415 {
416  struct GNUNET_REST_Plugin *api = cls;
417  struct Plugin *plugin = api->cls;
418 
419  plugin->cfg = NULL;
420  GNUNET_free (api);
421  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "CONFIG REST plugin is finished\n");
422  return NULL;
423 }
424 
425 
426 /* end of plugin_rest_config.c */
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.
int GNUNET_CONFIGURATION_write(struct GNUNET_CONFIGURATION_Handle *cfg, const char *filename)
Write configuration file.
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.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
void(* process_request)(struct GNUNET_REST_RequestHandle *handle, GNUNET_REST_ResultProcessor proc, void *proc_cls)
Function to process a REST call.
#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 void rest_config_process_request(struct GNUNET_REST_RequestHandle *conndata_handle, GNUNET_REST_ResultProcessor proc, void *proc_cls)
Function processing the REST call.
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.
void * libgnunet_plugin_rest_config_init(void *cls)
Entry point for the plugin.
char * getenv()
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)
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.