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 it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your 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 Affero General Public License for more details.
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 * @author Martin Schanzenbach
20 * @file namestore/plugin_rest_namestore.c
21 * @brief GNUnet Namestore REST plugin
26 #include "gnunet_rest_plugin.h"
27 #include "gnunet_gns_service.h"
28 #include "gnunet_namestore_service.h"
29 #include "gnunet_identity_service.h"
30 #include "gnunet_rest_lib.h"
31 #include "gnunet_jsonapi_lib.h"
32 #include "gnunet_jsonapi_util.h"
33 #include "microhttpd.h"
36 #define GNUNET_REST_API_NS_NAMESTORE "/names"
38 #define GNUNET_REST_API_NS_NAMESTORE_ZKEY "/names/zkey"
40 #define GNUNET_REST_JSONAPI_NAMESTORE_TYPEINFO "record"
42 #define GNUNET_REST_JSONAPI_NAMESTORE_NAME "name"
44 #define GNUNET_REST_JSONAPI_NAMESTORE_REVINFO "revinfo"
46 #define GNUNET_REST_JSONAPI_NAMESTORE_RECORD GNUNET_REST_JSONAPI_NAMESTORE_TYPEINFO
48 #define GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE "record_type"
50 #define GNUNET_REST_JSONAPI_NAMESTORE_VALUE "value"
52 #define GNUNET_REST_JSONAPI_NAMESTORE_PUBLIC "public"
54 #define GNUNET_REST_JSONAPI_NAMESTORE_SHADOW "shadow"
56 #define GNUNET_REST_JSONAPI_NAMESTORE_PKEY "pkey"
58 #define GNUNET_REST_JSONAPI_NAMESTORE_ZKEY "zkey"
60 #define GNUNET_REST_JSONAPI_NAMESTORE_EXPIRATION "expiration"
62 #define GNUNET_REST_JSONAPI_NAMESTORE_EGO "ego"
65 * @brief struct returned by the initialization function of the plugin
69 const struct GNUNET_CONFIGURATION_Handle *cfg;
74 * HTTP methods allows for this plugin
76 static char* allow_methods;
78 const struct GNUNET_CONFIGURATION_Handle *cfg;
85 struct RecordEntry *next;
90 struct RecordEntry *prev;
99 struct RecordEntry *record_head;
104 struct record_entry *record_tail;
107 * JSON response object
109 struct GNUNET_JSONAPI_Document *resp_object;
114 struct GNUNET_REST_RequestHandle *rest_handle;
117 * Handle to GNS service.
119 struct GNUNET_IDENTITY_Handle *identity_handle;
122 * Handle to NAMESTORE
124 struct GNUNET_NAMESTORE_Handle *ns_handle;
127 * Handle to NAMESTORE it
129 struct GNUNET_NAMESTORE_ZoneIterator *list_it;
132 * Private key for the zone
134 struct GNUNET_CRYPTO_EcdsaPrivateKey zone_pkey;
137 * Handle to identity lookup
139 struct GNUNET_IDENTITY_EgoLookup *ego_lookup;
142 * Default Ego operation
144 struct GNUNET_IDENTITY_Operation *get_default;
162 * Name of the record to modify
167 * Value of the record
174 const char* zkey_str;
184 struct GNUNET_GNSRECORD_Data *rd;
189 unsigned int rd_count;
192 * NAMESTORE Operation
194 struct GNUNET_NAMESTORE_QueueEntry *add_qe;
197 * NAMESTORE Operation
199 struct GNUNET_NAMESTORE_QueueEntry *reverse_qe;
202 * Desired timeout for the lookup (default is no timeout).
204 struct GNUNET_TIME_Relative timeout;
207 * ID of a task associated with the resolution process.
209 struct GNUNET_SCHEDULER_Task * timeout_task;
212 * The plugin result processor
214 GNUNET_REST_ResultProcessor proc;
217 * The closure of the result processor
229 const struct GNUNET_CONFIGURATION_Handle *cfg;
240 * Cleanup lookup handle
242 * @param handle Handle to clean up
245 cleanup_handle (struct RequestHandle *handle)
247 struct RecordEntry *record_entry;
248 struct RecordEntry *record_tmp;
250 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
252 if (NULL != handle->resp_object)
253 GNUNET_JSONAPI_document_delete (handle->resp_object);
254 if (NULL != handle->name)
255 GNUNET_free (handle->name);
256 if (NULL != handle->timeout_task)
257 GNUNET_SCHEDULER_cancel (handle->timeout_task);
258 if (NULL != handle->ego_lookup)
259 GNUNET_IDENTITY_ego_lookup_cancel (handle->ego_lookup);
260 if (NULL != handle->get_default)
261 GNUNET_IDENTITY_cancel (handle->get_default);
262 if (NULL != handle->list_it)
263 GNUNET_NAMESTORE_zone_iteration_stop (handle->list_it);
264 if (NULL != handle->add_qe)
265 GNUNET_NAMESTORE_cancel (handle->add_qe);
266 if (NULL != handle->identity_handle)
267 GNUNET_IDENTITY_disconnect (handle->identity_handle);
268 if (NULL != handle->ns_handle)
269 GNUNET_NAMESTORE_disconnect (handle->ns_handle);
270 if (NULL != handle->url)
271 GNUNET_free (handle->url);
272 if (NULL != handle->value)
273 GNUNET_free (handle->value);
274 if (NULL != handle->rd)
276 for (unsigned int i = 0; i < handle->rd_count; i++)
278 if (NULL != handle->rd[i].data)
279 GNUNET_free ((void*)handle->rd[i].data);
281 GNUNET_free (handle->rd);
283 if (NULL != handle->ego_name)
284 GNUNET_free (handle->ego_name);
285 for (record_entry = handle->record_head;
286 NULL != record_entry;)
288 record_tmp = record_entry;
289 record_entry = record_entry->next;
290 GNUNET_free (record_tmp);
292 GNUNET_free (handle);
297 * Create json representation of a GNSRECORD
299 * @param rd the GNSRECORD_Data
302 gnsrecord_to_json (const struct GNUNET_GNSRECORD_Data *rd)
304 const char *typename;
309 typename = GNUNET_GNSRECORD_number_to_typename (rd->record_type);
310 string_val = GNUNET_GNSRECORD_value_to_string (rd->record_type,
314 if (NULL == string_val)
316 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
317 "Record of type %d malformed, skipping\n",
318 (int) rd->record_type);
321 record_obj = json_object();
322 json_object_set_new (record_obj,
323 GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE,
324 json_string (typename));
325 json_object_set_new (record_obj,
326 GNUNET_REST_JSONAPI_NAMESTORE_VALUE,
327 json_string (string_val));
328 GNUNET_free (string_val);
330 if (GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION & rd->flags)
332 struct GNUNET_TIME_Relative time_rel;
333 time_rel.rel_value_us = rd->expiration_time;
334 exp_str = GNUNET_STRINGS_relative_time_to_string (time_rel, 1);
338 struct GNUNET_TIME_Absolute time_abs;
339 time_abs.abs_value_us = rd->expiration_time;
340 exp_str = GNUNET_STRINGS_absolute_time_to_string (time_abs);
342 json_object_set_new (record_obj, GNUNET_REST_JSONAPI_NAMESTORE_EXPIRATION, json_string (exp_str));
344 json_object_set_new (record_obj, "expired",
345 json_boolean (GNUNET_YES == GNUNET_GNSRECORD_is_expired (rd)));
351 * Task run on error. Generates error response and cleans up.
353 * @param cls the request to generate an error response for
358 struct RequestHandle *handle = cls;
359 struct MHD_Response *resp = GNUNET_REST_create_response (NULL);
361 handle->proc (handle->proc_cls, resp, handle->response_code);
362 cleanup_handle (handle);
367 * Task run on timeout.
369 * @param cls the request to time out
372 do_timeout (void *cls)
374 struct RequestHandle *handle = cls;
376 handle->timeout_task = NULL;
382 cleanup_handle_delayed (void *cls)
384 cleanup_handle (cls);
389 * Iteration over all results finished, build final
392 * @param cls the `struct RequestHandle`
395 namestore_list_finished (void *cls)
397 struct RequestHandle *handle = cls;
399 struct MHD_Response *resp;
401 handle->list_it = NULL;
402 if (NULL == handle->resp_object)
403 handle->resp_object = GNUNET_JSONAPI_document_new ();
406 GNUNET_JSONAPI_document_serialize (handle->resp_object,
409 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
410 GNUNET_SCHEDULER_add_now (&do_error,
414 resp = GNUNET_REST_create_response (result);
415 handle->proc (handle->proc_cls,
418 GNUNET_free_non_null (result);
419 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed,
426 * Create a response with requested records
428 * @param handle the RequestHandle
431 namestore_list_response (void *cls,
432 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
435 const struct GNUNET_GNSRECORD_Data *rd)
437 struct RequestHandle *handle = cls;
438 struct GNUNET_JSONAPI_Resource *json_resource;
439 json_t *result_array;
442 if (NULL == handle->resp_object)
443 handle->resp_object = GNUNET_JSONAPI_document_new ();
445 if ( (NULL != handle->name) &&
446 (0 != strcmp (handle->name,
449 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
450 "%s does not match %s\n",
453 GNUNET_NAMESTORE_zone_iterator_next (handle->list_it,
458 result_array = json_array ();
459 for (unsigned int i=0; i<rd_len; i++)
461 if ( (GNUNET_GNSRECORD_TYPE_NICK == rd[i].record_type) &&
462 (0 != strcmp (rname, GNUNET_GNS_EMPTY_LABEL_AT)) )
465 if ( (rd[i].record_type != handle->type) &&
466 (GNUNET_GNSRECORD_TYPE_ANY != handle->type) )
468 record_obj = gnsrecord_to_json (&rd[i]);
469 json_array_append (result_array,
471 json_decref (record_obj);
474 if (0 < json_array_size(result_array))
476 json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_NAMESTORE_TYPEINFO,
478 GNUNET_JSONAPI_resource_add_attr (json_resource,
479 GNUNET_REST_JSONAPI_NAMESTORE_RECORD,
481 GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
484 json_decref (result_array);
485 GNUNET_NAMESTORE_zone_iterator_next (handle->list_it,
491 create_finished (void *cls, int32_t success, const char *emsg)
493 struct RequestHandle *handle = cls;
494 struct MHD_Response *resp;
496 handle->add_qe = NULL;
497 if (GNUNET_YES != success)
499 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
500 "Error storing records%s%s\n",
501 (NULL == emsg) ? "" : ": ",
502 (NULL == emsg) ? "" : emsg);
503 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
506 resp = GNUNET_REST_create_response (NULL);
507 handle->proc (handle->proc_cls, resp, MHD_HTTP_NO_CONTENT);
508 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
513 * We're storing a new record; this requires
514 * that no record already exists
516 * @param cls closure, unused
517 * @param zone_key private key of the zone
518 * @param rec_name name that is being mapped (at most 255 characters long)
519 * @param rd_count number of entries in @a rd array
520 * @param rd array of records with data to store
523 create_new_record_cont (void *cls,
524 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
525 const char *rec_name,
526 unsigned int rd_count,
527 const struct GNUNET_GNSRECORD_Data *rd)
529 struct RequestHandle *handle = cls;
531 handle->add_qe = NULL;
532 if (0 != strcmp (rec_name, handle->name))
541 handle->proc (handle->proc_cls,
542 GNUNET_REST_create_response (NULL),
544 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
548 GNUNET_assert (NULL != handle->name);
549 handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
560 del_finished (void *cls,
564 struct RequestHandle *handle = cls;
566 handle->add_qe = NULL;
567 if (GNUNET_NO == success)
569 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
570 _("Deleting record failed, record does not exist%s%s\n"),
571 (NULL != emsg) ? ": " : "",
572 (NULL != emsg) ? emsg : "");
573 GNUNET_SCHEDULER_add_now (&do_error, handle); //do_not_found TODO
576 if (GNUNET_SYSERR == success)
578 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
579 _("Deleting record failed%s%s\n"),
580 (NULL != emsg) ? ": " : "",
581 (NULL != emsg) ? emsg : "");
582 GNUNET_SCHEDULER_add_now (&do_error, handle);
585 handle->proc (handle->proc_cls,
586 GNUNET_REST_create_response (NULL),
587 MHD_HTTP_NO_CONTENT);
588 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
594 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
596 unsigned int rd_count,
597 const struct GNUNET_GNSRECORD_Data *rd)
599 struct RequestHandle *handle = cls;
601 handle->add_qe = NULL;
604 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
605 _("There are no records under label `%s' that could be deleted.\n"),
611 handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
621 namestore_delete_cont (struct GNUNET_REST_RequestHandle *con,
625 struct RequestHandle *handle = cls;
627 if (NULL == handle->name)
629 GNUNET_SCHEDULER_add_now (&do_error, handle);
633 handle->add_qe = GNUNET_NAMESTORE_records_lookup (handle->ns_handle,
644 json_to_gnsrecord (const json_t *records_json,
645 struct GNUNET_GNSRECORD_Data **rd,
646 unsigned int *rd_count)
648 struct GNUNET_TIME_Relative etime_rel;
649 struct GNUNET_TIME_Absolute etime_abs;
653 const char *typestring;
654 const char *expirationstring;
660 *rd_count = json_array_size (records_json);
661 *rd = GNUNET_new_array (*rd_count,
662 struct GNUNET_GNSRECORD_Data);
663 for (unsigned int i = 0; i < *rd_count; i++)
667 sizeof (struct GNUNET_GNSRECORD_Data));
668 record_json = json_array_get (records_json,
670 type_json = json_object_get (record_json,
671 GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE);
672 if (! json_is_string (type_json))
674 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
675 "Type property is no string\n");
676 return GNUNET_SYSERR;
678 typestring = json_string_value (type_json);
679 (*rd)[i].record_type = GNUNET_GNSRECORD_typename_to_number (typestring);
680 if (UINT32_MAX == (*rd)[i].record_type)
682 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Unsupported type `%s'\n"),
683 json_string_value (type_json));
684 return GNUNET_SYSERR;
686 value_json = json_object_get (record_json,
687 GNUNET_REST_JSONAPI_NAMESTORE_VALUE);
688 if (! json_is_string (value_json))
690 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
691 "Value property is no string\n");
692 return GNUNET_SYSERR;
694 value = GNUNET_strdup (json_string_value (value_json));
696 GNUNET_GNSRECORD_string_to_value ((*rd)[i].record_type,
701 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
702 _("Value `%s' invalid for record type `%s'\n"),
705 return GNUNET_SYSERR;
707 (*rd)[i].data = rdata;
708 (*rd)[i].data_size = rdata_size;
710 * if (1 == handle->is_shadow)
711 rde->flags |= GNUNET_GNSRECORD_RF_SHADOW_RECORD;
712 if (1 != handle->is_public)
713 rde->flags |= GNUNET_GNSRECORD_RF_PRIVATE;
715 exp_json = json_object_get (record_json,
716 GNUNET_REST_JSONAPI_NAMESTORE_EXPIRATION);
717 if (! json_is_string (exp_json))
719 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
720 "Expiration property is no string\n");
721 return GNUNET_SYSERR;
723 expirationstring = json_string_value (exp_json);
724 if (0 == strcmp (expirationstring, "never"))
726 (*rd)[i].expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
728 else if (GNUNET_OK ==
729 GNUNET_STRINGS_fancy_time_to_relative (expirationstring,
732 (*rd)[i].expiration_time = etime_rel.rel_value_us;
733 (*rd)[i].flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
735 else if (GNUNET_OK ==
736 GNUNET_STRINGS_fancy_time_to_absolute (expirationstring,
739 (*rd)[i].expiration_time = etime_abs.abs_value_us;
743 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
744 _("Value `%s' invalid for record type `%s'\n"),
747 return GNUNET_SYSERR;
755 namestore_create_cont (struct GNUNET_REST_RequestHandle *con,
759 struct RequestHandle *handle = cls;
760 struct MHD_Response *resp;
761 struct GNUNET_JSONAPI_Document *json_obj;
762 struct GNUNET_JSONAPI_Resource *json_res;
763 json_t *records_json;
766 char term_data[handle->rest_handle->data_size+1];
767 struct GNUNET_JSON_Specification docspec[] = {
768 GNUNET_JSON_spec_jsonapi_document (&json_obj),
769 GNUNET_JSON_spec_end()
772 if (strlen (GNUNET_REST_API_NS_NAMESTORE) != strlen (handle->url))
774 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
775 "Cannot create under %s\n", handle->url);
776 GNUNET_SCHEDULER_add_now (&do_error, handle);
779 if (0 >= handle->rest_handle->data_size)
781 GNUNET_SCHEDULER_add_now (&do_error, handle);
784 term_data[handle->rest_handle->data_size] = '\0';
785 GNUNET_memcpy (term_data,
786 handle->rest_handle->data,
787 handle->rest_handle->data_size);
788 data_js = json_loads (term_data,
791 GNUNET_assert (GNUNET_OK ==
792 GNUNET_JSON_parse (data_js, docspec,
794 json_decref (data_js);
795 if (NULL == json_obj)
797 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
798 "Unable to parse JSONAPI Object from %s\n",
800 GNUNET_SCHEDULER_add_now (&do_error, handle);
803 if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
805 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
806 "Cannot create more than 1 resource! (Got %d)\n",
807 GNUNET_JSONAPI_document_resource_count (json_obj));
808 GNUNET_JSONAPI_document_delete (json_obj);
809 GNUNET_SCHEDULER_add_now (&do_error, handle);
812 json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
813 if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res,
814 GNUNET_REST_JSONAPI_NAMESTORE_RECORD))
816 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
817 "Unsupported JSON data type\n");
818 GNUNET_JSONAPI_document_delete (json_obj);
819 resp = GNUNET_REST_create_response (NULL);
820 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
821 cleanup_handle (handle);
824 handle->name = GNUNET_strdup (GNUNET_JSONAPI_resource_get_id (json_res));
825 records_json = GNUNET_JSONAPI_resource_read_attr (json_res,
826 GNUNET_REST_JSONAPI_NAMESTORE_RECORD);
827 if (NULL == records_json)
829 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
830 "No records given\n");
831 GNUNET_JSONAPI_document_delete (json_obj);
832 GNUNET_SCHEDULER_add_now (&do_error, handle);
835 if (GNUNET_SYSERR == json_to_gnsrecord (records_json, &handle->rd, &handle->rd_count))
837 GNUNET_JSONAPI_document_delete (json_obj);
838 GNUNET_SCHEDULER_add_now (&do_error, handle);
841 GNUNET_JSONAPI_document_delete (json_obj);
843 handle->add_qe = GNUNET_NAMESTORE_records_lookup (handle->ns_handle,
848 &create_new_record_cont,
854 namestore_zkey_response (void *cls,
855 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
857 unsigned int rd_count,
858 const struct GNUNET_GNSRECORD_Data *rd)
860 struct RequestHandle *handle = cls;
861 struct MHD_Response *resp;
862 struct GNUNET_JSONAPI_Document *json_obj;
863 struct GNUNET_JSONAPI_Resource *json_res;
867 handle->reverse_qe = NULL;
868 json_obj = GNUNET_JSONAPI_document_new ();
871 name_json = json_string (label);
872 json_res = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_NAMESTORE_REVINFO,
874 GNUNET_JSONAPI_resource_add_attr (json_res,
875 GNUNET_REST_JSONAPI_NAMESTORE_NAME,
877 GNUNET_JSONAPI_document_resource_add (json_obj, json_res);
878 json_decref (name_json);
881 if (GNUNET_SYSERR == GNUNET_JSONAPI_document_serialize (json_obj, &result))
883 GNUNET_JSONAPI_document_delete (json_obj);
884 GNUNET_SCHEDULER_add_now (&do_error, handle);
887 resp = GNUNET_REST_create_response (result);
888 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
889 GNUNET_JSONAPI_document_delete (json_obj);
890 GNUNET_free (result);
891 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
896 namestore_zkey_cont (struct GNUNET_REST_RequestHandle *con,
900 struct RequestHandle *handle = cls;
901 struct GNUNET_HashCode key;
902 struct GNUNET_CRYPTO_EcdsaPublicKey pubkey;
904 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_NAMESTORE_ZKEY,
905 strlen (GNUNET_REST_JSONAPI_NAMESTORE_ZKEY),
908 GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
911 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
912 "No zkey given %s\n", handle->url);
913 GNUNET_SCHEDULER_add_now (&do_error, handle);
916 handle->zkey_str = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
918 if ((NULL == handle->zkey_str) ||
920 GNUNET_CRYPTO_ecdsa_public_key_from_string (handle->zkey_str,
921 strlen (handle->zkey_str),
924 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
925 "Zkey invalid %s\n", handle->zkey_str);
926 GNUNET_SCHEDULER_add_now (&do_error, handle);
929 handle->reverse_qe = GNUNET_NAMESTORE_zone_to_name (handle->ns_handle,
934 &namestore_zkey_response,
940 namestore_info_cont (struct GNUNET_REST_RequestHandle *con,
944 struct RequestHandle *handle = cls;
946 handle->list_it = GNUNET_NAMESTORE_zone_iteration_start (handle->ns_handle,
950 &namestore_list_response,
952 &namestore_list_finished,
958 get_name_from_url (const char* url)
960 if (strlen (url) <= strlen (GNUNET_REST_API_NS_NAMESTORE))
962 return (char*)url + strlen (GNUNET_REST_API_NS_NAMESTORE) + 1;
966 * Respond to OPTIONS request
968 * @param con_handle the connection handle
970 * @param cls the RequestHandle
973 options_cont (struct GNUNET_REST_RequestHandle *con_handle,
977 struct MHD_Response *resp;
978 struct RequestHandle *handle = cls;
980 //For now, independent of path return all options
981 resp = GNUNET_REST_create_response (NULL);
982 MHD_add_response_header (resp,
983 "Access-Control-Allow-Methods",
985 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
986 cleanup_handle (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;
1003 struct GNUNET_REST_RequestHandlerError err;
1004 static const struct GNUNET_REST_RequestHandler handlers[] = {
1005 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_NAMESTORE_ZKEY, &namestore_zkey_cont}, //reverse
1006 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_NAMESTORE, &namestore_info_cont}, //list
1007 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_NAMESTORE, &namestore_create_cont}, //create
1008 // {MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_NAMESTORE, &namestore_edit_cont}, //update. TODO this shoul be PATCH
1009 {MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_NAMESTORE, &namestore_delete_cont}, //delete
1010 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_NAMESTORE, &options_cont},
1011 GNUNET_REST_HANDLER_END
1014 handle->ego_lookup = NULL;
1017 if (NULL != handle->ego_name)
1019 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1020 _("Ego `%s' not known to identity service\n"),
1023 resp = GNUNET_REST_create_response (NULL);
1024 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
1025 cleanup_handle (handle);
1028 handle->zone_pkey = *GNUNET_IDENTITY_ego_get_private_key (ego);
1029 handle->ns_handle = GNUNET_NAMESTORE_connect (cfg);
1030 if (NULL == handle->ns_handle)
1032 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1033 _("Failed to connect to namestore\n"));
1034 GNUNET_SCHEDULER_add_now (&do_error, handle);
1039 GNUNET_JSONAPI_handle_request (handle->rest_handle,
1044 handle->response_code = err.error_code;
1045 GNUNET_SCHEDULER_add_now (&do_error,
1052 default_ego_cb (void *cls,
1053 struct GNUNET_IDENTITY_Ego *ego,
1057 struct RequestHandle *handle = cls;
1058 struct MHD_Response *resp;
1059 handle->get_default = NULL;
1062 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1063 _("No default ego configured in identity service\n"));
1064 resp = GNUNET_REST_create_response (NULL);
1065 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
1066 cleanup_handle (handle);
1071 identity_cb (cls, ego);
1076 id_connect_cb (void *cls,
1077 struct GNUNET_IDENTITY_Ego *ego,
1081 struct RequestHandle *handle = cls;
1084 handle->get_default = GNUNET_IDENTITY_get (handle->identity_handle,
1086 &default_ego_cb, handle);
1092 * Function processing the REST call
1094 * @param method HTTP method
1095 * @param url URL of the HTTP request
1096 * @param data body of the HTTP request (optional)
1097 * @param data_size length of the body
1098 * @param proc callback function for the result
1099 * @param proc_cls closure for callback function
1100 * @return #GNUNET_OK if request accepted
1103 rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle,
1104 GNUNET_REST_ResultProcessor proc,
1107 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1108 struct MHD_Response *resp;
1109 struct GNUNET_HashCode key;
1114 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1115 handle->proc_cls = proc_cls;
1116 handle->proc = proc;
1117 handle->rest_handle = rest_handle;
1118 handle->url = GNUNET_strdup (rest_handle->url);
1119 if (handle->url[strlen (handle->url)-1] == '/')
1120 handle->url[strlen (handle->url)-1] = '\0';
1121 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1125 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_NAMESTORE_EGO,
1126 strlen (GNUNET_REST_JSONAPI_NAMESTORE_EGO),
1129 GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1132 ego = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
1136 handle->type = GNUNET_GNSRECORD_TYPE_ANY;
1137 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE,
1138 strlen (GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE),
1141 GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1144 type = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
1147 handle->type = GNUNET_GNSRECORD_typename_to_number (type);
1149 name = get_name_from_url (handle->url);
1151 handle->ego_name = GNUNET_strdup (ego);
1153 handle->name = GNUNET_strdup (name);
1154 if (NULL == handle->ego_name)
1156 handle->identity_handle = GNUNET_IDENTITY_connect (handle->cfg, &id_connect_cb, handle);
1157 if (NULL == handle->identity_handle)
1159 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Cannot connect to identity service\n"));
1160 resp = GNUNET_REST_create_response (NULL);
1161 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
1162 cleanup_handle (handle);
1166 handle->ego_lookup = GNUNET_IDENTITY_ego_lookup (cfg,
1170 handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout,
1176 * Entry point for the plugin.
1178 * @param cls Config info
1179 * @return NULL on error, otherwise the plugin context
1182 libgnunet_plugin_rest_namestore_init (void *cls)
1184 static struct Plugin plugin;
1186 struct GNUNET_REST_Plugin *api;
1188 if (NULL != plugin.cfg)
1189 return NULL; /* can only initialize once! */
1190 memset (&plugin, 0, sizeof (struct Plugin));
1192 api = GNUNET_new (struct GNUNET_REST_Plugin);
1194 api->name = GNUNET_REST_API_NS_NAMESTORE;
1195 api->process_request = &rest_identity_process_request;
1196 GNUNET_asprintf (&allow_methods,
1197 "%s, %s, %s, %s, %s",
1198 MHD_HTTP_METHOD_GET,
1199 MHD_HTTP_METHOD_POST,
1200 MHD_HTTP_METHOD_PUT,
1201 MHD_HTTP_METHOD_DELETE,
1202 MHD_HTTP_METHOD_OPTIONS);
1203 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1204 _("Namestore REST API initialized\n"));
1210 * Exit point from the plugin.
1212 * @param cls the plugin context (as returned by "init")
1213 * @return always NULL
1216 libgnunet_plugin_rest_namestore_done (void *cls)
1218 struct GNUNET_REST_Plugin *api = cls;
1219 struct Plugin *plugin = api->cls;
1223 GNUNET_free_non_null (allow_methods);
1224 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1225 "Namestore REST plugin is finished\n");
1229 /* end of plugin_rest_namestore.c */