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.c1153
1 files changed, 0 insertions, 1153 deletions
diff --git a/src/namestore/plugin_rest_namestore.c b/src/namestore/plugin_rest_namestore.c
deleted file mode 100644
index 0475960eb..000000000
--- a/src/namestore/plugin_rest_namestore.c
+++ /dev/null
@@ -1,1153 +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 handle->record_type = GNUNET_GNSRECORD_TYPE_ANY;
644 if (GNUNET_YES ==
645 GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map, &key))
646 {
647 typename = GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map,
648 &key);
649 if (NULL != typename)
650 handle->record_type = GNUNET_GNSRECORD_typename_to_number (typename);
651 }
652 labelname = &egoname[strlen (ego_entry->identifier)];
653 // set zone to name if given
654 if (1 >= strlen (labelname))
655 {
656 handle->list_it =
657 GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
658 handle->zone_pkey,
659 &namestore_iteration_error,
660 handle,
661 &namestore_list_iteration,
662 handle,
663 &namestore_list_finished,
664 handle);
665 if (NULL == handle->list_it)
666 {
667 handle->emsg = GNUNET_strdup (GNUNET_REST_NAMESTORE_FAILED);
668 GNUNET_SCHEDULER_add_now (&do_error, handle);
669 return;
670 }
671 return;
672 }
673 handle->record_name = GNUNET_strdup (labelname + 1);
674 handle->ns_qe = GNUNET_NAMESTORE_records_lookup (ns_handle,
675 handle->zone_pkey,
676 handle->record_name,
677 &ns_lookup_error_cb,
678 handle,
679 &ns_get_lookup_cb,
680 handle);
681 if (NULL == handle->ns_qe)
682 {
683 handle->emsg = GNUNET_strdup (GNUNET_REST_NAMESTORE_FAILED);
684 GNUNET_SCHEDULER_add_now (&do_error, handle);
685 return;
686 }
687}
688
689
690static void
691ns_lookup_cb (void *cls,
692 const struct GNUNET_IDENTITY_PrivateKey *zone,
693 const char *label,
694 unsigned int rd_count,
695 const struct GNUNET_GNSRECORD_Data *rd)
696{
697 struct RequestHandle *handle = cls;
698 struct GNUNET_GNSRECORD_Data rd_new[rd_count + handle->rd_count];
699 int i = 0;
700 int j = 0;
701
702 if (UPDATE_STRATEGY_APPEND == handle->update_strategy)
703 {
704 for (i = 0; i < rd_count; i++)
705 rd_new[i] = rd[i];
706 }
707 for (j = 0; j < handle->rd_count; j++)
708 rd_new[i + j] = handle->rd[j];
709 handle->ns_qe = GNUNET_NAMESTORE_records_store (ns_handle,
710 handle->zone_pkey,
711 handle->record_name,
712 i + j,
713 rd_new,
714 &create_finished,
715 handle);
716 if (NULL == handle->ns_qe)
717 {
718 handle->emsg = GNUNET_strdup (GNUNET_REST_NAMESTORE_FAILED);
719 GNUNET_SCHEDULER_add_now (&do_error, handle);
720 return;
721 }
722}
723
724
725/**
726 * Handle namestore POST/PUT request
727 *
728 * @param con_handle the connection handle
729 * @param url the url
730 * @param cls the RequestHandle
731 */
732void
733namestore_add_or_update (struct GNUNET_REST_RequestHandle *con_handle,
734 const char *url,
735 void *cls)
736{
737 struct RequestHandle *handle = cls;
738 struct EgoEntry *ego_entry;
739 char *egoname;
740 json_t *data_js;
741 json_error_t err;
742
743 char term_data[handle->rest_handle->data_size + 1];
744
745 if (0 >= handle->rest_handle->data_size)
746 {
747 handle->response_code = MHD_HTTP_BAD_REQUEST;
748 handle->emsg = GNUNET_strdup (GNUNET_REST_NAMESTORE_NO_DATA);
749 GNUNET_SCHEDULER_add_now (&do_error, handle);
750 return;
751 }
752 term_data[handle->rest_handle->data_size] = '\0';
753 GNUNET_memcpy (term_data,
754 handle->rest_handle->data,
755 handle->rest_handle->data_size);
756 data_js = json_loads (term_data, JSON_DECODE_ANY, &err);
757 struct GNUNET_JSON_Specification gnsspec[] =
758 { GNUNET_GNSRECORD_JSON_spec_gnsrecord (&handle->rd, &handle->rd_count,
759 &handle->record_name),
760 GNUNET_JSON_spec_end () };
761 if (GNUNET_OK != GNUNET_JSON_parse (data_js, gnsspec, NULL, NULL))
762 {
763 handle->emsg = GNUNET_strdup (GNUNET_REST_NAMESTORE_INVALID_DATA);
764 GNUNET_SCHEDULER_add_now (&do_error, handle);
765 json_decref (data_js);
766 return;
767 }
768 GNUNET_JSON_parse_free (gnsspec);
769 if (0 >= strlen (handle->record_name))
770 {
771 handle->response_code = MHD_HTTP_BAD_REQUEST;
772 handle->emsg = GNUNET_strdup (GNUNET_REST_NAMESTORE_INVALID_DATA);
773 GNUNET_SCHEDULER_add_now (&do_error, handle);
774 json_decref (data_js);
775 return;
776 }
777 json_decref (data_js);
778
779 egoname = NULL;
780 ego_entry = NULL;
781
782 // set zone to name if given
783 if (strlen (GNUNET_REST_API_NS_NAMESTORE) + 1 >= strlen (handle->url))
784 {
785 handle->response_code = MHD_HTTP_NOT_FOUND;
786 handle->emsg = GNUNET_strdup (GNUNET_REST_IDENTITY_NOT_FOUND);
787 GNUNET_SCHEDULER_add_now (&do_error, handle);
788 return;
789 }
790 egoname = &handle->url[strlen (GNUNET_REST_API_NS_NAMESTORE) + 1];
791 ego_entry = get_egoentry_namestore (handle, egoname);
792
793 if (NULL == ego_entry)
794 {
795 handle->response_code = MHD_HTTP_NOT_FOUND;
796 handle->emsg = GNUNET_strdup (GNUNET_REST_IDENTITY_NOT_FOUND);
797 GNUNET_SCHEDULER_add_now (&do_error, handle);
798 return;
799 }
800 handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
801 handle->ns_qe = GNUNET_NAMESTORE_records_lookup (ns_handle,
802 handle->zone_pkey,
803 handle->record_name,
804 &ns_lookup_error_cb,
805 handle,
806 &ns_lookup_cb,
807 handle);
808 if (NULL == handle->ns_qe)
809 {
810 handle->emsg = GNUNET_strdup (GNUNET_REST_NAMESTORE_FAILED);
811 GNUNET_SCHEDULER_add_now (&do_error, handle);
812 return;
813 }
814}
815
816
817/**
818 * Handle namestore PUT request
819 *
820 * @param con_handle the connection handle
821 * @param url the url
822 * @param cls the RequestHandle
823 */
824void
825namestore_update (struct GNUNET_REST_RequestHandle *con_handle,
826 const char *url,
827 void *cls)
828{
829 struct RequestHandle *handle = cls;
830 handle->update_strategy = UPDATE_STRATEGY_REPLACE;
831 namestore_add_or_update (con_handle, url, cls);
832}
833
834
835/**
836 * Handle namestore POST request
837 *
838 * @param con_handle the connection handle
839 * @param url the url
840 * @param cls the RequestHandle
841 */
842void
843namestore_add (struct GNUNET_REST_RequestHandle *con_handle,
844 const char *url,
845 void *cls)
846{
847 struct RequestHandle *handle = cls;
848 handle->update_strategy = UPDATE_STRATEGY_APPEND;
849 namestore_add_or_update (con_handle, url, cls);
850}
851
852
853/**
854 * Handle namestore DELETE request
855 *
856 * @param con_handle the connection handle
857 * @param url the url
858 * @param cls the RequestHandle
859 */
860void
861namestore_delete (struct GNUNET_REST_RequestHandle *con_handle,
862 const char *url,
863 void *cls)
864{
865 struct RequestHandle *handle = cls;
866 struct EgoEntry *ego_entry;
867 char *egoname;
868 char *labelname;
869
870 egoname = NULL;
871 ego_entry = NULL;
872
873 // set zone to name if given
874 if (strlen (GNUNET_REST_API_NS_NAMESTORE) + 1 >= strlen (handle->url))
875 {
876 handle->response_code = MHD_HTTP_NOT_FOUND;
877 handle->emsg = GNUNET_strdup (GNUNET_REST_IDENTITY_NOT_FOUND);
878 GNUNET_SCHEDULER_add_now (&do_error, handle);
879 return;
880 }
881 egoname = &handle->url[strlen (GNUNET_REST_API_NS_NAMESTORE) + 1];
882 ego_entry = get_egoentry_namestore (handle, egoname);
883 if (NULL == ego_entry)
884 {
885 handle->response_code = MHD_HTTP_NOT_FOUND;
886 handle->emsg = GNUNET_strdup (GNUNET_REST_IDENTITY_NOT_FOUND);
887 GNUNET_SCHEDULER_add_now (&do_error, handle);
888 return;
889 }
890 handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
891 labelname = &egoname[strlen (ego_entry->identifier)];
892 // set zone to name if given
893 if (1 >= strlen (labelname))
894 {
895 /* label is only "/" */
896 handle->response_code = MHD_HTTP_BAD_REQUEST;
897 handle->emsg = GNUNET_strdup ("Label missing");
898 GNUNET_SCHEDULER_add_now (&do_error, handle);
899 }
900
901 handle->record_name = GNUNET_strdup (labelname + 1);
902 handle->ns_qe = GNUNET_NAMESTORE_records_store (ns_handle,
903 handle->zone_pkey,
904 handle->record_name,
905 0,
906 NULL,
907 &del_finished,
908 handle);
909 if (NULL == handle->ns_qe)
910 {
911 handle->emsg = GNUNET_strdup (GNUNET_REST_NAMESTORE_FAILED);
912 GNUNET_SCHEDULER_add_now (&do_error, handle);
913 return;
914 }
915}
916
917
918/**
919 * Respond to OPTIONS request
920 *
921 * @param con_handle the connection handle
922 * @param url the url
923 * @param cls the RequestHandle
924 */
925static void
926options_cont (struct GNUNET_REST_RequestHandle *con_handle,
927 const char *url,
928 void *cls)
929{
930 struct MHD_Response *resp;
931 struct RequestHandle *handle = cls;
932
933 // independent of path return all options
934 resp = GNUNET_REST_create_response (NULL);
935 MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods);
936 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
937 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
938 return;
939}
940
941
942static void
943list_ego (void *cls,
944 struct GNUNET_IDENTITY_Ego *ego,
945 void **ctx,
946 const char *identifier)
947{
948 struct EgoEntry *ego_entry;
949 struct GNUNET_IDENTITY_PublicKey pk;
950
951 if ((NULL == ego) && (ID_REST_STATE_INIT == state))
952 {
953 state = ID_REST_STATE_POST_INIT;
954 return;
955 }
956 if (NULL == ego)
957 {
958 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
959 "Called with NULL ego\n");
960 return;
961 }
962 if (ID_REST_STATE_INIT == state)
963 {
964 ego_entry = GNUNET_new (struct EgoEntry);
965 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
966 ego_entry->keystring = GNUNET_IDENTITY_public_key_to_string (&pk);
967 ego_entry->ego = ego;
968 ego_entry->identifier = GNUNET_strdup (identifier);
969 GNUNET_CONTAINER_DLL_insert_tail (ego_head,
970 ego_tail,
971 ego_entry);
972 }
973 /* Ego renamed or added */
974 if (identifier != NULL)
975 {
976 for (ego_entry = ego_head; NULL != ego_entry;
977 ego_entry = ego_entry->next)
978 {
979 if (ego_entry->ego == ego)
980 {
981 /* Rename */
982 GNUNET_free (ego_entry->identifier);
983 ego_entry->identifier = GNUNET_strdup (identifier);
984 break;
985 }
986 }
987 if (NULL == ego_entry)
988 {
989 /* Add */
990 ego_entry = GNUNET_new (struct EgoEntry);
991 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
992 ego_entry->keystring = GNUNET_IDENTITY_public_key_to_string (&pk);
993 ego_entry->ego = ego;
994 ego_entry->identifier = GNUNET_strdup (identifier);
995 GNUNET_CONTAINER_DLL_insert_tail (ego_head,
996 ego_tail,
997 ego_entry);
998 }
999 }
1000 else
1001 {
1002 /* Delete */
1003 for (ego_entry = ego_head; NULL != ego_entry;
1004 ego_entry = ego_entry->next)
1005 {
1006 if (ego_entry->ego == ego)
1007 break;
1008 }
1009 if (NULL == ego_entry)
1010 return; /* Not found */
1011
1012 GNUNET_CONTAINER_DLL_remove (ego_head,
1013 ego_tail,
1014 ego_entry);
1015 GNUNET_free (ego_entry->identifier);
1016 GNUNET_free (ego_entry->keystring);
1017 GNUNET_free (ego_entry);
1018 return;
1019 }
1020
1021}
1022
1023
1024/**
1025 * Function processing the REST call
1026 *
1027 * @param method HTTP method
1028 * @param url URL of the HTTP request
1029 * @param data body of the HTTP request (optional)
1030 * @param data_size length of the body
1031 * @param proc callback function for the result
1032 * @param proc_cls closure for callback function
1033 * @return GNUNET_OK if request accepted
1034 */
1035static enum GNUNET_GenericReturnValue
1036rest_process_request (struct GNUNET_REST_RequestHandle *rest_handle,
1037 GNUNET_REST_ResultProcessor proc,
1038 void *proc_cls)
1039{
1040 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1041 struct GNUNET_REST_RequestHandlerError err;
1042 static const struct GNUNET_REST_RequestHandler handlers[] =
1043 { { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_NAMESTORE, &namestore_get },
1044 { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_NAMESTORE, &namestore_add },
1045 { MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_NAMESTORE, &namestore_update },
1046 { MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_NAMESTORE, &namestore_delete },
1047 { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_NAMESTORE, &options_cont },
1048 GNUNET_REST_HANDLER_END };
1049
1050 handle->response_code = 0;
1051 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1052 handle->proc_cls = proc_cls;
1053 handle->proc = proc;
1054 handle->rest_handle = rest_handle;
1055 handle->zone_pkey = NULL;
1056 handle->timeout_task =
1057 GNUNET_SCHEDULER_add_delayed (handle->timeout, &do_error, handle);
1058 handle->url = GNUNET_strdup (rest_handle->url);
1059 if (handle->url[strlen (handle->url) - 1] == '/')
1060 handle->url[strlen (handle->url) - 1] = '\0';
1061 GNUNET_CONTAINER_DLL_insert (requests_head,
1062 requests_tail,
1063 handle);
1064 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n");
1065 if (GNUNET_NO ==
1066 GNUNET_REST_handle_request (handle->rest_handle, handlers, &err, handle))
1067 {
1068 cleanup_handle (handle);
1069 return GNUNET_NO;
1070 }
1071
1072 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected\n");
1073 return GNUNET_YES;
1074}
1075
1076
1077/**
1078 * Entry point for the plugin.
1079 *
1080 * @param cls Config info
1081 * @return NULL on error, otherwise the plugin context
1082 */
1083void *
1084libgnunet_plugin_rest_namestore_init (void *cls)
1085{
1086 static struct Plugin plugin;
1087 struct GNUNET_REST_Plugin *api;
1088
1089 cfg = cls;
1090 if (NULL != plugin.cfg)
1091 return NULL; /* can only initialize once! */
1092 memset (&plugin, 0, sizeof(struct Plugin));
1093 plugin.cfg = cfg;
1094 api = GNUNET_new (struct GNUNET_REST_Plugin);
1095 api->cls = &plugin;
1096 api->name = GNUNET_REST_API_NS_NAMESTORE;
1097 api->process_request = &rest_process_request;
1098 state = ID_REST_STATE_INIT;
1099 GNUNET_asprintf (&allow_methods,
1100 "%s, %s, %s, %s, %s",
1101 MHD_HTTP_METHOD_GET,
1102 MHD_HTTP_METHOD_POST,
1103 MHD_HTTP_METHOD_PUT,
1104 MHD_HTTP_METHOD_DELETE,
1105 MHD_HTTP_METHOD_OPTIONS);
1106 ns_handle = GNUNET_NAMESTORE_connect (cfg);
1107 identity_handle = GNUNET_IDENTITY_connect (cfg, &list_ego, NULL);
1108
1109 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _ ("Namestore REST API initialized\n"));
1110 return api;
1111}
1112
1113
1114/**
1115 * Exit point from the plugin.
1116 *
1117 * @param cls the plugin context (as returned by "init")
1118 * @return always NULL
1119 */
1120void *
1121libgnunet_plugin_rest_namestore_done (void *cls)
1122{
1123 struct GNUNET_REST_Plugin *api = cls;
1124 struct Plugin *plugin = api->cls;
1125 struct RequestHandle *request;
1126 struct EgoEntry *ego_entry;
1127 struct EgoEntry *ego_tmp;
1128
1129 plugin->cfg = NULL;
1130 while (NULL != (request = requests_head))
1131 do_error (request);
1132 if (NULL != identity_handle)
1133 GNUNET_IDENTITY_disconnect (identity_handle);
1134 if (NULL != ns_handle)
1135 GNUNET_NAMESTORE_disconnect (ns_handle);
1136
1137 for (ego_entry = ego_head; NULL != ego_entry;)
1138 {
1139 ego_tmp = ego_entry;
1140 ego_entry = ego_entry->next;
1141 GNUNET_free (ego_tmp->identifier);
1142 GNUNET_free (ego_tmp->keystring);
1143 GNUNET_free (ego_tmp);
1144 }
1145
1146 GNUNET_free (allow_methods);
1147 GNUNET_free (api);
1148 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Namestore REST plugin is finished\n");
1149 return NULL;
1150}
1151
1152
1153/* end of plugin_rest_namestore.c */