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 "gnunet_jsonapi_util.h"
34 #include "microhttpd.h"
37 #define GNUNET_REST_API_NS_NAMESTORE "/names"
39 #define GNUNET_REST_API_NS_NAMESTORE_ZKEY "/names/zkey"
41 #define GNUNET_REST_JSONAPI_NAMESTORE_TYPEINFO "record"
43 #define GNUNET_REST_JSONAPI_NAMESTORE_NAME "name"
45 #define GNUNET_REST_JSONAPI_NAMESTORE_REVINFO "revinfo"
47 #define GNUNET_REST_JSONAPI_NAMESTORE_RECORD GNUNET_REST_JSONAPI_NAMESTORE_TYPEINFO
49 #define GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE "record_type"
51 #define GNUNET_REST_JSONAPI_NAMESTORE_VALUE "value"
53 #define GNUNET_REST_JSONAPI_NAMESTORE_PUBLIC "public"
55 #define GNUNET_REST_JSONAPI_NAMESTORE_SHADOW "shadow"
57 #define GNUNET_REST_JSONAPI_NAMESTORE_PKEY "pkey"
59 #define GNUNET_REST_JSONAPI_NAMESTORE_ZKEY "zkey"
61 #define GNUNET_REST_JSONAPI_NAMESTORE_EXPIRATION "expiration"
63 #define GNUNET_REST_JSONAPI_NAMESTORE_EGO "ego"
66 * @brief struct returned by the initialization function of the plugin
70 const struct GNUNET_CONFIGURATION_Handle *cfg;
75 * HTTP methods allows for this plugin
77 static char* allow_methods;
79 const struct GNUNET_CONFIGURATION_Handle *cfg;
86 struct RecordEntry *next;
91 struct RecordEntry *prev;
100 struct RecordEntry *record_head;
105 struct record_entry *record_tail;
108 * JSON response object
110 struct GNUNET_JSONAPI_Document *resp_object;
115 struct GNUNET_REST_RequestHandle *rest_handle;
118 * Handle to GNS service.
120 struct GNUNET_IDENTITY_Handle *identity_handle;
123 * Handle to NAMESTORE
125 struct GNUNET_NAMESTORE_Handle *ns_handle;
128 * Handle to NAMESTORE it
130 struct GNUNET_NAMESTORE_ZoneIterator *list_it;
133 * Private key for the zone
135 struct GNUNET_CRYPTO_EcdsaPrivateKey zone_pkey;
138 * Handle to identity lookup
140 struct GNUNET_IDENTITY_EgoLookup *ego_lookup;
143 * Default Ego operation
145 struct GNUNET_IDENTITY_Operation *get_default;
163 * Name of the record to modify
168 * Value of the record
175 const char* zkey_str;
185 struct GNUNET_GNSRECORD_Data *rd;
190 unsigned int rd_count;
193 * NAMESTORE Operation
195 struct GNUNET_NAMESTORE_QueueEntry *add_qe;
198 * NAMESTORE Operation
200 struct GNUNET_NAMESTORE_QueueEntry *reverse_qe;
203 * Desired timeout for the lookup (default is no timeout).
205 struct GNUNET_TIME_Relative timeout;
208 * ID of a task associated with the resolution process.
210 struct GNUNET_SCHEDULER_Task * timeout_task;
213 * The plugin result processor
215 GNUNET_REST_ResultProcessor proc;
218 * The closure of the result processor
230 const struct GNUNET_CONFIGURATION_Handle *cfg;
241 * Cleanup lookup handle
243 * @param handle Handle to clean up
246 cleanup_handle (struct RequestHandle *handle)
248 struct RecordEntry *record_entry;
249 struct RecordEntry *record_tmp;
252 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
254 if (NULL != handle->resp_object)
255 GNUNET_JSONAPI_document_delete (handle->resp_object);
256 if (NULL != handle->name)
257 GNUNET_free (handle->name);
258 if (NULL != handle->timeout_task)
259 GNUNET_SCHEDULER_cancel (handle->timeout_task);
260 if (NULL != handle->ego_lookup)
261 GNUNET_IDENTITY_ego_lookup_cancel (handle->ego_lookup);
262 if (NULL != handle->get_default)
263 GNUNET_IDENTITY_cancel (handle->get_default);
264 if (NULL != handle->list_it)
265 GNUNET_NAMESTORE_zone_iteration_stop (handle->list_it);
266 if (NULL != handle->add_qe)
267 GNUNET_NAMESTORE_cancel (handle->add_qe);
268 if (NULL != handle->identity_handle)
269 GNUNET_IDENTITY_disconnect (handle->identity_handle);
270 if (NULL != handle->ns_handle)
271 GNUNET_NAMESTORE_disconnect (handle->ns_handle);
272 if (NULL != handle->url)
273 GNUNET_free (handle->url);
274 if (NULL != handle->value)
275 GNUNET_free (handle->value);
276 if (NULL != handle->rd)
278 for (i = 0; i < handle->rd_count; i++)
280 if (NULL != handle->rd[i].data)
281 GNUNET_free ((void*)handle->rd[i].data);
283 GNUNET_free (handle->rd);
285 if (NULL != handle->ego_name)
286 GNUNET_free (handle->ego_name);
287 for (record_entry = handle->record_head;
288 NULL != record_entry;)
290 record_tmp = record_entry;
291 record_entry = record_entry->next;
292 GNUNET_free (record_tmp);
294 GNUNET_free (handle);
299 * Create json representation of a GNSRECORD
301 * @param rd the GNSRECORD_Data
304 gnsrecord_to_json (const struct GNUNET_GNSRECORD_Data *rd)
306 const char *typename;
311 typename = GNUNET_GNSRECORD_number_to_typename (rd->record_type);
312 string_val = GNUNET_GNSRECORD_value_to_string (rd->record_type,
316 if (NULL == string_val)
318 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
319 "Record of type %d malformed, skipping\n",
320 (int) rd->record_type);
323 record_obj = json_object();
324 json_object_set_new (record_obj,
325 GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE,
326 json_string (typename));
327 json_object_set_new (record_obj,
328 GNUNET_REST_JSONAPI_NAMESTORE_VALUE,
329 json_string (string_val));
330 GNUNET_free (string_val);
332 if (GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION & rd->flags)
334 struct GNUNET_TIME_Relative time_rel;
335 time_rel.rel_value_us = rd->expiration_time;
336 exp_str = GNUNET_STRINGS_relative_time_to_string (time_rel, 1);
340 struct GNUNET_TIME_Absolute time_abs;
341 time_abs.abs_value_us = rd->expiration_time;
342 exp_str = GNUNET_STRINGS_absolute_time_to_string (time_abs);
344 json_object_set_new (record_obj, GNUNET_REST_JSONAPI_NAMESTORE_EXPIRATION, json_string (exp_str));
346 json_object_set_new (record_obj, "expired",
347 json_boolean (GNUNET_YES == GNUNET_GNSRECORD_is_expired (rd)));
353 * Task run on error. Generates error response and cleans up.
355 * @param cls the request to generate an error response for
360 struct RequestHandle *handle = cls;
361 struct MHD_Response *resp = GNUNET_REST_create_response (NULL);
363 handle->proc (handle->proc_cls, resp, handle->response_code);
364 cleanup_handle (handle);
369 * Task run on timeout.
371 * @param cls the request to time out
374 do_timeout (void *cls)
376 struct RequestHandle *handle = cls;
378 handle->timeout_task = NULL;
384 cleanup_handle_delayed (void *cls)
386 cleanup_handle (cls);
391 * Create a response with requested records
393 * @param handle the RequestHandle
396 namestore_list_response (void *cls,
397 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
400 const struct GNUNET_GNSRECORD_Data *rd)
402 struct RequestHandle *handle = cls;
403 struct GNUNET_JSONAPI_Resource *json_resource;
404 struct MHD_Response *resp;
405 json_t *result_array;
410 if (NULL == handle->resp_object)
411 handle->resp_object = GNUNET_JSONAPI_document_new ();
415 handle->list_it = NULL;
417 if (GNUNET_SYSERR == GNUNET_JSONAPI_document_serialize (handle->resp_object, &result))
419 GNUNET_SCHEDULER_add_now (&do_error, handle);
422 resp = GNUNET_REST_create_response (result);
423 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
424 GNUNET_free_non_null (result);
425 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
429 if ( (NULL != handle->name) &&
430 (0 != strcmp (handle->name, rname)) )
432 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
433 "%s does not match %s\n", rname, handle->name);
434 GNUNET_NAMESTORE_zone_iterator_next (handle->list_it);
438 result_array = json_array ();
439 for (i=0; i<rd_len; i++)
441 if ( (GNUNET_GNSRECORD_TYPE_NICK == rd[i].record_type) &&
442 (0 != strcmp (rname, "+")) )
445 if ( (rd[i].record_type != handle->type) &&
446 (GNUNET_GNSRECORD_TYPE_ANY != handle->type) )
448 record_obj = gnsrecord_to_json (&(rd[i]));
449 json_array_append (result_array, record_obj);
450 json_decref (record_obj);
453 if (0 < json_array_size(result_array))
455 json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_NAMESTORE_TYPEINFO,
457 GNUNET_JSONAPI_resource_add_attr (json_resource,
458 GNUNET_REST_JSONAPI_NAMESTORE_RECORD,
460 GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
463 json_decref (result_array);
464 GNUNET_NAMESTORE_zone_iterator_next (handle->list_it);
468 create_finished (void *cls, int32_t success, const char *emsg)
470 struct RequestHandle *handle = cls;
471 struct MHD_Response *resp;
473 handle->add_qe = NULL;
474 if (GNUNET_YES != success)
476 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
477 "Error storing records%s%s\n",
478 (NULL == emsg) ? "" : ": ",
479 (NULL == emsg) ? "" : emsg);
480 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
483 resp = GNUNET_REST_create_response (NULL);
484 handle->proc (handle->proc_cls, resp, MHD_HTTP_NO_CONTENT);
485 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
490 * We're storing a new record; this requires
491 * that no record already exists
493 * @param cls closure, unused
494 * @param zone_key private key of the zone
495 * @param rec_name name that is being mapped (at most 255 characters long)
496 * @param rd_count number of entries in @a rd array
497 * @param rd array of records with data to store
500 create_new_record_cont (void *cls,
501 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
502 const char *rec_name,
503 unsigned int rd_count,
504 const struct GNUNET_GNSRECORD_Data *rd)
506 struct RequestHandle *handle = cls;
508 handle->add_qe = NULL;
509 if ( (NULL != zone_key) &&
510 (0 != strcmp (rec_name, handle->name)) )
513 GNUNET_SCHEDULER_add_now (&do_error, handle);
519 handle->proc (handle->proc_cls,
520 GNUNET_REST_create_response (NULL),
522 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
526 GNUNET_assert (NULL != handle->name);
527 handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
537 del_finished (void *cls,
541 struct RequestHandle *handle = cls;
543 handle->add_qe = NULL;
544 if (GNUNET_NO == success)
546 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
547 _("Deleting record failed, record does not exist%s%s\n"),
548 (NULL != emsg) ? ": " : "",
549 (NULL != emsg) ? emsg : "");
550 GNUNET_SCHEDULER_add_now (&do_error, handle); //do_not_found TODO
553 if (GNUNET_SYSERR == success)
555 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
556 _("Deleting record failed%s%s\n"),
557 (NULL != emsg) ? ": " : "",
558 (NULL != emsg) ? emsg : "");
559 GNUNET_SCHEDULER_add_now (&do_error, handle);
562 handle->proc (handle->proc_cls,
563 GNUNET_REST_create_response (NULL),
564 MHD_HTTP_NO_CONTENT);
565 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
570 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
572 unsigned int rd_count,
573 const struct GNUNET_GNSRECORD_Data *rd)
575 struct RequestHandle *handle = cls;
576 handle->add_qe = NULL;
579 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
580 _("There are no records under label `%s' that could be deleted.\n"),
582 GNUNET_SCHEDULER_add_now (&do_error, handle);
586 handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
595 namestore_delete_cont (struct GNUNET_REST_RequestHandle *con,
599 struct RequestHandle *handle = cls;
601 if (NULL == handle->name)
603 GNUNET_SCHEDULER_add_now (&do_error, handle);
607 handle->add_qe = GNUNET_NAMESTORE_records_lookup (handle->ns_handle,
615 json_to_gnsrecord (const json_t *records_json,
616 struct GNUNET_GNSRECORD_Data **rd,
617 unsigned int *rd_count)
619 struct GNUNET_TIME_Relative etime_rel;
620 struct GNUNET_TIME_Absolute etime_abs;
624 const char *typestring;
625 const char *expirationstring;
632 *rd_count = json_array_size (records_json);
633 *rd = GNUNET_malloc (sizeof (struct GNUNET_GNSRECORD_Data) * *rd_count);
634 for (i = 0; i < *rd_count; i++)
636 memset (&((*rd)[i]), 0, sizeof (struct GNUNET_GNSRECORD_Data));
637 record_json = json_array_get (records_json, i);
638 type_json = json_object_get (record_json,
639 GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE);
640 if (!json_is_string (type_json))
642 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
643 "Type property is no string\n");
644 return GNUNET_SYSERR;
646 typestring = json_string_value (type_json);
647 (*rd)[i].record_type = GNUNET_GNSRECORD_typename_to_number (typestring);
648 if (UINT32_MAX == (*rd)[i].record_type)
650 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Unsupported type `%s'\n"),
651 json_string_value (type_json));
652 return GNUNET_SYSERR;
654 value_json = json_object_get (record_json,
655 GNUNET_REST_JSONAPI_NAMESTORE_VALUE);
656 if (!json_is_string (value_json))
658 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
659 "Value property is no string\n");
660 return GNUNET_SYSERR;
662 value = GNUNET_strdup (json_string_value (value_json));
663 if (GNUNET_OK != GNUNET_GNSRECORD_string_to_value ((*rd)[i].record_type,
668 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Value `%s' invalid for record type `%s'\n"),
670 return GNUNET_SYSERR;
672 (*rd)[i].data = rdata;
673 (*rd)[i].data_size = rdata_size;
675 * if (1 == handle->is_shadow)
676 rde->flags |= GNUNET_GNSRECORD_RF_SHADOW_RECORD;
677 if (1 != handle->is_public)
678 rde->flags |= GNUNET_GNSRECORD_RF_PRIVATE;
680 exp_json = json_object_get (record_json,
681 GNUNET_REST_JSONAPI_NAMESTORE_EXPIRATION);
682 if (!json_is_string (exp_json))
684 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
685 "Expiration property is no string\n");
686 return GNUNET_SYSERR;
688 expirationstring = json_string_value (exp_json);
689 if (0 == strcmp (expirationstring, "never"))
691 (*rd)[i].expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
693 else if (GNUNET_OK ==
694 GNUNET_STRINGS_fancy_time_to_relative (expirationstring,
697 (*rd)[i].expiration_time = etime_rel.rel_value_us;
698 (*rd)[i].flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
700 else if (GNUNET_OK ==
701 GNUNET_STRINGS_fancy_time_to_absolute (expirationstring,
704 (*rd)[i].expiration_time = etime_abs.abs_value_us;
708 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Value `%s' invalid for record type `%s'\n"),
710 return GNUNET_SYSERR;
717 namestore_create_cont (struct GNUNET_REST_RequestHandle *con,
721 struct RequestHandle *handle = cls;
722 struct MHD_Response *resp;
723 struct GNUNET_JSONAPI_Document *json_obj;
724 struct GNUNET_JSONAPI_Resource *json_res;
725 json_t *records_json;
728 char term_data[handle->rest_handle->data_size+1];
729 struct GNUNET_JSON_Specification docspec[] = {
730 GNUNET_JSON_spec_jsonapi_document (&json_obj),
731 GNUNET_JSON_spec_end()
734 if (strlen (GNUNET_REST_API_NS_NAMESTORE) != strlen (handle->url))
736 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
737 "Cannot create under %s\n", handle->url);
738 GNUNET_SCHEDULER_add_now (&do_error, handle);
741 if (0 >= handle->rest_handle->data_size)
743 GNUNET_SCHEDULER_add_now (&do_error, handle);
746 term_data[handle->rest_handle->data_size] = '\0';
748 handle->rest_handle->data,
749 handle->rest_handle->data_size);
750 data_js = json_loads (term_data,
753 GNUNET_assert (GNUNET_OK ==
754 GNUNET_JSON_parse (data_js, docspec,
756 json_decref (data_js);
757 if (NULL == json_obj)
759 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
760 "Unable to parse JSONAPI Object from %s\n",
762 GNUNET_SCHEDULER_add_now (&do_error, handle);
765 if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
767 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
768 "Cannot create more than 1 resource! (Got %d)\n",
769 GNUNET_JSONAPI_document_resource_count (json_obj));
770 GNUNET_JSONAPI_document_delete (json_obj);
771 GNUNET_SCHEDULER_add_now (&do_error, handle);
774 json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
775 if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res,
776 GNUNET_REST_JSONAPI_NAMESTORE_RECORD))
778 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
779 "Unsupported JSON data type\n");
780 GNUNET_JSONAPI_document_delete (json_obj);
781 resp = GNUNET_REST_create_response (NULL);
782 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
783 cleanup_handle (handle);
786 handle->name = GNUNET_strdup (GNUNET_JSONAPI_resource_get_id (json_res));
787 records_json = GNUNET_JSONAPI_resource_read_attr (json_res,
788 GNUNET_REST_JSONAPI_NAMESTORE_RECORD);
789 if (NULL == records_json)
791 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
792 "No records given\n");
793 GNUNET_JSONAPI_document_delete (json_obj);
794 GNUNET_SCHEDULER_add_now (&do_error, handle);
797 if (GNUNET_SYSERR == json_to_gnsrecord (records_json, &handle->rd, &handle->rd_count))
799 GNUNET_JSONAPI_document_delete (json_obj);
800 GNUNET_SCHEDULER_add_now (&do_error, handle);
803 GNUNET_JSONAPI_document_delete (json_obj);
805 handle->add_qe = GNUNET_NAMESTORE_records_lookup (handle->ns_handle,
808 &create_new_record_cont, handle );
812 namestore_zkey_response (void *cls,
813 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
815 unsigned int rd_count,
816 const struct GNUNET_GNSRECORD_Data *rd)
818 struct RequestHandle *handle = cls;
819 struct MHD_Response *resp;
820 struct GNUNET_JSONAPI_Document *json_obj;
821 struct GNUNET_JSONAPI_Resource *json_res;
825 handle->reverse_qe = NULL;
826 json_obj = GNUNET_JSONAPI_document_new ();
829 name_json = json_string (label);
830 json_res = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_NAMESTORE_REVINFO,
832 GNUNET_JSONAPI_resource_add_attr (json_res,
833 GNUNET_REST_JSONAPI_NAMESTORE_NAME,
835 GNUNET_JSONAPI_document_resource_add (json_obj, json_res);
836 json_decref (name_json);
839 if (GNUNET_SYSERR == GNUNET_JSONAPI_document_serialize (json_obj, &result))
841 GNUNET_JSONAPI_document_delete (json_obj);
842 GNUNET_SCHEDULER_add_now (&do_error, handle);
845 resp = GNUNET_REST_create_response (result);
846 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
847 GNUNET_JSONAPI_document_delete (json_obj);
848 GNUNET_free (result);
849 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
855 namestore_zkey_cont (struct GNUNET_REST_RequestHandle *con,
859 struct RequestHandle *handle = cls;
860 struct GNUNET_HashCode key;
861 struct GNUNET_CRYPTO_EcdsaPublicKey pubkey;
863 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_NAMESTORE_ZKEY,
864 strlen (GNUNET_REST_JSONAPI_NAMESTORE_ZKEY),
867 GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
870 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
871 "No zkey given %s\n", handle->url);
872 GNUNET_SCHEDULER_add_now (&do_error, handle);
875 handle->zkey_str = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
878 GNUNET_CRYPTO_ecdsa_public_key_from_string (handle->zkey_str,
879 strlen (handle->zkey_str),
882 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
883 "Zkey invalid %s\n", handle->zkey_str);
884 GNUNET_SCHEDULER_add_now (&do_error, handle);
887 handle->reverse_qe = GNUNET_NAMESTORE_zone_to_name (handle->ns_handle,
890 &namestore_zkey_response,
895 namestore_info_cont (struct GNUNET_REST_RequestHandle *con,
899 struct RequestHandle *handle = cls;
900 handle->list_it = GNUNET_NAMESTORE_zone_iteration_start (handle->ns_handle,
902 &namestore_list_response,
907 get_name_from_url (const char* url)
909 if (strlen (url) <= strlen (GNUNET_REST_API_NS_NAMESTORE))
911 return (char*)url + strlen (GNUNET_REST_API_NS_NAMESTORE) + 1;
915 * Respond to OPTIONS request
917 * @param con_handle the connection handle
919 * @param cls the RequestHandle
922 options_cont (struct GNUNET_REST_RequestHandle *con_handle,
926 struct MHD_Response *resp;
927 struct RequestHandle *handle = cls;
929 //For now, independent of path return all options
930 resp = GNUNET_REST_create_response (NULL);
931 MHD_add_response_header (resp,
932 "Access-Control-Allow-Methods",
934 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
935 cleanup_handle (handle);
940 * Function called with the result from the check if the namestore
941 * service is actually running. If it is, we start the actual
944 * @param cls closure with our configuration
945 * @param result #GNUNET_YES if the namestore service is running
948 testservice_task (void *cls,
951 struct RequestHandle *handle = cls;
952 struct GNUNET_REST_RequestHandlerError err;
953 static const struct GNUNET_REST_RequestHandler handlers[] = {
954 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_NAMESTORE_ZKEY, &namestore_zkey_cont}, //reverse
955 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_NAMESTORE, &namestore_info_cont}, //list
956 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_NAMESTORE, &namestore_create_cont}, //create
957 // {MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_NAMESTORE, &namestore_edit_cont}, //update. TODO this shoul be PATCH
958 {MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_NAMESTORE, &namestore_delete_cont}, //delete
959 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_NAMESTORE, &options_cont},
960 GNUNET_REST_HANDLER_END
963 if (GNUNET_YES != result)
965 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Service `%s' is not running\n"),
967 GNUNET_SCHEDULER_add_now (&do_error, handle);
970 handle->ns_handle = GNUNET_NAMESTORE_connect (cfg);
971 if (NULL == handle->ns_handle)
973 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
974 _("Failed to connect to namestore\n"));
975 GNUNET_SCHEDULER_add_now (&do_error, handle);
979 if (GNUNET_OK != GNUNET_JSONAPI_handle_request (handle->rest_handle,
984 handle->response_code = err.error_code;
985 GNUNET_SCHEDULER_add_now (&do_error, (void*) handle);
991 * Callback invoked from identity service with ego information.
992 * An @a ego of NULL means the ego was not found.
994 * @param cls closure with the configuration
995 * @param ego an ego known to identity service, or NULL
998 identity_cb (void *cls,
999 const struct GNUNET_IDENTITY_Ego *ego)
1001 struct RequestHandle *handle = cls;
1002 struct MHD_Response *resp;
1004 handle->ego_lookup = NULL;
1007 if (NULL != handle->ego_name)
1009 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1010 _("Ego `%s' not known to identity service\n"),
1013 resp = GNUNET_REST_create_response (NULL);
1014 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
1015 cleanup_handle (handle);
1018 handle->zone_pkey = *GNUNET_IDENTITY_ego_get_private_key (ego);
1019 GNUNET_CLIENT_service_test ("namestore", handle->cfg,
1020 GNUNET_TIME_UNIT_SECONDS,
1026 default_ego_cb (void *cls,
1027 struct GNUNET_IDENTITY_Ego *ego,
1031 struct RequestHandle *handle = cls;
1032 struct MHD_Response *resp;
1033 handle->get_default = NULL;
1036 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1037 _("No default ego configured in identity service\n"));
1038 resp = GNUNET_REST_create_response (NULL);
1039 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
1040 cleanup_handle (handle);
1045 identity_cb (cls, ego);
1050 id_connect_cb (void *cls,
1051 struct GNUNET_IDENTITY_Ego *ego,
1055 struct RequestHandle *handle = cls;
1058 handle->get_default = GNUNET_IDENTITY_get (handle->identity_handle,
1060 &default_ego_cb, handle);
1065 testservice_id_task (void *cls, int result)
1067 struct RequestHandle *handle = cls;
1068 struct MHD_Response *resp;
1069 struct GNUNET_HashCode key;
1074 if (result != GNUNET_YES)
1076 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1077 _("Identity service is not running\n"));
1078 resp = GNUNET_REST_create_response (NULL);
1079 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
1080 cleanup_handle (handle);
1084 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_NAMESTORE_EGO,
1085 strlen (GNUNET_REST_JSONAPI_NAMESTORE_EGO),
1088 GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1091 ego = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
1095 handle->type = GNUNET_GNSRECORD_TYPE_ANY;
1096 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE,
1097 strlen (GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE),
1100 GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1103 type = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
1106 handle->type = GNUNET_GNSRECORD_typename_to_number (type);
1108 name = get_name_from_url (handle->url);
1110 handle->ego_name = GNUNET_strdup (ego);
1112 handle->name = GNUNET_strdup (name);
1113 if (NULL == handle->ego_name)
1115 handle->identity_handle = GNUNET_IDENTITY_connect (handle->cfg, &id_connect_cb, handle);
1116 if (NULL == handle->identity_handle)
1118 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Cannot connect to identity service\n"));
1119 resp = GNUNET_REST_create_response (NULL);
1120 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
1121 cleanup_handle (handle);
1125 handle->ego_lookup = GNUNET_IDENTITY_ego_lookup (cfg,
1132 * Function processing the REST call
1134 * @param method HTTP method
1135 * @param url URL of the HTTP request
1136 * @param data body of the HTTP request (optional)
1137 * @param data_size length of the body
1138 * @param proc callback function for the result
1139 * @param proc_cls closure for callback function
1140 * @return GNUNET_OK if request accepted
1143 rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle,
1144 GNUNET_REST_ResultProcessor proc,
1147 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1149 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1150 handle->proc_cls = proc_cls;
1151 handle->proc = proc;
1152 handle->rest_handle = rest_handle;
1153 handle->url = GNUNET_strdup (rest_handle->url);
1154 if (handle->url[strlen (handle->url)-1] == '/')
1155 handle->url[strlen (handle->url)-1] = '\0';
1156 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1159 GNUNET_CLIENT_service_test ("identity",
1161 GNUNET_TIME_UNIT_SECONDS,
1162 &testservice_id_task,
1164 handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout,
1170 * Entry point for the plugin.
1172 * @param cls Config info
1173 * @return NULL on error, otherwise the plugin context
1176 libgnunet_plugin_rest_namestore_init (void *cls)
1178 static struct Plugin plugin;
1180 struct GNUNET_REST_Plugin *api;
1182 if (NULL != plugin.cfg)
1183 return NULL; /* can only initialize once! */
1184 memset (&plugin, 0, sizeof (struct Plugin));
1186 api = GNUNET_new (struct GNUNET_REST_Plugin);
1188 api->name = GNUNET_REST_API_NS_NAMESTORE;
1189 api->process_request = &rest_identity_process_request;
1190 GNUNET_asprintf (&allow_methods,
1191 "%s, %s, %s, %s, %s",
1192 MHD_HTTP_METHOD_GET,
1193 MHD_HTTP_METHOD_POST,
1194 MHD_HTTP_METHOD_PUT,
1195 MHD_HTTP_METHOD_DELETE,
1196 MHD_HTTP_METHOD_OPTIONS);
1197 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1198 _("Namestore REST API initialized\n"));
1204 * Exit point from the plugin.
1206 * @param cls the plugin context (as returned by "init")
1207 * @return always NULL
1210 libgnunet_plugin_rest_namestore_done (void *cls)
1212 struct GNUNET_REST_Plugin *api = cls;
1213 struct Plugin *plugin = api->cls;
1217 GNUNET_free_non_null (allow_methods);
1218 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1219 "Namestore REST plugin is finished\n");
1223 /* end of plugin_rest_namestore.c */