GNUnet  0.10.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  const struct GNUNET_CONFIGURATION_Handle *cfg;
40 };
41 
43 
44 struct RequestHandle {
48  struct GNUNET_REST_RequestHandle *rest_handle;
49 
54 
58  void *proc_cls;
59 
63  int response_code;
64 
68  char *url;
69 };
70 
71 
77 static void
79 {
80  GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
81  if (NULL != handle->url)
82  GNUNET_free(handle->url);
83  GNUNET_free(handle);
84 }
85 
86 
93 static void
94 do_error(void *cls)
95 {
96  struct RequestHandle *handle = cls;
97  struct MHD_Response *resp;
98 
99  resp = GNUNET_REST_create_response(NULL);
100  handle->proc(handle->proc_cls, resp, handle->response_code);
101  cleanup_handle(handle);
102 }
103 
104 
105 static void
106 add_sections(void *cls,
107  const char *section,
108  const char *option,
109  const char *value)
110 {
111  json_t *sections_obj = cls;
112  json_t *sec_obj;
113 
114  sec_obj = json_object_get(sections_obj, section);
115  if (NULL != sec_obj)
116  {
117  json_object_set_new(sec_obj, option, json_string(value));
118  return;
119  }
120  sec_obj = json_object();
121  json_object_set_new(sec_obj, option, json_string(value));
122  json_object_set_new(sections_obj, section, sec_obj);
123 }
124 
125 static void
127  const char *section,
128  const char *option,
129  const char *value)
130 {
131  json_t *section_obj = cls;
132 
133  json_object_set_new(section_obj, option, json_string(value));
134 }
135 
141 static void
143  const char *url,
144  void *cls)
145 {
146  struct MHD_Response *resp;
147  struct RequestHandle *handle = cls;
148  const char *section;
149  char *response;
150  json_t *result;
151 
152  if (strlen(GNUNET_REST_API_NS_CONFIG) > strlen(handle->url))
153  {
154  handle->response_code = MHD_HTTP_BAD_REQUEST;
156  return;
157  }
158  if (strlen(GNUNET_REST_API_NS_CONFIG) == strlen(handle->url))
159  {
160  result = json_object();
162  }
163  else
164  {
165  result = json_object();
166  section = &handle->url[strlen(GNUNET_REST_API_NS_CONFIG) + 1];
168  section,
170  result);
171  }
172  response = json_dumps(result, 0);
173  resp = GNUNET_REST_create_response(response);
174  handle->proc(handle->proc_cls, resp, MHD_HTTP_OK);
175  cleanup_handle(handle);
176  GNUNET_free(response);
177  json_decref(result);
178 }
179 
182  const char *section,
183  const char *option,
184  json_t *value)
185 {
186  if (json_is_string(value))
187  GNUNET_CONFIGURATION_set_value_string(config, section, option, json_string_value(value));
188  else if (json_is_number(value))
189  GNUNET_CONFIGURATION_set_value_number(config, section, option, json_integer_value(value));
190  else if (json_is_null(value))
191  GNUNET_CONFIGURATION_set_value_string(config, section, option, NULL);
192  else if (json_is_true(value))
193  GNUNET_CONFIGURATION_set_value_string(config, section, option, "yes");
194  else if (json_is_false(value))
195  GNUNET_CONFIGURATION_set_value_string(config, section, option, "no");
196  else
197  return NULL;
198  return config; // for error handling (0 -> success, 1 -> error)
199 }
200 
206 static void
208  const char *url,
209  void *cls)
210 {
211  struct RequestHandle *handle = cls;
212  char term_data[handle->rest_handle->data_size + 1];
214 
215  json_error_t err;
216  json_t *data_json;
217  const char *section;
218  const char *option;
219  json_t *sec_obj;
220  json_t *value;
221  char *cfg_fn;
222 
223  // invalid url
224  if (strlen(GNUNET_REST_API_NS_CONFIG) > strlen(handle->url))
225  {
226  handle->response_code = MHD_HTTP_BAD_REQUEST;
228  return;
229  }
230 
231  // extract data from handle
232  term_data[handle->rest_handle->data_size] = '\0';
233  GNUNET_memcpy(term_data,
234  handle->rest_handle->data,
235  handle->rest_handle->data_size);
236  data_json = json_loads(term_data, JSON_DECODE_ANY, &err);
237 
238  if (NULL == data_json)
239  {
241  "Unable to parse JSON Object from %s\n",
242  term_data);
244  return;
245  }
246 
247  // POST /config => {<section> : {<option> : <value>}}
248  if (strlen(GNUNET_REST_API_NS_CONFIG) == strlen(handle->url)) // POST /config
249  {
250  // iterate over sections
251  json_object_foreach(data_json, section, sec_obj)
252  {
253  // iterate over options
254  json_object_foreach(sec_obj, option, value)
255  {
256  out = set_value(out, section, option, value);
257  if (NULL == out)
258  {
259  handle->response_code = MHD_HTTP_BAD_REQUEST;
261  json_decref(data_json);
262  return;
263  }
264  }
265  }
266  }
267  else // POST /config/<section> => {<option> : <value>}
268  {
269  // extract the "<section>" part from the url
270  section = &handle->url[strlen(GNUNET_REST_API_NS_CONFIG) + 1];
271  // iterate over options
272  json_object_foreach(data_json, option, value)
273  {
274  out = set_value(out, section, option, value);
275  if (NULL == out)
276  {
277  handle->response_code = MHD_HTTP_BAD_REQUEST;
279  json_decref(data_json);
280  return;
281  }
282  }
283  }
284  json_decref(data_json);
285 
286 
287  // get cfg file path
288  cfg_fn = NULL;
289  const char *xdg = getenv("XDG_CONFIG_HOME");
290  if (NULL != xdg)
291  GNUNET_asprintf(&cfg_fn,
292  "%s%s%s",
293  xdg,
296  else
297  cfg_fn = GNUNET_strdup(GNUNET_OS_project_data_get()->user_config_file);
298 
299  GNUNET_CONFIGURATION_write(out, cfg_fn);
300  cfg = out;
301  handle->proc(handle->proc_cls,
303  MHD_HTTP_OK);
304  cleanup_handle(handle);
305 }
306 
312 static void
314  const char *url,
315  void *cls)
316 {
317  struct MHD_Response *resp;
318  struct RequestHandle *handle = cls;
319 
320  resp = GNUNET_REST_create_response(NULL);
321  MHD_add_response_header(resp,
322  "Access-Control-Allow-Methods",
323  MHD_HTTP_METHOD_GET);
324  handle->proc(handle->proc_cls, resp, MHD_HTTP_OK);
325  cleanup_handle(handle);
326 }
327 
328 
340 static void
343  void *proc_cls)
344 {
345  static const struct GNUNET_REST_RequestHandler handlers[] = {
346  { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_CONFIG, &get_cont },
347  { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_CONFIG, &set_cont },
348  { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_CONFIG, &options_cont },
350  };
351  struct RequestHandle *handle = GNUNET_new(struct RequestHandle);
353 
354  handle->proc_cls = proc_cls;
355  handle->proc = proc;
356  handle->rest_handle = conndata_handle;
357  handle->url = GNUNET_strdup(conndata_handle->url);
358  if (handle->url[strlen(handle->url) - 1] == '/')
359  handle->url[strlen(handle->url) - 1] = '\0';
360 
361  if (GNUNET_NO ==
362  GNUNET_REST_handle_request(conndata_handle, handlers, &err, handle))
363  {
364  handle->response_code = err.error_code;
366  }
367 }
368 
369 
376 void *
378 {
379  static struct Plugin plugin;
380 
381  cfg = cls;
382  struct GNUNET_REST_Plugin *api;
383 
384  if (NULL != plugin.cfg)
385  return NULL; /* can only initialize once! */
386  memset(&plugin, 0, sizeof(struct Plugin));
387  plugin.cfg = cfg;
388  api = GNUNET_new(struct GNUNET_REST_Plugin);
389  api->cls = &plugin;
392  GNUNET_log(GNUNET_ERROR_TYPE_INFO, _("CONFIG REST API initialized\n"));
393  return api;
394 }
395 
396 
403 void *
405 {
406  struct GNUNET_REST_Plugin *api = cls;
407  struct Plugin *plugin = api->cls;
408 
409  plugin->cfg = NULL;
410  GNUNET_free(api);
411  GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "CONFIG REST plugin is finished\n");
412  return NULL;
413 }
414 
415 /* 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:79
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_NO
Definition: gnunet_common.h:78
#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:46
The request handle.
#define _(String)
GNU gettext support macro.
Definition: platform.h:181
static char * section
Name of the section.
Definition: gnunet-config.c:33
static struct GNUNET_ATS_SolverFunctions * plugin
Our solver.
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:1264
#define DIR_SEPARATOR_STR
Definition: platform.h:168
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:75
static void add_section_contents(void *cls, const char *section, const char *option, const char *value)
struct GNUNET_REST_RequestHandle * rest_handle
Handle to rest request.
int response_code
HTTP response code.
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:83
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:56
#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.