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