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_JSONAPI_NAMESTORE_TYPEINFO "record"
39 #define GNUNET_REST_JSONAPI_NAMESTORE_RECORD GNUNET_REST_JSONAPI_NAMESTORE_TYPEINFO
41 #define GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE "record_type"
43 #define GNUNET_REST_JSONAPI_NAMESTORE_VALUE "value"
45 #define GNUNET_REST_JSONAPI_NAMESTORE_PUBLIC "public"
47 #define GNUNET_REST_JSONAPI_NAMESTORE_SHADOW "shadow"
49 #define GNUNET_REST_JSONAPI_NAMESTORE_PKEY "pkey"
51 #define GNUNET_REST_JSONAPI_NAMESTORE_EXPIRATION "expiration"
53 #define GNUNET_REST_JSONAPI_NAMESTORE_EGO "ego"
56 * @brief struct returned by the initialization function of the plugin
60 const struct GNUNET_CONFIGURATION_Handle *cfg;
65 * HTTP methods allows for this plugin
67 static char* allow_methods;
69 const struct GNUNET_CONFIGURATION_Handle *cfg;
76 struct RecordEntry *next;
81 struct RecordEntry *prev;
90 struct RecordEntry *record_head;
95 struct record_entry *record_tail;
98 * JSON response object
100 struct JsonApiObject *resp_object;
105 struct RestConnectionDataHandle *conndata_handle;
108 * Handle to GNS service.
110 struct GNUNET_IDENTITY_Handle *identity_handle;
113 * Handle to NAMESTORE
115 struct GNUNET_NAMESTORE_Handle *ns_handle;
118 * Handle to NAMESTORE it
120 struct GNUNET_NAMESTORE_ZoneIterator *list_it;
123 * Private key for the zone
125 struct GNUNET_CRYPTO_EcdsaPrivateKey zone_pkey;
128 * Handle to identity lookup
130 struct GNUNET_IDENTITY_EgoLookup *ego_lookup;
133 * Default Ego operation
135 struct GNUNET_IDENTITY_Operation *get_default;
153 * Name of the record to modify
158 * Value of the record
170 struct GNUNET_GNSRECORD_Data *rd;
175 unsigned int rd_count;
178 * NAMESTORE Operation
180 struct GNUNET_NAMESTORE_QueueEntry *add_qe;
183 * Desired timeout for the lookup (default is no timeout).
185 struct GNUNET_TIME_Relative timeout;
188 * ID of a task associated with the resolution process.
190 struct GNUNET_SCHEDULER_Task * timeout_task;
193 * The plugin result processor
195 GNUNET_REST_ResultProcessor proc;
198 * The closure of the result processor
208 * The data from the REST request
213 * the length of the REST data
220 const struct GNUNET_CONFIGURATION_Handle *cfg;
226 * Cleanup lookup handle
227 * @param handle Handle to clean up
230 cleanup_handle (struct RequestHandle *handle)
232 struct RecordEntry *record_entry;
233 struct RecordEntry *record_tmp;
235 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
237 if (NULL != handle->resp_object)
238 GNUNET_REST_jsonapi_object_delete (handle->resp_object);
239 if (NULL != handle->name)
240 GNUNET_free (handle->name);
241 if (NULL != handle->timeout_task)
242 GNUNET_SCHEDULER_cancel (handle->timeout_task);
243 if (NULL != handle->ego_lookup)
244 GNUNET_IDENTITY_ego_lookup_cancel (handle->ego_lookup);
245 if (NULL != handle->get_default)
246 GNUNET_IDENTITY_cancel (handle->get_default);
247 if (NULL != handle->list_it)
248 GNUNET_NAMESTORE_zone_iteration_stop (handle->list_it);
249 if (NULL != handle->add_qe)
250 GNUNET_NAMESTORE_cancel (handle->add_qe);
251 if (NULL != handle->identity_handle)
252 GNUNET_IDENTITY_disconnect (handle->identity_handle);
253 if (NULL != handle->ns_handle)
254 GNUNET_NAMESTORE_disconnect (handle->ns_handle);
255 if (NULL != handle->url)
256 GNUNET_free (handle->url);
257 if (NULL != handle->value)
258 GNUNET_free (handle->value);
259 if (NULL != handle->rd)
261 for (i = 0; i < handle->rd_count; i++)
263 if (NULL != handle->rd[i].data)
264 GNUNET_free ((void*)handle->rd[i].data);
266 GNUNET_free (handle->rd);
268 if (NULL != handle->ego_name)
269 GNUNET_free (handle->ego_name);
270 for (record_entry = handle->record_head;
271 NULL != record_entry;)
273 record_tmp = record_entry;
274 record_entry = record_entry->next;
275 GNUNET_free (record_tmp);
277 GNUNET_free (handle);
281 * Create json representation of a GNSRECORD
283 * @param rd the GNSRECORD_Data
286 gnsrecord_to_json (const struct GNUNET_GNSRECORD_Data *rd)
288 const char *typename;
293 typename = GNUNET_GNSRECORD_number_to_typename (rd->record_type);
294 string_val = GNUNET_GNSRECORD_value_to_string (rd->record_type,
298 if (NULL == string_val)
300 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
301 "Record of type %d malformed, skipping\n",
302 (int) rd->record_type);
305 record_obj = json_object();
306 json_object_set_new (record_obj,
307 GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE,
308 json_string (typename));
309 json_object_set_new (record_obj,
310 GNUNET_REST_JSONAPI_NAMESTORE_VALUE,
311 json_string (string_val));
312 GNUNET_free (string_val);
314 if (GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION & rd->flags)
316 struct GNUNET_TIME_Relative time_rel;
317 time_rel.rel_value_us = rd->expiration_time;
318 exp_str = GNUNET_STRINGS_relative_time_to_string (time_rel, 1);
322 struct GNUNET_TIME_Absolute time_abs;
323 time_abs.abs_value_us = rd->expiration_time;
324 exp_str = GNUNET_STRINGS_absolute_time_to_string (time_abs);
326 json_object_set_new (record_obj, GNUNET_REST_JSONAPI_NAMESTORE_EXPIRATION, json_string (exp_str));
328 json_object_set_new (record_obj, "expired",
329 json_boolean (GNUNET_YES == GNUNET_GNSRECORD_is_expired (rd)));
335 * Task run on shutdown. Cleans up everything.
338 * @param tc scheduler context
342 const struct GNUNET_SCHEDULER_TaskContext *tc)
344 struct RequestHandle *handle = cls;
345 struct MHD_Response *resp = GNUNET_REST_create_json_response (NULL);
346 handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
347 cleanup_handle (handle);
351 cleanup_handle_delayed (void *cls,
352 const struct GNUNET_SCHEDULER_TaskContext *tc)
354 cleanup_handle (cls);
358 * Create a response with requested records
360 * @param handle the RequestHandle
363 namestore_list_response (void *cls,
364 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
367 const struct GNUNET_GNSRECORD_Data *rd)
369 struct RequestHandle *handle = cls;
370 struct JsonApiResource *json_resource;
371 struct MHD_Response *resp;
372 json_t *result_array;
377 if (NULL == handle->resp_object)
378 handle->resp_object = GNUNET_REST_jsonapi_object_new ();
382 handle->list_it = NULL;
384 if (GNUNET_SYSERR == GNUNET_REST_jsonapi_data_serialize (handle->resp_object, &result))
386 GNUNET_SCHEDULER_add_now (&do_error, handle);
389 resp = GNUNET_REST_create_json_response (result);
390 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
391 GNUNET_free (result);
392 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
396 if ( (NULL != handle->name) &&
397 (0 != strcmp (handle->name, rname)) )
399 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
400 "%s does not match %s\n", rname, handle->name);
401 GNUNET_NAMESTORE_zone_iterator_next (handle->list_it);
405 result_array = json_array ();
406 for (i=0; i<rd_len; i++)
408 if ( (GNUNET_GNSRECORD_TYPE_NICK == rd[i].record_type) &&
409 (0 != strcmp (rname, "+")) )
412 if ( (rd[i].record_type != handle->type) &&
413 (GNUNET_GNSRECORD_TYPE_ANY != handle->type) )
415 record_obj = gnsrecord_to_json (&(rd[i]));
416 json_array_append (result_array, record_obj);
417 json_decref (record_obj);
420 if (0 < json_array_size(result_array))
422 json_resource = GNUNET_REST_jsonapi_resource_new (GNUNET_REST_JSONAPI_NAMESTORE_TYPEINFO,
424 GNUNET_REST_jsonapi_resource_add_attr (json_resource,
425 GNUNET_REST_JSONAPI_NAMESTORE_RECORD,
427 GNUNET_REST_jsonapi_object_resource_add (handle->resp_object, json_resource);
430 json_decref (result_array);
431 GNUNET_NAMESTORE_zone_iterator_next (handle->list_it);
435 create_finished (void *cls, int32_t success, const char *emsg)
437 struct RequestHandle *handle = cls;
438 struct MHD_Response *resp;
440 handle->add_qe = NULL;
441 if (GNUNET_YES != success)
443 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
444 "Error storing records%s%s\n",
445 (NULL == emsg) ? "" : ": ",
446 (NULL == emsg) ? "" : emsg);
447 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
450 resp = GNUNET_REST_create_json_response (NULL);
451 handle->proc (handle->proc_cls, resp, MHD_HTTP_NO_CONTENT);
452 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
457 * We're storing a new record; this requires
458 * that no record already exists
460 * @param cls closure, unused
461 * @param zone_key private key of the zone
462 * @param rec_name name that is being mapped (at most 255 characters long)
463 * @param rd_count number of entries in @a rd array
464 * @param rd array of records with data to store
467 create_new_record_cont (void *cls,
468 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
469 const char *rec_name,
470 unsigned int rd_count,
471 const struct GNUNET_GNSRECORD_Data *rd)
473 struct RequestHandle *handle = cls;
475 handle->add_qe = NULL;
476 if ( (NULL != zone_key) &&
477 (0 != strcmp (rec_name, handle->name)) )
480 GNUNET_SCHEDULER_add_now (&do_error, handle);
484 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
485 "Received %u records for name `%s'\n",
489 handle->proc (handle->proc_cls,
490 GNUNET_REST_create_json_response (NULL),
492 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
496 GNUNET_assert (NULL != handle->name);
497 handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
507 del_finished (void *cls,
511 struct RequestHandle *handle = cls;
513 handle->add_qe = NULL;
514 if (GNUNET_NO == success)
516 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
517 _("Deleting record failed, record does not exist%s%s\n"),
518 (NULL != emsg) ? ": " : "",
519 (NULL != emsg) ? emsg : "");
520 GNUNET_SCHEDULER_add_now (&do_error, handle); //do_not_found TODO
523 if (GNUNET_SYSERR == success)
525 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
526 _("Deleting record failed%s%s\n"),
527 (NULL != emsg) ? ": " : "",
528 (NULL != emsg) ? emsg : "");
529 GNUNET_SCHEDULER_add_now (&do_error, handle);
532 handle->proc (handle->proc_cls,
533 GNUNET_REST_create_json_response (NULL),
534 MHD_HTTP_NO_CONTENT);
535 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
540 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
542 unsigned int rd_count,
543 const struct GNUNET_GNSRECORD_Data *rd)
545 struct RequestHandle *handle = cls;
549 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
550 _("There are no records under label `%s' that could be deleted.\n"),
552 GNUNET_SCHEDULER_add_now (&do_error, handle);
556 handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
565 namestore_delete_cont (struct RestConnectionDataHandle *con,
569 struct RequestHandle *handle = cls;
571 if (NULL == handle->name)
573 GNUNET_SCHEDULER_add_now (&do_error, handle);
577 handle->add_qe = GNUNET_NAMESTORE_records_lookup (handle->ns_handle,
585 json_to_gnsrecord (const json_t *records_json,
586 struct GNUNET_GNSRECORD_Data **rd,
587 unsigned int *rd_count)
589 struct GNUNET_TIME_Relative etime_rel;
590 struct GNUNET_TIME_Absolute etime_abs;
594 const char *typestring;
595 const char *expirationstring;
602 *rd_count = json_array_size (records_json);
603 *rd = GNUNET_malloc (sizeof (struct GNUNET_GNSRECORD_Data) * *rd_count);
604 for (i = 0; i < *rd_count; i++)
606 memset (&((*rd)[i]), 0, sizeof (struct GNUNET_GNSRECORD_Data));
607 record_json = json_array_get (records_json, i);
608 type_json = json_object_get (record_json,
609 GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE);
610 if (!json_is_string (type_json))
612 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
613 "Type property is no string\n");
614 return GNUNET_SYSERR;
616 typestring = json_string_value (type_json);
617 (*rd)[i].record_type = GNUNET_GNSRECORD_typename_to_number (typestring);
618 if (UINT32_MAX == (*rd)[i].record_type)
620 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Unsupported type `%s'\n"),
621 json_string_value (type_json));
622 return GNUNET_SYSERR;
624 value_json = json_object_get (record_json,
625 GNUNET_REST_JSONAPI_NAMESTORE_VALUE);
626 if (!json_is_string (value_json))
628 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
629 "Value property is no string\n");
630 return GNUNET_SYSERR;
632 GNUNET_asprintf (&value, "%s", json_string_value (value_json));
633 if (GNUNET_OK != GNUNET_GNSRECORD_string_to_value ((*rd)[i].record_type,
638 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Value `%s' invalid for record type `%s'\n"),
640 return GNUNET_SYSERR;
642 (*rd)[i].data = rdata;
643 (*rd)[i].data_size = rdata_size;
645 * if (1 == handle->is_shadow)
646 rde->flags |= GNUNET_GNSRECORD_RF_SHADOW_RECORD;
647 if (1 != handle->is_public)
648 rde->flags |= GNUNET_GNSRECORD_RF_PRIVATE;
650 exp_json = json_object_get (record_json,
651 GNUNET_REST_JSONAPI_NAMESTORE_EXPIRATION);
652 if (!json_is_string (exp_json))
654 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
655 "Expiration property is no string\n");
656 return GNUNET_SYSERR;
658 expirationstring = json_string_value (exp_json);
659 if (0 == strcmp (expirationstring, "never"))
661 (*rd)[i].expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
663 else if (GNUNET_OK ==
664 GNUNET_STRINGS_fancy_time_to_relative (expirationstring,
667 (*rd)[i].expiration_time = etime_rel.rel_value_us;
668 (*rd)[i].flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
670 else if (GNUNET_OK ==
671 GNUNET_STRINGS_fancy_time_to_absolute (expirationstring,
674 (*rd)[i].expiration_time = etime_abs.abs_value_us;
678 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Value `%s' invalid for record type `%s'\n"),
680 return GNUNET_SYSERR;
687 namestore_create_cont (struct RestConnectionDataHandle *con,
691 struct RequestHandle *handle = cls;
692 struct MHD_Response *resp;
693 struct JsonApiObject *json_obj;
694 struct JsonApiResource *json_res;
696 json_t *records_json;
697 char term_data[handle->data_size+1];
699 if (strlen (GNUNET_REST_API_NS_NAMESTORE) != strlen (handle->url))
701 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
702 "Cannot create under %s\n", handle->url);
703 GNUNET_SCHEDULER_add_now (&do_error, handle);
706 if (0 >= handle->data_size)
708 GNUNET_SCHEDULER_add_now (&do_error, handle);
711 term_data[handle->data_size] = '\0';
712 memcpy (term_data, handle->data, handle->data_size);
713 json_obj = GNUNET_REST_jsonapi_object_parse (term_data);
714 if (NULL == json_obj)
716 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
717 "Unable to parse JSONAPI Object from %s\n",
719 GNUNET_SCHEDULER_add_now (&do_error, handle);
722 if (1 != GNUNET_REST_jsonapi_object_resource_count (json_obj))
724 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
725 "Cannot create more than 1 resource! (Got %d)\n",
726 GNUNET_REST_jsonapi_object_resource_count (json_obj));
727 GNUNET_REST_jsonapi_object_delete (json_obj);
728 GNUNET_SCHEDULER_add_now (&do_error, handle);
731 json_res = GNUNET_REST_jsonapi_object_get_resource (json_obj, 0);
732 if (GNUNET_NO == GNUNET_REST_jsonapi_resource_check_type (json_res,
733 GNUNET_REST_JSONAPI_NAMESTORE_RECORD))
735 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
736 "Unsupported JSON data type\n");
737 GNUNET_REST_jsonapi_object_delete (json_obj);
738 resp = GNUNET_REST_create_json_response (NULL);
739 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
740 cleanup_handle (handle);
743 name_json = GNUNET_REST_jsonapi_resource_read_attr (json_res, GNUNET_REST_JSONAPI_KEY_ID);
744 if (!json_is_string (name_json))
746 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
747 "Name property is no string\n");
748 GNUNET_REST_jsonapi_object_delete (json_obj);
749 GNUNET_SCHEDULER_add_now (&do_error, handle);
752 GNUNET_asprintf (&handle->name, "%s", json_string_value (name_json));
753 records_json = GNUNET_REST_jsonapi_resource_read_attr (json_res,
754 GNUNET_REST_JSONAPI_NAMESTORE_RECORD);
755 if (NULL == records_json)
757 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
758 "No records given\n");
759 GNUNET_REST_jsonapi_object_delete (json_obj);
760 GNUNET_SCHEDULER_add_now (&do_error, handle);
763 if (GNUNET_SYSERR == json_to_gnsrecord (records_json, &handle->rd, &handle->rd_count))
765 GNUNET_REST_jsonapi_object_delete (json_obj);
766 GNUNET_SCHEDULER_add_now (&do_error, handle);
769 GNUNET_REST_jsonapi_object_delete (json_obj);
771 handle->add_qe = GNUNET_NAMESTORE_records_lookup (handle->ns_handle,
774 &create_new_record_cont, handle );
782 namestore_info_cont (struct RestConnectionDataHandle *con,
786 struct RequestHandle *handle = cls;
787 handle->list_it = GNUNET_NAMESTORE_zone_iteration_start (handle->ns_handle,
789 &namestore_list_response,
794 get_name_from_url (const char* url)
796 if (strlen (url) <= strlen (GNUNET_REST_API_NS_NAMESTORE))
798 return (char*)url + strlen (GNUNET_REST_API_NS_NAMESTORE) + 1;
802 * Respond to OPTIONS request
804 * @param con_handle the connection handle
806 * @param cls the RequestHandle
809 options_cont (struct RestConnectionDataHandle *con_handle,
813 struct MHD_Response *resp;
814 struct RequestHandle *handle = cls;
816 //For now, independent of path return all options
817 resp = GNUNET_REST_create_json_response (NULL);
818 MHD_add_response_header (resp,
819 "Access-Control-Allow-Methods",
821 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
822 cleanup_handle (handle);
827 * Function called with the result from the check if the namestore
828 * service is actually running. If it is, we start the actual
831 * @param cls closure with our configuration
832 * @param result #GNUNET_YES if the namestore service is running
835 testservice_task (void *cls,
838 struct RequestHandle *handle = cls;
839 static const struct GNUNET_REST_RestConnectionHandler handlers[] = {
840 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_NAMESTORE, &namestore_info_cont}, //list
841 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_NAMESTORE, &namestore_create_cont}, //create
842 // {MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_NAMESTORE, &namestore_edit_cont}, //update. TODO this shoul be PATCH
843 {MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_NAMESTORE, &namestore_delete_cont}, //delete
844 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_NAMESTORE, &options_cont},
845 GNUNET_REST_HANDLER_END
848 if (GNUNET_YES != result)
850 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Service `%s' is not running\n"),
852 GNUNET_SCHEDULER_add_now (&do_error, handle);
855 handle->ns_handle = GNUNET_NAMESTORE_connect (cfg);
856 if (NULL == handle->ns_handle)
858 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
859 _("Failed to connect to namestore\n"));
860 GNUNET_SCHEDULER_add_now (&do_error, handle);
864 if (GNUNET_NO == GNUNET_REST_handle_request (handle->conndata_handle, handlers, handle))
865 GNUNET_SCHEDULER_add_now (&do_error, (void*) handle);
870 * Callback invoked from identity service with ego information.
871 * An @a ego of NULL means the ego was not found.
873 * @param cls closure with the configuration
874 * @param ego an ego known to identity service, or NULL
877 identity_cb (void *cls,
878 const struct GNUNET_IDENTITY_Ego *ego)
880 struct RequestHandle *handle = cls;
881 struct MHD_Response *resp;
883 handle->ego_lookup = NULL;
886 if (NULL != handle->ego_name)
888 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
889 _("Ego `%s' not known to identity service\n"),
892 resp = GNUNET_REST_create_json_response (NULL);
893 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
894 cleanup_handle (handle);
897 handle->zone_pkey = *GNUNET_IDENTITY_ego_get_private_key (ego);
898 GNUNET_CLIENT_service_test ("namestore", handle->cfg,
899 GNUNET_TIME_UNIT_SECONDS,
905 default_ego_cb (void *cls,
906 struct GNUNET_IDENTITY_Ego *ego,
910 struct RequestHandle *handle = cls;
911 struct MHD_Response *resp;
912 handle->get_default = NULL;
915 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
916 _("No default ego configured in identity service\n"));
917 resp = GNUNET_REST_create_json_response (NULL);
918 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
919 cleanup_handle (handle);
924 identity_cb (cls, ego);
929 id_connect_cb (void *cls,
930 struct GNUNET_IDENTITY_Ego *ego,
934 struct RequestHandle *handle = cls;
937 handle->get_default = GNUNET_IDENTITY_get (handle->identity_handle,
939 &default_ego_cb, handle);
944 testservice_id_task (void *cls, int result)
946 struct RequestHandle *handle = cls;
947 struct MHD_Response *resp;
948 struct GNUNET_HashCode key;
953 if (result != GNUNET_YES)
955 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
956 _("Identity service is not running\n"));
957 resp = GNUNET_REST_create_json_response (NULL);
958 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
959 cleanup_handle (handle);
963 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_NAMESTORE_EGO,
964 strlen (GNUNET_REST_JSONAPI_NAMESTORE_EGO),
967 GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
970 ego = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
974 handle->type = GNUNET_GNSRECORD_TYPE_ANY;
975 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE,
976 strlen (GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE),
979 GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
982 type = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
985 handle->type = GNUNET_GNSRECORD_typename_to_number (type);
987 name = get_name_from_url (handle->url);
989 GNUNET_asprintf (&handle->ego_name, "%s", ego);
991 GNUNET_asprintf (&handle->name, "%s", name);
992 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", handle->ego_name);
993 if (NULL == handle->ego_name)
995 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", handle->ego_name);
996 handle->identity_handle = GNUNET_IDENTITY_connect (handle->cfg, &id_connect_cb, handle);
997 if (NULL == handle->identity_handle)
999 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Cannot connect to identity service\n"));
1000 resp = GNUNET_REST_create_json_response (NULL);
1001 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
1002 cleanup_handle (handle);
1006 handle->ego_lookup = GNUNET_IDENTITY_ego_lookup (cfg,
1013 * Function processing the REST call
1015 * @param method HTTP method
1016 * @param url URL of the HTTP request
1017 * @param data body of the HTTP request (optional)
1018 * @param data_size length of the body
1019 * @param proc callback function for the result
1020 * @param proc_cls closure for callback function
1021 * @return GNUNET_OK if request accepted
1024 rest_identity_process_request(struct RestConnectionDataHandle *conndata_handle,
1025 GNUNET_REST_ResultProcessor proc,
1028 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1030 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1031 handle->proc_cls = proc_cls;
1032 handle->proc = proc;
1033 handle->conndata_handle = conndata_handle;
1034 handle->data = conndata_handle->data;
1035 handle->data_size = conndata_handle->data_size;
1036 GNUNET_asprintf (&handle->url, "%s", conndata_handle->url);
1037 if (handle->url[strlen (handle->url)-1] == '/')
1038 handle->url[strlen (handle->url)-1] = '\0';
1039 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1042 GNUNET_CLIENT_service_test ("identity",
1044 GNUNET_TIME_UNIT_SECONDS,
1045 &testservice_id_task,
1047 handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout,
1055 * Entry point for the plugin.
1057 * @param cls Config info
1058 * @return NULL on error, otherwise the plugin context
1061 libgnunet_plugin_rest_namestore_init (void *cls)
1063 static struct Plugin plugin;
1065 struct GNUNET_REST_Plugin *api;
1067 if (NULL != plugin.cfg)
1068 return NULL; /* can only initialize once! */
1069 memset (&plugin, 0, sizeof (struct Plugin));
1071 api = GNUNET_new (struct GNUNET_REST_Plugin);
1073 api->name = GNUNET_REST_API_NS_NAMESTORE;
1074 api->process_request = &rest_identity_process_request;
1075 GNUNET_asprintf (&allow_methods,
1076 "%s, %s, %s, %s, %s",
1077 MHD_HTTP_METHOD_GET,
1078 MHD_HTTP_METHOD_POST,
1079 MHD_HTTP_METHOD_PUT,
1080 MHD_HTTP_METHOD_DELETE,
1081 MHD_HTTP_METHOD_OPTIONS);
1082 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1083 _("Namestore REST API initialized\n"));
1089 * Exit point from the plugin.
1091 * @param cls the plugin context (as returned by "init")
1092 * @return always NULL
1095 libgnunet_plugin_rest_namestore_done (void *cls)
1097 struct GNUNET_REST_Plugin *api = cls;
1098 struct Plugin *plugin = api->cls;
1102 GNUNET_free_non_null (allow_methods);
1103 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1104 "Namestore REST plugin is finished\n");
1108 /* end of plugin_rest_namestore.c */