aboutsummaryrefslogtreecommitdiff
path: root/src/gns/plugin_rest_gns.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gns/plugin_rest_gns.c')
-rw-r--r--src/gns/plugin_rest_gns.c485
1 files changed, 0 insertions, 485 deletions
diff --git a/src/gns/plugin_rest_gns.c b/src/gns/plugin_rest_gns.c
deleted file mode 100644
index 3a35c9999..000000000
--- a/src/gns/plugin_rest_gns.c
+++ /dev/null
@@ -1,485 +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 Philippe Buschmann
22 * @file gns/plugin_rest_gns.c
23 * @brief GNUnet Gns REST plugin
24 */
25
26#include "platform.h"
27#include "gnunet_rest_plugin.h"
28#include "gnunet_rest_lib.h"
29#include "gnunet_json_lib.h"
30#include "gnunet_gnsrecord_lib.h"
31#include "gnunet_gnsrecord_json_lib.h"
32#include "gnunet_gns_service.h"
33#include "microhttpd.h"
34#include <jansson.h>
35
36/**
37 * Rest API GNS Namespace
38 */
39#define GNUNET_REST_API_NS_GNS "/gns"
40
41/**
42 * Rest API GNS Parameter record_type
43 */
44#define GNUNET_REST_GNS_PARAM_RECORD_TYPE "record_type"
45
46/**
47 * Rest API GNS ERROR Unknown Error
48 */
49#define GNUNET_REST_GNS_ERROR_UNKNOWN "Unknown Error"
50
51/**
52 * Rest API GNS ERROR Record not found
53 */
54#define GNUNET_REST_GNS_NOT_FOUND "Record not found"
55
56/**
57 * The configuration handle
58 */
59const struct GNUNET_CONFIGURATION_Handle *cfg;
60
61/**
62 * HTTP methods allows for this plugin
63 */
64static char *allow_methods;
65
66/**
67 * Connection to GNS
68 */
69static struct GNUNET_GNS_Handle *gns;
70
71/**
72 * @brief struct returned by the initialization function of the plugin
73 */
74struct Plugin
75{
76 const struct GNUNET_CONFIGURATION_Handle *cfg;
77};
78
79/**
80 * The request handle
81 */
82struct RequestHandle
83{
84 /**
85 * DLL
86 */
87 struct RequestHandle *next;
88
89 /**
90 * DLL
91 */
92 struct RequestHandle *prev;
93
94 /**
95 * Active GNS lookup
96 */
97 struct GNUNET_GNS_LookupWithTldRequest *gns_lookup;
98
99 /**
100 * Name to look up
101 */
102 char *name;
103
104 /**
105 * Record type to look up
106 */
107 int record_type;
108
109 /**
110 * Rest connection
111 */
112 struct GNUNET_REST_RequestHandle *rest_handle;
113
114 /**
115 * Desired timeout for the lookup (default is no timeout).
116 */
117 struct GNUNET_TIME_Relative timeout;
118
119 /**
120 * ID of a task associated with the resolution process.
121 */
122 struct GNUNET_SCHEDULER_Task *timeout_task;
123
124 /**
125 * The plugin result processor
126 */
127 GNUNET_REST_ResultProcessor proc;
128
129 /**
130 * The closure of the result processor
131 */
132 void *proc_cls;
133
134 /**
135 * The url
136 */
137 char *url;
138
139 /**
140 * Error response message
141 */
142 char *emsg;
143
144 /**
145 * Response code
146 */
147 int response_code;
148};
149
150/**
151 * DLL
152 */
153static struct RequestHandle *requests_head;
154
155/**
156 * DLL
157 */
158static struct RequestHandle *requests_tail;
159
160/**
161 * Cleanup lookup handle
162 * @param handle Handle to clean up
163 */
164static void
165cleanup_handle (void *cls)
166{
167 struct RequestHandle *handle = cls;
168
169 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
170
171 if (NULL != handle->gns_lookup)
172 {
173 GNUNET_GNS_lookup_with_tld_cancel (handle->gns_lookup);
174 handle->gns_lookup = NULL;
175 }
176 if (NULL != handle->timeout_task)
177 {
178 GNUNET_SCHEDULER_cancel (handle->timeout_task);
179 handle->timeout_task = NULL;
180 }
181 if (NULL != handle->url)
182 GNUNET_free (handle->url);
183 if (NULL != handle->name)
184 GNUNET_free (handle->name);
185 if (NULL != handle->emsg)
186 GNUNET_free (handle->emsg);
187
188 GNUNET_CONTAINER_DLL_remove (requests_head,
189 requests_tail,
190 handle);
191 GNUNET_free (handle);
192}
193
194
195/**
196 * Task run on errors. Reports an error and cleans up everything.
197 *
198 * @param cls the `struct RequestHandle`
199 */
200static void
201do_error (void *cls)
202{
203 struct RequestHandle *handle = cls;
204 struct MHD_Response *resp;
205 json_t *json_error = json_object ();
206 char *response;
207
208 if (NULL != handle->timeout_task)
209 GNUNET_SCHEDULER_cancel (handle->timeout_task);
210 handle->timeout_task = NULL;
211 if (NULL == handle->emsg)
212 handle->emsg = GNUNET_strdup (GNUNET_REST_GNS_ERROR_UNKNOWN);
213
214 json_object_set_new (json_error, "error", json_string (handle->emsg));
215
216 if (0 == handle->response_code)
217 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
218 response = json_dumps (json_error, 0);
219 resp = GNUNET_REST_create_response (response);
220 MHD_add_response_header (resp, "Content-Type", "application/json");
221 handle->proc (handle->proc_cls, resp, handle->response_code);
222 json_decref (json_error);
223 GNUNET_free (response);
224 cleanup_handle(handle);
225}
226
227
228static void
229do_timeout (void *cls)
230{
231 struct RequestHandle *handle = cls;
232
233 handle->timeout_task = NULL;
234 handle->response_code = MHD_HTTP_REQUEST_TIMEOUT;
235 do_error (handle);
236}
237
238
239/**
240 * Iterator called on obtained result for a GNS lookup.
241 *
242 * @param cls closure with the object
243 * @param was_gns #GNUNET_NO if name was not a GNS name
244 * @param rd_count number of records in @a rd
245 * @param rd the records in reply
246 */
247static void
248handle_gns_response (void *cls,
249 int was_gns,
250 uint32_t rd_count,
251 const struct GNUNET_GNSRECORD_Data *rd)
252{
253 struct RequestHandle *handle = cls;
254 struct MHD_Response *resp;
255 json_t *result_obj;
256 char *result;
257
258 handle->gns_lookup = NULL;
259
260 if (GNUNET_NO == was_gns)
261 {
262 handle->response_code = MHD_HTTP_NOT_FOUND;
263 handle->emsg = GNUNET_strdup (GNUNET_REST_GNS_NOT_FOUND);
264 GNUNET_SCHEDULER_add_now (&do_error, handle);
265 return;
266 }
267
268 result_obj = GNUNET_GNSRECORD_JSON_from_gnsrecord (handle->name, rd, rd_count);
269
270 result = json_dumps (result_obj, 0);
271 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result);
272 resp = GNUNET_REST_create_response (result);
273 GNUNET_assert (MHD_NO != MHD_add_response_header (resp,
274 "Content-Type",
275 "application/json"));
276 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
277 GNUNET_free (result);
278 json_decref (result_obj);
279 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
280}
281
282
283/**
284 * Handle gns GET request
285 *
286 * @param con_handle the connection handle
287 * @param url the url
288 * @param cls the RequestHandle
289 */
290void
291get_gns_cont (struct GNUNET_REST_RequestHandle *con_handle,
292 const char *url,
293 void *cls)
294{
295 struct RequestHandle *handle = cls;
296 struct GNUNET_HashCode key;
297 char *record_type;
298 char *name;
299
300 name = NULL;
301 handle->name = NULL;
302 if (strlen (GNUNET_REST_API_NS_GNS) < strlen (handle->url))
303 {
304 name = &handle->url[strlen (GNUNET_REST_API_NS_GNS) + 1];
305 }
306
307 if (NULL == name)
308 {
309 handle->response_code = MHD_HTTP_NOT_FOUND;
310 handle->emsg = GNUNET_strdup (GNUNET_REST_GNS_NOT_FOUND);
311 GNUNET_SCHEDULER_add_now (&do_error, handle);
312 return;
313 }
314 if (0 >= strlen (name))
315 {
316 handle->response_code = MHD_HTTP_NOT_FOUND;
317 handle->emsg = GNUNET_strdup (GNUNET_REST_GNS_NOT_FOUND);
318 GNUNET_SCHEDULER_add_now (&do_error, handle);
319 return;
320 }
321 handle->name = GNUNET_strdup (name);
322
323 handle->record_type = UINT32_MAX;
324 GNUNET_CRYPTO_hash (GNUNET_REST_GNS_PARAM_RECORD_TYPE,
325 strlen (GNUNET_REST_GNS_PARAM_RECORD_TYPE),
326 &key);
327 if (GNUNET_YES ==
328 GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map, &key))
329 {
330 record_type =
331 GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map, &key);
332 handle->record_type = GNUNET_GNSRECORD_typename_to_number (record_type);
333 }
334
335 if (UINT32_MAX == handle->record_type)
336 {
337 handle->record_type = GNUNET_GNSRECORD_TYPE_ANY;
338 }
339
340 handle->gns_lookup = GNUNET_GNS_lookup_with_tld (gns,
341 handle->name,
342 handle->record_type,
343 GNUNET_GNS_LO_DEFAULT,
344 &handle_gns_response,
345 handle);
346}
347
348
349/**
350 * Respond to OPTIONS request
351 *
352 * @param con_handle the connection handle
353 * @param url the url
354 * @param cls the RequestHandle
355 */
356static void
357options_cont (struct GNUNET_REST_RequestHandle *con_handle,
358 const char *url,
359 void *cls)
360{
361 struct MHD_Response *resp;
362 struct RequestHandle *handle = cls;
363
364 // independent of path return all options
365 resp = GNUNET_REST_create_response (NULL);
366 MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods);
367 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
368 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
369 return;
370}
371
372
373/**
374 * Function processing the REST call
375 *
376 * @param method HTTP method
377 * @param url URL of the HTTP request
378 * @param data body of the HTTP request (optional)
379 * @param data_size length of the body
380 * @param proc callback function for the result
381 * @param proc_cls closure for callback function
382 * @return GNUNET_OK if request accepted
383 */
384static enum GNUNET_GenericReturnValue
385rest_process_request (struct GNUNET_REST_RequestHandle *rest_handle,
386 GNUNET_REST_ResultProcessor proc,
387 void *proc_cls)
388{
389 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
390 struct GNUNET_REST_RequestHandlerError err;
391 static const struct GNUNET_REST_RequestHandler handlers[] =
392 { { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_GNS, &get_gns_cont },
393 { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_GNS, &options_cont },
394 GNUNET_REST_HANDLER_END };
395
396 handle->response_code = 0;
397 handle->timeout =
398 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60);
399 handle->proc_cls = proc_cls;
400 handle->proc = proc;
401 handle->rest_handle = rest_handle;
402 handle->url = GNUNET_strdup (rest_handle->url);
403 handle->timeout_task =
404 GNUNET_SCHEDULER_add_delayed (handle->timeout, &do_timeout, handle);
405 GNUNET_CONTAINER_DLL_insert (requests_head,
406 requests_tail,
407 handle);
408 if (handle->url[strlen (handle->url) - 1] == '/')
409 handle->url[strlen (handle->url) - 1] = '\0';
410 if (GNUNET_NO ==
411 GNUNET_REST_handle_request (handle->rest_handle, handlers, &err, handle))
412 {
413 cleanup_handle (handle);
414 return GNUNET_NO;
415 }
416
417
418 return GNUNET_YES;
419}
420
421
422/**
423 * Entry point for the plugin.
424 *
425 * @param cls Config info
426 * @return NULL on error, otherwise the plugin context
427 */
428void *
429libgnunet_plugin_rest_gns_init (void *cls)
430{
431 static struct Plugin plugin;
432 struct GNUNET_REST_Plugin *api;
433
434 cfg = cls;
435 memset (&plugin, 0, sizeof(struct Plugin));
436 plugin.cfg = cfg;
437 api = GNUNET_new (struct GNUNET_REST_Plugin);
438 api->cls = &plugin;
439 api->name = GNUNET_REST_API_NS_GNS;
440 api->process_request = &rest_process_request;
441 GNUNET_asprintf (&allow_methods,
442 "%s, %s, %s, %s, %s",
443 MHD_HTTP_METHOD_GET,
444 MHD_HTTP_METHOD_POST,
445 MHD_HTTP_METHOD_PUT,
446 MHD_HTTP_METHOD_DELETE,
447 MHD_HTTP_METHOD_OPTIONS);
448 gns = GNUNET_GNS_connect (cfg);
449
450 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _ ("Gns REST API initialized\n"));
451 return api;
452}
453
454
455/**
456 * Exit point from the plugin.
457 *
458 * @param cls the plugin context (as returned by "init")
459 * @return always NULL
460 */
461void *
462libgnunet_plugin_rest_gns_done (void *cls)
463{
464 struct GNUNET_REST_Plugin *api = cls;
465 struct RequestHandle *request;
466 struct Plugin *plugin;
467
468 while (NULL != (request = requests_head))
469 do_error (request);
470
471 if (NULL != gns)
472 GNUNET_GNS_disconnect (gns);
473
474 plugin = api->cls;
475
476 plugin->cfg = NULL;
477
478 GNUNET_free (allow_methods);
479 GNUNET_free (api);
480 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Gns REST plugin is finished\n");
481 return NULL;
482}
483
484
485/* end of plugin_rest_gns.c */