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 "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
246 * @param handle Handle to clean up
249 cleanup_handle (struct RequestHandle *handle)
251 struct RecordEntry *record_entry;
252 struct RecordEntry *record_tmp;
255 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
257 if (NULL != handle->resp_object)
258 GNUNET_REST_jsonapi_object_delete (handle->resp_object);
259 if (NULL != handle->name)
260 GNUNET_free (handle->name);
261 if (NULL != handle->timeout_task)
262 GNUNET_SCHEDULER_cancel (handle->timeout_task);
263 if (NULL != handle->ego_lookup)
264 GNUNET_IDENTITY_ego_lookup_cancel (handle->ego_lookup);
265 if (NULL != handle->get_default)
266 GNUNET_IDENTITY_cancel (handle->get_default);
267 if (NULL != handle->list_it)
268 GNUNET_NAMESTORE_zone_iteration_stop (handle->list_it);
269 if (NULL != handle->add_qe)
270 GNUNET_NAMESTORE_cancel (handle->add_qe);
271 if (NULL != handle->identity_handle)
272 GNUNET_IDENTITY_disconnect (handle->identity_handle);
273 if (NULL != handle->ns_handle)
274 GNUNET_NAMESTORE_disconnect (handle->ns_handle);
275 if (NULL != handle->url)
276 GNUNET_free (handle->url);
277 if (NULL != handle->value)
278 GNUNET_free (handle->value);
279 if (NULL != handle->rd)
281 for (i = 0; i < handle->rd_count; i++)
283 if (NULL != handle->rd[i].data)
284 GNUNET_free ((void*)handle->rd[i].data);
286 GNUNET_free (handle->rd);
288 if (NULL != handle->ego_name)
289 GNUNET_free (handle->ego_name);
290 for (record_entry = handle->record_head;
291 NULL != record_entry;)
293 record_tmp = record_entry;
294 record_entry = record_entry->next;
295 GNUNET_free (record_tmp);
297 GNUNET_free (handle);
302 * Create json representation of a GNSRECORD
304 * @param rd the GNSRECORD_Data
307 gnsrecord_to_json (const struct GNUNET_GNSRECORD_Data *rd)
309 const char *typename;
314 typename = GNUNET_GNSRECORD_number_to_typename (rd->record_type);
315 string_val = GNUNET_GNSRECORD_value_to_string (rd->record_type,
319 if (NULL == string_val)
321 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
322 "Record of type %d malformed, skipping\n",
323 (int) rd->record_type);
326 record_obj = json_object();
327 json_object_set_new (record_obj,
328 GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE,
329 json_string (typename));
330 json_object_set_new (record_obj,
331 GNUNET_REST_JSONAPI_NAMESTORE_VALUE,
332 json_string (string_val));
333 GNUNET_free (string_val);
335 if (GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION & rd->flags)
337 struct GNUNET_TIME_Relative time_rel;
338 time_rel.rel_value_us = rd->expiration_time;
339 exp_str = GNUNET_STRINGS_relative_time_to_string (time_rel, 1);
343 struct GNUNET_TIME_Absolute time_abs;
344 time_abs.abs_value_us = rd->expiration_time;
345 exp_str = GNUNET_STRINGS_absolute_time_to_string (time_abs);
347 json_object_set_new (record_obj, GNUNET_REST_JSONAPI_NAMESTORE_EXPIRATION, json_string (exp_str));
349 json_object_set_new (record_obj, "expired",
350 json_boolean (GNUNET_YES == GNUNET_GNSRECORD_is_expired (rd)));
356 * Task run on error. Generates error response and cleans up.
358 * @param cls the request to generate an error response for
363 struct RequestHandle *handle = cls;
364 struct MHD_Response *resp = GNUNET_REST_create_json_response (NULL);
366 handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
367 cleanup_handle (handle);
372 * Task run on timeout.
374 * @param cls the request to time out
377 do_timeout (void *cls)
379 struct RequestHandle *handle = cls;
381 handle->timeout_task = NULL;
387 cleanup_handle_delayed (void *cls)
389 cleanup_handle (cls);
394 * Create a response with requested records
396 * @param handle the RequestHandle
399 namestore_list_response (void *cls,
400 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
403 const struct GNUNET_GNSRECORD_Data *rd)
405 struct RequestHandle *handle = cls;
406 struct JsonApiResource *json_resource;
407 struct MHD_Response *resp;
408 json_t *result_array;
413 if (NULL == handle->resp_object)
414 handle->resp_object = GNUNET_REST_jsonapi_object_new ();
418 handle->list_it = NULL;
420 if (GNUNET_SYSERR == GNUNET_REST_jsonapi_data_serialize (handle->resp_object, &result))
422 GNUNET_SCHEDULER_add_now (&do_error, handle);
425 resp = GNUNET_REST_create_json_response (result);
426 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
427 GNUNET_free (result);
428 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
432 if ( (NULL != handle->name) &&
433 (0 != strcmp (handle->name, rname)) )
435 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
436 "%s does not match %s\n", rname, handle->name);
437 GNUNET_NAMESTORE_zone_iterator_next (handle->list_it);
441 result_array = json_array ();
442 for (i=0; i<rd_len; i++)
444 if ( (GNUNET_GNSRECORD_TYPE_NICK == rd[i].record_type) &&
445 (0 != strcmp (rname, "+")) )
448 if ( (rd[i].record_type != handle->type) &&
449 (GNUNET_GNSRECORD_TYPE_ANY != handle->type) )
451 record_obj = gnsrecord_to_json (&(rd[i]));
452 json_array_append (result_array, record_obj);
453 json_decref (record_obj);
456 if (0 < json_array_size(result_array))
458 json_resource = GNUNET_REST_jsonapi_resource_new (GNUNET_REST_JSONAPI_NAMESTORE_TYPEINFO,
460 GNUNET_REST_jsonapi_resource_add_attr (json_resource,
461 GNUNET_REST_JSONAPI_NAMESTORE_RECORD,
463 GNUNET_REST_jsonapi_object_resource_add (handle->resp_object, json_resource);
466 json_decref (result_array);
467 GNUNET_NAMESTORE_zone_iterator_next (handle->list_it);
471 create_finished (void *cls, int32_t success, const char *emsg)
473 struct RequestHandle *handle = cls;
474 struct MHD_Response *resp;
476 handle->add_qe = NULL;
477 if (GNUNET_YES != success)
479 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
480 "Error storing records%s%s\n",
481 (NULL == emsg) ? "" : ": ",
482 (NULL == emsg) ? "" : emsg);
483 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
486 resp = GNUNET_REST_create_json_response (NULL);
487 handle->proc (handle->proc_cls, resp, MHD_HTTP_NO_CONTENT);
488 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
493 * We're storing a new record; this requires
494 * that no record already exists
496 * @param cls closure, unused
497 * @param zone_key private key of the zone
498 * @param rec_name name that is being mapped (at most 255 characters long)
499 * @param rd_count number of entries in @a rd array
500 * @param rd array of records with data to store
503 create_new_record_cont (void *cls,
504 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
505 const char *rec_name,
506 unsigned int rd_count,
507 const struct GNUNET_GNSRECORD_Data *rd)
509 struct RequestHandle *handle = cls;
511 handle->add_qe = NULL;
512 if ( (NULL != zone_key) &&
513 (0 != strcmp (rec_name, handle->name)) )
516 GNUNET_SCHEDULER_add_now (&do_error, handle);
522 handle->proc (handle->proc_cls,
523 GNUNET_REST_create_json_response (NULL),
525 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
529 GNUNET_assert (NULL != handle->name);
530 handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
540 del_finished (void *cls,
544 struct RequestHandle *handle = cls;
546 handle->add_qe = NULL;
547 if (GNUNET_NO == success)
549 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
550 _("Deleting record failed, record does not exist%s%s\n"),
551 (NULL != emsg) ? ": " : "",
552 (NULL != emsg) ? emsg : "");
553 GNUNET_SCHEDULER_add_now (&do_error, handle); //do_not_found TODO
556 if (GNUNET_SYSERR == success)
558 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
559 _("Deleting record failed%s%s\n"),
560 (NULL != emsg) ? ": " : "",
561 (NULL != emsg) ? emsg : "");
562 GNUNET_SCHEDULER_add_now (&do_error, handle);
565 handle->proc (handle->proc_cls,
566 GNUNET_REST_create_json_response (NULL),
567 MHD_HTTP_NO_CONTENT);
568 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
573 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
575 unsigned int rd_count,
576 const struct GNUNET_GNSRECORD_Data *rd)
578 struct RequestHandle *handle = cls;
579 handle->add_qe = NULL;
582 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
583 _("There are no records under label `%s' that could be deleted.\n"),
585 GNUNET_SCHEDULER_add_now (&do_error, handle);
589 handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
598 namestore_delete_cont (struct RestConnectionDataHandle *con,
602 struct RequestHandle *handle = cls;
604 if (NULL == handle->name)
606 GNUNET_SCHEDULER_add_now (&do_error, handle);
610 handle->add_qe = GNUNET_NAMESTORE_records_lookup (handle->ns_handle,
618 json_to_gnsrecord (const json_t *records_json,
619 struct GNUNET_GNSRECORD_Data **rd,
620 unsigned int *rd_count)
622 struct GNUNET_TIME_Relative etime_rel;
623 struct GNUNET_TIME_Absolute etime_abs;
627 const char *typestring;
628 const char *expirationstring;
635 *rd_count = json_array_size (records_json);
636 *rd = GNUNET_malloc (sizeof (struct GNUNET_GNSRECORD_Data) * *rd_count);
637 for (i = 0; i < *rd_count; i++)
639 memset (&((*rd)[i]), 0, sizeof (struct GNUNET_GNSRECORD_Data));
640 record_json = json_array_get (records_json, i);
641 type_json = json_object_get (record_json,
642 GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE);
643 if (!json_is_string (type_json))
645 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
646 "Type property is no string\n");
647 return GNUNET_SYSERR;
649 typestring = json_string_value (type_json);
650 (*rd)[i].record_type = GNUNET_GNSRECORD_typename_to_number (typestring);
651 if (UINT32_MAX == (*rd)[i].record_type)
653 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Unsupported type `%s'\n"),
654 json_string_value (type_json));
655 return GNUNET_SYSERR;
657 value_json = json_object_get (record_json,
658 GNUNET_REST_JSONAPI_NAMESTORE_VALUE);
659 if (!json_is_string (value_json))
661 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
662 "Value property is no string\n");
663 return GNUNET_SYSERR;
665 GNUNET_asprintf (&value, "%s", json_string_value (value_json));
666 if (GNUNET_OK != GNUNET_GNSRECORD_string_to_value ((*rd)[i].record_type,
671 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Value `%s' invalid for record type `%s'\n"),
673 return GNUNET_SYSERR;
675 (*rd)[i].data = rdata;
676 (*rd)[i].data_size = rdata_size;
678 * if (1 == handle->is_shadow)
679 rde->flags |= GNUNET_GNSRECORD_RF_SHADOW_RECORD;
680 if (1 != handle->is_public)
681 rde->flags |= GNUNET_GNSRECORD_RF_PRIVATE;
683 exp_json = json_object_get (record_json,
684 GNUNET_REST_JSONAPI_NAMESTORE_EXPIRATION);
685 if (!json_is_string (exp_json))
687 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
688 "Expiration property is no string\n");
689 return GNUNET_SYSERR;
691 expirationstring = json_string_value (exp_json);
692 if (0 == strcmp (expirationstring, "never"))
694 (*rd)[i].expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
696 else if (GNUNET_OK ==
697 GNUNET_STRINGS_fancy_time_to_relative (expirationstring,
700 (*rd)[i].expiration_time = etime_rel.rel_value_us;
701 (*rd)[i].flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
703 else if (GNUNET_OK ==
704 GNUNET_STRINGS_fancy_time_to_absolute (expirationstring,
707 (*rd)[i].expiration_time = etime_abs.abs_value_us;
711 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Value `%s' invalid for record type `%s'\n"),
713 return GNUNET_SYSERR;
720 namestore_create_cont (struct RestConnectionDataHandle *con,
724 struct RequestHandle *handle = cls;
725 struct MHD_Response *resp;
726 struct JsonApiObject *json_obj;
727 struct JsonApiResource *json_res;
729 json_t *records_json;
730 char term_data[handle->data_size+1];
732 if (strlen (GNUNET_REST_API_NS_NAMESTORE) != strlen (handle->url))
734 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
735 "Cannot create under %s\n", handle->url);
736 GNUNET_SCHEDULER_add_now (&do_error, handle);
739 if (0 >= handle->data_size)
741 GNUNET_SCHEDULER_add_now (&do_error, handle);
744 term_data[handle->data_size] = '\0';
745 memcpy (term_data, handle->data, handle->data_size);
746 json_obj = GNUNET_REST_jsonapi_object_parse (term_data);
747 if (NULL == json_obj)
749 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
750 "Unable to parse JSONAPI Object from %s\n",
752 GNUNET_SCHEDULER_add_now (&do_error, handle);
755 if (1 != GNUNET_REST_jsonapi_object_resource_count (json_obj))
757 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
758 "Cannot create more than 1 resource! (Got %d)\n",
759 GNUNET_REST_jsonapi_object_resource_count (json_obj));
760 GNUNET_REST_jsonapi_object_delete (json_obj);
761 GNUNET_SCHEDULER_add_now (&do_error, handle);
764 json_res = GNUNET_REST_jsonapi_object_get_resource (json_obj, 0);
765 if (GNUNET_NO == GNUNET_REST_jsonapi_resource_check_type (json_res,
766 GNUNET_REST_JSONAPI_NAMESTORE_RECORD))
768 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
769 "Unsupported JSON data type\n");
770 GNUNET_REST_jsonapi_object_delete (json_obj);
771 resp = GNUNET_REST_create_json_response (NULL);
772 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
773 cleanup_handle (handle);
776 name_json = GNUNET_REST_jsonapi_resource_read_attr (json_res, GNUNET_REST_JSONAPI_KEY_ID);
777 if (!json_is_string (name_json))
779 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
780 "Name property is no string\n");
781 GNUNET_REST_jsonapi_object_delete (json_obj);
782 GNUNET_SCHEDULER_add_now (&do_error, handle);
785 GNUNET_asprintf (&handle->name, "%s", json_string_value (name_json));
786 records_json = GNUNET_REST_jsonapi_resource_read_attr (json_res,
787 GNUNET_REST_JSONAPI_NAMESTORE_RECORD);
788 if (NULL == records_json)
790 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
791 "No records given\n");
792 GNUNET_REST_jsonapi_object_delete (json_obj);
793 GNUNET_SCHEDULER_add_now (&do_error, handle);
796 if (GNUNET_SYSERR == json_to_gnsrecord (records_json, &handle->rd, &handle->rd_count))
798 GNUNET_REST_jsonapi_object_delete (json_obj);
799 GNUNET_SCHEDULER_add_now (&do_error, handle);
802 GNUNET_REST_jsonapi_object_delete (json_obj);
804 handle->add_qe = GNUNET_NAMESTORE_records_lookup (handle->ns_handle,
807 &create_new_record_cont, handle );
811 namestore_zkey_response (void *cls,
812 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
814 unsigned int rd_count,
815 const struct GNUNET_GNSRECORD_Data *rd)
817 struct RequestHandle *handle = cls;
818 struct MHD_Response *resp;
819 struct JsonApiObject *json_obj;
820 struct JsonApiResource *json_res;
824 handle->reverse_qe = NULL;
825 json_obj = GNUNET_REST_jsonapi_object_new ();
828 name_json = json_string (label);
829 json_res = GNUNET_REST_jsonapi_resource_new (GNUNET_REST_JSONAPI_NAMESTORE_REVINFO,
831 GNUNET_REST_jsonapi_resource_add_attr (json_res,
832 GNUNET_REST_JSONAPI_NAMESTORE_NAME,
834 GNUNET_REST_jsonapi_object_resource_add (json_obj, json_res);
835 json_decref (name_json);
838 if (GNUNET_SYSERR == GNUNET_REST_jsonapi_data_serialize (json_obj, &result))
840 GNUNET_REST_jsonapi_object_delete (json_obj);
841 GNUNET_SCHEDULER_add_now (&do_error, handle);
844 resp = GNUNET_REST_create_json_response (result);
845 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
846 GNUNET_REST_jsonapi_object_delete (json_obj);
847 GNUNET_free (result);
848 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
854 namestore_zkey_cont (struct RestConnectionDataHandle *con,
858 struct RequestHandle *handle = cls;
859 struct GNUNET_HashCode key;
860 struct GNUNET_CRYPTO_EcdsaPublicKey pubkey;
862 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_NAMESTORE_ZKEY,
863 strlen (GNUNET_REST_JSONAPI_NAMESTORE_ZKEY),
866 GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
869 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
870 "No zkey given %s\n", handle->url);
871 GNUNET_SCHEDULER_add_now (&do_error, handle);
874 handle->zkey_str = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
877 GNUNET_CRYPTO_ecdsa_public_key_from_string (handle->zkey_str,
878 strlen (handle->zkey_str),
881 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
882 "Zkey invalid %s\n", handle->zkey_str);
883 GNUNET_SCHEDULER_add_now (&do_error, handle);
886 handle->reverse_qe = GNUNET_NAMESTORE_zone_to_name (handle->ns_handle,
889 &namestore_zkey_response,
894 namestore_info_cont (struct RestConnectionDataHandle *con,
898 struct RequestHandle *handle = cls;
899 handle->list_it = GNUNET_NAMESTORE_zone_iteration_start (handle->ns_handle,
901 &namestore_list_response,
906 get_name_from_url (const char* url)
908 if (strlen (url) <= strlen (GNUNET_REST_API_NS_NAMESTORE))
910 return (char*)url + strlen (GNUNET_REST_API_NS_NAMESTORE) + 1;
914 * Respond to OPTIONS request
916 * @param con_handle the connection handle
918 * @param cls the RequestHandle
921 options_cont (struct RestConnectionDataHandle *con_handle,
925 struct MHD_Response *resp;
926 struct RequestHandle *handle = cls;
928 //For now, independent of path return all options
929 resp = GNUNET_REST_create_json_response (NULL);
930 MHD_add_response_header (resp,
931 "Access-Control-Allow-Methods",
933 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
934 cleanup_handle (handle);
939 * Function called with the result from the check if the namestore
940 * service is actually running. If it is, we start the actual
943 * @param cls closure with our configuration
944 * @param result #GNUNET_YES if the namestore service is running
947 testservice_task (void *cls,
950 struct RequestHandle *handle = cls;
951 static const struct GNUNET_REST_RestConnectionHandler 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_NO == GNUNET_REST_handle_request (handle->conndata_handle, handlers, handle))
978 GNUNET_SCHEDULER_add_now (&do_error, (void*) handle);
983 * Callback invoked from identity service with ego information.
984 * An @a ego of NULL means the ego was not found.
986 * @param cls closure with the configuration
987 * @param ego an ego known to identity service, or NULL
990 identity_cb (void *cls,
991 const struct GNUNET_IDENTITY_Ego *ego)
993 struct RequestHandle *handle = cls;
994 struct MHD_Response *resp;
996 handle->ego_lookup = NULL;
999 if (NULL != handle->ego_name)
1001 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1002 _("Ego `%s' not known to identity service\n"),
1005 resp = GNUNET_REST_create_json_response (NULL);
1006 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
1007 cleanup_handle (handle);
1010 handle->zone_pkey = *GNUNET_IDENTITY_ego_get_private_key (ego);
1011 GNUNET_CLIENT_service_test ("namestore", handle->cfg,
1012 GNUNET_TIME_UNIT_SECONDS,
1018 default_ego_cb (void *cls,
1019 struct GNUNET_IDENTITY_Ego *ego,
1023 struct RequestHandle *handle = cls;
1024 struct MHD_Response *resp;
1025 handle->get_default = NULL;
1028 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1029 _("No default ego configured in identity service\n"));
1030 resp = GNUNET_REST_create_json_response (NULL);
1031 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
1032 cleanup_handle (handle);
1037 identity_cb (cls, ego);
1042 id_connect_cb (void *cls,
1043 struct GNUNET_IDENTITY_Ego *ego,
1047 struct RequestHandle *handle = cls;
1050 handle->get_default = GNUNET_IDENTITY_get (handle->identity_handle,
1052 &default_ego_cb, handle);
1057 testservice_id_task (void *cls, int result)
1059 struct RequestHandle *handle = cls;
1060 struct MHD_Response *resp;
1061 struct GNUNET_HashCode key;
1066 if (result != GNUNET_YES)
1068 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1069 _("Identity service is not running\n"));
1070 resp = GNUNET_REST_create_json_response (NULL);
1071 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
1072 cleanup_handle (handle);
1076 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_NAMESTORE_EGO,
1077 strlen (GNUNET_REST_JSONAPI_NAMESTORE_EGO),
1080 GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
1083 ego = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
1087 handle->type = GNUNET_GNSRECORD_TYPE_ANY;
1088 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE,
1089 strlen (GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE),
1092 GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
1095 type = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
1098 handle->type = GNUNET_GNSRECORD_typename_to_number (type);
1100 name = get_name_from_url (handle->url);
1102 GNUNET_asprintf (&handle->ego_name, "%s", ego);
1104 GNUNET_asprintf (&handle->name, "%s", name);
1105 if (NULL == handle->ego_name)
1107 handle->identity_handle = GNUNET_IDENTITY_connect (handle->cfg, &id_connect_cb, handle);
1108 if (NULL == handle->identity_handle)
1110 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Cannot connect to identity service\n"));
1111 resp = GNUNET_REST_create_json_response (NULL);
1112 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
1113 cleanup_handle (handle);
1117 handle->ego_lookup = GNUNET_IDENTITY_ego_lookup (cfg,
1124 * Function processing the REST call
1126 * @param method HTTP method
1127 * @param url URL of the HTTP request
1128 * @param data body of the HTTP request (optional)
1129 * @param data_size length of the body
1130 * @param proc callback function for the result
1131 * @param proc_cls closure for callback function
1132 * @return GNUNET_OK if request accepted
1135 rest_identity_process_request(struct RestConnectionDataHandle *conndata_handle,
1136 GNUNET_REST_ResultProcessor proc,
1139 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1141 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1142 handle->proc_cls = proc_cls;
1143 handle->proc = proc;
1144 handle->conndata_handle = conndata_handle;
1145 handle->data = conndata_handle->data;
1146 handle->data_size = conndata_handle->data_size;
1147 GNUNET_asprintf (&handle->url, "%s", conndata_handle->url);
1148 if (handle->url[strlen (handle->url)-1] == '/')
1149 handle->url[strlen (handle->url)-1] = '\0';
1150 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1153 GNUNET_CLIENT_service_test ("identity",
1155 GNUNET_TIME_UNIT_SECONDS,
1156 &testservice_id_task,
1158 handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout,
1164 * Entry point for the plugin.
1166 * @param cls Config info
1167 * @return NULL on error, otherwise the plugin context
1170 libgnunet_plugin_rest_namestore_init (void *cls)
1172 static struct Plugin plugin;
1174 struct GNUNET_REST_Plugin *api;
1176 if (NULL != plugin.cfg)
1177 return NULL; /* can only initialize once! */
1178 memset (&plugin, 0, sizeof (struct Plugin));
1180 api = GNUNET_new (struct GNUNET_REST_Plugin);
1182 api->name = GNUNET_REST_API_NS_NAMESTORE;
1183 api->process_request = &rest_identity_process_request;
1184 GNUNET_asprintf (&allow_methods,
1185 "%s, %s, %s, %s, %s",
1186 MHD_HTTP_METHOD_GET,
1187 MHD_HTTP_METHOD_POST,
1188 MHD_HTTP_METHOD_PUT,
1189 MHD_HTTP_METHOD_DELETE,
1190 MHD_HTTP_METHOD_OPTIONS);
1191 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1192 _("Namestore REST API initialized\n"));
1198 * Exit point from the plugin.
1200 * @param cls the plugin context (as returned by "init")
1201 * @return always NULL
1204 libgnunet_plugin_rest_namestore_done (void *cls)
1206 struct GNUNET_REST_Plugin *api = cls;
1207 struct Plugin *plugin = api->cls;
1211 GNUNET_free_non_null (allow_methods);
1212 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1213 "Namestore REST plugin is finished\n");
1217 /* end of plugin_rest_namestore.c */