2 This file is part of GNUnet.
3 Copyright (C) 2012-2015 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
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 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
21 * @author Martin Schanzenbach
22 * @file namestore/plugin_rest_namestore.c
23 * @brief GNUnet Namestore REST plugin
28 #include "gnunet_rest_plugin.h"
29 #include "gnunet_namestore_service.h"
30 #include "gnunet_identity_service.h"
31 #include "gnunet_rest_lib.h"
32 #include "microhttpd.h"
35 #define GNUNET_REST_API_NS_NAMESTORE "/names"
37 #define GNUNET_REST_API_NS_NAMESTORE_ZKEY "/names/zkey"
39 #define GNUNET_REST_JSONAPI_NAMESTORE_TYPEINFO "record"
41 #define GNUNET_REST_JSONAPI_NAMESTORE_NAME "name"
43 #define GNUNET_REST_JSONAPI_NAMESTORE_REVINFO "revinfo"
45 #define GNUNET_REST_JSONAPI_NAMESTORE_RECORD GNUNET_REST_JSONAPI_NAMESTORE_TYPEINFO
47 #define GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE "record_type"
49 #define GNUNET_REST_JSONAPI_NAMESTORE_VALUE "value"
51 #define GNUNET_REST_JSONAPI_NAMESTORE_PUBLIC "public"
53 #define GNUNET_REST_JSONAPI_NAMESTORE_SHADOW "shadow"
55 #define GNUNET_REST_JSONAPI_NAMESTORE_PKEY "pkey"
57 #define GNUNET_REST_JSONAPI_NAMESTORE_ZKEY "zkey"
59 #define GNUNET_REST_JSONAPI_NAMESTORE_EXPIRATION "expiration"
61 #define GNUNET_REST_JSONAPI_NAMESTORE_EGO "ego"
64 * @brief struct returned by the initialization function of the plugin
68 const struct GNUNET_CONFIGURATION_Handle *cfg;
73 * HTTP methods allows for this plugin
75 static char* allow_methods;
77 const struct GNUNET_CONFIGURATION_Handle *cfg;
84 struct RecordEntry *next;
89 struct RecordEntry *prev;
98 struct RecordEntry *record_head;
103 struct record_entry *record_tail;
106 * JSON response object
108 struct JsonApiObject *resp_object;
113 struct RestConnectionDataHandle *conndata_handle;
116 * Handle to GNS service.
118 struct GNUNET_IDENTITY_Handle *identity_handle;
121 * Handle to NAMESTORE
123 struct GNUNET_NAMESTORE_Handle *ns_handle;
126 * Handle to NAMESTORE it
128 struct GNUNET_NAMESTORE_ZoneIterator *list_it;
131 * Private key for the zone
133 struct GNUNET_CRYPTO_EcdsaPrivateKey zone_pkey;
136 * Handle to identity lookup
138 struct GNUNET_IDENTITY_EgoLookup *ego_lookup;
141 * Default Ego operation
143 struct GNUNET_IDENTITY_Operation *get_default;
161 * Name of the record to modify
166 * Value of the record
173 const char* zkey_str;
183 struct GNUNET_GNSRECORD_Data *rd;
188 unsigned int rd_count;
191 * NAMESTORE Operation
193 struct GNUNET_NAMESTORE_QueueEntry *add_qe;
196 * NAMESTORE Operation
198 struct GNUNET_NAMESTORE_QueueEntry *reverse_qe;
201 * Desired timeout for the lookup (default is no timeout).
203 struct GNUNET_TIME_Relative timeout;
206 * ID of a task associated with the resolution process.
208 struct GNUNET_SCHEDULER_Task * timeout_task;
211 * The plugin result processor
213 GNUNET_REST_ResultProcessor proc;
216 * The closure of the result processor
226 * The data from the REST request
231 * the length of the REST data
238 const struct GNUNET_CONFIGURATION_Handle *cfg;
244 * Cleanup lookup handle
245 * @param handle Handle to clean up
248 cleanup_handle (struct RequestHandle *handle)
250 struct RecordEntry *record_entry;
251 struct RecordEntry *record_tmp;
253 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
255 if (NULL != handle->resp_object)
256 GNUNET_REST_jsonapi_object_delete (handle->resp_object);
257 if (NULL != handle->name)
258 GNUNET_free (handle->name);
259 if (NULL != handle->timeout_task)
260 GNUNET_SCHEDULER_cancel (handle->timeout_task);
261 if (NULL != handle->ego_lookup)
262 GNUNET_IDENTITY_ego_lookup_cancel (handle->ego_lookup);
263 if (NULL != handle->get_default)
264 GNUNET_IDENTITY_cancel (handle->get_default);
265 if (NULL != handle->list_it)
266 GNUNET_NAMESTORE_zone_iteration_stop (handle->list_it);
267 if (NULL != handle->add_qe)
268 GNUNET_NAMESTORE_cancel (handle->add_qe);
269 if (NULL != handle->identity_handle)
270 GNUNET_IDENTITY_disconnect (handle->identity_handle);
271 if (NULL != handle->ns_handle)
272 GNUNET_NAMESTORE_disconnect (handle->ns_handle);
273 if (NULL != handle->url)
274 GNUNET_free (handle->url);
275 if (NULL != handle->value)
276 GNUNET_free (handle->value);
277 if (NULL != handle->rd)
279 for (i = 0; i < handle->rd_count; i++)
281 if (NULL != handle->rd[i].data)
282 GNUNET_free ((void*)handle->rd[i].data);
284 GNUNET_free (handle->rd);
286 if (NULL != handle->ego_name)
287 GNUNET_free (handle->ego_name);
288 for (record_entry = handle->record_head;
289 NULL != record_entry;)
291 record_tmp = record_entry;
292 record_entry = record_entry->next;
293 GNUNET_free (record_tmp);
295 GNUNET_free (handle);
299 * Create json representation of a GNSRECORD
301 * @param rd the GNSRECORD_Data
304 gnsrecord_to_json (const struct GNUNET_GNSRECORD_Data *rd)
306 const char *typename;
311 typename = GNUNET_GNSRECORD_number_to_typename (rd->record_type);
312 string_val = GNUNET_GNSRECORD_value_to_string (rd->record_type,
316 if (NULL == string_val)
318 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
319 "Record of type %d malformed, skipping\n",
320 (int) rd->record_type);
323 record_obj = json_object();
324 json_object_set_new (record_obj,
325 GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE,
326 json_string (typename));
327 json_object_set_new (record_obj,
328 GNUNET_REST_JSONAPI_NAMESTORE_VALUE,
329 json_string (string_val));
330 GNUNET_free (string_val);
332 if (GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION & rd->flags)
334 struct GNUNET_TIME_Relative time_rel;
335 time_rel.rel_value_us = rd->expiration_time;
336 exp_str = GNUNET_STRINGS_relative_time_to_string (time_rel, 1);
340 struct GNUNET_TIME_Absolute time_abs;
341 time_abs.abs_value_us = rd->expiration_time;
342 exp_str = GNUNET_STRINGS_absolute_time_to_string (time_abs);
344 json_object_set_new (record_obj, GNUNET_REST_JSONAPI_NAMESTORE_EXPIRATION, json_string (exp_str));
346 json_object_set_new (record_obj, "expired",
347 json_boolean (GNUNET_YES == GNUNET_GNSRECORD_is_expired (rd)));
353 * Task run on shutdown. Cleans up everything.
356 * @param tc scheduler context
360 const struct GNUNET_SCHEDULER_TaskContext *tc)
362 struct RequestHandle *handle = cls;
363 struct MHD_Response *resp = GNUNET_REST_create_json_response (NULL);
364 handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
365 cleanup_handle (handle);
369 cleanup_handle_delayed (void *cls,
370 const struct GNUNET_SCHEDULER_TaskContext *tc)
372 cleanup_handle (cls);
376 * Create a response with requested records
378 * @param handle the RequestHandle
381 namestore_list_response (void *cls,
382 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
385 const struct GNUNET_GNSRECORD_Data *rd)
387 struct RequestHandle *handle = cls;
388 struct JsonApiResource *json_resource;
389 struct MHD_Response *resp;
390 json_t *result_array;
395 if (NULL == handle->resp_object)
396 handle->resp_object = GNUNET_REST_jsonapi_object_new ();
400 handle->list_it = NULL;
402 if (GNUNET_SYSERR == GNUNET_REST_jsonapi_data_serialize (handle->resp_object, &result))
404 GNUNET_SCHEDULER_add_now (&do_error, handle);
407 resp = GNUNET_REST_create_json_response (result);
408 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
409 GNUNET_free (result);
410 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
414 if ( (NULL != handle->name) &&
415 (0 != strcmp (handle->name, rname)) )
417 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
418 "%s does not match %s\n", rname, handle->name);
419 GNUNET_NAMESTORE_zone_iterator_next (handle->list_it);
423 result_array = json_array ();
424 for (i=0; i<rd_len; i++)
426 if ( (GNUNET_GNSRECORD_TYPE_NICK == rd[i].record_type) &&
427 (0 != strcmp (rname, "+")) )
430 if ( (rd[i].record_type != handle->type) &&
431 (GNUNET_GNSRECORD_TYPE_ANY != handle->type) )
433 record_obj = gnsrecord_to_json (&(rd[i]));
434 json_array_append (result_array, record_obj);
435 json_decref (record_obj);
438 if (0 < json_array_size(result_array))
440 json_resource = GNUNET_REST_jsonapi_resource_new (GNUNET_REST_JSONAPI_NAMESTORE_TYPEINFO,
442 GNUNET_REST_jsonapi_resource_add_attr (json_resource,
443 GNUNET_REST_JSONAPI_NAMESTORE_RECORD,
445 GNUNET_REST_jsonapi_object_resource_add (handle->resp_object, json_resource);
448 json_decref (result_array);
449 GNUNET_NAMESTORE_zone_iterator_next (handle->list_it);
453 create_finished (void *cls, int32_t success, const char *emsg)
455 struct RequestHandle *handle = cls;
456 struct MHD_Response *resp;
458 handle->add_qe = NULL;
459 if (GNUNET_YES != success)
461 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
462 "Error storing records%s%s\n",
463 (NULL == emsg) ? "" : ": ",
464 (NULL == emsg) ? "" : emsg);
465 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
468 resp = GNUNET_REST_create_json_response (NULL);
469 handle->proc (handle->proc_cls, resp, MHD_HTTP_NO_CONTENT);
470 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
475 * We're storing a new record; this requires
476 * that no record already exists
478 * @param cls closure, unused
479 * @param zone_key private key of the zone
480 * @param rec_name name that is being mapped (at most 255 characters long)
481 * @param rd_count number of entries in @a rd array
482 * @param rd array of records with data to store
485 create_new_record_cont (void *cls,
486 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
487 const char *rec_name,
488 unsigned int rd_count,
489 const struct GNUNET_GNSRECORD_Data *rd)
491 struct RequestHandle *handle = cls;
493 handle->add_qe = NULL;
494 if ( (NULL != zone_key) &&
495 (0 != strcmp (rec_name, handle->name)) )
498 GNUNET_SCHEDULER_add_now (&do_error, handle);
502 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
503 "Received %u records for name `%s'\n",
507 handle->proc (handle->proc_cls,
508 GNUNET_REST_create_json_response (NULL),
510 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
514 GNUNET_assert (NULL != handle->name);
515 handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
525 del_finished (void *cls,
529 struct RequestHandle *handle = cls;
531 handle->add_qe = NULL;
532 if (GNUNET_NO == success)
534 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
535 _("Deleting record failed, record does not exist%s%s\n"),
536 (NULL != emsg) ? ": " : "",
537 (NULL != emsg) ? emsg : "");
538 GNUNET_SCHEDULER_add_now (&do_error, handle); //do_not_found TODO
541 if (GNUNET_SYSERR == success)
543 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
544 _("Deleting record failed%s%s\n"),
545 (NULL != emsg) ? ": " : "",
546 (NULL != emsg) ? emsg : "");
547 GNUNET_SCHEDULER_add_now (&do_error, handle);
550 handle->proc (handle->proc_cls,
551 GNUNET_REST_create_json_response (NULL),
552 MHD_HTTP_NO_CONTENT);
553 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
558 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
560 unsigned int rd_count,
561 const struct GNUNET_GNSRECORD_Data *rd)
563 struct RequestHandle *handle = cls;
567 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
568 _("There are no records under label `%s' that could be deleted.\n"),
570 GNUNET_SCHEDULER_add_now (&do_error, handle);
574 handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
583 namestore_delete_cont (struct RestConnectionDataHandle *con,
587 struct RequestHandle *handle = cls;
589 if (NULL == handle->name)
591 GNUNET_SCHEDULER_add_now (&do_error, handle);
595 handle->add_qe = GNUNET_NAMESTORE_records_lookup (handle->ns_handle,
603 json_to_gnsrecord (const json_t *records_json,
604 struct GNUNET_GNSRECORD_Data **rd,
605 unsigned int *rd_count)
607 struct GNUNET_TIME_Relative etime_rel;
608 struct GNUNET_TIME_Absolute etime_abs;
612 const char *typestring;
613 const char *expirationstring;
620 *rd_count = json_array_size (records_json);
621 *rd = GNUNET_malloc (sizeof (struct GNUNET_GNSRECORD_Data) * *rd_count);
622 for (i = 0; i < *rd_count; i++)
624 memset (&((*rd)[i]), 0, sizeof (struct GNUNET_GNSRECORD_Data));
625 record_json = json_array_get (records_json, i);
626 type_json = json_object_get (record_json,
627 GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE);
628 if (!json_is_string (type_json))
630 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
631 "Type property is no string\n");
632 return GNUNET_SYSERR;
634 typestring = json_string_value (type_json);
635 (*rd)[i].record_type = GNUNET_GNSRECORD_typename_to_number (typestring);
636 if (UINT32_MAX == (*rd)[i].record_type)
638 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Unsupported type `%s'\n"),
639 json_string_value (type_json));
640 return GNUNET_SYSERR;
642 value_json = json_object_get (record_json,
643 GNUNET_REST_JSONAPI_NAMESTORE_VALUE);
644 if (!json_is_string (value_json))
646 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
647 "Value property is no string\n");
648 return GNUNET_SYSERR;
650 GNUNET_asprintf (&value, "%s", json_string_value (value_json));
651 if (GNUNET_OK != GNUNET_GNSRECORD_string_to_value ((*rd)[i].record_type,
656 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Value `%s' invalid for record type `%s'\n"),
658 return GNUNET_SYSERR;
660 (*rd)[i].data = rdata;
661 (*rd)[i].data_size = rdata_size;
663 * if (1 == handle->is_shadow)
664 rde->flags |= GNUNET_GNSRECORD_RF_SHADOW_RECORD;
665 if (1 != handle->is_public)
666 rde->flags |= GNUNET_GNSRECORD_RF_PRIVATE;
668 exp_json = json_object_get (record_json,
669 GNUNET_REST_JSONAPI_NAMESTORE_EXPIRATION);
670 if (!json_is_string (exp_json))
672 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
673 "Expiration property is no string\n");
674 return GNUNET_SYSERR;
676 expirationstring = json_string_value (exp_json);
677 if (0 == strcmp (expirationstring, "never"))
679 (*rd)[i].expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
681 else if (GNUNET_OK ==
682 GNUNET_STRINGS_fancy_time_to_relative (expirationstring,
685 (*rd)[i].expiration_time = etime_rel.rel_value_us;
686 (*rd)[i].flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
688 else if (GNUNET_OK ==
689 GNUNET_STRINGS_fancy_time_to_absolute (expirationstring,
692 (*rd)[i].expiration_time = etime_abs.abs_value_us;
696 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Value `%s' invalid for record type `%s'\n"),
698 return GNUNET_SYSERR;
705 namestore_create_cont (struct RestConnectionDataHandle *con,
709 struct RequestHandle *handle = cls;
710 struct MHD_Response *resp;
711 struct JsonApiObject *json_obj;
712 struct JsonApiResource *json_res;
714 json_t *records_json;
715 char term_data[handle->data_size+1];
717 if (strlen (GNUNET_REST_API_NS_NAMESTORE) != strlen (handle->url))
719 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
720 "Cannot create under %s\n", handle->url);
721 GNUNET_SCHEDULER_add_now (&do_error, handle);
724 if (0 >= handle->data_size)
726 GNUNET_SCHEDULER_add_now (&do_error, handle);
729 term_data[handle->data_size] = '\0';
730 memcpy (term_data, handle->data, handle->data_size);
731 json_obj = GNUNET_REST_jsonapi_object_parse (term_data);
732 if (NULL == json_obj)
734 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
735 "Unable to parse JSONAPI Object from %s\n",
737 GNUNET_SCHEDULER_add_now (&do_error, handle);
740 if (1 != GNUNET_REST_jsonapi_object_resource_count (json_obj))
742 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
743 "Cannot create more than 1 resource! (Got %d)\n",
744 GNUNET_REST_jsonapi_object_resource_count (json_obj));
745 GNUNET_REST_jsonapi_object_delete (json_obj);
746 GNUNET_SCHEDULER_add_now (&do_error, handle);
749 json_res = GNUNET_REST_jsonapi_object_get_resource (json_obj, 0);
750 if (GNUNET_NO == GNUNET_REST_jsonapi_resource_check_type (json_res,
751 GNUNET_REST_JSONAPI_NAMESTORE_RECORD))
753 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
754 "Unsupported JSON data type\n");
755 GNUNET_REST_jsonapi_object_delete (json_obj);
756 resp = GNUNET_REST_create_json_response (NULL);
757 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
758 cleanup_handle (handle);
761 name_json = GNUNET_REST_jsonapi_resource_read_attr (json_res, GNUNET_REST_JSONAPI_KEY_ID);
762 if (!json_is_string (name_json))
764 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
765 "Name property is no string\n");
766 GNUNET_REST_jsonapi_object_delete (json_obj);
767 GNUNET_SCHEDULER_add_now (&do_error, handle);
770 GNUNET_asprintf (&handle->name, "%s", json_string_value (name_json));
771 records_json = GNUNET_REST_jsonapi_resource_read_attr (json_res,
772 GNUNET_REST_JSONAPI_NAMESTORE_RECORD);
773 if (NULL == records_json)
775 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
776 "No records given\n");
777 GNUNET_REST_jsonapi_object_delete (json_obj);
778 GNUNET_SCHEDULER_add_now (&do_error, handle);
781 if (GNUNET_SYSERR == json_to_gnsrecord (records_json, &handle->rd, &handle->rd_count))
783 GNUNET_REST_jsonapi_object_delete (json_obj);
784 GNUNET_SCHEDULER_add_now (&do_error, handle);
787 GNUNET_REST_jsonapi_object_delete (json_obj);
789 handle->add_qe = GNUNET_NAMESTORE_records_lookup (handle->ns_handle,
792 &create_new_record_cont, handle );
796 namestore_zkey_response (void *cls,
797 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
799 unsigned int rd_count,
800 const struct GNUNET_GNSRECORD_Data *rd)
802 struct RequestHandle *handle = cls;
803 struct MHD_Response *resp;
804 struct JsonApiObject *json_obj;
805 struct JsonApiResource *json_res;
809 handle->reverse_qe = NULL;
810 json_obj = GNUNET_REST_jsonapi_object_new ();
813 name_json = json_string (label);
814 json_res = GNUNET_REST_jsonapi_resource_new (GNUNET_REST_JSONAPI_NAMESTORE_REVINFO,
816 GNUNET_REST_jsonapi_resource_add_attr (json_res,
817 GNUNET_REST_JSONAPI_NAMESTORE_NAME,
819 GNUNET_REST_jsonapi_object_resource_add (json_obj, json_res);
820 json_decref (name_json);
823 if (GNUNET_SYSERR == GNUNET_REST_jsonapi_data_serialize (json_obj, &result))
825 GNUNET_REST_jsonapi_object_delete (json_obj);
826 GNUNET_SCHEDULER_add_now (&do_error, handle);
829 resp = GNUNET_REST_create_json_response (result);
830 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
831 GNUNET_free (result);
832 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
838 namestore_zkey_cont (struct RestConnectionDataHandle *con,
842 struct RequestHandle *handle = cls;
843 struct GNUNET_HashCode key;
844 struct GNUNET_CRYPTO_EcdsaPublicKey pubkey;
846 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_NAMESTORE_ZKEY,
847 strlen (GNUNET_REST_JSONAPI_NAMESTORE_ZKEY),
850 GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
853 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
854 "No zkey given %s\n", handle->url);
855 GNUNET_SCHEDULER_add_now (&do_error, handle);
858 handle->zkey_str = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
861 GNUNET_CRYPTO_ecdsa_public_key_from_string (handle->zkey_str,
862 strlen (handle->zkey_str),
865 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
866 "Zkey invalid %s\n", handle->zkey_str);
867 GNUNET_SCHEDULER_add_now (&do_error, handle);
870 handle->reverse_qe = GNUNET_NAMESTORE_zone_to_name (handle->ns_handle,
873 &namestore_zkey_response,
878 namestore_info_cont (struct RestConnectionDataHandle *con,
882 struct RequestHandle *handle = cls;
883 handle->list_it = GNUNET_NAMESTORE_zone_iteration_start (handle->ns_handle,
885 &namestore_list_response,
890 get_name_from_url (const char* url)
892 if (strlen (url) <= strlen (GNUNET_REST_API_NS_NAMESTORE))
894 return (char*)url + strlen (GNUNET_REST_API_NS_NAMESTORE) + 1;
898 * Respond to OPTIONS request
900 * @param con_handle the connection handle
902 * @param cls the RequestHandle
905 options_cont (struct RestConnectionDataHandle *con_handle,
909 struct MHD_Response *resp;
910 struct RequestHandle *handle = cls;
912 //For now, independent of path return all options
913 resp = GNUNET_REST_create_json_response (NULL);
914 MHD_add_response_header (resp,
915 "Access-Control-Allow-Methods",
917 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
918 cleanup_handle (handle);
923 * Function called with the result from the check if the namestore
924 * service is actually running. If it is, we start the actual
927 * @param cls closure with our configuration
928 * @param result #GNUNET_YES if the namestore service is running
931 testservice_task (void *cls,
934 struct RequestHandle *handle = cls;
935 static const struct GNUNET_REST_RestConnectionHandler handlers[] = {
936 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_NAMESTORE_ZKEY, &namestore_zkey_cont}, //reverse
937 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_NAMESTORE, &namestore_info_cont}, //list
938 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_NAMESTORE, &namestore_create_cont}, //create
939 // {MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_NAMESTORE, &namestore_edit_cont}, //update. TODO this shoul be PATCH
940 {MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_NAMESTORE, &namestore_delete_cont}, //delete
941 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_NAMESTORE, &options_cont},
942 GNUNET_REST_HANDLER_END
945 if (GNUNET_YES != result)
947 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Service `%s' is not running\n"),
949 GNUNET_SCHEDULER_add_now (&do_error, handle);
952 handle->ns_handle = GNUNET_NAMESTORE_connect (cfg);
953 if (NULL == handle->ns_handle)
955 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
956 _("Failed to connect to namestore\n"));
957 GNUNET_SCHEDULER_add_now (&do_error, handle);
961 if (GNUNET_NO == GNUNET_REST_handle_request (handle->conndata_handle, handlers, handle))
962 GNUNET_SCHEDULER_add_now (&do_error, (void*) handle);
967 * Callback invoked from identity service with ego information.
968 * An @a ego of NULL means the ego was not found.
970 * @param cls closure with the configuration
971 * @param ego an ego known to identity service, or NULL
974 identity_cb (void *cls,
975 const struct GNUNET_IDENTITY_Ego *ego)
977 struct RequestHandle *handle = cls;
978 struct MHD_Response *resp;
980 handle->ego_lookup = NULL;
983 if (NULL != handle->ego_name)
985 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
986 _("Ego `%s' not known to identity service\n"),
989 resp = GNUNET_REST_create_json_response (NULL);
990 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
991 cleanup_handle (handle);
994 handle->zone_pkey = *GNUNET_IDENTITY_ego_get_private_key (ego);
995 GNUNET_CLIENT_service_test ("namestore", handle->cfg,
996 GNUNET_TIME_UNIT_SECONDS,
1002 default_ego_cb (void *cls,
1003 struct GNUNET_IDENTITY_Ego *ego,
1007 struct RequestHandle *handle = cls;
1008 struct MHD_Response *resp;
1009 handle->get_default = NULL;
1012 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1013 _("No default ego configured in identity service\n"));
1014 resp = GNUNET_REST_create_json_response (NULL);
1015 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
1016 cleanup_handle (handle);
1021 identity_cb (cls, ego);
1026 id_connect_cb (void *cls,
1027 struct GNUNET_IDENTITY_Ego *ego,
1031 struct RequestHandle *handle = cls;
1034 handle->get_default = GNUNET_IDENTITY_get (handle->identity_handle,
1036 &default_ego_cb, handle);
1041 testservice_id_task (void *cls, int result)
1043 struct RequestHandle *handle = cls;
1044 struct MHD_Response *resp;
1045 struct GNUNET_HashCode key;
1050 if (result != GNUNET_YES)
1052 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1053 _("Identity service is not running\n"));
1054 resp = GNUNET_REST_create_json_response (NULL);
1055 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
1056 cleanup_handle (handle);
1060 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_NAMESTORE_EGO,
1061 strlen (GNUNET_REST_JSONAPI_NAMESTORE_EGO),
1064 GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
1067 ego = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
1071 handle->type = GNUNET_GNSRECORD_TYPE_ANY;
1072 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE,
1073 strlen (GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE),
1076 GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
1079 type = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
1082 handle->type = GNUNET_GNSRECORD_typename_to_number (type);
1084 name = get_name_from_url (handle->url);
1086 GNUNET_asprintf (&handle->ego_name, "%s", ego);
1088 GNUNET_asprintf (&handle->name, "%s", name);
1089 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", handle->ego_name);
1090 if (NULL == handle->ego_name)
1092 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", handle->ego_name);
1093 handle->identity_handle = GNUNET_IDENTITY_connect (handle->cfg, &id_connect_cb, handle);
1094 if (NULL == handle->identity_handle)
1096 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Cannot connect to identity service\n"));
1097 resp = GNUNET_REST_create_json_response (NULL);
1098 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
1099 cleanup_handle (handle);
1103 handle->ego_lookup = GNUNET_IDENTITY_ego_lookup (cfg,
1110 * Function processing the REST call
1112 * @param method HTTP method
1113 * @param url URL of the HTTP request
1114 * @param data body of the HTTP request (optional)
1115 * @param data_size length of the body
1116 * @param proc callback function for the result
1117 * @param proc_cls closure for callback function
1118 * @return GNUNET_OK if request accepted
1121 rest_identity_process_request(struct RestConnectionDataHandle *conndata_handle,
1122 GNUNET_REST_ResultProcessor proc,
1125 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1127 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1128 handle->proc_cls = proc_cls;
1129 handle->proc = proc;
1130 handle->conndata_handle = conndata_handle;
1131 handle->data = conndata_handle->data;
1132 handle->data_size = conndata_handle->data_size;
1133 GNUNET_asprintf (&handle->url, "%s", conndata_handle->url);
1134 if (handle->url[strlen (handle->url)-1] == '/')
1135 handle->url[strlen (handle->url)-1] = '\0';
1136 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1139 GNUNET_CLIENT_service_test ("identity",
1141 GNUNET_TIME_UNIT_SECONDS,
1142 &testservice_id_task,
1144 handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout,
1152 * Entry point for the plugin.
1154 * @param cls Config info
1155 * @return NULL on error, otherwise the plugin context
1158 libgnunet_plugin_rest_namestore_init (void *cls)
1160 static struct Plugin plugin;
1162 struct GNUNET_REST_Plugin *api;
1164 if (NULL != plugin.cfg)
1165 return NULL; /* can only initialize once! */
1166 memset (&plugin, 0, sizeof (struct Plugin));
1168 api = GNUNET_new (struct GNUNET_REST_Plugin);
1170 api->name = GNUNET_REST_API_NS_NAMESTORE;
1171 api->process_request = &rest_identity_process_request;
1172 GNUNET_asprintf (&allow_methods,
1173 "%s, %s, %s, %s, %s",
1174 MHD_HTTP_METHOD_GET,
1175 MHD_HTTP_METHOD_POST,
1176 MHD_HTTP_METHOD_PUT,
1177 MHD_HTTP_METHOD_DELETE,
1178 MHD_HTTP_METHOD_OPTIONS);
1179 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1180 _("Namestore REST API initialized\n"));
1186 * Exit point from the plugin.
1188 * @param cls the plugin context (as returned by "init")
1189 * @return always NULL
1192 libgnunet_plugin_rest_namestore_done (void *cls)
1194 struct GNUNET_REST_Plugin *api = cls;
1195 struct Plugin *plugin = api->cls;
1199 GNUNET_free_non_null (allow_methods);
1200 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1201 "Namestore REST plugin is finished\n");
1205 /* end of plugin_rest_namestore.c */