diff options
Diffstat (limited to 'src/gns/plugin_rest_gns.c')
-rw-r--r-- | src/gns/plugin_rest_gns.c | 485 |
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 | */ | ||
59 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
60 | |||
61 | /** | ||
62 | * HTTP methods allows for this plugin | ||
63 | */ | ||
64 | static char *allow_methods; | ||
65 | |||
66 | /** | ||
67 | * Connection to GNS | ||
68 | */ | ||
69 | static struct GNUNET_GNS_Handle *gns; | ||
70 | |||
71 | /** | ||
72 | * @brief struct returned by the initialization function of the plugin | ||
73 | */ | ||
74 | struct Plugin | ||
75 | { | ||
76 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
77 | }; | ||
78 | |||
79 | /** | ||
80 | * The request handle | ||
81 | */ | ||
82 | struct 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 | */ | ||
153 | static struct RequestHandle *requests_head; | ||
154 | |||
155 | /** | ||
156 | * DLL | ||
157 | */ | ||
158 | static struct RequestHandle *requests_tail; | ||
159 | |||
160 | /** | ||
161 | * Cleanup lookup handle | ||
162 | * @param handle Handle to clean up | ||
163 | */ | ||
164 | static void | ||
165 | cleanup_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 | */ | ||
200 | static void | ||
201 | do_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 | |||
228 | static void | ||
229 | do_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 | */ | ||
247 | static void | ||
248 | handle_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 | */ | ||
290 | void | ||
291 | get_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 | */ | ||
356 | static void | ||
357 | options_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 | */ | ||
384 | static enum GNUNET_GenericReturnValue | ||
385 | rest_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 | */ | ||
428 | void * | ||
429 | libgnunet_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 | */ | ||
461 | void * | ||
462 | libgnunet_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 */ | ||