2 This file is part of GNUnet.
3 Copyright (C) 2012-2015 GNUnet e.V.
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 "gnunet_jsonapi_lib.h"
33 #include "microhttpd.h"
36 #define GNUNET_REST_API_NS_NAMESTORE "/names"
38 #define GNUNET_REST_API_NS_NAMESTORE_ZKEY "/names/zkey"
40 #define GNUNET_REST_JSONAPI_NAMESTORE_TYPEINFO "record"
42 #define GNUNET_REST_JSONAPI_NAMESTORE_NAME "name"
44 #define GNUNET_REST_JSONAPI_NAMESTORE_REVINFO "revinfo"
46 #define GNUNET_REST_JSONAPI_NAMESTORE_RECORD GNUNET_REST_JSONAPI_NAMESTORE_TYPEINFO
48 #define GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE "record_type"
50 #define GNUNET_REST_JSONAPI_NAMESTORE_VALUE "value"
52 #define GNUNET_REST_JSONAPI_NAMESTORE_PUBLIC "public"
54 #define GNUNET_REST_JSONAPI_NAMESTORE_SHADOW "shadow"
56 #define GNUNET_REST_JSONAPI_NAMESTORE_PKEY "pkey"
58 #define GNUNET_REST_JSONAPI_NAMESTORE_ZKEY "zkey"
60 #define GNUNET_REST_JSONAPI_NAMESTORE_EXPIRATION "expiration"
62 #define GNUNET_REST_JSONAPI_NAMESTORE_EGO "ego"
65 * @brief struct returned by the initialization function of the plugin
69 const struct GNUNET_CONFIGURATION_Handle *cfg;
74 * HTTP methods allows for this plugin
76 static char* allow_methods;
78 const struct GNUNET_CONFIGURATION_Handle *cfg;
85 struct RecordEntry *next;
90 struct RecordEntry *prev;
99 struct RecordEntry *record_head;
104 struct record_entry *record_tail;
107 * JSON response object
109 struct GNUNET_JSONAPI_Object *resp_object;
114 struct GNUNET_REST_RequestHandle *rest_handle;
117 * Handle to GNS service.
119 struct GNUNET_IDENTITY_Handle *identity_handle;
122 * Handle to NAMESTORE
124 struct GNUNET_NAMESTORE_Handle *ns_handle;
127 * Handle to NAMESTORE it
129 struct GNUNET_NAMESTORE_ZoneIterator *list_it;
132 * Private key for the zone
134 struct GNUNET_CRYPTO_EcdsaPrivateKey zone_pkey;
137 * Handle to identity lookup
139 struct GNUNET_IDENTITY_EgoLookup *ego_lookup;
142 * Default Ego operation
144 struct GNUNET_IDENTITY_Operation *get_default;
162 * Name of the record to modify
167 * Value of the record
174 const char* zkey_str;
184 struct GNUNET_GNSRECORD_Data *rd;
189 unsigned int rd_count;
192 * NAMESTORE Operation
194 struct GNUNET_NAMESTORE_QueueEntry *add_qe;
197 * NAMESTORE Operation
199 struct GNUNET_NAMESTORE_QueueEntry *reverse_qe;
202 * Desired timeout for the lookup (default is no timeout).
204 struct GNUNET_TIME_Relative timeout;
207 * ID of a task associated with the resolution process.
209 struct GNUNET_SCHEDULER_Task * timeout_task;
212 * The plugin result processor
214 GNUNET_REST_ResultProcessor proc;
217 * The closure of the result processor
229 const struct GNUNET_CONFIGURATION_Handle *cfg;
240 * Cleanup lookup handle
242 * @param handle Handle to clean up
245 cleanup_handle (struct RequestHandle *handle)
247 struct RecordEntry *record_entry;
248 struct RecordEntry *record_tmp;
251 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
253 if (NULL != handle->resp_object)
254 GNUNET_JSONAPI_object_delete (handle->resp_object);
255 if (NULL != handle->name)
256 GNUNET_free (handle->name);
257 if (NULL != handle->timeout_task)
258 GNUNET_SCHEDULER_cancel (handle->timeout_task);
259 if (NULL != handle->ego_lookup)
260 GNUNET_IDENTITY_ego_lookup_cancel (handle->ego_lookup);
261 if (NULL != handle->get_default)
262 GNUNET_IDENTITY_cancel (handle->get_default);
263 if (NULL != handle->list_it)
264 GNUNET_NAMESTORE_zone_iteration_stop (handle->list_it);
265 if (NULL != handle->add_qe)
266 GNUNET_NAMESTORE_cancel (handle->add_qe);
267 if (NULL != handle->identity_handle)
268 GNUNET_IDENTITY_disconnect (handle->identity_handle);
269 if (NULL != handle->ns_handle)
270 GNUNET_NAMESTORE_disconnect (handle->ns_handle);
271 if (NULL != handle->url)
272 GNUNET_free (handle->url);
273 if (NULL != handle->value)
274 GNUNET_free (handle->value);
275 if (NULL != handle->rd)
277 for (i = 0; i < handle->rd_count; i++)
279 if (NULL != handle->rd[i].data)
280 GNUNET_free ((void*)handle->rd[i].data);
282 GNUNET_free (handle->rd);
284 if (NULL != handle->ego_name)
285 GNUNET_free (handle->ego_name);
286 for (record_entry = handle->record_head;
287 NULL != record_entry;)
289 record_tmp = record_entry;
290 record_entry = record_entry->next;
291 GNUNET_free (record_tmp);
293 GNUNET_free (handle);
298 * Create json representation of a GNSRECORD
300 * @param rd the GNSRECORD_Data
303 gnsrecord_to_json (const struct GNUNET_GNSRECORD_Data *rd)
305 const char *typename;
310 typename = GNUNET_GNSRECORD_number_to_typename (rd->record_type);
311 string_val = GNUNET_GNSRECORD_value_to_string (rd->record_type,
315 if (NULL == string_val)
317 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
318 "Record of type %d malformed, skipping\n",
319 (int) rd->record_type);
322 record_obj = json_object();
323 json_object_set_new (record_obj,
324 GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE,
325 json_string (typename));
326 json_object_set_new (record_obj,
327 GNUNET_REST_JSONAPI_NAMESTORE_VALUE,
328 json_string (string_val));
329 GNUNET_free (string_val);
331 if (GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION & rd->flags)
333 struct GNUNET_TIME_Relative time_rel;
334 time_rel.rel_value_us = rd->expiration_time;
335 exp_str = GNUNET_STRINGS_relative_time_to_string (time_rel, 1);
339 struct GNUNET_TIME_Absolute time_abs;
340 time_abs.abs_value_us = rd->expiration_time;
341 exp_str = GNUNET_STRINGS_absolute_time_to_string (time_abs);
343 json_object_set_new (record_obj, GNUNET_REST_JSONAPI_NAMESTORE_EXPIRATION, json_string (exp_str));
345 json_object_set_new (record_obj, "expired",
346 json_boolean (GNUNET_YES == GNUNET_GNSRECORD_is_expired (rd)));
352 * Task run on error. Generates error response and cleans up.
354 * @param cls the request to generate an error response for
359 struct RequestHandle *handle = cls;
360 struct MHD_Response *resp = GNUNET_REST_create_json_response (NULL);
362 handle->proc (handle->proc_cls, resp, handle->response_code);
363 cleanup_handle (handle);
368 * Task run on timeout.
370 * @param cls the request to time out
373 do_timeout (void *cls)
375 struct RequestHandle *handle = cls;
377 handle->timeout_task = NULL;
383 cleanup_handle_delayed (void *cls)
385 cleanup_handle (cls);
390 * Create a response with requested records
392 * @param handle the RequestHandle
395 namestore_list_response (void *cls,
396 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
399 const struct GNUNET_GNSRECORD_Data *rd)
401 struct RequestHandle *handle = cls;
402 struct GNUNET_JSONAPI_Resource *json_resource;
403 struct MHD_Response *resp;
404 json_t *result_array;
409 if (NULL == handle->resp_object)
410 handle->resp_object = GNUNET_JSONAPI_object_new ();
414 handle->list_it = NULL;
416 if (GNUNET_SYSERR == GNUNET_JSONAPI_data_serialize (handle->resp_object, &result))
418 GNUNET_SCHEDULER_add_now (&do_error, handle);
421 resp = GNUNET_REST_create_json_response (result);
422 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
423 GNUNET_free (result);
424 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
428 if ( (NULL != handle->name) &&
429 (0 != strcmp (handle->name, rname)) )
431 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
432 "%s does not match %s\n", rname, handle->name);
433 GNUNET_NAMESTORE_zone_iterator_next (handle->list_it);
437 result_array = json_array ();
438 for (i=0; i<rd_len; i++)
440 if ( (GNUNET_GNSRECORD_TYPE_NICK == rd[i].record_type) &&
441 (0 != strcmp (rname, "+")) )
444 if ( (rd[i].record_type != handle->type) &&
445 (GNUNET_GNSRECORD_TYPE_ANY != handle->type) )
447 record_obj = gnsrecord_to_json (&(rd[i]));
448 json_array_append (result_array, record_obj);
449 json_decref (record_obj);
452 if (0 < json_array_size(result_array))
454 json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_NAMESTORE_TYPEINFO,
456 GNUNET_JSONAPI_resource_add_attr (json_resource,
457 GNUNET_REST_JSONAPI_NAMESTORE_RECORD,
459 GNUNET_JSONAPI_object_resource_add (handle->resp_object, json_resource);
462 json_decref (result_array);
463 GNUNET_NAMESTORE_zone_iterator_next (handle->list_it);
467 create_finished (void *cls, int32_t success, const char *emsg)
469 struct RequestHandle *handle = cls;
470 struct MHD_Response *resp;
472 handle->add_qe = NULL;
473 if (GNUNET_YES != success)
475 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
476 "Error storing records%s%s\n",
477 (NULL == emsg) ? "" : ": ",
478 (NULL == emsg) ? "" : emsg);
479 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
482 resp = GNUNET_REST_create_json_response (NULL);
483 handle->proc (handle->proc_cls, resp, MHD_HTTP_NO_CONTENT);
484 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
489 * We're storing a new record; this requires
490 * that no record already exists
492 * @param cls closure, unused
493 * @param zone_key private key of the zone
494 * @param rec_name name that is being mapped (at most 255 characters long)
495 * @param rd_count number of entries in @a rd array
496 * @param rd array of records with data to store
499 create_new_record_cont (void *cls,
500 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
501 const char *rec_name,
502 unsigned int rd_count,
503 const struct GNUNET_GNSRECORD_Data *rd)
505 struct RequestHandle *handle = cls;
507 handle->add_qe = NULL;
508 if ( (NULL != zone_key) &&
509 (0 != strcmp (rec_name, handle->name)) )
512 GNUNET_SCHEDULER_add_now (&do_error, handle);
518 handle->proc (handle->proc_cls,
519 GNUNET_REST_create_json_response (NULL),
521 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
525 GNUNET_assert (NULL != handle->name);
526 handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
536 del_finished (void *cls,
540 struct RequestHandle *handle = cls;
542 handle->add_qe = NULL;
543 if (GNUNET_NO == success)
545 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
546 _("Deleting record failed, record does not exist%s%s\n"),
547 (NULL != emsg) ? ": " : "",
548 (NULL != emsg) ? emsg : "");
549 GNUNET_SCHEDULER_add_now (&do_error, handle); //do_not_found TODO
552 if (GNUNET_SYSERR == success)
554 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
555 _("Deleting record failed%s%s\n"),
556 (NULL != emsg) ? ": " : "",
557 (NULL != emsg) ? emsg : "");
558 GNUNET_SCHEDULER_add_now (&do_error, handle);
561 handle->proc (handle->proc_cls,
562 GNUNET_REST_create_json_response (NULL),
563 MHD_HTTP_NO_CONTENT);
564 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
569 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
571 unsigned int rd_count,
572 const struct GNUNET_GNSRECORD_Data *rd)
574 struct RequestHandle *handle = cls;
575 handle->add_qe = NULL;
578 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
579 _("There are no records under label `%s' that could be deleted.\n"),
581 GNUNET_SCHEDULER_add_now (&do_error, handle);
585 handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
594 namestore_delete_cont (struct GNUNET_REST_RequestHandle *con,
598 struct RequestHandle *handle = cls;
600 if (NULL == handle->name)
602 GNUNET_SCHEDULER_add_now (&do_error, handle);
606 handle->add_qe = GNUNET_NAMESTORE_records_lookup (handle->ns_handle,
614 json_to_gnsrecord (const json_t *records_json,
615 struct GNUNET_GNSRECORD_Data **rd,
616 unsigned int *rd_count)
618 struct GNUNET_TIME_Relative etime_rel;
619 struct GNUNET_TIME_Absolute etime_abs;
623 const char *typestring;
624 const char *expirationstring;
631 *rd_count = json_array_size (records_json);
632 *rd = GNUNET_malloc (sizeof (struct GNUNET_GNSRECORD_Data) * *rd_count);
633 for (i = 0; i < *rd_count; i++)
635 memset (&((*rd)[i]), 0, sizeof (struct GNUNET_GNSRECORD_Data));
636 record_json = json_array_get (records_json, i);
637 type_json = json_object_get (record_json,
638 GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE);
639 if (!json_is_string (type_json))
641 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
642 "Type property is no string\n");
643 return GNUNET_SYSERR;
645 typestring = json_string_value (type_json);
646 (*rd)[i].record_type = GNUNET_GNSRECORD_typename_to_number (typestring);
647 if (UINT32_MAX == (*rd)[i].record_type)
649 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Unsupported type `%s'\n"),
650 json_string_value (type_json));
651 return GNUNET_SYSERR;
653 value_json = json_object_get (record_json,
654 GNUNET_REST_JSONAPI_NAMESTORE_VALUE);
655 if (!json_is_string (value_json))
657 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
658 "Value property is no string\n");
659 return GNUNET_SYSERR;
661 GNUNET_asprintf (&value, "%s", json_string_value (value_json));
662 if (GNUNET_OK != GNUNET_GNSRECORD_string_to_value ((*rd)[i].record_type,
667 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Value `%s' invalid for record type `%s'\n"),
669 return GNUNET_SYSERR;
671 (*rd)[i].data = rdata;
672 (*rd)[i].data_size = rdata_size;
674 * if (1 == handle->is_shadow)
675 rde->flags |= GNUNET_GNSRECORD_RF_SHADOW_RECORD;
676 if (1 != handle->is_public)
677 rde->flags |= GNUNET_GNSRECORD_RF_PRIVATE;
679 exp_json = json_object_get (record_json,
680 GNUNET_REST_JSONAPI_NAMESTORE_EXPIRATION);
681 if (!json_is_string (exp_json))
683 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
684 "Expiration property is no string\n");
685 return GNUNET_SYSERR;
687 expirationstring = json_string_value (exp_json);
688 if (0 == strcmp (expirationstring, "never"))
690 (*rd)[i].expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
692 else if (GNUNET_OK ==
693 GNUNET_STRINGS_fancy_time_to_relative (expirationstring,
696 (*rd)[i].expiration_time = etime_rel.rel_value_us;
697 (*rd)[i].flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
699 else if (GNUNET_OK ==
700 GNUNET_STRINGS_fancy_time_to_absolute (expirationstring,
703 (*rd)[i].expiration_time = etime_abs.abs_value_us;
707 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Value `%s' invalid for record type `%s'\n"),
709 return GNUNET_SYSERR;
716 namestore_create_cont (struct GNUNET_REST_RequestHandle *con,
720 struct RequestHandle *handle = cls;
721 struct MHD_Response *resp;
722 struct GNUNET_JSONAPI_Object *json_obj;
723 struct GNUNET_JSONAPI_Resource *json_res;
725 json_t *records_json;
726 char term_data[handle->rest_handle->data_size+1];
728 if (strlen (GNUNET_REST_API_NS_NAMESTORE) != strlen (handle->url))
730 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
731 "Cannot create under %s\n", handle->url);
732 GNUNET_SCHEDULER_add_now (&do_error, handle);
735 if (0 >= handle->rest_handle->data_size)
737 GNUNET_SCHEDULER_add_now (&do_error, handle);
740 term_data[handle->rest_handle->data_size] = '\0';
742 handle->rest_handle->data,
743 handle->rest_handle->data_size);
744 GNUNET_assert (GNUNET_OK == GNUNET_JSONAPI_object_parse (term_data,
746 if (NULL == json_obj)
748 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
749 "Unable to parse JSONAPI Object from %s\n",
751 GNUNET_SCHEDULER_add_now (&do_error, handle);
754 if (1 != GNUNET_JSONAPI_object_resource_count (json_obj))
756 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
757 "Cannot create more than 1 resource! (Got %d)\n",
758 GNUNET_JSONAPI_object_resource_count (json_obj));
759 GNUNET_JSONAPI_object_delete (json_obj);
760 GNUNET_SCHEDULER_add_now (&do_error, handle);
763 json_res = GNUNET_JSONAPI_object_get_resource (json_obj, 0);
764 if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res,
765 GNUNET_REST_JSONAPI_NAMESTORE_RECORD))
767 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
768 "Unsupported JSON data type\n");
769 GNUNET_JSONAPI_object_delete (json_obj);
770 resp = GNUNET_REST_create_json_response (NULL);
771 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
772 cleanup_handle (handle);
775 name_json = GNUNET_JSONAPI_resource_get_id (json_res);
776 if (!json_is_string (name_json))
778 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
779 "Name property is no string\n");
780 GNUNET_JSONAPI_object_delete (json_obj);
781 GNUNET_SCHEDULER_add_now (&do_error, handle);
784 GNUNET_asprintf (&handle->name, "%s", json_string_value (name_json));
785 records_json = GNUNET_JSONAPI_resource_read_attr (json_res,
786 GNUNET_REST_JSONAPI_NAMESTORE_RECORD);
787 if (NULL == records_json)
789 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
790 "No records given\n");
791 GNUNET_JSONAPI_object_delete (json_obj);
792 GNUNET_SCHEDULER_add_now (&do_error, handle);
795 if (GNUNET_SYSERR == json_to_gnsrecord (records_json, &handle->rd, &handle->rd_count))
797 GNUNET_JSONAPI_object_delete (json_obj);
798 GNUNET_SCHEDULER_add_now (&do_error, handle);
801 GNUNET_JSONAPI_object_delete (json_obj);
803 handle->add_qe = GNUNET_NAMESTORE_records_lookup (handle->ns_handle,
806 &create_new_record_cont, handle );
810 namestore_zkey_response (void *cls,
811 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
813 unsigned int rd_count,
814 const struct GNUNET_GNSRECORD_Data *rd)
816 struct RequestHandle *handle = cls;
817 struct MHD_Response *resp;
818 struct GNUNET_JSONAPI_Object *json_obj;
819 struct GNUNET_JSONAPI_Resource *json_res;
823 handle->reverse_qe = NULL;
824 json_obj = GNUNET_JSONAPI_object_new ();
827 name_json = json_string (label);
828 json_res = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_NAMESTORE_REVINFO,
830 GNUNET_JSONAPI_resource_add_attr (json_res,
831 GNUNET_REST_JSONAPI_NAMESTORE_NAME,
833 GNUNET_JSONAPI_object_resource_add (json_obj, json_res);
834 json_decref (name_json);
837 if (GNUNET_SYSERR == GNUNET_JSONAPI_data_serialize (json_obj, &result))
839 GNUNET_JSONAPI_object_delete (json_obj);
840 GNUNET_SCHEDULER_add_now (&do_error, handle);
843 resp = GNUNET_REST_create_json_response (result);
844 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
845 GNUNET_JSONAPI_object_delete (json_obj);
846 GNUNET_free (result);
847 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
853 namestore_zkey_cont (struct GNUNET_REST_RequestHandle *con,
857 struct RequestHandle *handle = cls;
858 struct GNUNET_HashCode key;
859 struct GNUNET_CRYPTO_EcdsaPublicKey pubkey;
861 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_NAMESTORE_ZKEY,
862 strlen (GNUNET_REST_JSONAPI_NAMESTORE_ZKEY),
865 GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
868 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
869 "No zkey given %s\n", handle->url);
870 GNUNET_SCHEDULER_add_now (&do_error, handle);
873 handle->zkey_str = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
876 GNUNET_CRYPTO_ecdsa_public_key_from_string (handle->zkey_str,
877 strlen (handle->zkey_str),
880 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
881 "Zkey invalid %s\n", handle->zkey_str);
882 GNUNET_SCHEDULER_add_now (&do_error, handle);
885 handle->reverse_qe = GNUNET_NAMESTORE_zone_to_name (handle->ns_handle,
888 &namestore_zkey_response,
893 namestore_info_cont (struct GNUNET_REST_RequestHandle *con,
897 struct RequestHandle *handle = cls;
898 handle->list_it = GNUNET_NAMESTORE_zone_iteration_start (handle->ns_handle,
900 &namestore_list_response,
905 get_name_from_url (const char* url)
907 if (strlen (url) <= strlen (GNUNET_REST_API_NS_NAMESTORE))
909 return (char*)url + strlen (GNUNET_REST_API_NS_NAMESTORE) + 1;
913 * Respond to OPTIONS request
915 * @param con_handle the connection handle
917 * @param cls the RequestHandle
920 options_cont (struct GNUNET_REST_RequestHandle *con_handle,
924 struct MHD_Response *resp;
925 struct RequestHandle *handle = cls;
927 //For now, independent of path return all options
928 resp = GNUNET_REST_create_json_response (NULL);
929 MHD_add_response_header (resp,
930 "Access-Control-Allow-Methods",
932 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
933 cleanup_handle (handle);
938 * Function called with the result from the check if the namestore
939 * service is actually running. If it is, we start the actual
942 * @param cls closure with our configuration
943 * @param result #GNUNET_YES if the namestore service is running
946 testservice_task (void *cls,
949 struct RequestHandle *handle = cls;
950 struct GNUNET_REST_RequestHandlerError err;
951 static const struct GNUNET_REST_RequestHandler handlers[] = {
952 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_NAMESTORE_ZKEY, &namestore_zkey_cont}, //reverse
953 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_NAMESTORE, &namestore_info_cont}, //list
954 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_NAMESTORE, &namestore_create_cont}, //create
955 // {MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_NAMESTORE, &namestore_edit_cont}, //update. TODO this shoul be PATCH
956 {MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_NAMESTORE, &namestore_delete_cont}, //delete
957 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_NAMESTORE, &options_cont},
958 GNUNET_REST_HANDLER_END
961 if (GNUNET_YES != result)
963 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Service `%s' is not running\n"),
965 GNUNET_SCHEDULER_add_now (&do_error, handle);
968 handle->ns_handle = GNUNET_NAMESTORE_connect (cfg);
969 if (NULL == handle->ns_handle)
971 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
972 _("Failed to connect to namestore\n"));
973 GNUNET_SCHEDULER_add_now (&do_error, handle);
977 if (GNUNET_OK != GNUNET_JSONAPI_handle_request (handle->rest_handle,
982 handle->response_code = err.error_code;
983 GNUNET_SCHEDULER_add_now (&do_error, (void*) handle);
989 * Callback invoked from identity service with ego information.
990 * An @a ego of NULL means the ego was not found.
992 * @param cls closure with the configuration
993 * @param ego an ego known to identity service, or NULL
996 identity_cb (void *cls,
997 const struct GNUNET_IDENTITY_Ego *ego)
999 struct RequestHandle *handle = cls;
1000 struct MHD_Response *resp;
1002 handle->ego_lookup = NULL;
1005 if (NULL != handle->ego_name)
1007 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1008 _("Ego `%s' not known to identity service\n"),
1011 resp = GNUNET_REST_create_json_response (NULL);
1012 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
1013 cleanup_handle (handle);
1016 handle->zone_pkey = *GNUNET_IDENTITY_ego_get_private_key (ego);
1017 GNUNET_CLIENT_service_test ("namestore", handle->cfg,
1018 GNUNET_TIME_UNIT_SECONDS,
1024 default_ego_cb (void *cls,
1025 struct GNUNET_IDENTITY_Ego *ego,
1029 struct RequestHandle *handle = cls;
1030 struct MHD_Response *resp;
1031 handle->get_default = NULL;
1034 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1035 _("No default ego configured in identity service\n"));
1036 resp = GNUNET_REST_create_json_response (NULL);
1037 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
1038 cleanup_handle (handle);
1043 identity_cb (cls, ego);
1048 id_connect_cb (void *cls,
1049 struct GNUNET_IDENTITY_Ego *ego,
1053 struct RequestHandle *handle = cls;
1056 handle->get_default = GNUNET_IDENTITY_get (handle->identity_handle,
1058 &default_ego_cb, handle);
1063 testservice_id_task (void *cls, int result)
1065 struct RequestHandle *handle = cls;
1066 struct MHD_Response *resp;
1067 struct GNUNET_HashCode key;
1072 if (result != GNUNET_YES)
1074 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1075 _("Identity service is not running\n"));
1076 resp = GNUNET_REST_create_json_response (NULL);
1077 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
1078 cleanup_handle (handle);
1082 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_NAMESTORE_EGO,
1083 strlen (GNUNET_REST_JSONAPI_NAMESTORE_EGO),
1086 GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1089 ego = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
1093 handle->type = GNUNET_GNSRECORD_TYPE_ANY;
1094 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE,
1095 strlen (GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE),
1098 GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1101 type = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
1104 handle->type = GNUNET_GNSRECORD_typename_to_number (type);
1106 name = get_name_from_url (handle->url);
1108 GNUNET_asprintf (&handle->ego_name, "%s", ego);
1110 GNUNET_asprintf (&handle->name, "%s", name);
1111 if (NULL == handle->ego_name)
1113 handle->identity_handle = GNUNET_IDENTITY_connect (handle->cfg, &id_connect_cb, handle);
1114 if (NULL == handle->identity_handle)
1116 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Cannot connect to identity service\n"));
1117 resp = GNUNET_REST_create_json_response (NULL);
1118 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
1119 cleanup_handle (handle);
1123 handle->ego_lookup = GNUNET_IDENTITY_ego_lookup (cfg,
1130 * Function processing the REST call
1132 * @param method HTTP method
1133 * @param url URL of the HTTP request
1134 * @param data body of the HTTP request (optional)
1135 * @param data_size length of the body
1136 * @param proc callback function for the result
1137 * @param proc_cls closure for callback function
1138 * @return GNUNET_OK if request accepted
1141 rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle,
1142 GNUNET_REST_ResultProcessor proc,
1145 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1147 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1148 handle->proc_cls = proc_cls;
1149 handle->proc = proc;
1150 handle->rest_handle = rest_handle;
1151 GNUNET_asprintf (&handle->url, "%s", rest_handle->url);
1152 if (handle->url[strlen (handle->url)-1] == '/')
1153 handle->url[strlen (handle->url)-1] = '\0';
1154 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1157 GNUNET_CLIENT_service_test ("identity",
1159 GNUNET_TIME_UNIT_SECONDS,
1160 &testservice_id_task,
1162 handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout,
1168 * Entry point for the plugin.
1170 * @param cls Config info
1171 * @return NULL on error, otherwise the plugin context
1174 libgnunet_plugin_rest_namestore_init (void *cls)
1176 static struct Plugin plugin;
1178 struct GNUNET_REST_Plugin *api;
1180 if (NULL != plugin.cfg)
1181 return NULL; /* can only initialize once! */
1182 memset (&plugin, 0, sizeof (struct Plugin));
1184 api = GNUNET_new (struct GNUNET_REST_Plugin);
1186 api->name = GNUNET_REST_API_NS_NAMESTORE;
1187 api->process_request = &rest_identity_process_request;
1188 GNUNET_asprintf (&allow_methods,
1189 "%s, %s, %s, %s, %s",
1190 MHD_HTTP_METHOD_GET,
1191 MHD_HTTP_METHOD_POST,
1192 MHD_HTTP_METHOD_PUT,
1193 MHD_HTTP_METHOD_DELETE,
1194 MHD_HTTP_METHOD_OPTIONS);
1195 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1196 _("Namestore REST API initialized\n"));
1202 * Exit point from the plugin.
1204 * @param cls the plugin context (as returned by "init")
1205 * @return always NULL
1208 libgnunet_plugin_rest_namestore_done (void *cls)
1210 struct GNUNET_REST_Plugin *api = cls;
1211 struct Plugin *plugin = api->cls;
1215 GNUNET_free_non_null (allow_methods);
1216 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1217 "Namestore REST plugin is finished\n");
1221 /* end of plugin_rest_namestore.c */