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.c456
1 files changed, 0 insertions, 456 deletions
diff --git a/src/rest/plugin_rest_config.c b/src/rest/plugin_rest_config.c
deleted file mode 100644
index b0f18754c..000000000
--- a/src/rest/plugin_rest_config.c
+++ /dev/null
@@ -1,456 +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 * @param tc scheduler context
117 */
118static void
119do_error (void *cls)
120{
121 struct RequestHandle *handle = cls;
122 struct MHD_Response *resp;
123
124 resp = GNUNET_REST_create_response (NULL);
125 handle->proc (handle->proc_cls, resp, handle->response_code);
126 cleanup_handle (handle);
127}
128
129
130static void
131add_sections (void *cls,
132 const char *section,
133 const char *option,
134 const char *value)
135{
136 json_t *sections_obj = cls;
137 json_t *sec_obj;
138
139 sec_obj = json_object_get (sections_obj, section);
140 if (NULL != sec_obj)
141 {
142 json_object_set_new (sec_obj, option, json_string (value));
143 return;
144 }
145 sec_obj = json_object ();
146 json_object_set_new (sec_obj, option, json_string (value));
147 json_object_set_new (sections_obj, section, sec_obj);
148}
149
150
151static void
152add_section_contents (void *cls,
153 const char *section,
154 const char *option,
155 const char *value)
156{
157 json_t *section_obj = cls;
158
159 json_object_set_new (section_obj, option, json_string (value));
160}
161
162
163/**
164 * Handle rest request
165 *
166 * @param handle the lookup handle
167 */
168static void
169get_cont (struct GNUNET_REST_RequestHandle *con_handle,
170 const char *url,
171 void *cls)
172{
173 struct MHD_Response *resp;
174 struct RequestHandle *handle = cls;
175 const char *section;
176 char *response;
177 json_t *result;
178
179 if (strlen (GNUNET_REST_API_NS_CONFIG) > strlen (handle->url))
180 {
181 handle->response_code = MHD_HTTP_BAD_REQUEST;
182 GNUNET_SCHEDULER_add_now (&do_error, handle);
183 return;
184 }
185 if (strlen (GNUNET_REST_API_NS_CONFIG) == strlen (handle->url))
186 {
187 result = json_object ();
188 GNUNET_CONFIGURATION_iterate (cfg, &add_sections, result);
189 }
190 else
191 {
192 result = json_object ();
193 section = &handle->url[strlen (GNUNET_REST_API_NS_CONFIG) + 1];
194 GNUNET_CONFIGURATION_iterate_section_values (cfg,
195 section,
196 &add_section_contents,
197 result);
198 }
199 response = json_dumps (result, 0);
200 resp = GNUNET_REST_create_response (response);
201 GNUNET_assert (MHD_NO != MHD_add_response_header (resp,
202 "Content-Type",
203 "application/json"));
204 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
205 cleanup_handle (handle);
206 GNUNET_free (response);
207 json_decref (result);
208}
209
210
211struct GNUNET_CONFIGURATION_Handle *
212set_value (struct GNUNET_CONFIGURATION_Handle *config,
213 const char *section,
214 const char *option,
215 json_t *value)
216{
217 if (json_is_string (value))
218 GNUNET_CONFIGURATION_set_value_string (config, section, option,
219 json_string_value (value));
220 else if (json_is_number (value))
221 GNUNET_CONFIGURATION_set_value_number (config, section, option,
222 json_integer_value (value));
223 else if (json_is_null (value))
224 GNUNET_CONFIGURATION_set_value_string (config, section, option, NULL);
225 else if (json_is_true (value))
226 GNUNET_CONFIGURATION_set_value_string (config, section, option, "yes");
227 else if (json_is_false (value))
228 GNUNET_CONFIGURATION_set_value_string (config, section, option, "no");
229 else
230 return NULL;
231 return config; // for error handling (0 -> success, 1 -> error)
232}
233
234
235/**
236 * Handle REST POST request
237 *
238 * @param handle the lookup handle
239 */
240static void
241set_cont (struct GNUNET_REST_RequestHandle *con_handle,
242 const char *url,
243 void *cls)
244{
245 struct RequestHandle *handle = cls;
246 char term_data[handle->rest_handle->data_size + 1];
247 struct GNUNET_CONFIGURATION_Handle *out = GNUNET_CONFIGURATION_dup (cfg);
248
249 json_error_t err;
250 json_t *data_json;
251 const char *section;
252 const char *option;
253 json_t *sec_obj;
254 json_t *value;
255 char *cfg_fn;
256
257 // invalid url
258 if (strlen (GNUNET_REST_API_NS_CONFIG) > strlen (handle->url))
259 {
260 handle->response_code = MHD_HTTP_BAD_REQUEST;
261 GNUNET_SCHEDULER_add_now (&do_error, handle);
262 return;
263 }
264
265 // extract data from handle
266 term_data[handle->rest_handle->data_size] = '\0';
267 GNUNET_memcpy (term_data,
268 handle->rest_handle->data,
269 handle->rest_handle->data_size);
270 data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
271
272 if (NULL == data_json)
273 {
274 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
275 "Unable to parse JSON Object from %s\n",
276 term_data);
277 GNUNET_SCHEDULER_add_now (&do_error, handle);
278 return;
279 }
280
281 // POST /config => {<section> : {<option> : <value>}}
282 if (strlen (GNUNET_REST_API_NS_CONFIG) == strlen (handle->url)) // POST /config
283 {
284 // iterate over sections
285 json_object_foreach (data_json, section, sec_obj)
286 {
287 // iterate over options
288 json_object_foreach (sec_obj, option, value)
289 {
290 out = set_value (out, section, option, value);
291 if (NULL == out)
292 {
293 handle->response_code = MHD_HTTP_BAD_REQUEST;
294 GNUNET_SCHEDULER_add_now (&do_error, handle);
295 json_decref (data_json);
296 return;
297 }
298 }
299 }
300 }
301 else // POST /config/<section> => {<option> : <value>}
302 {
303 // extract the "<section>" part from the url
304 section = &handle->url[strlen (GNUNET_REST_API_NS_CONFIG) + 1];
305 // iterate over options
306 json_object_foreach (data_json, option, value)
307 {
308 out = set_value (out, section, option, value);
309 if (NULL == out)
310 {
311 handle->response_code = MHD_HTTP_BAD_REQUEST;
312 GNUNET_SCHEDULER_add_now (&do_error, handle);
313 json_decref (data_json);
314 return;
315 }
316 }
317 }
318 json_decref (data_json);
319
320
321 // get cfg file path
322 cfg_fn = NULL;
323 const char *xdg = getenv ("XDG_CONFIG_HOME");
324 if (NULL != xdg)
325 GNUNET_asprintf (&cfg_fn,
326 "%s%s%s",
327 xdg,
328 DIR_SEPARATOR_STR,
329 GNUNET_OS_project_data_get ()->config_file);
330 else
331 cfg_fn = GNUNET_strdup (GNUNET_OS_project_data_get ()->user_config_file);
332
333 GNUNET_CONFIGURATION_write (out, cfg_fn);
334 cfg = out;
335 handle->proc (handle->proc_cls,
336 GNUNET_REST_create_response (NULL),
337 MHD_HTTP_OK);
338 GNUNET_free (cfg_fn);
339 cleanup_handle (handle);
340}
341
342
343/**
344 * Handle rest request
345 *
346 * @param handle the lookup handle
347 */
348static void
349options_cont (struct GNUNET_REST_RequestHandle *con_handle,
350 const char *url,
351 void *cls)
352{
353 struct MHD_Response *resp;
354 struct RequestHandle *handle = cls;
355
356 resp = GNUNET_REST_create_response (NULL);
357 GNUNET_assert (MHD_NO != MHD_add_response_header (resp,
358 "Access-Control-Allow-Methods",
359 MHD_HTTP_METHOD_GET));
360 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
361 cleanup_handle (handle);
362}
363
364
365/**
366 * Function processing the REST call
367 *
368 * @param method HTTP method
369 * @param url URL of the HTTP request
370 * @param data body of the HTTP request (optional)
371 * @param data_size length of the body
372 * @param proc callback function for the result
373 * @param proc_cls closure for @a proc
374 * @return #GNUNET_OK if request accepted
375 */
376static enum GNUNET_GenericReturnValue
377rest_config_process_request (struct GNUNET_REST_RequestHandle *conndata_handle,
378 GNUNET_REST_ResultProcessor proc,
379 void *proc_cls)
380{
381 static const struct GNUNET_REST_RequestHandler handlers[] = {
382 { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_CONFIG, &get_cont },
383 { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_CONFIG, &set_cont },
384 { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_CONFIG, &options_cont },
385 GNUNET_REST_HANDLER_END
386 };
387 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
388 struct GNUNET_REST_RequestHandlerError err;
389
390 handle->proc_cls = proc_cls;
391 handle->proc = proc;
392 handle->rest_handle = conndata_handle;
393 handle->url = GNUNET_strdup (conndata_handle->url);
394 if (handle->url[strlen (handle->url) - 1] == '/')
395 handle->url[strlen (handle->url) - 1] = '\0';
396 GNUNET_CONTAINER_DLL_insert (requests_head,
397 requests_tail,
398 handle);
399 if (GNUNET_NO ==
400 GNUNET_REST_handle_request (conndata_handle, handlers, &err, handle))
401 {
402 cleanup_handle (handle);
403 return GNUNET_NO;
404 }
405 return GNUNET_YES;
406}
407
408
409/**
410 * Entry point for the plugin.
411 *
412 * @param cls the "struct GNUNET_NAMESTORE_PluginEnvironment*"
413 * @return NULL on error, otherwise the plugin context
414 */
415void *
416libgnunet_plugin_rest_config_init (void *cls)
417{
418 static struct Plugin plugin;
419
420 cfg = cls;
421 struct GNUNET_REST_Plugin *api;
422
423 memset (&plugin, 0, sizeof(struct Plugin));
424 plugin.cfg = cfg;
425 api = GNUNET_new (struct GNUNET_REST_Plugin);
426 api->cls = &plugin;
427 api->name = GNUNET_REST_API_NS_CONFIG;
428 api->process_request = &rest_config_process_request;
429 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("CONFIG REST API initialized\n"));
430 return api;
431}
432
433
434/**
435 * Exit point from the plugin.
436 *
437 * @param cls the plugin context (as returned by "init")
438 * @return always NULL
439 */
440void *
441libgnunet_plugin_rest_config_done (void *cls)
442{
443 struct GNUNET_REST_Plugin *api = cls;
444 struct Plugin *plugin;
445
446 while (NULL != requests_head)
447 cleanup_handle (requests_head);
448 plugin = api->cls;
449 plugin->cfg = NULL;
450 GNUNET_free (api);
451 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "CONFIG REST plugin is finished\n");
452 return NULL;
453}
454
455
456/* end of plugin_rest_config.c */