aboutsummaryrefslogtreecommitdiff
path: root/src/namestore/plugin_rest_namestore.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/namestore/plugin_rest_namestore.c')
-rw-r--r--src/namestore/plugin_rest_namestore.c1155
1 files changed, 0 insertions, 1155 deletions
diff --git a/src/namestore/plugin_rest_namestore.c b/src/namestore/plugin_rest_namestore.c
deleted file mode 100644
index ff5494dc7..000000000
--- a/src/namestore/plugin_rest_namestore.c
+++ /dev/null
@@ -1,1155 +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 * @author Philippe Buschmann
23 * @file namestore/plugin_rest_namestore.c
24 * @brief GNUnet Namestore REST plugin
25 */
26
27#include "platform.h"
28#include "gnunet_rest_plugin.h"
29#include "gnunet_gns_service.h"
30#include "gnunet_namestore_service.h"
31#include "gnunet_identity_service.h"
32#include "gnunet_rest_lib.h"
33#include "gnunet_gnsrecord_json_lib.h"
34#include "microhttpd.h"
35#include <jansson.h>
36
37/**
38 * Namestore Namespace
39 */
40#define GNUNET_REST_API_NS_NAMESTORE "/namestore"
41
42/**
43 * Error message Unknown Error
44 */
45#define GNUNET_REST_NAMESTORE_ERROR_UNKNOWN "Unknown Error"
46
47/**
48 * Error message No identity found
49 */
50#define GNUNET_REST_IDENTITY_NOT_FOUND "No identity found"
51
52
53/**
54 * Error message Failed request
55 */
56#define GNUNET_REST_NAMESTORE_FAILED "Namestore action failed"
57
58/**
59 * Error message invalid data
60 */
61#define GNUNET_REST_NAMESTORE_INVALID_DATA "Data invalid"
62
63/**
64 * Error message No data
65 */
66#define GNUNET_REST_NAMESTORE_NO_DATA "No data"
67
68/**
69 * State while collecting all egos
70 */
71#define ID_REST_STATE_INIT 0
72
73/**
74 * Done collecting egos
75 */
76#define ID_REST_STATE_POST_INIT 1
77/**
78 * The configuration handle
79 */
80const struct GNUNET_CONFIGURATION_Handle *cfg;
81
82/**
83 * HTTP methods allows for this plugin
84 */
85static char *allow_methods;
86
87/**
88 * Ego list
89 */
90static struct EgoEntry *ego_head;
91
92/**
93 * Ego list
94 */
95static struct EgoEntry *ego_tail;
96
97/**
98 * The processing state
99 */
100static int state;
101
102/**
103 * Handle to NAMESTORE
104 */
105static struct GNUNET_NAMESTORE_Handle *ns_handle;
106
107/**
108 * Handle to Identity service.
109 */
110static struct GNUNET_IDENTITY_Handle *identity_handle;
111
112/**
113 * @brief struct returned by the initialization function of the plugin
114 */
115struct Plugin
116{
117 const struct GNUNET_CONFIGURATION_Handle *cfg;
118};
119
120/**
121 * The default namestore ego
122 */
123struct EgoEntry
124{
125 /**
126 * DLL
127 */
128 struct EgoEntry *next;
129
130 /**
131 * DLL
132 */
133 struct EgoEntry *prev;
134
135 /**
136 * Ego Identifier
137 */
138 char *identifier;
139
140 /**
141 * Public key string
142 */
143 char *keystring;
144
145 /**
146 * The Ego
147 */
148 struct GNUNET_IDENTITY_Ego *ego;
149};
150
151
152enum UpdateStrategy
153{
154 UPDATE_STRATEGY_REPLACE,
155 UPDATE_STRATEGY_APPEND
156};
157
158/**
159 * The request handle
160 */
161struct RequestHandle
162{
163 /**
164 * DLL
165 */
166 struct RequestHandle *next;
167
168 /**
169 * DLL
170 */
171 struct RequestHandle *prev;
172
173 /**
174 * Records to store
175 */
176 char *record_name;
177
178 /**
179 * Record type filter
180 */
181 uint32_t record_type;
182
183 /**
184 * How to update the record set
185 */
186 enum UpdateStrategy update_strategy;
187
188 /**
189 * Records to store
190 */
191 struct GNUNET_GNSRECORD_Data *rd;
192
193 /**
194 * Number of records in rd
195 */
196 unsigned int rd_count;
197
198 /**
199 * NAMESTORE Operation
200 */
201 struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
202
203 /**
204 * Response object
205 */
206 json_t *resp_object;
207
208
209 /**
210 * Handle to NAMESTORE it
211 */
212 struct GNUNET_NAMESTORE_ZoneIterator *list_it;
213
214 /**
215 * Private key for the zone
216 */
217 const struct GNUNET_IDENTITY_PrivateKey *zone_pkey;
218
219 /**
220 * IDENTITY Operation
221 */
222 struct EgoEntry *ego_entry;
223
224 /**
225 * IDENTITY Operation
226 */
227 struct GNUNET_IDENTITY_Operation *op;
228
229 /**
230 * Rest connection
231 */
232 struct GNUNET_REST_RequestHandle *rest_handle;
233
234 /**
235 * Desired timeout for the lookup (default is no timeout).
236 */
237 struct GNUNET_TIME_Relative timeout;
238
239 /**
240 * ID of a task associated with the resolution process.
241 */
242 struct GNUNET_SCHEDULER_Task *timeout_task;
243
244 /**
245 * The plugin result processor
246 */
247 GNUNET_REST_ResultProcessor proc;
248
249 /**
250 * The closure of the result processor
251 */
252 void *proc_cls;
253
254 /**
255 * The url
256 */
257 char *url;
258
259 /**
260 * Error response message
261 */
262 char *emsg;
263
264 /**
265 * Response code
266 */
267 int response_code;
268};
269
270/**
271 * DLL
272 */
273static struct RequestHandle *requests_head;
274
275/**
276 * DLL
277 */
278static struct RequestHandle *requests_tail;
279
280
281/**
282 * Cleanup lookup handle
283 * @param handle Handle to clean up
284 */
285static void
286cleanup_handle (void *cls)
287{
288 struct RequestHandle *handle = cls;
289
290 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
291 if (NULL != handle->timeout_task)
292 {
293 GNUNET_SCHEDULER_cancel (handle->timeout_task);
294 handle->timeout_task = NULL;
295 }
296 if (NULL != handle->record_name)
297 GNUNET_free (handle->record_name);
298 if (NULL != handle->url)
299 GNUNET_free (handle->url);
300 if (NULL != handle->emsg)
301 GNUNET_free (handle->emsg);
302 if (NULL != handle->rd)
303 {
304 for (int i = 0; i < handle->rd_count; i++)
305 {
306 if (NULL != handle->rd[i].data)
307 GNUNET_free_nz ((void *) handle->rd[i].data);
308 }
309 GNUNET_free (handle->rd);
310 }
311 if (NULL != handle->timeout_task)
312 GNUNET_SCHEDULER_cancel (handle->timeout_task);
313 if (NULL != handle->list_it)
314 GNUNET_NAMESTORE_zone_iteration_stop (handle->list_it);
315 if (NULL != handle->ns_qe)
316 GNUNET_NAMESTORE_cancel (handle->ns_qe);
317
318 if (NULL != handle->resp_object)
319 {
320 json_decref (handle->resp_object);
321 }
322 GNUNET_CONTAINER_DLL_remove (requests_head,
323 requests_tail,
324 handle);
325 GNUNET_free (handle);
326}
327
328
329/**
330 * Task run on errors. Reports an error and cleans up everything.
331 *
332 * @param cls the `struct RequestHandle`
333 */
334static void
335do_error (void *cls)
336{
337 struct RequestHandle *handle = cls;
338 struct MHD_Response *resp;
339 json_t *json_error = json_object ();
340 char *response;
341
342 if (NULL == handle->emsg)
343 handle->emsg = GNUNET_strdup (GNUNET_REST_NAMESTORE_ERROR_UNKNOWN);
344
345 json_object_set_new (json_error, "error", json_string (handle->emsg));
346
347 if (0 == handle->response_code)
348 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
349 response = json_dumps (json_error, 0);
350 resp = GNUNET_REST_create_response (response);
351 MHD_add_response_header (resp, "Content-Type", "application/json");
352 handle->proc (handle->proc_cls, resp, handle->response_code);
353 json_decref (json_error);
354 GNUNET_free (response);
355 cleanup_handle (handle);
356}
357
358
359/**
360 * Get EgoEntry from list with either a public key or a name
361 * If public key and name are not NULL, it returns the public key result first
362 *
363 * @param handle the RequestHandle
364 * @param pubkey the public key of an identity (only one can be NULL)
365 * @param name the name of an identity (only one can be NULL)
366 * @return EgoEntry or NULL if not found
367 */
368struct EgoEntry *
369get_egoentry_namestore (struct RequestHandle *handle, char *name)
370{
371 struct EgoEntry *ego_entry;
372 char *copy = GNUNET_strdup (name);
373 char *tmp;
374
375 if (NULL == name)
376 return NULL;
377 tmp = strtok (copy, "/");
378 if (NULL == tmp)
379 return NULL;
380 for (ego_entry = ego_head; NULL != ego_entry;
381 ego_entry = ego_entry->next)
382 {
383 if (0 != strcasecmp (tmp, ego_entry->identifier))
384 continue;
385 GNUNET_free (copy);
386 return ego_entry;
387 }
388 GNUNET_free (copy);
389 return NULL;
390}
391
392
393/**
394 * Does internal server error when iteration failed.
395 *
396 * @param cls the `struct RequestHandle`
397 */
398static void
399namestore_iteration_error (void *cls)
400{
401 struct RequestHandle *handle = cls;
402
403 handle->emsg = GNUNET_strdup (GNUNET_REST_NAMESTORE_FAILED);
404 GNUNET_SCHEDULER_add_now (&do_error, handle);
405 return;
406}
407
408
409/**
410 * Create finished callback
411 *
412 * @param cls the `struct RequestHandle`
413 * @param success the success indicating integer, GNUNET_OK on success
414 * @param emsg the error message (can be NULL)
415 */
416static void
417create_finished (void *cls, int32_t success, const char *emsg)
418{
419 struct RequestHandle *handle = cls;
420 struct MHD_Response *resp;
421
422 handle->ns_qe = NULL;
423 if (GNUNET_YES != success)
424 {
425 if (NULL != emsg)
426 {
427 handle->emsg = GNUNET_strdup (emsg);
428 GNUNET_SCHEDULER_add_now (&do_error, handle);
429 return;
430 }
431 handle->emsg = GNUNET_strdup ("Error storing records");
432 GNUNET_SCHEDULER_add_now (&do_error, handle);
433 return;
434 }
435 resp = GNUNET_REST_create_response (NULL);
436 handle->proc (handle->proc_cls, resp, MHD_HTTP_NO_CONTENT);
437 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
438}
439
440
441/**
442 * Delete finished callback
443 *
444 * @param cls the `struct RequestHandle`
445 * @param success the success indicating integer, GNUNET_OK on success
446 * @param emsg the error message (can be NULL)
447 */
448static void
449del_finished (void *cls, int32_t success, const char *emsg)
450{
451 struct RequestHandle *handle = cls;
452
453 handle->ns_qe = NULL;
454 if (GNUNET_NO == success)
455 {
456 handle->response_code = MHD_HTTP_NOT_FOUND;
457 handle->emsg = GNUNET_strdup ("No record found");
458 GNUNET_SCHEDULER_add_now (&do_error, handle);
459 return;
460 }
461 if (GNUNET_SYSERR == success)
462 {
463 if (NULL != emsg)
464 {
465 handle->emsg = GNUNET_strdup (emsg);
466 GNUNET_SCHEDULER_add_now (&do_error, handle);
467 return;
468 }
469 handle->emsg = GNUNET_strdup ("Deleting record failed");
470 GNUNET_SCHEDULER_add_now (&do_error, handle);
471 return;
472 }
473 handle->proc (handle->proc_cls,
474 GNUNET_REST_create_response (NULL),
475 MHD_HTTP_NO_CONTENT);
476 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
477}
478
479
480/**
481 * Iteration over all results finished, build final
482 * response.
483 *
484 * @param cls the `struct RequestHandle`
485 */
486static void
487namestore_list_finished (void *cls)
488{
489 struct RequestHandle *handle = cls;
490 char *result_str;
491 struct MHD_Response *resp;
492
493 handle->list_it = NULL;
494
495 if (NULL == handle->resp_object)
496 handle->resp_object = json_array ();
497
498 result_str = json_dumps (handle->resp_object, 0);
499 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
500 resp = GNUNET_REST_create_response (result_str);
501 MHD_add_response_header (resp, "Content-Type", "application/json");
502 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
503 GNUNET_free (result_str);
504 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
505}
506
507
508/**
509 * Create a response with requested records
510 *
511 * @param handle the RequestHandle
512 */
513static void
514namestore_list_iteration (void *cls,
515 const struct GNUNET_IDENTITY_PrivateKey *zone_key,
516 const char *rname,
517 unsigned int rd_len,
518 const struct GNUNET_GNSRECORD_Data *rd)
519{
520 struct RequestHandle *handle = cls;
521 struct GNUNET_GNSRECORD_Data rd_filtered[rd_len];
522 json_t *record_obj;
523 int i = 0;
524 int j = 0;
525
526 if (NULL == handle->resp_object)
527 handle->resp_object = json_array ();
528 for (i = 0; i < rd_len; i++)
529 {
530 if ((GNUNET_GNSRECORD_TYPE_ANY != handle->record_type) &&
531 (rd[i].record_type != handle->record_type))
532 continue; /* Apply filter */
533 rd_filtered[j] = rd[i];
534 rd_filtered[j].data = rd[i].data;
535 j++;
536 }
537 /** Only add if not empty **/
538 if (j > 0)
539 {
540 record_obj = GNUNET_GNSRECORD_JSON_from_gnsrecord (rname,
541 rd_filtered,
542 j);
543 json_array_append_new (handle->resp_object, record_obj);
544 }
545 GNUNET_NAMESTORE_zone_iterator_next (handle->list_it, 1);
546}
547
548
549/**
550 * Handle lookup error
551 *
552 * @param cls the request handle
553 */
554static void
555ns_lookup_error_cb (void *cls)
556{
557 struct RequestHandle *handle = cls;
558
559 handle->emsg = GNUNET_strdup (GNUNET_REST_NAMESTORE_FAILED);
560 GNUNET_SCHEDULER_add_now (&do_error, handle);
561}
562
563
564static void
565ns_get_lookup_cb (void *cls,
566 const struct GNUNET_IDENTITY_PrivateKey *zone,
567 const char *label,
568 unsigned int rd_len,
569 const struct GNUNET_GNSRECORD_Data *rd)
570{
571 struct RequestHandle *handle = cls;
572 struct GNUNET_GNSRECORD_Data rd_filtered[rd_len];
573 json_t *record_obj;
574 int i = 0;
575 int j = 0;
576
577 handle->ns_qe = NULL;
578 if (NULL == handle->resp_object)
579 handle->resp_object = json_array ();
580 for (i = 0; i < rd_len; i++)
581 {
582 if ((GNUNET_GNSRECORD_TYPE_ANY != handle->record_type) &&
583 (rd[i].record_type != handle->record_type))
584 continue; /* Apply filter */
585 rd_filtered[j] = rd[i];
586 rd_filtered[j].data = rd[i].data;
587 j++;
588 }
589 /** Only add if not empty **/
590 if (j > 0)
591 {
592 record_obj = GNUNET_GNSRECORD_JSON_from_gnsrecord (label,
593 rd_filtered,
594 j);
595 json_array_append_new (handle->resp_object, record_obj);
596 }
597 GNUNET_SCHEDULER_add_now (&namestore_list_finished, handle);
598}
599
600
601/**
602 * Handle namestore GET request
603 *
604 * @param con_handle the connection handle
605 * @param url the url
606 * @param cls the RequestHandle
607 */
608void
609namestore_get (struct GNUNET_REST_RequestHandle *con_handle,
610 const char *url,
611 void *cls)
612{
613 struct RequestHandle *handle = cls;
614 struct EgoEntry *ego_entry;
615 struct GNUNET_HashCode key;
616 char *egoname;
617 char *labelname;
618 char *typename;
619
620 egoname = NULL;
621 ego_entry = NULL;
622
623 // set zone to name if given
624 if (strlen (GNUNET_REST_API_NS_NAMESTORE) + 1 >= strlen (handle->url))
625 {
626 handle->response_code = MHD_HTTP_NOT_FOUND;
627 handle->emsg = GNUNET_strdup (GNUNET_REST_IDENTITY_NOT_FOUND);
628 GNUNET_SCHEDULER_add_now (&do_error, handle);
629 return;
630 }
631 egoname = &handle->url[strlen (GNUNET_REST_API_NS_NAMESTORE) + 1];
632 ego_entry = get_egoentry_namestore (handle, egoname);
633 if (NULL == ego_entry)
634 {
635 handle->response_code = MHD_HTTP_NOT_FOUND;
636 handle->emsg = GNUNET_strdup (GNUNET_REST_IDENTITY_NOT_FOUND);
637 GNUNET_SCHEDULER_add_now (&do_error, handle);
638 return;
639 }
640 handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
641
642 GNUNET_CRYPTO_hash ("record_type", strlen ("record_type"), &key);
643 if (GNUNET_NO ==
644 GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map, &key))
645 {
646 handle->record_type = GNUNET_GNSRECORD_TYPE_ANY;
647 }
648 else
649 {
650 typename = GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map,
651 &key);
652 handle->record_type = GNUNET_GNSRECORD_typename_to_number (typename);
653 }
654 labelname = &egoname[strlen (ego_entry->identifier)];
655 // set zone to name if given
656 if (1 >= strlen (labelname))
657 {
658 handle->list_it =
659 GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
660 handle->zone_pkey,
661 &namestore_iteration_error,
662 handle,
663 &namestore_list_iteration,
664 handle,
665 &namestore_list_finished,
666 handle);
667 if (NULL == handle->list_it)
668 {
669 handle->emsg = GNUNET_strdup (GNUNET_REST_NAMESTORE_FAILED);
670 GNUNET_SCHEDULER_add_now (&do_error, handle);
671 return;
672 }
673 return;
674 }
675 handle->record_name = GNUNET_strdup (labelname + 1);
676 handle->ns_qe = GNUNET_NAMESTORE_records_lookup (ns_handle,
677 handle->zone_pkey,
678 handle->record_name,
679 &ns_lookup_error_cb,
680 handle,
681 &ns_get_lookup_cb,
682 handle);
683 if (NULL == handle->ns_qe)
684 {
685 handle->emsg = GNUNET_strdup (GNUNET_REST_NAMESTORE_FAILED);
686 GNUNET_SCHEDULER_add_now (&do_error, handle);
687 return;
688 }
689}
690
691
692static void
693ns_lookup_cb (void *cls,
694 const struct GNUNET_IDENTITY_PrivateKey *zone,
695 const char *label,
696 unsigned int rd_count,
697 const struct GNUNET_GNSRECORD_Data *rd)
698{
699 struct RequestHandle *handle = cls;
700 struct GNUNET_GNSRECORD_Data rd_new[rd_count + handle->rd_count];
701 int i = 0;
702 int j = 0;
703
704 if (UPDATE_STRATEGY_APPEND == handle->update_strategy)
705 {
706 for (i = 0; i < rd_count; i++)
707 rd_new[i] = rd[i];
708 }
709 for (j = 0; j < handle->rd_count; j++)
710 rd_new[i + j] = handle->rd[j];
711 handle->ns_qe = GNUNET_NAMESTORE_records_store (ns_handle,
712 handle->zone_pkey,
713 handle->record_name,
714 i + j,
715 rd_new,
716 &create_finished,
717 handle);
718 if (NULL == handle->ns_qe)
719 {
720 handle->emsg = GNUNET_strdup (GNUNET_REST_NAMESTORE_FAILED);
721 GNUNET_SCHEDULER_add_now (&do_error, handle);
722 return;
723 }
724}
725
726
727/**
728 * Handle namestore POST/PUT request
729 *
730 * @param con_handle the connection handle
731 * @param url the url
732 * @param cls the RequestHandle
733 */
734void
735namestore_add_or_update (struct GNUNET_REST_RequestHandle *con_handle,
736 const char *url,
737 void *cls)
738{
739 struct RequestHandle *handle = cls;
740 struct EgoEntry *ego_entry;
741 char *egoname;
742 json_t *data_js;
743 json_error_t err;
744
745 char term_data[handle->rest_handle->data_size + 1];
746
747 if (0 >= handle->rest_handle->data_size)
748 {
749 handle->response_code = MHD_HTTP_BAD_REQUEST;
750 handle->emsg = GNUNET_strdup (GNUNET_REST_NAMESTORE_NO_DATA);
751 GNUNET_SCHEDULER_add_now (&do_error, handle);
752 return;
753 }
754 term_data[handle->rest_handle->data_size] = '\0';
755 GNUNET_memcpy (term_data,
756 handle->rest_handle->data,
757 handle->rest_handle->data_size);
758 data_js = json_loads (term_data, JSON_DECODE_ANY, &err);
759 struct GNUNET_JSON_Specification gnsspec[] =
760 { GNUNET_GNSRECORD_JSON_spec_gnsrecord (&handle->rd, &handle->rd_count,
761 &handle->record_name),
762 GNUNET_JSON_spec_end () };
763 if (GNUNET_OK != GNUNET_JSON_parse (data_js, gnsspec, NULL, NULL))
764 {
765 handle->emsg = GNUNET_strdup (GNUNET_REST_NAMESTORE_INVALID_DATA);
766 GNUNET_SCHEDULER_add_now (&do_error, handle);
767 json_decref (data_js);
768 return;
769 }
770 GNUNET_JSON_parse_free (gnsspec);
771 if (0 >= strlen (handle->record_name))
772 {
773 handle->response_code = MHD_HTTP_BAD_REQUEST;
774 handle->emsg = GNUNET_strdup (GNUNET_REST_NAMESTORE_INVALID_DATA);
775 GNUNET_SCHEDULER_add_now (&do_error, handle);
776 json_decref (data_js);
777 return;
778 }
779 json_decref (data_js);
780
781 egoname = NULL;
782 ego_entry = NULL;
783
784 // set zone to name if given
785 if (strlen (GNUNET_REST_API_NS_NAMESTORE) + 1 >= strlen (handle->url))
786 {
787 handle->response_code = MHD_HTTP_NOT_FOUND;
788 handle->emsg = GNUNET_strdup (GNUNET_REST_IDENTITY_NOT_FOUND);
789 GNUNET_SCHEDULER_add_now (&do_error, handle);
790 return;
791 }
792 egoname = &handle->url[strlen (GNUNET_REST_API_NS_NAMESTORE) + 1];
793 ego_entry = get_egoentry_namestore (handle, egoname);
794
795 if (NULL == ego_entry)
796 {
797 handle->response_code = MHD_HTTP_NOT_FOUND;
798 handle->emsg = GNUNET_strdup (GNUNET_REST_IDENTITY_NOT_FOUND);
799 GNUNET_SCHEDULER_add_now (&do_error, handle);
800 return;
801 }
802 handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
803 handle->ns_qe = GNUNET_NAMESTORE_records_lookup (ns_handle,
804 handle->zone_pkey,
805 handle->record_name,
806 &ns_lookup_error_cb,
807 handle,
808 &ns_lookup_cb,
809 handle);
810 if (NULL == handle->ns_qe)
811 {
812 handle->emsg = GNUNET_strdup (GNUNET_REST_NAMESTORE_FAILED);
813 GNUNET_SCHEDULER_add_now (&do_error, handle);
814 return;
815 }
816}
817
818
819/**
820 * Handle namestore PUT request
821 *
822 * @param con_handle the connection handle
823 * @param url the url
824 * @param cls the RequestHandle
825 */
826void
827namestore_update (struct GNUNET_REST_RequestHandle *con_handle,
828 const char *url,
829 void *cls)
830{
831 struct RequestHandle *handle = cls;
832 handle->update_strategy = UPDATE_STRATEGY_REPLACE;
833 namestore_add_or_update (con_handle, url, cls);
834}
835
836
837/**
838 * Handle namestore POST request
839 *
840 * @param con_handle the connection handle
841 * @param url the url
842 * @param cls the RequestHandle
843 */
844void
845namestore_add (struct GNUNET_REST_RequestHandle *con_handle,
846 const char *url,
847 void *cls)
848{
849 struct RequestHandle *handle = cls;
850 handle->update_strategy = UPDATE_STRATEGY_APPEND;
851 namestore_add_or_update (con_handle, url, cls);
852}
853
854
855/**
856 * Handle namestore DELETE request
857 *
858 * @param con_handle the connection handle
859 * @param url the url
860 * @param cls the RequestHandle
861 */
862void
863namestore_delete (struct GNUNET_REST_RequestHandle *con_handle,
864 const char *url,
865 void *cls)
866{
867 struct RequestHandle *handle = cls;
868 struct EgoEntry *ego_entry;
869 char *egoname;
870 char *labelname;
871
872 egoname = NULL;
873 ego_entry = NULL;
874
875 // set zone to name if given
876 if (strlen (GNUNET_REST_API_NS_NAMESTORE) + 1 >= strlen (handle->url))
877 {
878 handle->response_code = MHD_HTTP_NOT_FOUND;
879 handle->emsg = GNUNET_strdup (GNUNET_REST_IDENTITY_NOT_FOUND);
880 GNUNET_SCHEDULER_add_now (&do_error, handle);
881 return;
882 }
883 egoname = &handle->url[strlen (GNUNET_REST_API_NS_NAMESTORE) + 1];
884 ego_entry = get_egoentry_namestore (handle, egoname);
885 if (NULL == ego_entry)
886 {
887 handle->response_code = MHD_HTTP_NOT_FOUND;
888 handle->emsg = GNUNET_strdup (GNUNET_REST_IDENTITY_NOT_FOUND);
889 GNUNET_SCHEDULER_add_now (&do_error, handle);
890 return;
891 }
892 handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
893 labelname = &egoname[strlen (ego_entry->identifier)];
894 // set zone to name if given
895 if (1 >= strlen (labelname))
896 {
897 /* label is only "/" */
898 handle->response_code = MHD_HTTP_BAD_REQUEST;
899 handle->emsg = GNUNET_strdup ("Label missing");
900 GNUNET_SCHEDULER_add_now (&do_error, handle);
901 }
902
903 handle->record_name = GNUNET_strdup (labelname + 1);
904 handle->ns_qe = GNUNET_NAMESTORE_records_store (ns_handle,
905 handle->zone_pkey,
906 handle->record_name,
907 0,
908 NULL,
909 &del_finished,
910 handle);
911 if (NULL == handle->ns_qe)
912 {
913 handle->emsg = GNUNET_strdup (GNUNET_REST_NAMESTORE_FAILED);
914 GNUNET_SCHEDULER_add_now (&do_error, handle);
915 return;
916 }
917}
918
919
920/**
921 * Respond to OPTIONS request
922 *
923 * @param con_handle the connection handle
924 * @param url the url
925 * @param cls the RequestHandle
926 */
927static void
928options_cont (struct GNUNET_REST_RequestHandle *con_handle,
929 const char *url,
930 void *cls)
931{
932 struct MHD_Response *resp;
933 struct RequestHandle *handle = cls;
934
935 // independent of path return all options
936 resp = GNUNET_REST_create_response (NULL);
937 MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods);
938 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
939 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
940 return;
941}
942
943
944static void
945list_ego (void *cls,
946 struct GNUNET_IDENTITY_Ego *ego,
947 void **ctx,
948 const char *identifier)
949{
950 struct EgoEntry *ego_entry;
951 struct GNUNET_IDENTITY_PublicKey pk;
952
953 if ((NULL == ego) && (ID_REST_STATE_INIT == state))
954 {
955 state = ID_REST_STATE_POST_INIT;
956 return;
957 }
958 if (NULL == ego)
959 {
960 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
961 "Called with NULL ego\n");
962 return;
963 }
964 if (ID_REST_STATE_INIT == state)
965 {
966 ego_entry = GNUNET_new (struct EgoEntry);
967 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
968 ego_entry->keystring = GNUNET_IDENTITY_public_key_to_string (&pk);
969 ego_entry->ego = ego;
970 ego_entry->identifier = GNUNET_strdup (identifier);
971 GNUNET_CONTAINER_DLL_insert_tail (ego_head,
972 ego_tail,
973 ego_entry);
974 }
975 /* Ego renamed or added */
976 if (identifier != NULL)
977 {
978 for (ego_entry = ego_head; NULL != ego_entry;
979 ego_entry = ego_entry->next)
980 {
981 if (ego_entry->ego == ego)
982 {
983 /* Rename */
984 GNUNET_free (ego_entry->identifier);
985 ego_entry->identifier = GNUNET_strdup (identifier);
986 break;
987 }
988 }
989 if (NULL == ego_entry)
990 {
991 /* Add */
992 ego_entry = GNUNET_new (struct EgoEntry);
993 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
994 ego_entry->keystring = GNUNET_IDENTITY_public_key_to_string (&pk);
995 ego_entry->ego = ego;
996 ego_entry->identifier = GNUNET_strdup (identifier);
997 GNUNET_CONTAINER_DLL_insert_tail (ego_head,
998 ego_tail,
999 ego_entry);
1000 }
1001 }
1002 else
1003 {
1004 /* Delete */
1005 for (ego_entry = ego_head; NULL != ego_entry;
1006 ego_entry = ego_entry->next)
1007 {
1008 if (ego_entry->ego == ego)
1009 break;
1010 }
1011 if (NULL == ego_entry)
1012 return; /* Not found */
1013
1014 GNUNET_CONTAINER_DLL_remove (ego_head,
1015 ego_tail,
1016 ego_entry);
1017 GNUNET_free (ego_entry->identifier);
1018 GNUNET_free (ego_entry->keystring);
1019 GNUNET_free (ego_entry);
1020 return;
1021 }
1022
1023}
1024
1025
1026/**
1027 * Function processing the REST call
1028 *
1029 * @param method HTTP method
1030 * @param url URL of the HTTP request
1031 * @param data body of the HTTP request (optional)
1032 * @param data_size length of the body
1033 * @param proc callback function for the result
1034 * @param proc_cls closure for callback function
1035 * @return GNUNET_OK if request accepted
1036 */
1037static enum GNUNET_GenericReturnValue
1038rest_process_request (struct GNUNET_REST_RequestHandle *rest_handle,
1039 GNUNET_REST_ResultProcessor proc,
1040 void *proc_cls)
1041{
1042 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1043 struct GNUNET_REST_RequestHandlerError err;
1044 static const struct GNUNET_REST_RequestHandler handlers[] =
1045 { { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_NAMESTORE, &namestore_get },
1046 { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_NAMESTORE, &namestore_add },
1047 { MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_NAMESTORE, &namestore_update },
1048 { MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_NAMESTORE, &namestore_delete },
1049 { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_NAMESTORE, &options_cont },
1050 GNUNET_REST_HANDLER_END };
1051
1052 handle->response_code = 0;
1053 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1054 handle->proc_cls = proc_cls;
1055 handle->proc = proc;
1056 handle->rest_handle = rest_handle;
1057 handle->zone_pkey = NULL;
1058 handle->timeout_task =
1059 GNUNET_SCHEDULER_add_delayed (handle->timeout, &do_error, handle);
1060 handle->url = GNUNET_strdup (rest_handle->url);
1061 if (handle->url[strlen (handle->url) - 1] == '/')
1062 handle->url[strlen (handle->url) - 1] = '\0';
1063 GNUNET_CONTAINER_DLL_insert (requests_head,
1064 requests_tail,
1065 handle);
1066 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n");
1067 if (GNUNET_NO ==
1068 GNUNET_REST_handle_request (handle->rest_handle, handlers, &err, handle))
1069 {
1070 cleanup_handle (handle);
1071 return GNUNET_NO;
1072 }
1073
1074 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected\n");
1075 return GNUNET_YES;
1076}
1077
1078
1079/**
1080 * Entry point for the plugin.
1081 *
1082 * @param cls Config info
1083 * @return NULL on error, otherwise the plugin context
1084 */
1085void *
1086libgnunet_plugin_rest_namestore_init (void *cls)
1087{
1088 static struct Plugin plugin;
1089 struct GNUNET_REST_Plugin *api;
1090
1091 cfg = cls;
1092 if (NULL != plugin.cfg)
1093 return NULL; /* can only initialize once! */
1094 memset (&plugin, 0, sizeof(struct Plugin));
1095 plugin.cfg = cfg;
1096 api = GNUNET_new (struct GNUNET_REST_Plugin);
1097 api->cls = &plugin;
1098 api->name = GNUNET_REST_API_NS_NAMESTORE;
1099 api->process_request = &rest_process_request;
1100 state = ID_REST_STATE_INIT;
1101 GNUNET_asprintf (&allow_methods,
1102 "%s, %s, %s, %s, %s",
1103 MHD_HTTP_METHOD_GET,
1104 MHD_HTTP_METHOD_POST,
1105 MHD_HTTP_METHOD_PUT,
1106 MHD_HTTP_METHOD_DELETE,
1107 MHD_HTTP_METHOD_OPTIONS);
1108 ns_handle = GNUNET_NAMESTORE_connect (cfg);
1109 identity_handle = GNUNET_IDENTITY_connect (cfg, &list_ego, NULL);
1110
1111 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _ ("Namestore REST API initialized\n"));
1112 return api;
1113}
1114
1115
1116/**
1117 * Exit point from the plugin.
1118 *
1119 * @param cls the plugin context (as returned by "init")
1120 * @return always NULL
1121 */
1122void *
1123libgnunet_plugin_rest_namestore_done (void *cls)
1124{
1125 struct GNUNET_REST_Plugin *api = cls;
1126 struct Plugin *plugin = api->cls;
1127 struct RequestHandle *request;
1128 struct EgoEntry *ego_entry;
1129 struct EgoEntry *ego_tmp;
1130
1131 plugin->cfg = NULL;
1132 while (NULL != (request = requests_head))
1133 do_error (request);
1134 if (NULL != identity_handle)
1135 GNUNET_IDENTITY_disconnect (identity_handle);
1136 if (NULL != ns_handle)
1137 GNUNET_NAMESTORE_disconnect (ns_handle);
1138
1139 for (ego_entry = ego_head; NULL != ego_entry;)
1140 {
1141 ego_tmp = ego_entry;
1142 ego_entry = ego_entry->next;
1143 GNUNET_free (ego_tmp->identifier);
1144 GNUNET_free (ego_tmp->keystring);
1145 GNUNET_free (ego_tmp);
1146 }
1147
1148 GNUNET_free (allow_methods);
1149 GNUNET_free (api);
1150 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Namestore REST plugin is finished\n");
1151 return NULL;
1152}
1153
1154
1155/* end of plugin_rest_namestore.c */