aboutsummaryrefslogtreecommitdiff
path: root/src/rest/plugin_rest_config.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/rest/plugin_rest_config.c')
-rw-r--r--src/rest/plugin_rest_config.c455
1 files changed, 0 insertions, 455 deletions
diff --git a/src/rest/plugin_rest_config.c b/src/rest/plugin_rest_config.c
deleted file mode 100644
index 826188702..000000000
--- a/src/rest/plugin_rest_config.c
+++ /dev/null
@@ -1,455 +0,0 @@
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 */
20/**
21 * @author Martin Schanzenbach
22 * @file gns/plugin_rest_config.c
23 * @brief REST plugin for configuration
24 *
25 */
26
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
35/**
36 * @brief struct returned by the initialization function of the plugin
37 */
38struct Plugin
39{
40 const struct GNUNET_CONFIGURATION_Handle *cfg;
41};
42
43const struct GNUNET_CONFIGURATION_Handle *cfg;
44
45struct RequestHandle
46{
47 /**
48 * DLL
49 */
50 struct RequestHandle *next;
51
52 /**
53 * DLL
54 */
55 struct RequestHandle *prev;
56
57 /**
58 * Handle to rest request
59 */
60 struct GNUNET_REST_RequestHandle *rest_handle;
61
62 /**
63 * The plugin result processor
64 */
65 GNUNET_REST_ResultProcessor proc;
66
67 /**
68 * The closure of the result processor
69 */
70 void *proc_cls;
71
72 /**
73 * HTTP response code
74 */
75 int response_code;
76
77 /**
78 * The URL
79 */
80 char *url;
81};
82
83/**
84 * DLL
85 */
86static struct RequestHandle *requests_head;
87
88/**
89 * DLL
90 */
91static struct RequestHandle *requests_tail;
92
93
94/**
95 * Cleanup request handle.
96 *
97 * @param handle Handle to clean up
98 */
99static void
100cleanup_handle (struct RequestHandle *handle)
101{
102 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
103 if (NULL != handle->url)
104 GNUNET_free (handle->url);
105 GNUNET_CONTAINER_DLL_remove (requests_head,
106 requests_tail,
107 handle);
108 GNUNET_free (handle);
109}
110
111
112/**
113 * Task run on shutdown. Cleans up everything.
114 *
115 * @param cls unused
116 */
117static void
118do_error (void *cls)
119{
120 struct RequestHandle *handle = cls;
121 struct MHD_Response *resp;
122
123 resp = GNUNET_REST_create_response (NULL);
124 handle->proc (handle->proc_cls, resp, handle->response_code);
125 cleanup_handle (handle);
126}
127
128
129static void
130add_sections (void *cls,
131 const char *section,
132 const char *option,
133 const char *value)
134{
135 json_t *sections_obj = cls;
136 json_t *sec_obj;
137
138 sec_obj = json_object_get (sections_obj, section);
139 if (NULL != sec_obj)
140 {
141 json_object_set_new (sec_obj, option, json_string (value));
142 return;
143 }
144 sec_obj = json_object ();
145 json_object_set_new (sec_obj, option, json_string (value));
146 json_object_set_new (sections_obj, section, sec_obj);
147}
148
149
150static void
151add_section_contents (void *cls,
152 const char *section,
153 const char *option,
154 const char *value)
155{
156 json_t *section_obj = cls;
157
158 json_object_set_new (section_obj, option, json_string (value));
159}
160
161
162/**
163 * Handle rest request
164 *
165 * @param handle the lookup handle
166 */
167static void
168get_cont (struct GNUNET_REST_RequestHandle *con_handle,
169 const char *url,
170 void *cls)
171{
172 struct MHD_Response *resp;
173 struct RequestHandle *handle = cls;
174 const char *section;
175 char *response;
176 json_t *result;
177
178 if (strlen (GNUNET_REST_API_NS_CONFIG) > strlen (handle->url))
179 {
180 handle->response_code = MHD_HTTP_BAD_REQUEST;
181 GNUNET_SCHEDULER_add_now (&do_error, handle);
182 return;
183 }
184 if (strlen (GNUNET_REST_API_NS_CONFIG) == strlen (handle->url))
185 {
186 result = json_object ();
187 GNUNET_CONFIGURATION_iterate (cfg, &add_sections, result);
188 }
189 else
190 {
191 result = json_object ();
192 section = &handle->url[strlen (GNUNET_REST_API_NS_CONFIG) + 1];
193 GNUNET_CONFIGURATION_iterate_section_values (cfg,
194 section,
195 &add_section_contents,
196 result);
197 }
198 response = json_dumps (result, 0);
199 resp = GNUNET_REST_create_response (response);
200 GNUNET_assert (MHD_NO != MHD_add_response_header (resp,
201 "Content-Type",
202 "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
210struct GNUNET_CONFIGURATION_Handle *
211set_value (struct GNUNET_CONFIGURATION_Handle *config,
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
234/**
235 * Handle REST POST request
236 *
237 * @param handle the lookup handle
238 */
239static void
240set_cont (struct GNUNET_REST_RequestHandle *con_handle,
241 const char *url,
242 void *cls)
243{
244 struct RequestHandle *handle = cls;
245 char term_data[handle->rest_handle->data_size + 1];
246 struct GNUNET_CONFIGURATION_Handle *out = GNUNET_CONFIGURATION_dup (cfg);
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;
260 GNUNET_SCHEDULER_add_now (&do_error, handle);
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 {
273 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
274 "Unable to parse JSON Object from %s\n",
275 term_data);
276 GNUNET_SCHEDULER_add_now (&do_error, handle);
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;
293 GNUNET_SCHEDULER_add_now (&do_error, handle);
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;
311 GNUNET_SCHEDULER_add_now (&do_error, handle);
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,
327 DIR_SEPARATOR_STR,
328 GNUNET_OS_project_data_get ()->config_file);
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,
335 GNUNET_REST_create_response (NULL),
336 MHD_HTTP_OK);
337 GNUNET_free (cfg_fn);
338 cleanup_handle (handle);
339}
340
341
342/**
343 * Handle rest request
344 *
345 * @param handle the lookup handle
346 */
347static void
348options_cont (struct GNUNET_REST_RequestHandle *con_handle,
349 const char *url,
350 void *cls)
351{
352 struct MHD_Response *resp;
353 struct RequestHandle *handle = cls;
354
355 resp = GNUNET_REST_create_response (NULL);
356 GNUNET_assert (MHD_NO != MHD_add_response_header (resp,
357 "Access-Control-Allow-Methods",
358 MHD_HTTP_METHOD_GET));
359 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
360 cleanup_handle (handle);
361}
362
363
364/**
365 * Function processing the REST call
366 *
367 * @param method HTTP method
368 * @param url URL of the HTTP request
369 * @param data body of the HTTP request (optional)
370 * @param data_size length of the body
371 * @param proc callback function for the result
372 * @param proc_cls closure for @a proc
373 * @return #GNUNET_OK if request accepted
374 */
375static enum GNUNET_GenericReturnValue
376rest_config_process_request (struct GNUNET_REST_RequestHandle *conndata_handle,
377 GNUNET_REST_ResultProcessor proc,
378 void *proc_cls)
379{
380 static const struct GNUNET_REST_RequestHandler handlers[] = {
381 { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_CONFIG, &get_cont },
382 { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_CONFIG, &set_cont },
383 { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_CONFIG, &options_cont },
384 GNUNET_REST_HANDLER_END
385 };
386 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
387 struct GNUNET_REST_RequestHandlerError err;
388
389 handle->proc_cls = proc_cls;
390 handle->proc = proc;
391 handle->rest_handle = conndata_handle;
392 handle->url = GNUNET_strdup (conndata_handle->url);
393 if (handle->url[strlen (handle->url) - 1] == '/')
394 handle->url[strlen (handle->url) - 1] = '\0';
395 GNUNET_CONTAINER_DLL_insert (requests_head,
396 requests_tail,
397 handle);
398 if (GNUNET_NO ==
399 GNUNET_REST_handle_request (conndata_handle, handlers, &err, handle))
400 {
401 cleanup_handle (handle);
402 return GNUNET_NO;
403 }
404 return GNUNET_YES;
405}
406
407
408/**
409 * Entry point for the plugin.
410 *
411 * @param cls the "struct GNUNET_NAMESTORE_PluginEnvironment*"
412 * @return NULL on error, otherwise the plugin context
413 */
414void *
415libgnunet_plugin_rest_config_init (void *cls)
416{
417 static struct Plugin plugin;
418
419 cfg = cls;
420 struct GNUNET_REST_Plugin *api;
421
422 memset (&plugin, 0, sizeof(struct Plugin));
423 plugin.cfg = cfg;
424 api = GNUNET_new (struct GNUNET_REST_Plugin);
425 api->cls = &plugin;
426 api->name = GNUNET_REST_API_NS_CONFIG;
427 api->process_request = &rest_config_process_request;
428 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("CONFIG REST API initialized\n"));
429 return api;
430}
431
432
433/**
434 * Exit point from the plugin.
435 *
436 * @param cls the plugin context (as returned by "init")
437 * @return always NULL
438 */
439void *
440libgnunet_plugin_rest_config_done (void *cls)
441{
442 struct GNUNET_REST_Plugin *api = cls;
443 struct Plugin *plugin;
444
445 while (NULL != requests_head)
446 cleanup_handle (requests_head);
447 plugin = api->cls;
448 plugin->cfg = NULL;
449 GNUNET_free (api);
450 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "CONFIG REST plugin is finished\n");
451 return NULL;
452}
453
454
455/* end of plugin_rest_config.c */