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 "microhttpd.h"
34 #include "gnunet_signatures.h"
39 #define GNUNET_REST_API_NS_IDENTITY "/identity"
42 * State while collecting all egos
44 #define ID_REST_STATE_INIT 0
47 * Done collecting egos
49 #define ID_REST_STATE_POST_INIT 1
54 #define GNUNET_REST_JSONAPI_IDENTITY_EGO "ego"
59 #define GNUNET_REST_JSONAPI_IDENTITY_NAME "name"
62 * Attribute to rename "name" TODO we changed id to the pubkey
63 * so this can be unified with "name"
65 #define GNUNET_REST_JSONAPI_IDENTITY_NEWNAME "newname"
68 * URL parameter to change the subsytem for ego
70 #define GNUNET_REST_JSONAPI_IDENTITY_SUBSYSTEM "subsystem"
76 #define GNUNET_REST_ERROR_RESOURCE_INVALID "Resource location invalid"
77 #define GNUNET_REST_ERROR_NO_DATA "No data"
80 * GNUid token lifetime
82 #define GNUNET_GNUID_TOKEN_EXPIRATION_MICROSECONDS 300000000
85 * The configuration handle
87 const struct GNUNET_CONFIGURATION_Handle *cfg;
90 * HTTP methods allows for this plugin
92 static char* allow_methods;
95 * @brief struct returned by the initialization function of the plugin
99 const struct GNUNET_CONFIGURATION_Handle *cfg;
110 struct EgoEntry *next;
115 struct EgoEntry *prev;
130 struct GNUNET_IDENTITY_Ego *ego;
139 struct EgoEntry *ego_head;
144 struct EgoEntry *ego_tail;
147 * Handle to the rest connection
149 struct GNUNET_REST_RequestHandle *conndata_handle;
157 * The processing state
162 * Handle to GNS service.
164 struct GNUNET_IDENTITY_Handle *identity_handle;
169 struct GNUNET_IDENTITY_Operation *op;
172 * Desired timeout for the lookup (default is no timeout).
174 struct GNUNET_TIME_Relative timeout;
177 * ID of a task associated with the resolution process.
179 struct GNUNET_SCHEDULER_Task * timeout_task;
182 * The plugin result processor
184 GNUNET_REST_ResultProcessor proc;
187 * The closure of the result processor
192 * The name to look up
197 * The subsystem set from REST
207 * The data from the REST request
212 * the length of the REST data
222 * Error response message
230 * Cleanup lookup handle
231 * @param handle Handle to clean up
234 cleanup_handle (struct RequestHandle *handle)
236 struct EgoEntry *ego_entry;
237 struct EgoEntry *ego_tmp;
238 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
240 if (NULL != handle->name)
241 GNUNET_free (handle->name);
242 if (NULL != handle->timeout_task)
243 GNUNET_SCHEDULER_cancel (handle->timeout_task);
244 if (NULL != handle->identity_handle)
245 GNUNET_IDENTITY_disconnect (handle->identity_handle);
246 if (NULL != handle->subsys)
247 GNUNET_free (handle->subsys);
248 if (NULL != handle->url)
249 GNUNET_free (handle->url);
250 if (NULL != handle->emsg)
251 GNUNET_free (handle->emsg);
252 for (ego_entry = handle->ego_head;
256 ego_entry = ego_entry->next;
257 GNUNET_free (ego_tmp->identifier);
258 GNUNET_free (ego_tmp->keystring);
259 GNUNET_free (ego_tmp);
261 GNUNET_free (handle);
266 * Task run on errors. Reports an error and cleans up everything.
268 * @param cls the `struct RequestHandle`
273 struct RequestHandle *handle = cls;
274 struct MHD_Response *resp;
277 GNUNET_asprintf (&json_error,
278 "{Error while processing request: %s}",
281 resp = GNUNET_REST_create_json_response (json_error);
282 handle->proc (handle->proc_cls,
284 handle->response_code);
285 cleanup_handle (handle);
286 GNUNET_free (json_error);
291 * Callback for IDENTITY_get()
293 * @param cls the RequestHandle
294 * @param ego the Ego found
295 * @param ctx the context
296 * @param name the id of the ego
299 get_ego_for_subsys (void *cls,
300 struct GNUNET_IDENTITY_Ego *ego,
304 struct RequestHandle *handle = cls;
305 struct GNUNET_JSONAPI_Document *json_document;
306 struct GNUNET_JSONAPI_Resource *json_resource;
307 struct EgoEntry *ego_entry;
308 struct MHD_Response *resp;
312 json_document = GNUNET_JSONAPI_document_new ();
314 for (ego_entry = handle->ego_head;
316 ego_entry = ego_entry->next)
318 if ( (NULL != name) && (0 != strcmp (name, ego_entry->identifier)) )
322 json_resource = GNUNET_JSONAPI_resource_new
323 (GNUNET_REST_JSONAPI_IDENTITY_EGO, ego_entry->keystring);
324 name_json = json_string (ego_entry->identifier);
325 GNUNET_JSONAPI_resource_add_attr (json_resource,
326 GNUNET_REST_JSONAPI_IDENTITY_NAME,
328 json_decref (name_json);
329 GNUNET_JSONAPI_document_resource_add (json_document, json_resource);
332 if (0 == GNUNET_JSONAPI_document_resource_count (json_document))
334 GNUNET_JSONAPI_document_delete (json_document);
335 handle->emsg = GNUNET_strdup("No identity matches results!");
336 GNUNET_SCHEDULER_add_now (&do_error, handle);
339 GNUNET_JSONAPI_document_serialize (json_document, &result_str);
340 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
341 resp = GNUNET_REST_create_json_response (result_str);
342 GNUNET_JSONAPI_document_delete (json_document);
343 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
344 GNUNET_free (result_str);
345 cleanup_handle (handle);
349 * Create a response with requested ego(s)
351 * @param con the Rest handle
352 * @param url the requested url
353 * @param cls the request handle
356 ego_info_response (struct GNUNET_REST_RequestHandle *con,
364 struct RequestHandle *handle = cls;
365 struct EgoEntry *ego_entry;
366 struct GNUNET_HashCode key;
367 struct MHD_Response *resp;
368 struct GNUNET_JSONAPI_Document *json_document;
369 struct GNUNET_JSONAPI_Resource *json_resource;
372 if (GNUNET_NO == GNUNET_REST_namespace_match (handle->url, GNUNET_REST_API_NS_IDENTITY))
374 resp = GNUNET_REST_create_json_response (NULL);
375 handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
376 cleanup_handle (handle);
381 if (strlen (GNUNET_REST_API_NS_IDENTITY) < strlen (handle->url))
383 keystring = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY)+1];
385 for (ego_entry = handle->ego_head;
387 ego_entry = ego_entry->next)
389 if ( (NULL != keystring) && (0 != strcmp (keystring, ego_entry->keystring)) )
391 egoname = ego_entry->identifier;
395 if ( NULL == egoname ) {
396 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_IDENTITY_SUBSYSTEM,
397 strlen (GNUNET_REST_JSONAPI_IDENTITY_SUBSYSTEM),
400 GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
403 subsys_val = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
405 if (NULL != subsys_val)
407 GNUNET_asprintf (&handle->subsys, "%s", subsys_val);
408 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Looking for %s's ego\n", subsys_val);
409 handle->op = GNUNET_IDENTITY_get (handle->identity_handle,
418 json_document = GNUNET_JSONAPI_document_new ();
421 for (ego_entry = handle->ego_head;
423 ego_entry = ego_entry->next)
425 if ( (NULL != egoname) && (0 != strcmp (egoname, ego_entry->identifier)) )
427 json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_EGO,
428 ego_entry->keystring);
429 name_str = json_string (ego_entry->identifier);
430 GNUNET_JSONAPI_resource_add_attr (
432 GNUNET_REST_JSONAPI_IDENTITY_NAME,
434 json_decref (name_str);
435 GNUNET_JSONAPI_document_resource_add (json_document, json_resource);
437 if (0 == GNUNET_JSONAPI_document_resource_count (json_document))
439 GNUNET_JSONAPI_document_delete (json_document);
440 handle->emsg = GNUNET_strdup ("No identities found!");
441 GNUNET_SCHEDULER_add_now (&do_error, handle);
444 GNUNET_JSONAPI_document_serialize (json_document, &result_str);
445 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
446 resp = GNUNET_REST_create_json_response (result_str);
447 GNUNET_JSONAPI_document_delete (json_document);
448 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
449 GNUNET_free (result_str);
450 cleanup_handle (handle);
454 * Processing finished
456 * @param cls request handle
457 * @param emsg error message
460 do_finished (void *cls, const char *emsg)
462 struct RequestHandle *handle = cls;
463 struct MHD_Response *resp;
468 handle->emsg = GNUNET_strdup (emsg);
469 GNUNET_SCHEDULER_add_now (&do_error, handle);
472 resp = GNUNET_REST_create_json_response (NULL);
473 handle->proc (handle->proc_cls, resp, MHD_HTTP_NO_CONTENT);
474 cleanup_handle (handle);
480 * @param con rest handle
482 * @param cls request handle
485 ego_create_cont (struct GNUNET_REST_RequestHandle *con,
489 struct RequestHandle *handle = cls;
490 struct EgoEntry *ego_entry;
491 struct MHD_Response *resp;
492 struct GNUNET_JSONAPI_Document *json_obj;
493 struct GNUNET_JSONAPI_Resource *json_res;
494 json_t *egoname_json;
496 char term_data[handle->data_size+1];
498 if (strlen (GNUNET_REST_API_NS_IDENTITY) != strlen (handle->url))
500 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_RESOURCE_INVALID);
501 GNUNET_SCHEDULER_add_now (&do_error, handle);
504 if (0 >= handle->data_size)
506 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_NO_DATA);
507 GNUNET_SCHEDULER_add_now (&do_error, handle);
510 term_data[handle->data_size] = '\0';
511 memcpy (term_data, handle->data, handle->data_size);
512 GNUNET_assert (GNUNET_OK == GNUNET_JSONAPI_document_parse (term_data,
514 if (NULL == json_obj)
516 GNUNET_SCHEDULER_add_now (&do_error, handle);
519 if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
521 GNUNET_JSONAPI_document_delete (json_obj);
522 handle->emsg = GNUNET_strdup ("Provided resource count invalid");
523 GNUNET_SCHEDULER_add_now (&do_error, handle);
526 json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
527 if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res, GNUNET_REST_JSONAPI_IDENTITY_EGO))
529 GNUNET_JSONAPI_document_delete (json_obj);
530 resp = GNUNET_REST_create_json_response (NULL);
531 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
532 cleanup_handle (handle);
535 egoname_json = GNUNET_JSONAPI_resource_read_attr (json_res, GNUNET_REST_JSONAPI_IDENTITY_NAME);
536 if (!json_is_string (egoname_json))
538 GNUNET_JSONAPI_document_delete (json_obj);
539 handle->emsg = GNUNET_strdup ("No name provided");
540 GNUNET_SCHEDULER_add_now (&do_error, handle);
543 egoname = json_string_value (egoname_json);
544 for (ego_entry = handle->ego_head;
546 ego_entry = ego_entry->next)
548 if (0 == strcasecmp (egoname, ego_entry->identifier))
550 GNUNET_JSONAPI_document_delete (json_obj);
551 resp = GNUNET_REST_create_json_response (NULL);
552 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
553 cleanup_handle (handle);
557 GNUNET_asprintf (&handle->name, "%s", egoname);
558 GNUNET_JSONAPI_document_delete (json_obj);
559 handle->op = GNUNET_IDENTITY_create (handle->identity_handle,
567 * Handle ego edit request
569 * @param con rest connection handle
570 * @param url the url that is requested
571 * @param cls the RequestHandle
574 ego_edit_cont (struct GNUNET_REST_RequestHandle *con,
578 struct GNUNET_JSONAPI_Document *json_obj;
579 struct GNUNET_JSONAPI_Resource *json_res;
580 struct RequestHandle *handle = cls;
581 struct EgoEntry *ego_entry;
582 struct MHD_Response *resp;
585 const char *keystring;
588 char term_data[handle->data_size+1];
589 int ego_exists = GNUNET_NO;
591 if (strlen (GNUNET_REST_API_NS_IDENTITY) > strlen (handle->url))
593 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_RESOURCE_INVALID);
594 GNUNET_SCHEDULER_add_now (&do_error, handle);
598 keystring = &handle->url[strlen(GNUNET_REST_API_NS_IDENTITY)+1];
600 for (ego_entry = handle->ego_head;
602 ego_entry = ego_entry->next)
604 if (0 != strcasecmp (keystring, ego_entry->keystring))
606 ego_exists = GNUNET_YES;
610 if (GNUNET_NO == ego_exists)
612 resp = GNUNET_REST_create_json_response (NULL);
613 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
614 cleanup_handle (handle);
618 if (0 >= handle->data_size)
620 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_NO_DATA);
621 GNUNET_SCHEDULER_add_now (&do_error, handle);
625 term_data[handle->data_size] = '\0';
626 memcpy (term_data, handle->data, handle->data_size);
627 GNUNET_assert (GNUNET_OK == GNUNET_JSONAPI_document_parse (term_data,
630 if (NULL == json_obj)
632 handle->emsg = GNUNET_strdup ("Data invalid");
633 GNUNET_SCHEDULER_add_now (&do_error, handle);
637 if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
639 GNUNET_JSONAPI_document_delete (json_obj);
640 handle->emsg = GNUNET_strdup ("Resource amount invalid");
641 GNUNET_SCHEDULER_add_now (&do_error, handle);
644 json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
646 if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res, GNUNET_REST_JSONAPI_IDENTITY_EGO))
648 GNUNET_JSONAPI_document_delete (json_obj);
649 handle->emsg = GNUNET_strdup ("Resource type invalid");
650 GNUNET_SCHEDULER_add_now (&do_error, handle);
655 name_json = GNUNET_JSONAPI_resource_read_attr (json_res,
656 GNUNET_REST_JSONAPI_IDENTITY_NEWNAME);
657 if ((NULL != name_json) && json_is_string (name_json))
659 newname = json_string_value (name_json);
660 for (ego_entry = handle->ego_head;
662 ego_entry = ego_entry->next)
664 if (0 == strcasecmp (newname, ego_entry->identifier) &&
665 0 != strcasecmp (keystring, ego_entry->keystring))
667 //Ego with same name not allowed
668 GNUNET_JSONAPI_document_delete (json_obj);
669 resp = GNUNET_REST_create_json_response (NULL);
670 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
671 cleanup_handle (handle);
675 handle->op = GNUNET_IDENTITY_rename (handle->identity_handle,
676 ego_entry->identifier,
680 GNUNET_JSONAPI_document_delete (json_obj);
685 subsys_json = GNUNET_JSONAPI_resource_read_attr (json_res, GNUNET_REST_JSONAPI_IDENTITY_SUBSYSTEM);
686 if ( (NULL != subsys_json) && json_is_string (subsys_json))
688 subsys = json_string_value (subsys_json);
689 GNUNET_asprintf (&handle->subsys, "%s", subsys);
690 GNUNET_JSONAPI_document_delete (json_obj);
691 handle->op = GNUNET_IDENTITY_set (handle->identity_handle,
698 GNUNET_JSONAPI_document_delete (json_obj);
699 handle->emsg = GNUNET_strdup ("Subsystem not provided");
700 GNUNET_SCHEDULER_add_now (&do_error, handle);
704 ego_delete_cont (struct GNUNET_REST_RequestHandle *con_handle,
708 const char *keystring;
709 struct EgoEntry *ego_entry;
710 struct MHD_Response *resp;
711 struct RequestHandle *handle = cls;
712 int ego_exists = GNUNET_NO;
714 if (strlen (GNUNET_REST_API_NS_IDENTITY) >= strlen (handle->url))
716 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_RESOURCE_INVALID);
717 GNUNET_SCHEDULER_add_now (&do_error, handle);
721 keystring = &handle->url[strlen(GNUNET_REST_API_NS_IDENTITY)+1];
722 for (ego_entry = handle->ego_head;
724 ego_entry = ego_entry->next)
726 if (0 != strcasecmp (keystring, ego_entry->keystring))
728 ego_exists = GNUNET_YES;
731 if (GNUNET_NO == ego_exists)
733 resp = GNUNET_REST_create_json_response (NULL);
734 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
735 cleanup_handle (handle);
738 handle->op = GNUNET_IDENTITY_delete (handle->identity_handle,
739 ego_entry->identifier,
747 * Respond to OPTIONS request
749 * @param con_handle the connection handle
751 * @param cls the RequestHandle
754 options_cont (struct GNUNET_REST_RequestHandle *con_handle,
758 struct MHD_Response *resp;
759 struct RequestHandle *handle = cls;
761 //For now, independent of path return all options
762 resp = GNUNET_REST_create_json_response (NULL);
763 MHD_add_response_header (resp,
764 "Access-Control-Allow-Methods",
766 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
767 cleanup_handle (handle);
772 * Handle rest request
774 * @param handle the request handle
777 init_cont (struct RequestHandle *handle)
779 struct GNUNET_REST_RequestHandlerError err;
780 static const struct GNUNET_REST_RequestHandler handlers[] = {
781 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY, &ego_info_response},
782 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY, &ego_create_cont},
783 {MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_IDENTITY, &ego_edit_cont},
784 {MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_IDENTITY, &ego_delete_cont},
785 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY, &options_cont},
786 GNUNET_REST_HANDLER_END
789 if (GNUNET_NO == GNUNET_JSONAPI_handle_request (handle->conndata_handle,
794 handle->response_code = err.error_code;
795 GNUNET_SCHEDULER_add_now (&do_error, handle);
800 * If listing is enabled, prints information about the egos.
802 * This function is initially called for all egos and then again
803 * whenever a ego's identifier changes or if it is deleted. At the
804 * end of the initial pass over all egos, the function is once called
805 * with 'NULL' for 'ego'. That does NOT mean that the callback won't
806 * be invoked in the future or that there was an error.
808 * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
809 * this function is only called ONCE, and 'NULL' being passed in
810 * 'ego' does indicate an error (i.e. name is taken or no default
811 * value is known). If 'ego' is non-NULL and if '*ctx'
812 * is set in those callbacks, the value WILL be passed to a subsequent
813 * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
814 * that one was not NULL).
816 * When an identity is renamed, this function is called with the
817 * (known) ego but the NEW identifier.
819 * When an identity is deleted, this function is called with the
820 * (known) ego and "NULL" for the 'identifier'. In this case,
821 * the 'ego' is henceforth invalid (and the 'ctx' should also be
825 * @param ego ego handle
826 * @param ctx context for application to store data for this ego
827 * (during the lifetime of this process, initially NULL)
828 * @param identifier identifier assigned by the user for this ego,
829 * NULL if the user just deleted the ego and it
830 * must thus no longer be used
834 struct GNUNET_IDENTITY_Ego *ego,
836 const char *identifier)
838 struct RequestHandle *handle = cls;
839 struct EgoEntry *ego_entry;
840 struct GNUNET_CRYPTO_EcdsaPublicKey pk;
842 if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
844 handle->state = ID_REST_STATE_POST_INIT;
848 if (ID_REST_STATE_INIT == handle->state) {
849 ego_entry = GNUNET_new (struct EgoEntry);
850 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
851 ego_entry->keystring =
852 GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
853 ego_entry->ego = ego;
854 GNUNET_asprintf (&ego_entry->identifier, "%s", identifier);
855 GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry);
861 * Function processing the REST call
863 * @param method HTTP method
864 * @param url URL of the HTTP request
865 * @param data body of the HTTP request (optional)
866 * @param data_size length of the body
867 * @param proc callback function for the result
868 * @param proc_cls closure for callback function
869 * @return GNUNET_OK if request accepted
872 rest_identity_process_request(struct GNUNET_REST_RequestHandle *conndata_handle,
873 GNUNET_REST_ResultProcessor proc,
876 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
880 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
882 handle->proc_cls = proc_cls;
884 handle->state = ID_REST_STATE_INIT;
885 handle->conndata_handle = conndata_handle;
886 handle->data = conndata_handle->data;
887 handle->data_size = conndata_handle->data_size;
888 handle->method = conndata_handle->method;
889 GNUNET_asprintf (&handle->url, "%s", conndata_handle->url);
890 if (handle->url[strlen (handle->url)-1] == '/')
891 handle->url[strlen (handle->url)-1] = '\0';
892 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
894 handle->identity_handle = GNUNET_IDENTITY_connect (cfg,
897 handle->timeout_task =
898 GNUNET_SCHEDULER_add_delayed (handle->timeout,
903 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
908 * Entry point for the plugin.
910 * @param cls Config info
911 * @return NULL on error, otherwise the plugin context
914 libgnunet_plugin_rest_identity_init (void *cls)
916 static struct Plugin plugin;
917 struct GNUNET_REST_Plugin *api;
920 if (NULL != plugin.cfg)
921 return NULL; /* can only initialize once! */
922 memset (&plugin, 0, sizeof (struct Plugin));
924 api = GNUNET_new (struct GNUNET_REST_Plugin);
926 api->name = GNUNET_REST_API_NS_IDENTITY;
927 api->process_request = &rest_identity_process_request;
928 GNUNET_asprintf (&allow_methods,
929 "%s, %s, %s, %s, %s",
931 MHD_HTTP_METHOD_POST,
933 MHD_HTTP_METHOD_DELETE,
934 MHD_HTTP_METHOD_OPTIONS);
936 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
937 _("Identity REST API initialized\n"));
943 * Exit point from the plugin.
945 * @param cls the plugin context (as returned by "init")
946 * @return always NULL
949 libgnunet_plugin_rest_identity_done (void *cls)
951 struct GNUNET_REST_Plugin *api = cls;
952 struct Plugin *plugin = api->cls;
955 GNUNET_free_non_null (allow_methods);
957 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
958 "Identity REST plugin is finished\n");
962 /* end of plugin_rest_gns.c */