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 identity/plugin_rest_identity.c
23 * @brief GNUnet Namestore REST plugin
28 #include "gnunet_rest_plugin.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"
35 #include "gnunet_signatures.h"
40 #define GNUNET_REST_API_NS_IDENTITY "/identity"
43 * State while collecting all egos
45 #define ID_REST_STATE_INIT 0
48 * Done collecting egos
50 #define ID_REST_STATE_POST_INIT 1
55 #define GNUNET_REST_JSONAPI_IDENTITY_EGO "ego"
60 #define GNUNET_REST_JSONAPI_IDENTITY_NAME "name"
63 * Attribute to rename "name" TODO we changed id to the pubkey
64 * so this can be unified with "name"
66 #define GNUNET_REST_JSONAPI_IDENTITY_NEWNAME "newname"
69 * URL parameter to change the subsytem for ego
71 #define GNUNET_REST_JSONAPI_IDENTITY_SUBSYSTEM "subsystem"
77 #define GNUNET_REST_ERROR_RESOURCE_INVALID "Resource location invalid"
78 #define GNUNET_REST_ERROR_NO_DATA "No data"
81 * GNUid token lifetime
83 #define GNUNET_GNUID_TOKEN_EXPIRATION_MICROSECONDS 300000000
86 * The configuration handle
88 const struct GNUNET_CONFIGURATION_Handle *cfg;
91 * HTTP methods allows for this plugin
93 static char* allow_methods;
96 * @brief struct returned by the initialization function of the plugin
100 const struct GNUNET_CONFIGURATION_Handle *cfg;
111 struct EgoEntry *next;
116 struct EgoEntry *prev;
131 struct GNUNET_IDENTITY_Ego *ego;
140 struct EgoEntry *ego_head;
145 struct EgoEntry *ego_tail;
148 * Handle to the rest connection
150 struct GNUNET_REST_RequestHandle *conndata_handle;
158 * The processing state
163 * Handle to GNS service.
165 struct GNUNET_IDENTITY_Handle *identity_handle;
170 struct GNUNET_IDENTITY_Operation *op;
173 * Desired timeout for the lookup (default is no timeout).
175 struct GNUNET_TIME_Relative timeout;
178 * ID of a task associated with the resolution process.
180 struct GNUNET_SCHEDULER_Task * timeout_task;
183 * The plugin result processor
185 GNUNET_REST_ResultProcessor proc;
188 * The closure of the result processor
193 * The name to look up
198 * The subsystem set from REST
208 * The data from the REST request
213 * the length of the REST data
223 * Error response message
231 * Cleanup lookup handle
232 * @param handle Handle to clean up
235 cleanup_handle (struct RequestHandle *handle)
237 struct EgoEntry *ego_entry;
238 struct EgoEntry *ego_tmp;
239 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
241 if (NULL != handle->name)
242 GNUNET_free (handle->name);
243 if (NULL != handle->timeout_task)
244 GNUNET_SCHEDULER_cancel (handle->timeout_task);
245 if (NULL != handle->identity_handle)
246 GNUNET_IDENTITY_disconnect (handle->identity_handle);
247 if (NULL != handle->subsys)
248 GNUNET_free (handle->subsys);
249 if (NULL != handle->url)
250 GNUNET_free (handle->url);
251 if (NULL != handle->emsg)
252 GNUNET_free (handle->emsg);
253 for (ego_entry = handle->ego_head;
257 ego_entry = ego_entry->next;
258 GNUNET_free (ego_tmp->identifier);
259 GNUNET_free (ego_tmp->keystring);
260 GNUNET_free (ego_tmp);
262 GNUNET_free (handle);
267 * Task run on errors. Reports an error and cleans up everything.
269 * @param cls the `struct RequestHandle`
274 struct RequestHandle *handle = cls;
275 struct MHD_Response *resp;
278 GNUNET_asprintf (&json_error,
279 "{Error while processing request: %s}",
282 resp = GNUNET_REST_create_response (json_error);
283 handle->proc (handle->proc_cls,
285 handle->response_code);
286 cleanup_handle (handle);
287 GNUNET_free (json_error);
292 * Callback for IDENTITY_get()
294 * @param cls the RequestHandle
295 * @param ego the Ego found
296 * @param ctx the context
297 * @param name the id of the ego
300 get_ego_for_subsys (void *cls,
301 struct GNUNET_IDENTITY_Ego *ego,
305 struct RequestHandle *handle = cls;
306 struct GNUNET_JSONAPI_Document *json_document;
307 struct GNUNET_JSONAPI_Resource *json_resource;
308 struct EgoEntry *ego_entry;
309 struct MHD_Response *resp;
313 json_document = GNUNET_JSONAPI_document_new ();
315 for (ego_entry = handle->ego_head;
317 ego_entry = ego_entry->next)
319 if ( (NULL != name) && (0 != strcmp (name, ego_entry->identifier)) )
323 json_resource = GNUNET_JSONAPI_resource_new
324 (GNUNET_REST_JSONAPI_IDENTITY_EGO, ego_entry->keystring);
325 name_json = json_string (ego_entry->identifier);
326 GNUNET_JSONAPI_resource_add_attr (json_resource,
327 GNUNET_REST_JSONAPI_IDENTITY_NAME,
329 json_decref (name_json);
330 GNUNET_JSONAPI_document_resource_add (json_document, json_resource);
333 if (0 == GNUNET_JSONAPI_document_resource_count (json_document))
335 GNUNET_JSONAPI_document_delete (json_document);
336 handle->emsg = GNUNET_strdup("No identity matches results!");
337 GNUNET_SCHEDULER_add_now (&do_error, handle);
340 GNUNET_JSONAPI_document_serialize (json_document, &result_str);
341 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
342 resp = GNUNET_REST_create_response (result_str);
343 GNUNET_JSONAPI_document_delete (json_document);
344 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
345 GNUNET_free (result_str);
346 cleanup_handle (handle);
350 * Create a response with requested ego(s)
352 * @param con the Rest handle
353 * @param url the requested url
354 * @param cls the request handle
357 ego_info_response (struct GNUNET_REST_RequestHandle *con,
365 struct RequestHandle *handle = cls;
366 struct EgoEntry *ego_entry;
367 struct GNUNET_HashCode key;
368 struct MHD_Response *resp;
369 struct GNUNET_JSONAPI_Document *json_document;
370 struct GNUNET_JSONAPI_Resource *json_resource;
373 if (GNUNET_NO == GNUNET_REST_namespace_match (handle->url, GNUNET_REST_API_NS_IDENTITY))
375 resp = GNUNET_REST_create_response (NULL);
376 handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
377 cleanup_handle (handle);
382 if (strlen (GNUNET_REST_API_NS_IDENTITY) < strlen (handle->url))
384 keystring = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY)+1];
386 for (ego_entry = handle->ego_head;
388 ego_entry = ego_entry->next)
390 if ( (NULL != keystring) && (0 != strcmp (keystring, ego_entry->keystring)) )
392 egoname = ego_entry->identifier;
396 if ( NULL == egoname ) {
397 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_IDENTITY_SUBSYSTEM,
398 strlen (GNUNET_REST_JSONAPI_IDENTITY_SUBSYSTEM),
401 GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
404 subsys_val = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
406 if (NULL != subsys_val)
408 GNUNET_asprintf (&handle->subsys, "%s", subsys_val);
409 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Looking for %s's ego\n", subsys_val);
410 handle->op = GNUNET_IDENTITY_get (handle->identity_handle,
419 json_document = GNUNET_JSONAPI_document_new ();
422 for (ego_entry = handle->ego_head;
424 ego_entry = ego_entry->next)
426 if ( (NULL != egoname) && (0 != strcmp (egoname, ego_entry->identifier)) )
428 json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_EGO,
429 ego_entry->keystring);
430 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
432 ego_entry->identifier);
433 name_str = json_string (ego_entry->identifier);
434 GNUNET_JSONAPI_resource_add_attr (
436 GNUNET_REST_JSONAPI_IDENTITY_NAME,
438 json_decref (name_str);
439 GNUNET_JSONAPI_document_resource_add (json_document, json_resource);
441 if (0 == GNUNET_JSONAPI_document_resource_count (json_document))
443 GNUNET_JSONAPI_document_delete (json_document);
444 handle->emsg = GNUNET_strdup ("No identities found!");
445 GNUNET_SCHEDULER_add_now (&do_error, handle);
448 GNUNET_JSONAPI_document_serialize (json_document, &result_str);
449 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
450 resp = GNUNET_REST_create_response (result_str);
451 GNUNET_JSONAPI_document_delete (json_document);
452 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
453 GNUNET_free (result_str);
454 cleanup_handle (handle);
458 * Processing finished
460 * @param cls request handle
461 * @param emsg error message
464 do_finished (void *cls, const char *emsg)
466 struct RequestHandle *handle = cls;
467 struct MHD_Response *resp;
472 handle->emsg = GNUNET_strdup (emsg);
473 GNUNET_SCHEDULER_add_now (&do_error, handle);
476 resp = GNUNET_REST_create_response (NULL);
477 handle->proc (handle->proc_cls, resp, MHD_HTTP_NO_CONTENT);
478 cleanup_handle (handle);
484 * @param con rest handle
486 * @param cls request handle
489 ego_create_cont (struct GNUNET_REST_RequestHandle *con,
493 struct RequestHandle *handle = cls;
494 struct EgoEntry *ego_entry;
495 struct MHD_Response *resp;
496 struct GNUNET_JSONAPI_Document *json_obj;
497 struct GNUNET_JSONAPI_Resource *json_res;
498 json_t *egoname_json;
502 char term_data[handle->data_size+1];
503 struct GNUNET_JSON_Specification docspec[] = {
504 GNUNET_JSON_spec_jsonapi_document (&json_obj),
505 GNUNET_JSON_spec_end()
507 if (strlen (GNUNET_REST_API_NS_IDENTITY) != strlen (handle->url))
509 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_RESOURCE_INVALID);
510 GNUNET_SCHEDULER_add_now (&do_error, handle);
513 if (0 >= handle->data_size)
515 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_NO_DATA);
516 GNUNET_SCHEDULER_add_now (&do_error, handle);
519 term_data[handle->data_size] = '\0';
520 GNUNET_memcpy (term_data, handle->data, handle->data_size);
521 data_js = json_loads (term_data,
524 GNUNET_assert (NULL != data_js);
525 GNUNET_assert (GNUNET_OK ==
526 GNUNET_JSON_parse (data_js, docspec,
529 json_decref (data_js);
531 if (NULL == json_obj)
533 GNUNET_SCHEDULER_add_now (&do_error, handle);
536 if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
538 GNUNET_JSONAPI_document_delete (json_obj);
539 handle->emsg = GNUNET_strdup ("Provided resource count invalid");
540 GNUNET_SCHEDULER_add_now (&do_error, handle);
543 json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
544 if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res, GNUNET_REST_JSONAPI_IDENTITY_EGO))
546 GNUNET_JSONAPI_document_delete (json_obj);
547 resp = GNUNET_REST_create_response (NULL);
548 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
549 cleanup_handle (handle);
552 egoname_json = GNUNET_JSONAPI_resource_read_attr (json_res, GNUNET_REST_JSONAPI_IDENTITY_NAME);
553 if (!json_is_string (egoname_json))
555 GNUNET_JSONAPI_document_delete (json_obj);
556 handle->emsg = GNUNET_strdup ("No name provided");
557 GNUNET_SCHEDULER_add_now (&do_error, handle);
560 egoname = json_string_value (egoname_json);
561 for (ego_entry = handle->ego_head;
563 ego_entry = ego_entry->next)
565 if (0 == strcasecmp (egoname, ego_entry->identifier))
567 GNUNET_JSONAPI_document_delete (json_obj);
568 resp = GNUNET_REST_create_response (NULL);
569 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
570 cleanup_handle (handle);
574 GNUNET_asprintf (&handle->name, "%s", egoname);
575 GNUNET_JSONAPI_document_delete (json_obj);
576 handle->op = GNUNET_IDENTITY_create (handle->identity_handle,
584 * Handle ego edit request
586 * @param con rest connection handle
587 * @param url the url that is requested
588 * @param cls the RequestHandle
591 ego_edit_cont (struct GNUNET_REST_RequestHandle *con,
595 struct GNUNET_JSONAPI_Document *json_obj;
596 struct GNUNET_JSONAPI_Resource *json_res;
597 struct RequestHandle *handle = cls;
598 struct EgoEntry *ego_entry;
599 struct MHD_Response *resp;
604 const char *keystring;
607 char term_data[handle->data_size+1];
608 int ego_exists = GNUNET_NO;
609 struct GNUNET_JSON_Specification docspec[] = {
610 GNUNET_JSON_spec_jsonapi_document (&json_obj),
611 GNUNET_JSON_spec_end()
614 if (strlen (GNUNET_REST_API_NS_IDENTITY) > strlen (handle->url))
616 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_RESOURCE_INVALID);
617 GNUNET_SCHEDULER_add_now (&do_error, handle);
621 keystring = &handle->url[strlen(GNUNET_REST_API_NS_IDENTITY)+1];
623 for (ego_entry = handle->ego_head;
625 ego_entry = ego_entry->next)
627 if (0 != strcasecmp (keystring, ego_entry->keystring))
629 ego_exists = GNUNET_YES;
633 if (GNUNET_NO == ego_exists)
635 resp = GNUNET_REST_create_response (NULL);
636 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
637 cleanup_handle (handle);
641 if (0 >= handle->data_size)
643 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_NO_DATA);
644 GNUNET_SCHEDULER_add_now (&do_error, handle);
648 term_data[handle->data_size] = '\0';
649 GNUNET_memcpy (term_data, handle->data, handle->data_size);
650 data_js = json_loads (term_data,
653 GNUNET_assert (NULL != data_js);
654 GNUNET_assert (GNUNET_OK ==
655 GNUNET_JSON_parse (data_js, docspec,
658 json_decref (data_js);
660 if (NULL == json_obj)
662 handle->emsg = GNUNET_strdup ("Data invalid");
663 GNUNET_SCHEDULER_add_now (&do_error, handle);
667 if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
669 GNUNET_JSONAPI_document_delete (json_obj);
670 handle->emsg = GNUNET_strdup ("Resource amount invalid");
671 GNUNET_SCHEDULER_add_now (&do_error, handle);
674 json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
676 if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res, GNUNET_REST_JSONAPI_IDENTITY_EGO))
678 GNUNET_JSONAPI_document_delete (json_obj);
679 handle->emsg = GNUNET_strdup ("Resource type invalid");
680 GNUNET_SCHEDULER_add_now (&do_error, handle);
685 name_json = GNUNET_JSONAPI_resource_read_attr (json_res,
686 GNUNET_REST_JSONAPI_IDENTITY_NEWNAME);
687 if ((NULL != name_json) && json_is_string (name_json))
689 newname = json_string_value (name_json);
690 for (ego_entry = handle->ego_head;
692 ego_entry = ego_entry->next)
694 if (0 == strcasecmp (newname, ego_entry->identifier) &&
695 0 != strcasecmp (keystring, ego_entry->keystring))
697 //Ego with same name not allowed
698 GNUNET_JSONAPI_document_delete (json_obj);
699 resp = GNUNET_REST_create_response (NULL);
700 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
701 cleanup_handle (handle);
705 handle->op = GNUNET_IDENTITY_rename (handle->identity_handle,
706 ego_entry->identifier,
710 GNUNET_JSONAPI_document_delete (json_obj);
715 subsys_json = GNUNET_JSONAPI_resource_read_attr (json_res, GNUNET_REST_JSONAPI_IDENTITY_SUBSYSTEM);
716 if ( (NULL != subsys_json) && json_is_string (subsys_json))
718 subsys = json_string_value (subsys_json);
719 GNUNET_asprintf (&handle->subsys, "%s", subsys);
720 GNUNET_JSONAPI_document_delete (json_obj);
721 handle->op = GNUNET_IDENTITY_set (handle->identity_handle,
728 GNUNET_JSONAPI_document_delete (json_obj);
729 handle->emsg = GNUNET_strdup ("Subsystem not provided");
730 GNUNET_SCHEDULER_add_now (&do_error, handle);
734 ego_delete_cont (struct GNUNET_REST_RequestHandle *con_handle,
738 const char *keystring;
739 struct EgoEntry *ego_entry;
740 struct MHD_Response *resp;
741 struct RequestHandle *handle = cls;
742 int ego_exists = GNUNET_NO;
744 if (strlen (GNUNET_REST_API_NS_IDENTITY) >= strlen (handle->url))
746 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_RESOURCE_INVALID);
747 GNUNET_SCHEDULER_add_now (&do_error, handle);
751 keystring = &handle->url[strlen(GNUNET_REST_API_NS_IDENTITY)+1];
752 for (ego_entry = handle->ego_head;
754 ego_entry = ego_entry->next)
756 if (0 != strcasecmp (keystring, ego_entry->keystring))
758 ego_exists = GNUNET_YES;
761 if (GNUNET_NO == ego_exists)
763 resp = GNUNET_REST_create_response (NULL);
764 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
765 cleanup_handle (handle);
768 handle->op = GNUNET_IDENTITY_delete (handle->identity_handle,
769 ego_entry->identifier,
777 * Respond to OPTIONS request
779 * @param con_handle the connection handle
781 * @param cls the RequestHandle
784 options_cont (struct GNUNET_REST_RequestHandle *con_handle,
788 struct MHD_Response *resp;
789 struct RequestHandle *handle = cls;
791 //For now, independent of path return all options
792 resp = GNUNET_REST_create_response (NULL);
793 MHD_add_response_header (resp,
794 "Access-Control-Allow-Methods",
796 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
797 cleanup_handle (handle);
802 * Handle rest request
804 * @param handle the request handle
807 init_cont (struct RequestHandle *handle)
809 struct GNUNET_REST_RequestHandlerError err;
810 static const struct GNUNET_REST_RequestHandler handlers[] = {
811 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY, &ego_info_response},
812 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY, &ego_create_cont},
813 {MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_IDENTITY, &ego_edit_cont},
814 {MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_IDENTITY, &ego_delete_cont},
815 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY, &options_cont},
816 GNUNET_REST_HANDLER_END
819 if (GNUNET_NO == GNUNET_JSONAPI_handle_request (handle->conndata_handle,
824 handle->response_code = err.error_code;
825 GNUNET_SCHEDULER_add_now (&do_error, handle);
830 * If listing is enabled, prints information about the egos.
832 * This function is initially called for all egos and then again
833 * whenever a ego's identifier changes or if it is deleted. At the
834 * end of the initial pass over all egos, the function is once called
835 * with 'NULL' for 'ego'. That does NOT mean that the callback won't
836 * be invoked in the future or that there was an error.
838 * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
839 * this function is only called ONCE, and 'NULL' being passed in
840 * 'ego' does indicate an error (i.e. name is taken or no default
841 * value is known). If 'ego' is non-NULL and if '*ctx'
842 * is set in those callbacks, the value WILL be passed to a subsequent
843 * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
844 * that one was not NULL).
846 * When an identity is renamed, this function is called with the
847 * (known) ego but the NEW identifier.
849 * When an identity is deleted, this function is called with the
850 * (known) ego and "NULL" for the 'identifier'. In this case,
851 * the 'ego' is henceforth invalid (and the 'ctx' should also be
855 * @param ego ego handle
856 * @param ctx context for application to store data for this ego
857 * (during the lifetime of this process, initially NULL)
858 * @param identifier identifier assigned by the user for this ego,
859 * NULL if the user just deleted the ego and it
860 * must thus no longer be used
864 struct GNUNET_IDENTITY_Ego *ego,
866 const char *identifier)
868 struct RequestHandle *handle = cls;
869 struct EgoEntry *ego_entry;
870 struct GNUNET_CRYPTO_EcdsaPublicKey pk;
872 if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
874 handle->state = ID_REST_STATE_POST_INIT;
878 if (ID_REST_STATE_INIT == handle->state) {
879 ego_entry = GNUNET_new (struct EgoEntry);
880 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
881 ego_entry->keystring =
882 GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
883 ego_entry->ego = ego;
884 GNUNET_asprintf (&ego_entry->identifier, "%s", identifier);
885 GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry);
891 * Function processing the REST call
893 * @param method HTTP method
894 * @param url URL of the HTTP request
895 * @param data body of the HTTP request (optional)
896 * @param data_size length of the body
897 * @param proc callback function for the result
898 * @param proc_cls closure for callback function
899 * @return GNUNET_OK if request accepted
902 rest_identity_process_request(struct GNUNET_REST_RequestHandle *conndata_handle,
903 GNUNET_REST_ResultProcessor proc,
906 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
910 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
912 handle->proc_cls = proc_cls;
914 handle->state = ID_REST_STATE_INIT;
915 handle->conndata_handle = conndata_handle;
916 handle->data = conndata_handle->data;
917 handle->data_size = conndata_handle->data_size;
918 handle->method = conndata_handle->method;
919 GNUNET_asprintf (&handle->url, "%s", conndata_handle->url);
920 if (handle->url[strlen (handle->url)-1] == '/')
921 handle->url[strlen (handle->url)-1] = '\0';
922 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
924 handle->identity_handle = GNUNET_IDENTITY_connect (cfg,
927 handle->timeout_task =
928 GNUNET_SCHEDULER_add_delayed (handle->timeout,
933 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
938 * Entry point for the plugin.
940 * @param cls Config info
941 * @return NULL on error, otherwise the plugin context
944 libgnunet_plugin_rest_identity_init (void *cls)
946 static struct Plugin plugin;
947 struct GNUNET_REST_Plugin *api;
950 if (NULL != plugin.cfg)
951 return NULL; /* can only initialize once! */
952 memset (&plugin, 0, sizeof (struct Plugin));
954 api = GNUNET_new (struct GNUNET_REST_Plugin);
956 api->name = GNUNET_REST_API_NS_IDENTITY;
957 api->process_request = &rest_identity_process_request;
958 GNUNET_asprintf (&allow_methods,
959 "%s, %s, %s, %s, %s",
961 MHD_HTTP_METHOD_POST,
963 MHD_HTTP_METHOD_DELETE,
964 MHD_HTTP_METHOD_OPTIONS);
966 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
967 _("Identity REST API initialized\n"));
973 * Exit point from the plugin.
975 * @param cls the plugin context (as returned by "init")
976 * @return always NULL
979 libgnunet_plugin_rest_identity_done (void *cls)
981 struct GNUNET_REST_Plugin *api = cls;
982 struct Plugin *plugin = api->cls;
985 GNUNET_free_non_null (allow_methods);
987 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
988 "Identity REST plugin is finished\n");
992 /* end of plugin_rest_gns.c */