GNUnet 0.22.2
config_plugin.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#include "config_plugin.h"
33
34#define GNUNET_REST_API_NS_CONFIG "/config"
35
39struct Plugin
40{
41 const struct GNUNET_CONFIGURATION_Handle *cfg;
42};
43
45
47{
52
57
62
67
71 void *proc_cls;
72
77
81 char *url;
82
83};
84
89
94
95
101static void
103{
104 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
105 if (NULL != handle->url)
106 GNUNET_free (handle->url);
109 handle);
111}
112
113
119static void
120do_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);
128}
129
130
131static void
132add_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
152static 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
169static 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);
202 GNUNET_assert (MHD_NO != MHD_add_response_header (resp,
203 "Content-Type",
204 "application/json"));
205 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
208 json_decref (result);
209}
210
211
212static struct GNUNET_CONFIGURATION_Handle *
214 const char *section,
215 const char *option,
216 json_t *value)
217{
218 if (json_is_string (value))
220 json_string_value (value));
221 else if (json_is_number (value))
223 json_integer_value (value));
224 else if (json_is_null (value))
225 GNUNET_CONFIGURATION_set_value_string (config, section, option, NULL);
226 else if (json_is_true (value))
227 GNUNET_CONFIGURATION_set_value_string (config, section, option, "yes");
228 else if (json_is_false (value))
229 GNUNET_CONFIGURATION_set_value_string (config, section, option, "no");
230 else
231 return NULL;
232 return config; // for error handling (0 -> success, 1 -> error)
233}
234
235
241static void
243 const char *url,
244 void *cls)
245{
246 struct RequestHandle *handle = cls;
247 char term_data[handle->rest_handle->data_size + 1];
249 );
250
251 json_error_t err;
252 json_t *data_json;
253 const char *section;
254 const char *option;
255 json_t *sec_obj;
256 json_t *value;
257 char *cfg_fn;
258
259 // invalid url
260 if (strlen (GNUNET_REST_API_NS_CONFIG) > strlen (handle->url))
261 {
262 handle->response_code = MHD_HTTP_BAD_REQUEST;
264 return;
265 }
266
267 // extract data from handle
268 term_data[handle->rest_handle->data_size] = '\0';
269 GNUNET_memcpy (term_data,
270 handle->rest_handle->data,
271 handle->rest_handle->data_size);
272 data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
273
274 if (NULL == data_json)
275 {
277 "Unable to parse JSON Object from %s\n",
278 term_data);
280 return;
281 }
282
283 // POST /config => {<section> : {<option> : <value>}}
284 if (strlen (GNUNET_REST_API_NS_CONFIG) == strlen (handle->url)) // POST /config
285 {
286 // iterate over sections
287 json_object_foreach (data_json, section, sec_obj)
288 {
289 // iterate over options
290 json_object_foreach (sec_obj, option, value)
291 {
292 out = set_value (out, section, option, value);
293 if (NULL == out)
294 {
295 handle->response_code = MHD_HTTP_BAD_REQUEST;
297 json_decref (data_json);
298 return;
299 }
300 }
301 }
302 }
303 else // POST /config/<section> => {<option> : <value>}
304 {
305 // extract the "<section>" part from the url
306 section = &handle->url[strlen (GNUNET_REST_API_NS_CONFIG) + 1];
307 // iterate over options
308 json_object_foreach (data_json, option, value)
309 {
310 out = set_value (out, section, option, value);
311 if (NULL == out)
312 {
313 handle->response_code = MHD_HTTP_BAD_REQUEST;
315 json_decref (data_json);
316 return;
317 }
318 }
319 }
320 json_decref (data_json);
321
322
323 // get cfg file path
324 cfg_fn = NULL;
325 {
326 const char *xdg = getenv ("XDG_CONFIG_HOME");
327 if (NULL != xdg)
328 GNUNET_asprintf (&cfg_fn,
329 "%s%s%s",
330 xdg,
333 else
334 cfg_fn = GNUNET_strdup (GNUNET_OS_project_data_gnunet ()->user_config_file
335 );
336
337 }
338 GNUNET_CONFIGURATION_write (out, cfg_fn);
339 config_cfg = out;
340 handle->proc (handle->proc_cls,
343 GNUNET_free (cfg_fn);
345}
346
347
353static void
355 const char *url,
356 void *cls)
357{
358 struct MHD_Response *resp;
359 struct RequestHandle *handle = cls;
360
361 resp = GNUNET_REST_create_response (NULL);
362 GNUNET_assert (MHD_NO != MHD_add_response_header (resp,
363 "Access-Control-Allow-Methods",
364 MHD_HTTP_METHOD_GET));
365 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
367}
368
369
372 struct GNUNET_REST_RequestHandle *conndata_handle,
374 void *proc_cls)
375{
376 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
378 static const struct GNUNET_REST_RequestHandler handlers[] = {
379 { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_CONFIG, &get_cont },
380 { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_CONFIG, &set_cont },
381 { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_CONFIG, &options_cont },
383 };
384 (void) plugin;
385
386 handle->proc_cls = proc_cls;
387 handle->proc = proc;
388 handle->rest_handle = conndata_handle;
389 handle->url = GNUNET_strdup (conndata_handle->url);
390 if (handle->url[strlen (handle->url) - 1] == '/')
391 handle->url[strlen (handle->url) - 1] = '\0';
394 handle);
395 if (GNUNET_NO ==
396 GNUNET_REST_handle_request (conndata_handle, handlers, &err, handle))
397 {
399 return GNUNET_NO;
400 }
401 return GNUNET_YES;
402}
403
404
405void
407{
408 struct Plugin *plugin;
409
410 while (NULL != requests_head)
412 plugin = api->cls;
413 plugin->cfg = NULL;
415 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "CONFIG REST plugin is finished\n");
416}
417
418
425void *
427{
428 static struct Plugin plugin;
429 struct GNUNET_REST_Plugin *api;
430
431 config_cfg = c;
432
433 memset (&plugin, 0, sizeof(struct Plugin));
434 plugin.cfg = c;
435 api = GNUNET_new (struct GNUNET_REST_Plugin);
436 api->cls = &plugin;
438 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("CONFIG REST API initialized\n"));
439 return api;
440}
441
442
443/* end of plugin_rest_config.c */
struct GNUNET_MQ_MessageHandlers handlers[]
Definition: 003.c:1
void * REST_config_init(const struct GNUNET_CONFIGURATION_Handle *c)
Entry point for the plugin.
static struct GNUNET_CONFIGURATION_Handle * set_value(struct GNUNET_CONFIGURATION_Handle *config, const char *section, const char *option, json_t *value)
static void add_section_contents(void *cls, const char *section, const char *option, const char *value)
static struct RequestHandle * requests_head
DLL.
Definition: config_plugin.c:88
static void options_cont(struct GNUNET_REST_RequestHandle *con_handle, const char *url, void *cls)
Handle rest request.
static void set_cont(struct GNUNET_REST_RequestHandle *con_handle, const char *url, void *cls)
Handle REST POST request.
const struct GNUNET_CONFIGURATION_Handle * config_cfg
Definition: config_plugin.c:44
enum GNUNET_GenericReturnValue REST_config_process_request(void *plugin, struct GNUNET_REST_RequestHandle *conndata_handle, GNUNET_REST_ResultProcessor proc, void *proc_cls)
Function processing the REST call.
static void cleanup_handle(struct RequestHandle *handle)
Cleanup request handle.
#define GNUNET_REST_API_NS_CONFIG
Definition: config_plugin.c:34
static void add_sections(void *cls, const char *section, const char *option, const char *value)
static struct RequestHandle * requests_tail
DLL.
Definition: config_plugin.c:93
static void get_cont(struct GNUNET_REST_RequestHandle *con_handle, const char *url, void *cls)
Handle rest request.
static void do_error(void *cls)
Task run on shutdown.
void REST_config_done(struct GNUNET_REST_Plugin *api)
Exit point from the plugin.
char * getenv()
static char * config_file
Set to the name of the config file used.
Definition: gnunet-arm.c:83
static struct GNUNET_TESTING_PluginFunctions * plugin
Plugin to dynamically load a test case.
static struct MHD_Response * response
Our canonical response.
const struct GNUNET_CONFIGURATION_Handle * config
static char * value
Value of the record to add/remove.
static int result
Global testing status.
static struct GNUNET_VPN_Handle * handle
Handle to vpn service.
Definition: gnunet-vpn.c:35
API for helper library to parse/create REST.
GNUnet service REST plugin header.
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.
struct GNUNET_CONFIGURATION_Handle * GNUNET_CONFIGURATION_dup(const struct GNUNET_CONFIGURATION_Handle *cfg)
Duplicate an existing configuration object.
void GNUNET_CONFIGURATION_iterate(const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_CONFIGURATION_Iterator iter, void *iter_cls)
Iterate over all options in the configuration.
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.
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_write(struct GNUNET_CONFIGURATION_Handle *cfg, const char *filename)
Write configuration file.
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_remove(head, tail, element)
Remove an element from a DLL.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
#define GNUNET_log(kind,...)
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
GNUNET_GenericReturnValue
Named constants for return values.
@ GNUNET_YES
@ GNUNET_NO
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
@ GNUNET_ERROR_TYPE_ERROR
@ GNUNET_ERROR_TYPE_DEBUG
@ GNUNET_ERROR_TYPE_INFO
int int GNUNET_asprintf(char **buf, const char *format,...) __attribute__((format(printf
Like asprintf, just portable.
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_free(ptr)
Wrapper around free.
const struct GNUNET_OS_ProjectData * GNUNET_OS_project_data_gnunet(void)
Return default project data used by 'libgnunetutil' for GNUnet.
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:64
void(* GNUNET_REST_ResultProcessor)(void *cls, struct MHD_Response *resp, int status)
Iterator called on obtained result for a REST result.
#define GNUNET_REST_HANDLER_END
struct MHD_Response * GNUNET_REST_create_response(const char *data)
Create REST MHD response.
Definition: rest.c:44
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:1304
@ MHD_HTTP_BAD_REQUEST
Bad Request [RFC7231, Section 6.5.1].
@ MHD_HTTP_OK
OK [RFC7231, Section 6.3.1].
#define DIR_SEPARATOR_STR
Definition: platform.h:166
#define _(String)
GNU gettext support macro.
Definition: platform.h:178
void * cls
Closure for all of the callbacks.
struct returned by the initialization function of the plugin
void * cls
The closure of the plugin.
const char * name
Plugin name.
const char * url
The url as string.
void(* proc)(struct GNUNET_REST_RequestHandle *handle, const char *url, void *cls)
Namespace to handle.
Handle for a plugin.
Definition: block.c:38
struct GNUNET_BLOCK_PluginFunctions * api
Plugin API.
Definition: block.c:47
const struct GNUNET_CONFIGURATION_Handle * cfg
Our configuration.
The request handle.
Definition: config_plugin.c:47
struct RequestHandle * prev
DLL.
Definition: config_plugin.c:56
int response_code
HTTP response code.
Definition: config_plugin.c:76
void * proc_cls
The closure of the result processor.
Definition: config_plugin.c:71
GNUNET_REST_ResultProcessor proc
The plugin result processor.
Definition: config_plugin.c:66
struct RequestHandle * next
DLL.
Definition: config_plugin.c:51
struct GNUNET_REST_RequestHandle * rest_handle
Handle to rest request.
Definition: config_plugin.c:61
char * url
The URL.
Definition: config_plugin.c:81