aboutsummaryrefslogtreecommitdiff
path: root/src/rest
diff options
context:
space:
mode:
Diffstat (limited to 'src/rest')
-rw-r--r--src/rest/.gitignore1
-rw-r--r--src/rest/Makefile.am68
-rw-r--r--src/rest/gnunet-rest-server.c1279
-rw-r--r--src/rest/plugin_rest_config.c456
-rw-r--r--src/rest/plugin_rest_copying.c238
-rw-r--r--src/rest/rest.c112
-rw-r--r--src/rest/rest.conf12
7 files changed, 0 insertions, 2166 deletions
diff --git a/src/rest/.gitignore b/src/rest/.gitignore
deleted file mode 100644
index 07e69218e..000000000
--- a/src/rest/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
1gnunet-rest-server
diff --git a/src/rest/Makefile.am b/src/rest/Makefile.am
deleted file mode 100644
index 41b4c6508..000000000
--- a/src/rest/Makefile.am
+++ /dev/null
@@ -1,68 +0,0 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include
3
4plugindir = $(libdir)/gnunet
5
6pkgcfgdir= $(pkgdatadir)/config.d/
7
8libexecdir= $(pkglibdir)/libexec/
9
10pkgcfg_DATA = \
11 rest.conf
12
13if USE_COVERAGE
14 AM_CFLAGS = --coverage -O0
15 XLIBS = -lgcov
16endif
17
18lib_LTLIBRARIES = \
19 libgnunetrest.la
20
21libexec_PROGRAMS = \
22 gnunet-rest-server
23
24plugin_LTLIBRARIES = \
25 libgnunet_plugin_rest_copying.la \
26 libgnunet_plugin_rest_config.la
27
28EXTRA_DIST = \
29 rest.conf
30
31libgnunet_plugin_rest_copying_la_SOURCES = \
32 plugin_rest_copying.c
33libgnunet_plugin_rest_copying_la_LIBADD = \
34 libgnunetrest.la \
35 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \
36 $(LTLIBINTL) $(MHD_LIBS)
37libgnunet_plugin_rest_copying_la_LDFLAGS = \
38 $(GN_PLUGIN_LDFLAGS)
39libgnunet_plugin_rest_copying_la_CFLAGS = $(MHD_CFLAGS) $(AM_CFLAGS)
40
41libgnunet_plugin_rest_config_la_SOURCES = \
42 plugin_rest_config.c
43libgnunet_plugin_rest_config_la_LIBADD = \
44 libgnunetrest.la \
45 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \
46 $(LTLIBINTL) $(MHD_LIBS) -ljansson
47libgnunet_plugin_rest_config_la_LDFLAGS = \
48 $(GN_PLUGIN_LDFLAGS)
49libgnunet_plugin_rest_config_la_CFLAGS = $(MHD_CFLAGS) $(AM_CFLAGS)
50
51
52
53gnunet_rest_server_SOURCES = \
54 gnunet-rest-server.c
55gnunet_rest_server_LDADD = \
56 $(top_builddir)/src/util/libgnunetutil.la \
57 $(GN_LIBINTL) $(MHD_LIBS)
58gnunet_rest_server_CFLAGS = $(MHD_CFLAGS) $(AM_CFLAGS)
59
60libgnunetrest_la_SOURCES = \
61 rest.c
62libgnunetrest_la_LIBADD = \
63 $(top_builddir)/src/util/libgnunetutil.la $(XLIB) \
64 $(GN_LIBINTL) $(MHD_LIBS)
65libgnunetrest_la_LDFLAGS = \
66 $(GN_LIB_LDFLAGS) \
67 -version-info 0:0:0
68libgnunetrest_la_CFLAGS = $(MHD_CFLAGS) $(AM_CFLAGS)
diff --git a/src/rest/gnunet-rest-server.c b/src/rest/gnunet-rest-server.c
deleted file mode 100644
index 63847587b..000000000
--- a/src/rest/gnunet-rest-server.c
+++ /dev/null
@@ -1,1279 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012-2015 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 src/rest/gnunet-rest-server.c
23 * @brief REST service for GNUnet services
24 *
25 */
26#include "platform.h"
27#include <microhttpd.h>
28#include "gnunet_util_lib.h"
29#include "gnunet_rest_plugin.h"
30#include "gnunet_mhd_compat.h"
31
32/**
33 * Default Socks5 listen port.
34 */
35#define GNUNET_REST_SERVICE_PORT 7776
36
37/**
38 * Maximum supported length for a URI.
39 * Should die. @deprecated
40 */
41#define MAX_HTTP_URI_LENGTH 2048
42
43/**
44 * Port for plaintext HTTP.
45 */
46#define HTTP_PORT 80
47
48/**
49 * Port for HTTPS.
50 */
51#define HTTPS_PORT 443
52
53/**
54 * After how long do we clean up unused MHD SSL/TLS instances?
55 */
56#define MHD_CACHE_TIMEOUT \
57 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
58
59#define GN_REST_STATE_INIT 0
60#define GN_REST_STATE_PROCESSING 1
61
62/**
63 * The task ID
64 */
65static struct GNUNET_SCHEDULER_Task *httpd_task;
66
67/**
68 * The address to bind to
69 */
70static in_addr_t address;
71
72/**
73 * The IPv6 address to bind to
74 */
75static struct in6_addr address6;
76
77/**
78 * The port the service is running on (default 7776)
79 */
80static unsigned long long port = GNUNET_REST_SERVICE_PORT;
81
82/**
83 * The listen socket of the service for IPv4
84 */
85static struct GNUNET_NETWORK_Handle *lsock4;
86
87/**
88 * The listen socket of the service for IPv6
89 */
90static struct GNUNET_NETWORK_Handle *lsock6;
91
92/**
93 * The listen task ID for IPv4
94 */
95static struct GNUNET_SCHEDULER_Task *ltask4;
96
97/**
98 * The listen task ID for IPv6
99 */
100static struct GNUNET_SCHEDULER_Task *ltask6;
101
102/**
103 * Daemon for HTTP
104 */
105static struct MHD_Daemon *httpd;
106
107/**
108 * Response we return on failures.
109 */
110static struct MHD_Response *failure_response;
111
112/**
113 * Our configuration.
114 */
115static const struct GNUNET_CONFIGURATION_Handle *cfg;
116
117/**
118 * Echo request Origin in CORS
119 */
120static int echo_origin;
121
122/**
123 * Allowed Origins (CORS)
124 */
125static char *allow_origins;
126
127/**
128 * Allowed Headers (CORS)
129 */
130static char *allow_headers;
131
132/**
133 * Allowed Credentials (CORS)
134 */
135static char *allow_credentials;
136
137/**
138 * Plugin list head
139 */
140static struct PluginListEntry *plugins_head;
141
142/**
143 * Plugin list tail
144 */
145static struct PluginListEntry *plugins_tail;
146
147/**
148 * A plugin list entry
149 */
150struct PluginListEntry
151{
152 /* DLL */
153 struct PluginListEntry *next;
154
155 /* DLL */
156 struct PluginListEntry *prev;
157
158 /**
159 * libname (to cleanup)
160 */
161 char *libname;
162
163 /**
164 * The plugin
165 */
166 struct GNUNET_REST_Plugin *plugin;
167};
168
169/**
170 * MHD Connection handle
171 */
172struct MhdConnectionHandle
173{
174 struct MHD_Connection *con;
175
176 struct MHD_Response *response;
177
178 struct GNUNET_REST_RequestHandle *data_handle;
179
180 struct MHD_PostProcessor *pp;
181
182 int status;
183
184 int state;
185};
186
187/**
188 * Accepted requests
189 */
190struct AcceptedRequest
191{
192 /**
193 * DLL
194 */
195 struct AcceptedRequest *next;
196
197 /**
198 * DLL
199 */
200 struct AcceptedRequest *prev;
201
202 /**
203 * Socket
204 */
205 struct GNUNET_NETWORK_Handle *sock;
206
207 /**
208 * Connection
209 */
210 struct MhdConnectionHandle *con_handle;
211
212 /**
213 * State
214 */
215 int socket_with_mhd;
216};
217
218/**
219 * AcceptedRequest list head
220 */
221static struct AcceptedRequest *req_list_head;
222
223/**
224 * AcceptedRequest list tail
225 */
226static struct AcceptedRequest *req_list_tail;
227
228/* ************************* Global helpers ********************* */
229
230
231/**
232 * Task run whenever HTTP server operations are pending.
233 *
234 * @param cls NULL
235 */
236static void
237do_httpd (void *cls);
238
239
240/**
241 * Run MHD now, we have extra data ready for the callback.
242 */
243static void
244run_mhd_now ()
245{
246 if (NULL != httpd_task)
247 {
248 GNUNET_SCHEDULER_cancel (httpd_task);
249 httpd_task = NULL;
250 }
251 httpd_task = GNUNET_SCHEDULER_add_now (&do_httpd, NULL);
252}
253
254
255/**
256 * Plugin result callback
257 *
258 * @param cls closure (MHD connection handle)
259 * @param data the data to return to the caller
260 * @param len length of the data
261 * @param status #GNUNET_OK if successful
262 */
263static void
264plugin_callback (void *cls, struct MHD_Response *resp, int status)
265{
266 struct MhdConnectionHandle *handle = cls;
267
268 handle->status = status;
269 handle->response = resp;
270 MHD_resume_connection (handle->con);
271 run_mhd_now ();
272}
273
274
275static int
276cleanup_url_map (void *cls, const struct GNUNET_HashCode *key, void *value)
277{
278 GNUNET_free (value);
279 return GNUNET_YES;
280}
281
282static void
283cleanup_handle (struct MhdConnectionHandle *handle)
284{
285 if (NULL != handle->response)
286 MHD_destroy_response (handle->response);
287 if (NULL != handle->data_handle)
288 {
289 if (NULL != handle->data_handle->header_param_map)
290 {
291 GNUNET_CONTAINER_multihashmap_iterate (handle->data_handle
292 ->header_param_map,
293 &cleanup_url_map,
294 NULL);
295 GNUNET_CONTAINER_multihashmap_destroy (
296 handle->data_handle->header_param_map);
297 }
298 if (NULL != handle->data_handle->url_param_map)
299 {
300 GNUNET_CONTAINER_multihashmap_iterate (handle->data_handle->url_param_map,
301 &cleanup_url_map,
302 NULL);
303 GNUNET_CONTAINER_multihashmap_destroy (
304 handle->data_handle->url_param_map);
305 }
306 GNUNET_free (handle->data_handle);
307 }
308 GNUNET_free (handle);
309}
310
311static void
312cleanup_ar (struct AcceptedRequest *ar)
313{
314 if (NULL != ar->con_handle)
315 {
316 cleanup_handle (ar->con_handle);
317 }
318 if (GNUNET_YES == ar->socket_with_mhd)
319 {
320 GNUNET_NETWORK_socket_free_memory_only_ (ar->sock);
321 } else {
322 GNUNET_NETWORK_socket_close (ar->sock);
323 }
324 ar->sock = NULL;
325 GNUNET_CONTAINER_DLL_remove (req_list_head,
326 req_list_tail,
327 ar);
328 GNUNET_free (ar);
329}
330
331static int
332header_iterator (void *cls,
333 enum MHD_ValueKind kind,
334 const char *key,
335 const char *value)
336{
337 struct GNUNET_REST_RequestHandle *handle = cls;
338 struct GNUNET_HashCode hkey;
339 char *val;
340 char *lowerkey;
341
342 lowerkey = GNUNET_strdup (key);
343 GNUNET_STRINGS_utf8_tolower (key, lowerkey);
344 GNUNET_CRYPTO_hash (lowerkey, strlen (lowerkey), &hkey);
345 GNUNET_asprintf (&val, "%s", value);
346 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (
347 handle->header_param_map,
348 &hkey,
349 val,
350 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
351 {
352 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
353 "Could not load add header `%s'=%s\n",
354 lowerkey,
355 value);
356 }
357 GNUNET_free (lowerkey);
358 return MHD_YES;
359}
360
361
362static int
363url_iterator (void *cls,
364 enum MHD_ValueKind kind,
365 const char *key,
366 const char *value)
367{
368 struct GNUNET_REST_RequestHandle *handle = cls;
369 struct GNUNET_HashCode hkey;
370 char *val;
371
372 GNUNET_CRYPTO_hash (key, strlen (key), &hkey);
373 GNUNET_asprintf (&val, "%s", value);
374 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (
375 handle->url_param_map,
376 &hkey,
377 val,
378 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
379 {
380 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
381 "Could not load add url param `%s'=%s\n",
382 key,
383 value);
384 }
385 return MHD_YES;
386}
387
388
389static MHD_RESULT
390post_data_iter (void *cls,
391 enum MHD_ValueKind kind,
392 const char *key,
393 const char *filename,
394 const char *content_type,
395 const char *transfer_encoding,
396 const char *data,
397 uint64_t off,
398 size_t size)
399{
400 struct GNUNET_REST_RequestHandle *handle = cls;
401 struct GNUNET_HashCode hkey;
402 char *val;
403
404 if (MHD_POSTDATA_KIND != kind)
405 return MHD_YES;
406
407 GNUNET_CRYPTO_hash (key, strlen (key), &hkey);
408 val = GNUNET_CONTAINER_multihashmap_get (handle->url_param_map,
409 &hkey);
410 if (NULL == val)
411 {
412 val = GNUNET_malloc (65536);
413 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (
414 handle->url_param_map,
415 &hkey,
416 val,
417 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
418 {
419 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
420 "Could not add url param '%s'\n",
421 key);
422 GNUNET_free (val);
423 }
424 }
425 memcpy (val + off, data, size);
426 return MHD_YES;
427}
428
429
430/* ********************************* MHD response generation ******************* */
431
432/**
433 * Main MHD callback for handling requests.
434 *
435 * @param cls unused
436 * @param con MHD connection handle
437 * @param url the url in the request
438 * @param meth the HTTP method used ("GET", "PUT", etc.)
439 * @param ver the HTTP version string ("HTTP/1.1" for version 1.1, etc.)
440 * @param upload_data the data being uploaded (excluding HEADERS,
441 * for a POST that fits into memory and that is encoded
442 * with a supported encoding, the POST data will NOT be
443 * given in upload_data and is instead available as
444 * part of MHD_get_connection_values; very large POST
445 * data *will* be made available incrementally in
446 * upload_data)
447 * @param upload_data_size set initially to the size of the
448 * @a upload_data provided; the method must update this
449 * value to the number of bytes NOT processed;
450 * @param con_cls pointer to location where we store the 'struct Request'
451 * @return #MHD_YES if the connection was handled successfully,
452 * #MHD_NO if the socket must be closed due to a serious
453 * error while handling the request
454 */
455static MHD_RESULT
456create_response (void *cls,
457 struct MHD_Connection *con,
458 const char *url,
459 const char *meth,
460 const char *ver,
461 const char *upload_data,
462 size_t *upload_data_size,
463 void **con_cls)
464{
465 char *origin;
466 struct AcceptedRequest *ar;
467 struct GNUNET_HashCode key;
468 struct MhdConnectionHandle *con_handle;
469 struct GNUNET_REST_RequestHandle *rest_conndata_handle;
470 struct PluginListEntry *ple;
471
472 ar = *con_cls;
473 if (NULL == ar)
474 {
475 GNUNET_break (0);
476 return MHD_NO;
477 }
478
479 if (NULL == ar->con_handle)
480 {
481 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "New connection %s\n", url);
482 con_handle = GNUNET_new (struct MhdConnectionHandle);
483 con_handle->con = con;
484 con_handle->state = GN_REST_STATE_INIT;
485 ar->con_handle = con_handle;
486 return MHD_YES;
487 }
488 con_handle = ar->con_handle;
489 if (GN_REST_STATE_INIT == con_handle->state)
490 {
491 rest_conndata_handle = GNUNET_new (struct GNUNET_REST_RequestHandle);
492 rest_conndata_handle->method = meth;
493 rest_conndata_handle->url = url;
494 rest_conndata_handle->data = upload_data;
495 rest_conndata_handle->data_size = *upload_data_size;
496 rest_conndata_handle->url_param_map =
497 GNUNET_CONTAINER_multihashmap_create (16, GNUNET_NO);
498 rest_conndata_handle->header_param_map =
499 GNUNET_CONTAINER_multihashmap_create (16, GNUNET_NO);
500 con_handle->data_handle = rest_conndata_handle;
501 MHD_get_connection_values (con,
502 MHD_GET_ARGUMENT_KIND,
503 (MHD_KeyValueIterator) & url_iterator,
504 rest_conndata_handle);
505 MHD_get_connection_values (con,
506 MHD_HEADER_KIND,
507 (MHD_KeyValueIterator) & header_iterator,
508 rest_conndata_handle);
509
510 con_handle->pp = MHD_create_post_processor (con,
511 65536,
512 &post_data_iter,
513 rest_conndata_handle);
514 if (*upload_data_size)
515 {
516 MHD_post_process (con_handle->pp, upload_data, *upload_data_size);
517 }
518 MHD_destroy_post_processor (con_handle->pp);
519
520 con_handle->state = GN_REST_STATE_PROCESSING;
521 for (ple = plugins_head; NULL != ple; ple = ple->next)
522 {
523 if (GNUNET_YES == ple->plugin->process_request (rest_conndata_handle,
524 &plugin_callback,
525 con_handle))
526 break; /* Request handled */
527 }
528 if (NULL == ple)
529 {
530 /** Request not handled **/
531 MHD_queue_response (con, MHD_HTTP_NOT_FOUND, failure_response);
532 }
533 *upload_data_size = 0;
534 run_mhd_now ();
535 return MHD_YES;
536 }
537 if (NULL == con_handle->response)
538 {
539 // Suspend connection until plugin is done
540 MHD_suspend_connection (con_handle->con);
541 return MHD_YES;
542 }
543 //MHD_resume_connection (con_handle->con);
544 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
545 "Queueing response from plugin with MHD\n");
546 // Handle Preflights for extensions
547 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Checking origin\n");
548 GNUNET_CRYPTO_hash ("origin", strlen ("origin"), &key);
549 origin = GNUNET_CONTAINER_multihashmap_get (con_handle->data_handle
550 ->header_param_map,
551 &key);
552 if (NULL != origin)
553 {
554 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Origin: %s\n", origin);
555 // Only echo for browser plugins
556 if (GNUNET_YES == echo_origin)
557 {
558 if ((0 ==
559 strncmp ("moz-extension://", origin, strlen ("moz-extension://"))) ||
560 (0 == strncmp ("chrome-extension://",
561 origin,
562 strlen ("chrome-extension://"))))
563 {
564 MHD_add_response_header (con_handle->response,
565 MHD_HTTP_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN,
566 origin);
567 }
568 }
569 if (NULL != allow_origins)
570 {
571 char *tmp = GNUNET_strdup (allow_origins);
572 char *allow_origin = strtok (tmp, ",");
573 while (NULL != allow_origin)
574 {
575 if (0 == strncmp (allow_origin, origin, strlen (allow_origin)))
576 {
577 MHD_add_response_header (con_handle->response,
578 MHD_HTTP_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN,
579 allow_origin);
580 break;
581 }
582 allow_origin = strtok (NULL, ",");
583 }
584 GNUNET_free (tmp);
585 }
586 }
587 if (NULL != allow_credentials)
588 {
589 MHD_add_response_header (con_handle->response,
590 "Access-Control-Allow-Credentials",
591 allow_credentials);
592 }
593 if (NULL != allow_headers)
594 {
595 MHD_add_response_header (con_handle->response,
596 "Access-Control-Allow-Headers",
597 allow_headers);
598 }
599 run_mhd_now ();
600 {
601 MHD_RESULT ret = MHD_queue_response (con,
602 con_handle->status,
603 con_handle->response);
604 //cleanup_handle (con_handle);
605 return ret;
606 }
607}
608
609
610/* ******************** MHD HTTP setup and event loop ******************** */
611
612
613/**
614 * Kill the MHD daemon.
615 */
616static void
617kill_httpd ()
618{
619 if (NULL != httpd)
620 {
621 MHD_stop_daemon (httpd);
622 httpd = NULL;
623 }
624 if (NULL != httpd_task)
625 {
626 GNUNET_SCHEDULER_cancel (httpd_task);
627 httpd_task = NULL;
628 }
629 if (NULL != ltask4)
630 {
631 GNUNET_SCHEDULER_cancel (ltask4);
632 ltask4 = NULL;
633 }
634 if (NULL != ltask6)
635 {
636 GNUNET_SCHEDULER_cancel (ltask6);
637 ltask6 = NULL;
638 }
639
640 if (NULL != lsock4)
641 {
642 GNUNET_NETWORK_socket_close (lsock4);
643 lsock4 = NULL;
644 }
645 if (NULL != lsock6)
646 {
647 GNUNET_NETWORK_socket_close (lsock6);
648 lsock6 = NULL;
649 }
650}
651
652
653/**
654 * Schedule MHD. This function should be called initially when an
655 * MHD is first getting its client socket, and will then automatically
656 * always be called later whenever there is work to be done.
657 *
658 * @param hd the daemon to schedule
659 */
660static void
661schedule_httpd ()
662{
663 fd_set rs;
664 fd_set ws;
665 fd_set es;
666 struct GNUNET_NETWORK_FDSet *wrs;
667 struct GNUNET_NETWORK_FDSet *wws;
668 int max;
669 int haveto;
670 MHD_UNSIGNED_LONG_LONG timeout;
671 struct GNUNET_TIME_Relative tv;
672
673 FD_ZERO (&rs);
674 FD_ZERO (&ws);
675 FD_ZERO (&es);
676 max = -1;
677 if (MHD_YES != MHD_get_fdset (httpd, &rs, &ws, &es, &max))
678 {
679 kill_httpd ();
680 return;
681 }
682 haveto = MHD_get_timeout (httpd, &timeout);
683 if (MHD_YES == haveto)
684 tv.rel_value_us = (uint64_t) timeout * 1000LL;
685 else
686 tv = GNUNET_TIME_UNIT_FOREVER_REL;
687 if (-1 != max)
688 {
689 wrs = GNUNET_NETWORK_fdset_create ();
690 wws = GNUNET_NETWORK_fdset_create ();
691 GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1);
692 GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1);
693 }
694 else
695 {
696 wrs = NULL;
697 wws = NULL;
698 }
699 if (NULL != httpd_task)
700 {
701 GNUNET_SCHEDULER_cancel (httpd_task);
702 httpd_task = NULL;
703 }
704 if ((MHD_YES == haveto) || (-1 != max))
705 {
706 httpd_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
707 tv,
708 wrs,
709 wws,
710 &do_httpd,
711 NULL);
712 }
713 if (NULL != wrs)
714 GNUNET_NETWORK_fdset_destroy (wrs);
715 if (NULL != wws)
716 GNUNET_NETWORK_fdset_destroy (wws);
717}
718
719/**
720 * Function called when MHD first processes an incoming connection.
721 * Gives us the respective URI information.
722 *
723 * We use this to associate the `struct MHD_Connection` with our
724 * internal `struct AcceptedRequest` data structure (by checking
725 * for matching sockets).
726 *
727 * @param cls the HTTP server handle (a `struct MhdHttpList`)
728 * @param url the URL that is being requested
729 * @param connection MHD connection object for the request
730 * @return the `struct Socks5Request` that this @a connection is for
731 */
732static void *
733mhd_log_callback (void *cls,
734 const char *url,
735 struct MHD_Connection *connection)
736{
737 struct AcceptedRequest *ar;
738 const union MHD_ConnectionInfo *ci;
739
740 ci = MHD_get_connection_info (connection,
741 MHD_CONNECTION_INFO_SOCKET_CONTEXT);
742 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Processing %s\n", url);
743 if (NULL == ci)
744 {
745 GNUNET_break (0);
746 return NULL;
747 }
748 ar = ci->socket_context;
749 return ar;
750}
751
752
753
754/**
755 * Function called when MHD decides that we are done with a connection.
756 *
757 * @param cls NULL
758 * @param connection connection handle
759 * @param con_cls value as set by the last call to
760 * the MHD_AccessHandlerCallback, should be our handle
761 * @param toe reason for request termination (ignored)
762 */
763static void
764mhd_completed_cb (void *cls,
765 struct MHD_Connection *connection,
766 void **con_cls,
767 enum MHD_RequestTerminationCode toe)
768{
769 struct AcceptedRequest *ar = *con_cls;
770 if (MHD_REQUEST_TERMINATED_COMPLETED_OK != toe)
771 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
772 "MHD encountered error handling request: %d\n",
773 toe);
774 if (NULL == ar)
775 return;
776 if (NULL != ar->con_handle)
777 {
778 cleanup_handle (ar->con_handle);
779 ar->con_handle = NULL;
780 }
781 ar->socket_with_mhd = GNUNET_YES;
782 *con_cls = NULL;
783}
784
785/**
786 * Function called when MHD connection is opened or closed.
787 *
788 * @param cls NULL
789 * @param connection connection handle
790 * @param con_cls value as set by the last call to
791 * the MHD_AccessHandlerCallback, should be our `struct Socks5Request *`
792 * @param toe connection notification type
793 */
794static void
795mhd_connection_cb (void *cls,
796 struct MHD_Connection *connection,
797 void **con_cls,
798 enum MHD_ConnectionNotificationCode cnc)
799{
800 struct AcceptedRequest *ar;
801 const union MHD_ConnectionInfo *ci;
802 int sock;
803
804 switch (cnc)
805 {
806 case MHD_CONNECTION_NOTIFY_STARTED:
807 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connection started...\n");
808 ci = MHD_get_connection_info (connection,
809 MHD_CONNECTION_INFO_CONNECTION_FD);
810 if (NULL == ci)
811 {
812 GNUNET_break (0);
813 return;
814 }
815 sock = ci->connect_fd;
816 for (ar = req_list_head; NULL != ar; ar = ar->next)
817 {
818 if (GNUNET_NETWORK_get_fd (ar->sock) == sock)
819 {
820 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
821 "Context set...\n");
822 *con_cls = ar;
823 break;
824 }
825 }
826 break;
827
828 case MHD_CONNECTION_NOTIFY_CLOSED:
829 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
830 "Connection closed... cleaning up\n");
831 ar = *con_cls;
832 if (NULL == ar)
833 {
834 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
835 "Connection stale!\n");
836 return;
837 }
838 cleanup_ar (ar);
839 *con_cls = NULL;
840 break;
841
842 default:
843 GNUNET_break (0);
844 }
845}
846
847
848
849/**
850 * Task run whenever HTTP server operations are pending.
851 *
852 * @param cls NULL
853 */
854static void
855do_httpd (void *cls)
856{
857 httpd_task = NULL;
858 MHD_run (httpd);
859 schedule_httpd ();
860}
861
862
863/**
864 * Accept new incoming connections
865 *
866 * @param cls the closure with the lsock4 or lsock6
867 * @param tc the scheduler context
868 */
869static void
870do_accept (void *cls)
871{
872 struct GNUNET_NETWORK_Handle *lsock = cls;
873 struct AcceptedRequest *ar;
874 int fd;
875 const struct sockaddr *addr;
876 socklen_t len;
877
878 GNUNET_assert (NULL != lsock);
879 if (lsock == lsock4)
880 {
881 ltask4 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
882 lsock,
883 &do_accept,
884 lsock);
885 }
886 else if (lsock == lsock6)
887 {
888 ltask6 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
889 lsock,
890 &do_accept,
891 lsock);
892 }
893 else
894 GNUNET_assert (0);
895 ar = GNUNET_new (struct AcceptedRequest);
896 ar->socket_with_mhd = GNUNET_YES;
897 ar->sock = GNUNET_NETWORK_socket_accept (lsock, NULL, NULL);
898 if (NULL == ar->sock)
899 {
900 GNUNET_free (ar);
901 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "accept");
902 return;
903 }
904 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
905 "Got an inbound connection, waiting for data\n");
906 fd = GNUNET_NETWORK_get_fd (ar->sock);
907 addr = GNUNET_NETWORK_get_addr (ar->sock);
908 len = GNUNET_NETWORK_get_addrlen (ar->sock);
909 GNUNET_CONTAINER_DLL_insert (req_list_head,
910 req_list_tail,
911 ar);
912 if (MHD_YES != MHD_add_connection (httpd, fd, addr, len))
913 {
914 GNUNET_NETWORK_socket_close (ar->sock);
915 GNUNET_free (ar);
916 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
917 _ ("Failed to pass client to MHD\n"));
918 return;
919 }
920 schedule_httpd ();
921}
922
923
924/**
925 * Task run on shutdown
926 *
927 * @param cls closure
928 */
929static void
930do_shutdown (void *cls)
931{
932 struct PluginListEntry *ple;
933
934 while (NULL != plugins_head)
935 {
936 ple = plugins_head;
937 GNUNET_CONTAINER_DLL_remove (plugins_head,
938 plugins_tail,
939 ple);
940 GNUNET_PLUGIN_unload (ple->libname, ple->plugin);
941 GNUNET_free (ple->libname);
942 GNUNET_free (ple);
943 }
944 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Shutting down...\n");
945 kill_httpd ();
946 GNUNET_free (allow_credentials);
947 GNUNET_free (allow_headers);
948}
949
950
951/**
952 * Create an IPv4 listen socket bound to our port.
953 *
954 * @return NULL on error
955 */
956static struct GNUNET_NETWORK_Handle *
957bind_v4 ()
958{
959 struct GNUNET_NETWORK_Handle *ls;
960 struct sockaddr_in sa4;
961 int eno;
962
963 memset (&sa4, 0, sizeof(sa4));
964 sa4.sin_family = AF_INET;
965 sa4.sin_port = htons (port);
966 sa4.sin_addr.s_addr = address;
967#if HAVE_SOCKADDR_IN_SIN_LEN
968 sa4.sin_len = sizeof(sa4);
969#endif
970 ls = GNUNET_NETWORK_socket_create (AF_INET, SOCK_STREAM, 0);
971 if (NULL == ls)
972 return NULL;
973 if (GNUNET_OK != GNUNET_NETWORK_socket_bind (ls,
974 (const struct sockaddr *) &sa4,
975 sizeof(sa4)))
976 {
977 eno = errno;
978 GNUNET_NETWORK_socket_close (ls);
979 errno = eno;
980 return NULL;
981 }
982 return ls;
983}
984
985
986/**
987 * Create an IPv6 listen socket bound to our port.
988 *
989 * @return NULL on error
990 */
991static struct GNUNET_NETWORK_Handle *
992bind_v6 ()
993{
994 struct GNUNET_NETWORK_Handle *ls;
995 struct sockaddr_in6 sa6;
996 int eno;
997
998 memset (&sa6, 0, sizeof(sa6));
999 sa6.sin6_family = AF_INET6;
1000 sa6.sin6_port = htons (port);
1001 sa6.sin6_addr = address6;
1002#if HAVE_SOCKADDR_IN_SIN_LEN
1003 sa6.sin6_len = sizeof(sa6);
1004#endif
1005 ls = GNUNET_NETWORK_socket_create (AF_INET6, SOCK_STREAM, 0);
1006 if (NULL == ls)
1007 return NULL;
1008 if (GNUNET_OK != GNUNET_NETWORK_socket_bind (ls,
1009 (const struct sockaddr *) &sa6,
1010 sizeof(sa6)))
1011 {
1012 eno = errno;
1013 GNUNET_NETWORK_socket_close (ls);
1014 errno = eno;
1015 return NULL;
1016 }
1017 return ls;
1018}
1019
1020
1021/**
1022 * Callback for plugin load
1023 *
1024 * @param cls NULL
1025 * @param libname the name of the library loaded
1026 * @param lib_ret the object returned by the plugin initializer
1027 */
1028static void
1029load_plugin (void *cls, const char *libname, void *lib_ret)
1030{
1031 struct GNUNET_REST_Plugin *plugin = lib_ret;
1032 struct PluginListEntry *ple;
1033
1034 if (NULL == lib_ret)
1035 {
1036 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1037 "Could not load plugin `%s'\n",
1038 libname);
1039 return;
1040 }
1041 GNUNET_assert (1 < strlen (plugin->name));
1042 GNUNET_assert ('/' == *plugin->name);
1043 ple = GNUNET_new (struct PluginListEntry);
1044 ple->libname = GNUNET_strdup (libname);
1045 ple->plugin = plugin;
1046 GNUNET_CONTAINER_DLL_insert (plugins_head,
1047 plugins_tail,
1048 ple);
1049 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Loaded plugin `%s'\n", libname);
1050}
1051
1052
1053/**
1054 * Main function that will be run
1055 *
1056 * @param cls closure
1057 * @param args remaining command-line arguments
1058 * @param cfgfile name of the configuration file used (for saving, can be NULL)
1059 * @param c configuration
1060 */
1061static void
1062run (void *cls,
1063 char *const *args,
1064 const char *cfgfile,
1065 const struct GNUNET_CONFIGURATION_Handle *c)
1066{
1067 char *addr_str;
1068
1069 cfg = c;
1070 plugins_head = NULL;
1071 plugins_tail = NULL;
1072 /* Get port to bind to */
1073 if (GNUNET_OK !=
1074 GNUNET_CONFIGURATION_get_value_number (cfg, "rest", "HTTP_PORT", &port))
1075 {
1076 // No address specified
1077 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Using default port...\n");
1078 port = GNUNET_REST_SERVICE_PORT;
1079 }
1080
1081 /* Get address to bind to */
1082 if (GNUNET_OK !=
1083 GNUNET_CONFIGURATION_get_value_string (cfg, "rest", "BIND_TO", &addr_str))
1084 {
1085 // No address specified
1086 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Don't know what to bind to...\n");
1087 GNUNET_SCHEDULER_shutdown ();
1088 return;
1089 }
1090 if (1 != inet_pton (AF_INET, addr_str, &address))
1091 {
1092 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1093 "Unable to parse address %s\n",
1094 addr_str);
1095 GNUNET_free (addr_str);
1096 GNUNET_SCHEDULER_shutdown ();
1097 return;
1098 }
1099 GNUNET_free (addr_str);
1100 /* Get address to bind to */
1101 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg,
1102 "rest",
1103 "BIND_TO6",
1104 &addr_str))
1105 {
1106 // No address specified
1107 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Don't know what to bind6 to...\n");
1108 GNUNET_SCHEDULER_shutdown ();
1109 return;
1110 }
1111 if (1 != inet_pton (AF_INET6, addr_str, &address6))
1112 {
1113 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1114 "Unable to parse IPv6 address %s\n",
1115 addr_str);
1116 GNUNET_free (addr_str);
1117 GNUNET_SCHEDULER_shutdown ();
1118 return;
1119 }
1120 GNUNET_free (addr_str);
1121
1122
1123 /* Get CORS data from cfg */
1124 echo_origin =
1125 GNUNET_CONFIGURATION_get_value_yesno (cfg,
1126 "rest",
1127 "REST_ECHO_ORIGIN_WEBEXT");
1128 allow_origins = NULL;
1129 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg,
1130 "rest",
1131 "REST_ALLOW_ORIGIN",
1132 &allow_origins))
1133 {
1134 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1135 "No CORS Access-Control-Allow-Origin header will be sent...\n");
1136 }
1137 if (GNUNET_OK !=
1138 GNUNET_CONFIGURATION_get_value_string (cfg,
1139 "rest",
1140 "REST_ALLOW_CREDENTIALS",
1141 &allow_credentials))
1142 {
1143 // No origin specified
1144 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1145 "No CORS Credential Header will be sent...\n");
1146 }
1147
1148 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg,
1149 "rest",
1150 "REST_ALLOW_HEADERS",
1151 &allow_headers))
1152 {
1153 // No origin specified
1154 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1155 "No CORS Access-Control-Allow-Headers Header will be sent...\n");
1156 }
1157
1158 /* Open listen socket proxy */
1159 lsock6 = bind_v6 ();
1160 if (NULL == lsock6)
1161 {
1162 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind");
1163 }
1164 else
1165 {
1166 if (GNUNET_OK != GNUNET_NETWORK_socket_listen (lsock6, 5))
1167 {
1168 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "listen");
1169 GNUNET_NETWORK_socket_close (lsock6);
1170 lsock6 = NULL;
1171 }
1172 else
1173 {
1174 ltask6 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
1175 lsock6,
1176 &do_accept,
1177 lsock6);
1178 }
1179 }
1180 lsock4 = bind_v4 ();
1181 if (NULL == lsock4)
1182 {
1183 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind");
1184 }
1185 else
1186 {
1187 if (GNUNET_OK != GNUNET_NETWORK_socket_listen (lsock4, 5))
1188 {
1189 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "listen");
1190 GNUNET_NETWORK_socket_close (lsock4);
1191 lsock4 = NULL;
1192 }
1193 else
1194 {
1195 ltask4 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
1196 lsock4,
1197 &do_accept,
1198 lsock4);
1199 }
1200 }
1201 if ((NULL == lsock4) && (NULL == lsock6))
1202 {
1203 GNUNET_SCHEDULER_shutdown ();
1204 return;
1205 }
1206 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Service listens on port %llu\n", port);
1207 httpd = MHD_start_daemon (MHD_USE_DEBUG | MHD_USE_NO_LISTEN_SOCKET
1208 | MHD_ALLOW_SUSPEND_RESUME,
1209 0,
1210 NULL,
1211 NULL,
1212 &create_response,
1213 NULL,
1214 MHD_OPTION_CONNECTION_TIMEOUT,
1215 (unsigned int) 16,
1216 MHD_OPTION_NOTIFY_CONNECTION,
1217 &mhd_connection_cb,
1218 NULL,
1219 MHD_OPTION_URI_LOG_CALLBACK,
1220 mhd_log_callback,
1221 NULL,
1222 MHD_OPTION_NOTIFY_COMPLETED,
1223 &mhd_completed_cb,
1224 NULL,
1225 MHD_OPTION_END);
1226 if (NULL == httpd)
1227 {
1228 GNUNET_SCHEDULER_shutdown ();
1229 return;
1230 }
1231 /* Load plugins */
1232 GNUNET_PLUGIN_load_all_in_context (GNUNET_OS_project_data_default (),
1233 "libgnunet_plugin_rest",
1234 (void *) cfg,
1235 &load_plugin,
1236 NULL);
1237 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
1238}
1239
1240
1241/**
1242 *
1243 * The main function for gnunet-rest-service
1244 *
1245 * @param argc number of arguments from the cli
1246 * @param argv command line arguments
1247 * @return 0 ok, 1 on error
1248 *
1249 */
1250int
1251main (int argc, char *const *argv)
1252{
1253 struct GNUNET_GETOPT_CommandLineOption options[] =
1254 { GNUNET_GETOPT_OPTION_END };
1255 static const char *err_page = "{}";
1256 int ret;
1257
1258 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
1259 return 2;
1260 GNUNET_log_setup ("gnunet-rest-server", "WARNING", NULL);
1261 failure_response = MHD_create_response_from_buffer (strlen (err_page),
1262 (void *) err_page,
1263 MHD_RESPMEM_PERSISTENT);
1264 ret = (GNUNET_OK == GNUNET_PROGRAM_run (argc,
1265 argv,
1266 "gnunet-rest-server",
1267 _ ("GNUnet REST server"),
1268 options,
1269 &run,
1270 NULL))
1271 ? 0
1272 : 1;
1273 MHD_destroy_response (failure_response);
1274 GNUNET_free_nz ((char *) argv);
1275 return ret;
1276}
1277
1278
1279/* end of gnunet-rest-server.c */
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 */
diff --git a/src/rest/plugin_rest_copying.c b/src/rest/plugin_rest_copying.c
deleted file mode 100644
index 52783a81a..000000000
--- a/src/rest/plugin_rest_copying.c
+++ /dev/null
@@ -1,238 +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_copying.c
23 * @brief REST plugin that serves licensing information.
24 *
25 */
26
27#include "platform.h"
28#include "gnunet_rest_plugin.h"
29#include <gnunet_rest_lib.h>
30
31#define GNUNET_REST_API_NS_COPYING "/copying"
32
33#define GNUNET_REST_COPYING_TEXT \
34 "GNU Affero General Public License version 3 or later. See also: <http://www.gnu.org/licenses/>"
35
36/**
37 * @brief struct returned by the initialization function of the plugin
38 */
39struct Plugin
40{
41 const struct GNUNET_CONFIGURATION_Handle *cfg;
42};
43
44const struct GNUNET_CONFIGURATION_Handle *cfg;
45
46struct RequestHandle
47{
48 /**
49 * DLL
50 */
51 struct RequestHandle *next;
52
53 /**
54 * DLL
55 */
56 struct RequestHandle *prev;
57
58 /**
59 * Handle to rest request
60 */
61 struct GNUNET_REST_RequestHandle *rest_handle;
62
63 /**
64 * The plugin result processor
65 */
66 GNUNET_REST_ResultProcessor proc;
67
68 /**
69 * The closure of the result processor
70 */
71 void *proc_cls;
72
73 /**
74 * HTTP response code
75 */
76 int response_code;
77};
78
79/**
80 * DLL
81 */
82static struct RequestHandle *requests_head;
83
84/**
85 * DLL
86 */
87static struct RequestHandle *requests_tail;
88
89/**
90 * Cleanup request handle.
91 *
92 * @param handle Handle to clean up
93 */
94static void
95cleanup_handle (struct RequestHandle *handle)
96{
97 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
98 "Cleaning up\n");
99 GNUNET_CONTAINER_DLL_remove (requests_head,
100 requests_tail,
101 handle);
102 GNUNET_free (handle);
103}
104
105
106/**
107 * Handle rest request
108 *
109 * @param handle the lookup handle
110 */
111static void
112get_cont (struct GNUNET_REST_RequestHandle *con_handle,
113 const char*url,
114 void *cls)
115{
116 struct MHD_Response *resp;
117 struct RequestHandle *handle = cls;
118
119 resp = GNUNET_REST_create_response (GNUNET_REST_COPYING_TEXT);
120 handle->proc (handle->proc_cls,
121 resp,
122 MHD_HTTP_OK);
123 cleanup_handle (handle);
124}
125
126
127/**
128 * Handle rest request
129 *
130 * @param handle the lookup handle
131 */
132static void
133options_cont (struct GNUNET_REST_RequestHandle *con_handle,
134 const char*url,
135 void *cls)
136{
137 struct MHD_Response *resp;
138 struct RequestHandle *handle = cls;
139
140 resp = GNUNET_REST_create_response (NULL);
141 GNUNET_assert (MHD_NO != MHD_add_response_header (resp,
142 "Access-Control-Allow-Methods",
143 MHD_HTTP_METHOD_GET));
144 handle->proc (handle->proc_cls,
145 resp,
146 MHD_HTTP_OK);
147 cleanup_handle (handle);
148}
149
150
151/**
152 * Function processing the REST call
153 *
154 * @param method HTTP method
155 * @param url URL of the HTTP request
156 * @param data body of the HTTP request (optional)
157 * @param data_size length of the body
158 * @param proc callback function for the result
159 * @param proc_cls closure for @a proc
160 * @return #GNUNET_OK if request accepted
161 */
162static enum GNUNET_GenericReturnValue
163rest_copying_process_request (struct GNUNET_REST_RequestHandle *conndata_handle,
164 GNUNET_REST_ResultProcessor proc,
165 void *proc_cls)
166{
167 static const struct GNUNET_REST_RequestHandler handlers[] = {
168 { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_COPYING, &get_cont },
169 { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_COPYING, &options_cont },
170 GNUNET_REST_HANDLER_END
171 };
172 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
173 struct GNUNET_REST_RequestHandlerError err;
174
175 handle->proc_cls = proc_cls;
176 handle->proc = proc;
177 handle->rest_handle = conndata_handle;
178 GNUNET_CONTAINER_DLL_insert (requests_head,
179 requests_tail,
180 handle);
181 return GNUNET_REST_handle_request (conndata_handle,
182 handlers,
183 &err,
184 handle);
185}
186
187
188/**
189 * Entry point for the plugin.
190 *
191 * @param cls the "struct GNUNET_NAMESTORE_PluginEnvironment*"
192 * @return NULL on error, otherwise the plugin context
193 */
194void *
195libgnunet_plugin_rest_copying_init (void *cls)
196{
197 static struct Plugin plugin;
198
199 cfg = cls;
200 struct GNUNET_REST_Plugin *api;
201
202 if (NULL != plugin.cfg)
203 return NULL; /* can only initialize once! */
204 memset (&plugin, 0, sizeof(struct Plugin));
205 plugin.cfg = cfg;
206 api = GNUNET_new (struct GNUNET_REST_Plugin);
207 api->cls = &plugin;
208 api->name = GNUNET_REST_API_NS_COPYING;
209 api->process_request = &rest_copying_process_request;
210 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
211 _ ("COPYING REST API initialized\n"));
212 return api;
213}
214
215
216/**
217 * Exit point from the plugin.
218 *
219 * @param cls the plugin context (as returned by "init")
220 * @return always NULL
221 */
222void *
223libgnunet_plugin_rest_copying_done (void *cls)
224{
225 struct GNUNET_REST_Plugin *api = cls;
226 struct Plugin *plugin = api->cls;
227
228 while (NULL != requests_head)
229 cleanup_handle (requests_head);
230 plugin->cfg = NULL;
231 GNUNET_free (api);
232 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
233 "COPYING REST plugin is finished\n");
234 return NULL;
235}
236
237
238/* end of plugin_rest_copying.c */
diff --git a/src/rest/rest.c b/src/rest/rest.c
deleted file mode 100644
index 930f66243..000000000
--- a/src/rest/rest.c
+++ /dev/null
@@ -1,112 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2010-2015 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/**
22 * @file rest/rest.c
23 * @brief helper library to create JSON REST Objects and handle REST
24 * responses/requests.
25 * @author Martin Schanzenbach
26 */
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_rest_lib.h"
30#include "microhttpd.h"
31
32/**
33 * REST Utilities
34 */
35
36/**
37 * Check if namespace is in URL.
38 *
39 * @param url URL to check
40 * @param namespace namespace to check against
41 * @return GNUNET_YES if namespace matches
42 */
43int
44GNUNET_REST_namespace_match (const char *url, const char *namespace)
45{
46 return 0 == strncmp (namespace, url, strlen (namespace));
47}
48
49
50/**
51 * Create MHD response
52 *
53 * @param data result
54 * @return MHD response
55 */
56struct MHD_Response*
57GNUNET_REST_create_response (const char *data)
58{
59 struct MHD_Response *resp;
60 size_t len;
61
62 if (NULL == data)
63 {
64 len = 0;
65 data = "";
66 }
67 else
68 len = strlen (data);
69 resp = MHD_create_response_from_buffer (len,
70 (void *) data,
71 MHD_RESPMEM_MUST_COPY);
72 return resp;
73}
74
75
76int
77GNUNET_REST_handle_request (struct GNUNET_REST_RequestHandle *conn,
78 const struct GNUNET_REST_RequestHandler *handlers,
79 struct GNUNET_REST_RequestHandlerError *err,
80 void *cls)
81{
82 int count;
83 int i;
84 char *url;
85
86 count = 0;
87 while (NULL != handlers[count].method)
88 count++;
89
90 GNUNET_asprintf (&url, "%s", conn->url);
91 if (url[strlen (url) - 1] == '/')
92 url[strlen (url) - 1] = '\0';
93 for (i = 0; i < count; i++)
94 {
95 if (0 != strcasecmp (conn->method, handlers[i].method))
96 continue;
97 if (strlen (url) < strlen (handlers[i].namespace))
98 continue;
99 if (GNUNET_NO == GNUNET_REST_namespace_match (url, handlers[i].namespace))
100 continue;
101 // Match
102 handlers[i].proc (conn, (const char *) url, cls);
103 GNUNET_free (url);
104 return GNUNET_YES;
105 }
106 GNUNET_free (url);
107 err->error_code = MHD_HTTP_BAD_REQUEST;
108 return GNUNET_NO;
109}
110
111
112/* end of rest.c */
diff --git a/src/rest/rest.conf b/src/rest/rest.conf
deleted file mode 100644
index 0d6e33ada..000000000
--- a/src/rest/rest.conf
+++ /dev/null
@@ -1,12 +0,0 @@
1[rest]
2UNIXPATH = $GNUNET_USER_RUNTIME_DIR/gnunet-service-rest.sock
3BINARY=gnunet-rest-server
4IMMEDIATE_START=YES
5HTTP_PORT=7776
6BIND_TO=127.0.0.1
7BIND_TO6=::1
8REST_ALLOW_HEADERS=Authorization,Accept,Content-Type
9REST_ECHO_ORIGIN_WEBEXT=YES
10REST_ALLOW_ORIGIN=http://localhost:4200
11REST_ALLOW_CREDENTIALS=true
12RUN_PER_USER=YES