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->name)
238 GNUNET_free (handle->name);
239 if (NULL != handle->timeout_task)
240 GNUNET_SCHEDULER_cancel (handle->timeout_task);
241 if (NULL != handle->ego_lookup)
242 GNUNET_IDENTITY_ego_lookup_cancel (handle->ego_lookup);
243 if (NULL != handle->get_default)
244 GNUNET_IDENTITY_cancel (handle->get_default);
245 if (NULL != handle->list_it)
246 GNUNET_NAMESTORE_zone_iteration_stop (handle->list_it);
247 if (NULL != handle->add_qe)
248 GNUNET_NAMESTORE_cancel (handle->add_qe);
249 if (NULL != handle->identity_handle)
250 GNUNET_IDENTITY_disconnect (handle->identity_handle);
251 if (NULL != handle->ns_handle)
252 GNUNET_NAMESTORE_disconnect (handle->ns_handle);
253 if (NULL != handle->url)
254 GNUNET_free (handle->url);
255 if (NULL != handle->value)
256 GNUNET_free (handle->value);
257 if (NULL != handle->rd)
259 for (i = 0; i < handle->rd_count; i++)
261 if (NULL != handle->rd[i].data)
262 GNUNET_free ((void*)handle->rd[i].data);
264 GNUNET_free (handle->rd);
266 if (NULL != handle->ego_name)
267 GNUNET_free (handle->ego_name);
268 for (record_entry = handle->record_head;
269 NULL != record_entry;)
271 record_tmp = record_entry;
272 record_entry = record_entry->next;
273 GNUNET_free (record_tmp);
275 GNUNET_free (handle);
279 * Create json representation of a GNSRECORD
281 * @param rd the GNSRECORD_Data
284 gnsrecord_to_json (const struct GNUNET_GNSRECORD_Data *rd)
286 const char *typename;
291 typename = GNUNET_GNSRECORD_number_to_typename (rd->record_type);
292 string_val = GNUNET_GNSRECORD_value_to_string (rd->record_type,
296 if (NULL == string_val)
298 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
299 "Record of type %d malformed, skipping\n",
300 (int) rd->record_type);
303 record_obj = json_object();
304 json_object_set_new (record_obj,
305 GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE,
306 json_string (typename));
307 json_object_set_new (record_obj,
308 GNUNET_REST_JSONAPI_NAMESTORE_VALUE,
309 json_string (string_val));
310 GNUNET_free (string_val);
312 if (GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION & rd->flags)
314 struct GNUNET_TIME_Relative time_rel;
315 time_rel.rel_value_us = rd->expiration_time;
316 exp_str = GNUNET_STRINGS_relative_time_to_string (time_rel, 1);
320 struct GNUNET_TIME_Absolute time_abs;
321 time_abs.abs_value_us = rd->expiration_time;
322 exp_str = GNUNET_STRINGS_absolute_time_to_string (time_abs);
324 json_object_set_new (record_obj, GNUNET_REST_JSONAPI_NAMESTORE_EXPIRATION, json_string (exp_str));
326 json_object_set_new (record_obj, "expired",
327 json_boolean (GNUNET_YES == GNUNET_GNSRECORD_is_expired (rd)));
333 * Task run on shutdown. Cleans up everything.
336 * @param tc scheduler context
340 const struct GNUNET_SCHEDULER_TaskContext *tc)
342 struct RequestHandle *handle = cls;
343 struct MHD_Response *resp = GNUNET_REST_create_json_response (NULL);
344 handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
345 cleanup_handle (handle);
349 cleanup_handle_delayed (void *cls,
350 const struct GNUNET_SCHEDULER_TaskContext *tc)
352 cleanup_handle (cls);
356 * Create a response with requested records
358 * @param handle the RequestHandle
361 namestore_list_response (void *cls,
362 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
365 const struct GNUNET_GNSRECORD_Data *rd)
367 struct RequestHandle *handle = cls;
368 struct JsonApiResource *json_resource;
369 struct MHD_Response *resp;
370 json_t *result_array;
375 if (NULL == handle->resp_object)
376 handle->resp_object = GNUNET_REST_jsonapi_object_new ();
380 handle->list_it = NULL;
382 if (GNUNET_SYSERR == GNUNET_REST_jsonapi_data_serialize (handle->resp_object, &result))
384 GNUNET_SCHEDULER_add_now (&do_error, handle);
387 GNUNET_REST_jsonapi_object_delete (handle->resp_object);
388 resp = GNUNET_REST_create_json_response (result);
389 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
390 GNUNET_free (result);
391 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
395 if ( (NULL != handle->name) &&
396 (0 != strcmp (handle->name, rname)) )
398 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
399 "%s does not match %s\n", rname, handle->name);
400 GNUNET_NAMESTORE_zone_iterator_next (handle->list_it);
404 result_array = json_array ();
405 for (i=0; i<rd_len; i++)
407 if ( (GNUNET_GNSRECORD_TYPE_NICK == rd[i].record_type) &&
408 (0 != strcmp (rname, "+")) )
411 if ( (rd[i].record_type != handle->type) &&
412 (GNUNET_GNSRECORD_TYPE_ANY != handle->type) )
414 record_obj = gnsrecord_to_json (&(rd[i]));
415 json_array_append (result_array, record_obj);
416 json_decref (record_obj);
419 if (0 < json_array_size(result_array))
421 json_resource = GNUNET_REST_jsonapi_resource_new (GNUNET_REST_JSONAPI_NAMESTORE_TYPEINFO,
423 GNUNET_REST_jsonapi_resource_add_attr (json_resource,
424 GNUNET_REST_JSONAPI_NAMESTORE_RECORD,
426 GNUNET_REST_jsonapi_object_resource_add (handle->resp_object, json_resource);
429 json_decref (result_array);
430 GNUNET_NAMESTORE_zone_iterator_next (handle->list_it);
434 create_finished (void *cls, int32_t success, const char *emsg)
436 struct RequestHandle *handle = cls;
437 struct MHD_Response *resp;
439 handle->add_qe = NULL;
440 if (GNUNET_YES != success)
442 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
443 "Error storing records%s%s\n",
444 (NULL == emsg) ? "" : ": ",
445 (NULL == emsg) ? "" : emsg);
446 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
449 resp = GNUNET_REST_create_json_response (NULL);
450 handle->proc (handle->proc_cls, resp, MHD_HTTP_NO_CONTENT);
451 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
456 * We're storing a new record; this requires
457 * that no record already exists
459 * @param cls closure, unused
460 * @param zone_key private key of the zone
461 * @param rec_name name that is being mapped (at most 255 characters long)
462 * @param rd_count number of entries in @a rd array
463 * @param rd array of records with data to store
466 create_new_record_cont (void *cls,
467 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
468 const char *rec_name,
469 unsigned int rd_count,
470 const struct GNUNET_GNSRECORD_Data *rd)
472 struct RequestHandle *handle = cls;
474 handle->add_qe = NULL;
475 if ( (NULL != zone_key) &&
476 (0 != strcmp (rec_name, handle->name)) )
479 GNUNET_SCHEDULER_add_now (&do_error, handle);
483 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
484 "Received %u records for name `%s'\n",
488 handle->proc (handle->proc_cls,
489 GNUNET_REST_create_json_response (NULL),
491 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
495 GNUNET_assert (NULL != handle->name);
496 handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
506 del_finished (void *cls,
510 struct RequestHandle *handle = cls;
512 handle->add_qe = NULL;
513 if (GNUNET_NO == success)
515 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
516 _("Deleting record failed, record does not exist%s%s\n"),
517 (NULL != emsg) ? ": " : "",
518 (NULL != emsg) ? emsg : "");
519 GNUNET_SCHEDULER_add_now (&do_error, handle); //do_not_found TODO
522 if (GNUNET_SYSERR == success)
524 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
525 _("Deleting record failed%s%s\n"),
526 (NULL != emsg) ? ": " : "",
527 (NULL != emsg) ? emsg : "");
528 GNUNET_SCHEDULER_add_now (&do_error, handle);
531 handle->proc (handle->proc_cls,
532 GNUNET_REST_create_json_response (NULL),
533 MHD_HTTP_NO_CONTENT);
534 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
539 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
541 unsigned int rd_count,
542 const struct GNUNET_GNSRECORD_Data *rd)
544 struct RequestHandle *handle = cls;
548 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
549 _("There are no records under label `%s' that could be deleted.\n"),
551 GNUNET_SCHEDULER_add_now (&do_error, handle);
555 handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
564 namestore_delete_cont (struct RestConnectionDataHandle *con,
568 struct RequestHandle *handle = cls;
570 if (NULL == handle->name)
572 GNUNET_SCHEDULER_add_now (&do_error, handle);
576 handle->add_qe = GNUNET_NAMESTORE_records_lookup (handle->ns_handle,
584 json_to_gnsrecord (const json_t *records_json,
585 struct GNUNET_GNSRECORD_Data **rd,
586 unsigned int *rd_count)
588 struct GNUNET_TIME_Relative etime_rel;
589 struct GNUNET_TIME_Absolute etime_abs;
593 const char *typestring;
594 const char *expirationstring;
601 *rd_count = json_array_size (records_json);
602 *rd = GNUNET_malloc (sizeof (struct GNUNET_GNSRECORD_Data) * *rd_count);
603 for (i = 0; i < *rd_count; i++)
605 memset (&((*rd)[i]), 0, sizeof (struct GNUNET_GNSRECORD_Data));
606 record_json = json_array_get (records_json, i);
607 type_json = json_object_get (record_json,
608 GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE);
609 if (!json_is_string (type_json))
611 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
612 "Type property is no string\n");
613 return GNUNET_SYSERR;
615 typestring = json_string_value (type_json);
616 (*rd)[i].record_type = GNUNET_GNSRECORD_typename_to_number (typestring);
617 if (UINT32_MAX == (*rd)[i].record_type)
619 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Unsupported type `%s'\n"),
620 json_string_value (type_json));
621 return GNUNET_SYSERR;
623 value_json = json_object_get (record_json,
624 GNUNET_REST_JSONAPI_NAMESTORE_VALUE);
625 if (!json_is_string (value_json))
627 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
628 "Value property is no string\n");
629 return GNUNET_SYSERR;
631 GNUNET_asprintf (&value, "%s", json_string_value (value_json));
632 if (GNUNET_OK != GNUNET_GNSRECORD_string_to_value ((*rd)[i].record_type,
637 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Value `%s' invalid for record type `%s'\n"),
639 return GNUNET_SYSERR;
641 (*rd)[i].data = rdata;
642 (*rd)[i].data_size = rdata_size;
644 * if (1 == handle->is_shadow)
645 rde->flags |= GNUNET_GNSRECORD_RF_SHADOW_RECORD;
646 if (1 != handle->is_public)
647 rde->flags |= GNUNET_GNSRECORD_RF_PRIVATE;
649 exp_json = json_object_get (record_json,
650 GNUNET_REST_JSONAPI_NAMESTORE_EXPIRATION);
651 if (!json_is_string (exp_json))
653 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
654 "Expiration property is no string\n");
655 return GNUNET_SYSERR;
657 expirationstring = json_string_value (exp_json);
658 if (0 == strcmp (expirationstring, "never"))
660 (*rd)[i].expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
662 else if (GNUNET_OK ==
663 GNUNET_STRINGS_fancy_time_to_relative (expirationstring,
666 (*rd)[i].expiration_time = etime_rel.rel_value_us;
667 (*rd)[i].flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
669 else if (GNUNET_OK ==
670 GNUNET_STRINGS_fancy_time_to_absolute (expirationstring,
673 (*rd)[i].expiration_time = etime_abs.abs_value_us;
677 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Value `%s' invalid for record type `%s'\n"),
679 return GNUNET_SYSERR;
686 namestore_create_cont (struct RestConnectionDataHandle *con,
690 struct RequestHandle *handle = cls;
691 struct MHD_Response *resp;
692 struct JsonApiObject *json_obj;
693 struct JsonApiResource *json_res;
695 json_t *records_json;
696 char term_data[handle->data_size+1];
698 if (strlen (GNUNET_REST_API_NS_NAMESTORE) != strlen (handle->url))
700 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
701 "Cannot create under %s\n", handle->url);
702 GNUNET_SCHEDULER_add_now (&do_error, handle);
705 if (0 >= handle->data_size)
707 GNUNET_SCHEDULER_add_now (&do_error, handle);
710 term_data[handle->data_size] = '\0';
711 memcpy (term_data, handle->data, handle->data_size);
712 json_obj = GNUNET_REST_jsonapi_object_parse (term_data);
713 if (NULL == json_obj)
715 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
716 "Unable to parse JSONAPI Object from %s\n",
718 GNUNET_SCHEDULER_add_now (&do_error, handle);
721 if (1 != GNUNET_REST_jsonapi_object_resource_count (json_obj))
723 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
724 "Cannot create more than 1 resource! (Got %d)\n",
725 GNUNET_REST_jsonapi_object_resource_count (json_obj));
726 GNUNET_REST_jsonapi_object_delete (json_obj);
727 GNUNET_SCHEDULER_add_now (&do_error, handle);
730 json_res = GNUNET_REST_jsonapi_object_get_resource (json_obj, 0);
731 if (GNUNET_NO == GNUNET_REST_jsonapi_resource_check_type (json_res,
732 GNUNET_REST_JSONAPI_NAMESTORE_RECORD))
734 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
735 "Unsupported JSON data type\n");
736 GNUNET_REST_jsonapi_object_delete (json_obj);
737 resp = GNUNET_REST_create_json_response (NULL);
738 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
739 cleanup_handle (handle);
742 name_json = GNUNET_REST_jsonapi_resource_read_attr (json_res, GNUNET_REST_JSONAPI_KEY_ID);
743 if (!json_is_string (name_json))
745 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
746 "Name property is no string\n");
747 GNUNET_REST_jsonapi_object_delete (json_obj);
748 GNUNET_SCHEDULER_add_now (&do_error, handle);
751 GNUNET_asprintf (&handle->name, "%s", json_string_value (name_json));
752 records_json = GNUNET_REST_jsonapi_resource_read_attr (json_res,
753 GNUNET_REST_JSONAPI_NAMESTORE_RECORD);
754 if (NULL == records_json)
756 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
757 "No records given\n");
758 GNUNET_REST_jsonapi_object_delete (json_obj);
759 GNUNET_SCHEDULER_add_now (&do_error, handle);
762 if (GNUNET_SYSERR == json_to_gnsrecord (records_json, &handle->rd, &handle->rd_count))
764 GNUNET_REST_jsonapi_object_delete (json_obj);
765 GNUNET_SCHEDULER_add_now (&do_error, handle);
768 GNUNET_REST_jsonapi_object_delete (json_obj);
770 handle->add_qe = GNUNET_NAMESTORE_records_lookup (handle->ns_handle,
773 &create_new_record_cont, handle );
781 namestore_info_cont (struct RestConnectionDataHandle *con,
785 struct RequestHandle *handle = cls;
786 handle->list_it = GNUNET_NAMESTORE_zone_iteration_start (handle->ns_handle,
788 &namestore_list_response,
793 get_name_from_url (const char* url)
795 if (strlen (url) <= strlen (GNUNET_REST_API_NS_NAMESTORE))
797 return (char*)url + strlen (GNUNET_REST_API_NS_NAMESTORE) + 1;
801 * Respond to OPTIONS request
803 * @param con_handle the connection handle
805 * @param cls the RequestHandle
808 options_cont (struct RestConnectionDataHandle *con_handle,
812 struct MHD_Response *resp;
813 struct RequestHandle *handle = cls;
815 //For now, independent of path return all options
816 resp = GNUNET_REST_create_json_response (NULL);
817 MHD_add_response_header (resp,
818 "Access-Control-Allow-Methods",
820 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
821 cleanup_handle (handle);
826 * Function called with the result from the check if the namestore
827 * service is actually running. If it is, we start the actual
830 * @param cls closure with our configuration
831 * @param result #GNUNET_YES if the namestore service is running
834 testservice_task (void *cls,
837 struct RequestHandle *handle = cls;
838 static const struct GNUNET_REST_RestConnectionHandler handlers[] = {
839 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_NAMESTORE, &namestore_info_cont}, //list
840 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_NAMESTORE, &namestore_create_cont}, //create
841 // {MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_NAMESTORE, &namestore_edit_cont}, //update. TODO this shoul be PATCH
842 {MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_NAMESTORE, &namestore_delete_cont}, //delete
843 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_NAMESTORE, &options_cont},
844 GNUNET_REST_HANDLER_END
847 if (GNUNET_YES != result)
849 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Service `%s' is not running\n"),
851 GNUNET_SCHEDULER_add_now (&do_error, handle);
854 handle->ns_handle = GNUNET_NAMESTORE_connect (cfg);
855 if (NULL == handle->ns_handle)
857 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
858 _("Failed to connect to namestore\n"));
859 GNUNET_SCHEDULER_add_now (&do_error, handle);
863 if (GNUNET_NO == GNUNET_REST_handle_request (handle->conndata_handle, handlers, handle))
864 GNUNET_SCHEDULER_add_now (&do_error, (void*) handle);
869 * Callback invoked from identity service with ego information.
870 * An @a ego of NULL means the ego was not found.
872 * @param cls closure with the configuration
873 * @param ego an ego known to identity service, or NULL
876 identity_cb (void *cls,
877 const struct GNUNET_IDENTITY_Ego *ego)
879 struct RequestHandle *handle = cls;
880 struct MHD_Response *resp;
882 handle->ego_lookup = NULL;
885 if (NULL != handle->ego_name)
887 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
888 _("Ego `%s' not known to identity service\n"),
891 resp = GNUNET_REST_create_json_response (NULL);
892 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
893 cleanup_handle (handle);
896 handle->zone_pkey = *GNUNET_IDENTITY_ego_get_private_key (ego);
897 GNUNET_CLIENT_service_test ("namestore", handle->cfg,
898 GNUNET_TIME_UNIT_SECONDS,
904 default_ego_cb (void *cls,
905 struct GNUNET_IDENTITY_Ego *ego,
909 struct RequestHandle *handle = cls;
910 struct MHD_Response *resp;
911 handle->get_default = NULL;
914 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
915 _("No default ego configured in identity service\n"));
916 resp = GNUNET_REST_create_json_response (NULL);
917 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
918 cleanup_handle (handle);
923 identity_cb (cls, ego);
928 id_connect_cb (void *cls,
929 struct GNUNET_IDENTITY_Ego *ego,
933 struct RequestHandle *handle = cls;
936 handle->get_default = GNUNET_IDENTITY_get (handle->identity_handle,
938 &default_ego_cb, handle);
943 testservice_id_task (void *cls, int result)
945 struct RequestHandle *handle = cls;
946 struct MHD_Response *resp;
947 struct GNUNET_HashCode key;
952 if (result != GNUNET_YES)
954 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
955 _("Identity service is not running\n"));
956 resp = GNUNET_REST_create_json_response (NULL);
957 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
958 cleanup_handle (handle);
962 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_NAMESTORE_EGO,
963 strlen (GNUNET_REST_JSONAPI_NAMESTORE_EGO),
966 GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
969 ego = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
973 handle->type = GNUNET_GNSRECORD_TYPE_ANY;
974 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE,
975 strlen (GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE),
978 GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
981 type = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
984 handle->type = GNUNET_GNSRECORD_typename_to_number (type);
986 name = get_name_from_url (handle->url);
988 GNUNET_asprintf (&handle->ego_name, "%s", ego);
990 GNUNET_asprintf (&handle->name, "%s", name);
991 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", handle->ego_name);
992 if (NULL == handle->ego_name)
994 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", handle->ego_name);
995 handle->identity_handle = GNUNET_IDENTITY_connect (handle->cfg, &id_connect_cb, handle);
996 if (NULL == handle->identity_handle)
998 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Cannot connect to identity service\n"));
999 resp = GNUNET_REST_create_json_response (NULL);
1000 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
1001 cleanup_handle (handle);
1005 handle->ego_lookup = GNUNET_IDENTITY_ego_lookup (cfg,
1012 * Function processing the REST call
1014 * @param method HTTP method
1015 * @param url URL of the HTTP request
1016 * @param data body of the HTTP request (optional)
1017 * @param data_size length of the body
1018 * @param proc callback function for the result
1019 * @param proc_cls closure for callback function
1020 * @return GNUNET_OK if request accepted
1023 rest_identity_process_request(struct RestConnectionDataHandle *conndata_handle,
1024 GNUNET_REST_ResultProcessor proc,
1027 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1029 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1030 handle->proc_cls = proc_cls;
1031 handle->proc = proc;
1032 handle->conndata_handle = conndata_handle;
1033 handle->data = conndata_handle->data;
1034 handle->data_size = conndata_handle->data_size;
1035 GNUNET_asprintf (&handle->url, "%s", conndata_handle->url);
1036 if (handle->url[strlen (handle->url)-1] == '/')
1037 handle->url[strlen (handle->url)-1] = '\0';
1038 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1041 GNUNET_CLIENT_service_test ("identity",
1043 GNUNET_TIME_UNIT_SECONDS,
1044 &testservice_id_task,
1046 handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout,
1054 * Entry point for the plugin.
1056 * @param cls Config info
1057 * @return NULL on error, otherwise the plugin context
1060 libgnunet_plugin_rest_namestore_init (void *cls)
1062 static struct Plugin plugin;
1064 struct GNUNET_REST_Plugin *api;
1066 if (NULL != plugin.cfg)
1067 return NULL; /* can only initialize once! */
1068 memset (&plugin, 0, sizeof (struct Plugin));
1070 api = GNUNET_new (struct GNUNET_REST_Plugin);
1072 api->name = GNUNET_REST_API_NS_NAMESTORE;
1073 api->process_request = &rest_identity_process_request;
1074 GNUNET_asprintf (&allow_methods,
1075 "%s, %s, %s, %s, %s",
1076 MHD_HTTP_METHOD_GET,
1077 MHD_HTTP_METHOD_POST,
1078 MHD_HTTP_METHOD_PUT,
1079 MHD_HTTP_METHOD_DELETE,
1080 MHD_HTTP_METHOD_OPTIONS);
1081 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1082 _("Namestore REST API initialized\n"));
1088 * Exit point from the plugin.
1090 * @param cls the plugin context (as returned by "init")
1091 * @return always NULL
1094 libgnunet_plugin_rest_namestore_done (void *cls)
1096 struct GNUNET_REST_Plugin *api = cls;
1097 struct Plugin *plugin = api->cls;
1101 GNUNET_free_non_null (allow_methods);
1102 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1103 "Namestore REST plugin is finished\n");
1107 /* end of plugin_rest_namestore.c */