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 * @author Philippe Buschmann
21 * @file identity/plugin_rest_identity.c
22 * @brief GNUnet Namestore REST plugin
27 #include "gnunet_rest_plugin.h"
28 #include "gnunet_identity_service.h"
29 #include "gnunet_rest_lib.h"
30 #include "microhttpd.h"
32 #include "gnunet_signatures.h"
37 #define GNUNET_REST_API_NS_IDENTITY "/identity"
40 * State while collecting all egos
42 #define ID_REST_STATE_INIT 0
45 * Done collecting egos
47 #define ID_REST_STATE_POST_INIT 1
52 #define GNUNET_REST_JSON_IDENTITY_EGO "ego"
57 #define GNUNET_REST_JSON_IDENTITY_NAME "name"
60 * Attribute to rename "name" TODO we changed id to the pubkey
61 * so this can be unified with "name"
63 #define GNUNET_REST_JSON_IDENTITY_NEWNAME "newname"
66 * URL parameter to change the subsytem for ego
68 #define GNUNET_REST_JSON_IDENTITY_SUBSYSTEM "subsystem"
74 #define GNUNET_REST_ERROR_RESOURCE_INVALID "Resource location invalid"
75 #define GNUNET_REST_ERROR_NO_DATA "No data"
76 #define GNUNET_REST_ERROR_DATA_INVALID "Data invalid"
79 * GNUid token lifetime
81 #define GNUNET_GNUID_TOKEN_EXPIRATION_MICROSECONDS 300000000
84 * The configuration handle
86 const struct GNUNET_CONFIGURATION_Handle *cfg;
89 * HTTP methods allows for this plugin
91 static char* allow_methods;
94 * @brief struct returned by the initialization function of the plugin
98 const struct GNUNET_CONFIGURATION_Handle *cfg;
109 struct EgoEntry *next;
114 struct EgoEntry *prev;
129 struct GNUNET_IDENTITY_Ego *ego;
138 struct EgoEntry *ego_head;
143 struct EgoEntry *ego_tail;
146 * Handle to the rest connection
148 struct GNUNET_REST_RequestHandle *conndata_handle;
156 * The processing state
161 * Handle to GNS service.
163 struct GNUNET_IDENTITY_Handle *identity_handle;
168 struct GNUNET_IDENTITY_Operation *op;
171 * Desired timeout for the lookup (default is no timeout).
173 struct GNUNET_TIME_Relative timeout;
176 * ID of a task associated with the resolution process.
178 struct GNUNET_SCHEDULER_Task * timeout_task;
181 * The plugin result processor
183 GNUNET_REST_ResultProcessor proc;
186 * The closure of the result processor
191 * The name to look up
196 * The subsystem set from REST
206 * The data from the REST request
211 * the length of the REST data
221 * Error response message
229 * Cleanup lookup handle
230 * @param handle Handle to clean up
233 cleanup_handle (struct RequestHandle *handle)
235 struct EgoEntry *ego_entry;
236 struct EgoEntry *ego_tmp;
237 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
239 if (NULL != handle->name)
240 GNUNET_free (handle->name);
241 if (NULL != handle->timeout_task)
243 GNUNET_SCHEDULER_cancel (handle->timeout_task);
244 handle->timeout_task = NULL;
246 if (NULL != handle->identity_handle)
247 GNUNET_IDENTITY_disconnect (handle->identity_handle);
248 if (NULL != handle->subsys)
249 GNUNET_free (handle->subsys);
250 if (NULL != handle->url)
251 GNUNET_free (handle->url);
252 if (NULL != handle->emsg)
253 GNUNET_free (handle->emsg);
254 for (ego_entry = handle->ego_head;
258 ego_entry = ego_entry->next;
259 GNUNET_free (ego_tmp->identifier);
260 GNUNET_free (ego_tmp->keystring);
261 GNUNET_free (ego_tmp);
263 GNUNET_free (handle);
268 * Task run on errors. Reports an error and cleans up everything.
270 * @param cls the `struct RequestHandle`
275 struct RequestHandle *handle = cls;
276 struct MHD_Response *resp;
279 if (NULL == handle->emsg)
280 handle->emsg = GNUNET_strdup("Unknown Error");
282 GNUNET_asprintf (&json_error, "{\"error\": \"%s\"}", handle->emsg);
283 handle->response_code = MHD_HTTP_OK;
285 resp = GNUNET_REST_create_response (json_error);
286 handle->proc (handle->proc_cls, resp, handle->response_code);
287 cleanup_handle (handle);
288 GNUNET_free(json_error);
293 * Callback for IDENTITY_get()
295 * @param cls the RequestHandle
296 * @param ego the Ego found
297 * @param ctx the context
298 * @param name the id of the ego
301 get_ego_for_subsys (void *cls,
302 struct GNUNET_IDENTITY_Ego *ego,
306 struct RequestHandle *handle = cls;
307 struct EgoEntry *ego_entry;
308 struct MHD_Response *resp;
315 json_root = json_array();
317 for (ego_entry = handle->ego_head;
319 ego_entry = ego_entry->next)
321 if ( (NULL != name) && (0 != strcmp (name, ego_entry->identifier)) )
326 json_ego = json_object();
327 name_json = json_string (ego_entry->identifier);
328 json_object_set_new(json_ego, GNUNET_REST_JSON_IDENTITY_EGO, name_json);
329 json_array_append(json_root, json_ego);
334 if (0 == json_array_size(json_root))
336 json_decref(json_root);
337 handle->emsg = GNUNET_strdup("No identity matches results!");
338 GNUNET_SCHEDULER_add_now (&do_error, handle);
342 result_str = json_dumps(json_root, 0);
343 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
344 resp = GNUNET_REST_create_response (result_str);
346 json_array_foreach(json_root, index, json_ego )
348 json_decref(json_ego);
350 json_decref (json_root);
351 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
352 GNUNET_free (result_str);
353 cleanup_handle (handle);
358 * Create a response with requested ego(s)
360 * @param con the Rest handle
361 * @param url the requested url
362 * @param cls the request handle
365 ego_info_response (struct GNUNET_REST_RequestHandle *con,
373 struct RequestHandle *handle = cls;
374 struct EgoEntry *ego_entry;
375 struct GNUNET_HashCode key;
376 struct MHD_Response *resp;
382 if (GNUNET_NO == GNUNET_REST_namespace_match (handle->url, GNUNET_REST_API_NS_IDENTITY))
384 resp = GNUNET_REST_create_response (NULL);
385 handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
386 cleanup_handle (handle);
391 if (strlen (GNUNET_REST_API_NS_IDENTITY) < strlen (handle->url))
393 keystring = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY)+1];
395 for (ego_entry = handle->ego_head;
397 ego_entry = ego_entry->next)
399 if ( (NULL != keystring) && (0 != strcmp (keystring, ego_entry->keystring)) )
401 egoname = ego_entry->identifier;
405 if ( NULL == egoname ) {
406 GNUNET_CRYPTO_hash (GNUNET_REST_JSON_IDENTITY_SUBSYSTEM,
407 strlen (GNUNET_REST_JSON_IDENTITY_SUBSYSTEM),
410 GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
413 subsys_val = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
415 if (NULL != subsys_val)
417 GNUNET_asprintf (&handle->subsys, "%s", subsys_val);
418 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Looking for %s's ego\n", subsys_val);
419 handle->op = GNUNET_IDENTITY_get (handle->identity_handle,
428 json_root = json_array();
431 for (ego_entry = handle->ego_head;
433 ego_entry = ego_entry->next)
435 if ( (NULL != egoname) && (0 != strcmp (egoname, ego_entry->identifier)) )
438 json_ego = json_object();
440 json_object_set_new( json_ego, "id", json_string (ego_entry->keystring));
441 json_object_set_new( json_ego, "type", json_string (GNUNET_REST_JSON_IDENTITY_EGO));
442 name_str = json_string (ego_entry->identifier);
443 json_object_set_new( json_ego, "name", name_str);
445 json_array_append( json_root, json_ego );
448 if ((size_t)0 == json_array_size(json_root))
450 json_decref (json_root);
451 handle->emsg = GNUNET_strdup ("No identities found!");
452 GNUNET_SCHEDULER_add_now (&do_error, handle);
456 result_str = json_dumps(json_root, 0);
457 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
458 resp = GNUNET_REST_create_response (result_str);
460 //delete json_objects in json_array with macro
461 json_array_foreach(json_root, index, json_ego )
463 json_decref(json_ego);
465 json_decref (json_root);
466 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
467 GNUNET_free (result_str);
468 cleanup_handle (handle);
472 * Processing finished
474 * @param cls request handle
475 * @param emsg error message
478 do_finished (void *cls, const char *emsg)
480 struct RequestHandle *handle = cls;
481 struct MHD_Response *resp;
486 handle->emsg = GNUNET_strdup (emsg);
487 GNUNET_SCHEDULER_add_now (&do_error, handle);
490 resp = GNUNET_REST_create_response (NULL);
491 handle->proc (handle->proc_cls, resp, handle->response_code);
492 cleanup_handle (handle);
498 * @param con rest handle
500 * @param cls request handle
503 ego_create_cont (struct GNUNET_REST_RequestHandle *con,
507 struct RequestHandle *handle = cls;
508 struct EgoEntry *ego_entry;
509 struct MHD_Response *resp;
510 json_t *egoname_json;
514 char term_data[handle->data_size+1];
516 if (strlen (GNUNET_REST_API_NS_IDENTITY) != strlen (handle->url))
518 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_RESOURCE_INVALID);
519 GNUNET_SCHEDULER_add_now (&do_error, handle);
523 if (0 >= handle->data_size)
525 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_NO_DATA);
526 GNUNET_SCHEDULER_add_now (&do_error, handle);
529 term_data[handle->data_size] = '\0';
530 GNUNET_memcpy (term_data, handle->data, handle->data_size);
531 data_js = json_loads (term_data,
538 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_DATA_INVALID);
539 GNUNET_SCHEDULER_add_now (&do_error, handle);
543 if (!json_is_object(data_js))
545 json_decref(data_js);
546 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_DATA_INVALID);
547 GNUNET_SCHEDULER_add_now (&do_error, handle);
551 if (1 != json_object_size (data_js))
553 json_decref (data_js);
554 handle->emsg = GNUNET_strdup("Provided resource count invalid");
555 GNUNET_SCHEDULER_add_now (&do_error, handle);
559 egoname_json = json_object_get (data_js, GNUNET_REST_JSON_IDENTITY_NAME);
560 if (!json_is_string (egoname_json))
562 json_decref (data_js);
563 handle->emsg = GNUNET_strdup ("No name provided");
564 GNUNET_SCHEDULER_add_now (&do_error, handle);
567 egoname = json_string_value (egoname_json);
568 if(0 >= strlen(egoname))
570 json_decref (data_js);
571 handle->emsg = GNUNET_strdup ("No name provided");
572 GNUNET_SCHEDULER_add_now (&do_error, handle);
575 for (ego_entry = handle->ego_head;
577 ego_entry = ego_entry->next)
579 if (0 == strcasecmp (egoname, ego_entry->identifier))
581 json_decref (data_js);
582 resp = GNUNET_REST_create_response (NULL);
583 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
584 cleanup_handle (handle);
588 GNUNET_asprintf (&handle->name, "%s", egoname);
589 json_decref (data_js);
590 handle->response_code = MHD_HTTP_CREATED;
591 handle->op = GNUNET_IDENTITY_create (handle->identity_handle,
599 * Handle ego edit request
601 * @param con rest connection handle
602 * @param url the url that is requested
603 * @param cls the RequestHandle
606 ego_edit_cont (struct GNUNET_REST_RequestHandle *con,
610 struct RequestHandle *handle = cls;
611 struct EgoEntry *ego_entry;
612 struct EgoEntry *ego_entry_tmp;
613 struct MHD_Response *resp;
618 const char *keystring;
621 char term_data[handle->data_size+1];
622 int ego_exists = GNUNET_NO;
624 if (strlen (GNUNET_REST_API_NS_IDENTITY) > strlen (handle->url))
626 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_RESOURCE_INVALID);
627 GNUNET_SCHEDULER_add_now (&do_error, handle);
631 keystring = &handle->url[strlen(GNUNET_REST_API_NS_IDENTITY)+1];
633 for (ego_entry = handle->ego_head;
635 ego_entry = ego_entry->next)
637 if (0 != strcasecmp (keystring, ego_entry->keystring))
639 ego_exists = GNUNET_YES;
643 if (GNUNET_NO == ego_exists)
645 resp = GNUNET_REST_create_response (NULL);
646 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
647 cleanup_handle (handle);
651 if (0 >= handle->data_size)
653 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_NO_DATA);
654 GNUNET_SCHEDULER_add_now (&do_error, handle);
658 term_data[handle->data_size] = '\0';
659 GNUNET_memcpy (term_data, handle->data, handle->data_size);
660 data_js = json_loads (term_data,
665 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_NO_DATA);
666 GNUNET_SCHEDULER_add_now (&do_error, handle);
669 if (!json_is_object(data_js))
671 json_decref (data_js);
672 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_DATA_INVALID);
673 GNUNET_SCHEDULER_add_now (&do_error, handle);
677 if (1 != json_object_size(data_js))
679 json_decref (data_js);
680 handle->emsg = GNUNET_strdup ("Resource amount invalid");
681 GNUNET_SCHEDULER_add_now (&do_error, handle);
686 name_json = json_object_get (data_js, GNUNET_REST_JSON_IDENTITY_NEWNAME);
687 if ((NULL != name_json) && json_is_string (name_json))
689 newname = json_string_value (name_json);
690 if(0 >= strlen(newname))
692 json_decref (data_js);
693 handle->emsg = GNUNET_strdup ("No name provided");
694 GNUNET_SCHEDULER_add_now (&do_error, handle);
697 for (ego_entry_tmp = handle->ego_head;
698 NULL != ego_entry_tmp;
699 ego_entry_tmp = ego_entry_tmp->next)
701 if (0 == strcasecmp (newname, ego_entry_tmp->identifier) &&
702 0 != strcasecmp (keystring, ego_entry_tmp->keystring))
704 //Ego with same name not allowed
705 json_decref (data_js);
706 resp = GNUNET_REST_create_response (NULL);
707 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
708 cleanup_handle (handle);
712 handle->response_code = MHD_HTTP_NO_CONTENT;
713 handle->op = GNUNET_IDENTITY_rename (handle->identity_handle,
714 ego_entry->identifier,
718 json_decref (data_js);
723 subsys_json = json_object_get (data_js, GNUNET_REST_JSON_IDENTITY_SUBSYSTEM);
724 if ( (NULL != subsys_json) && json_is_string (subsys_json))
726 subsys = json_string_value (subsys_json);
727 if(0 >= strlen(subsys))
729 json_decref (data_js);
730 handle->emsg = GNUNET_strdup ("No name provided");
731 GNUNET_SCHEDULER_add_now (&do_error, handle);
734 GNUNET_asprintf (&handle->subsys, "%s", subsys);
735 json_decref (data_js);
736 handle->response_code = MHD_HTTP_NO_CONTENT;
737 handle->op = GNUNET_IDENTITY_set (handle->identity_handle,
744 json_decref (data_js);
745 handle->emsg = GNUNET_strdup ("Subsystem not provided");
746 GNUNET_SCHEDULER_add_now (&do_error, handle);
750 * Handle ego delete request
752 * @param con_handle the connection handle
754 * @param cls the RequestHandle
757 ego_delete_cont (struct GNUNET_REST_RequestHandle *con_handle,
761 const char *keystring;
762 struct EgoEntry *ego_entry;
763 struct MHD_Response *resp;
764 struct RequestHandle *handle = cls;
765 int ego_exists = GNUNET_NO;
767 if (strlen (GNUNET_REST_API_NS_IDENTITY) >= strlen (handle->url))
769 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_RESOURCE_INVALID);
770 GNUNET_SCHEDULER_add_now (&do_error, handle);
774 keystring = &handle->url[strlen(GNUNET_REST_API_NS_IDENTITY)+1];
775 for (ego_entry = handle->ego_head;
777 ego_entry = ego_entry->next)
779 if (0 != strcasecmp (keystring, ego_entry->keystring))
781 ego_exists = GNUNET_YES;
784 if (GNUNET_NO == ego_exists)
786 resp = GNUNET_REST_create_response (NULL);
787 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
788 cleanup_handle (handle);
791 handle->response_code = MHD_HTTP_NO_CONTENT;
792 handle->op = GNUNET_IDENTITY_delete (handle->identity_handle,
793 ego_entry->identifier,
801 * Respond to OPTIONS request
803 * @param con_handle the connection handle
805 * @param cls the RequestHandle
808 options_cont (struct GNUNET_REST_RequestHandle *con_handle,
812 struct MHD_Response *resp;
813 struct RequestHandle *handle = cls;
815 //For now, independent of path return all options
816 resp = GNUNET_REST_create_response (NULL);
817 MHD_add_response_header (resp,
818 "Access-Control-Allow-Methods",
820 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
821 cleanup_handle (handle);
826 * Handle rest request
828 * @param handle the request handle
831 init_cont (struct RequestHandle *handle)
833 struct GNUNET_REST_RequestHandlerError err;
834 static const struct GNUNET_REST_RequestHandler handlers[] = {
835 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY, &ego_info_response},
836 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY, &ego_create_cont},
837 {MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_IDENTITY, &ego_edit_cont},
838 {MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_IDENTITY, &ego_delete_cont},
839 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY, &options_cont},
840 GNUNET_REST_HANDLER_END
843 if (GNUNET_NO == GNUNET_REST_handle_request (handle->conndata_handle,
848 handle->response_code = err.error_code;
849 GNUNET_SCHEDULER_add_now (&do_error, handle);
854 * If listing is enabled, prints information about the egos.
856 * This function is initially called for all egos and then again
857 * whenever a ego's identifier changes or if it is deleted. At the
858 * end of the initial pass over all egos, the function is once called
859 * with 'NULL' for 'ego'. That does NOT mean that the callback won't
860 * be invoked in the future or that there was an error.
862 * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
863 * this function is only called ONCE, and 'NULL' being passed in
864 * 'ego' does indicate an error (i.e. name is taken or no default
865 * value is known). If 'ego' is non-NULL and if '*ctx'
866 * is set in those callbacks, the value WILL be passed to a subsequent
867 * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
868 * that one was not NULL).
870 * When an identity is renamed, this function is called with the
871 * (known) ego but the NEW identifier.
873 * When an identity is deleted, this function is called with the
874 * (known) ego and "NULL" for the 'identifier'. In this case,
875 * the 'ego' is henceforth invalid (and the 'ctx' should also be
879 * @param ego ego handle
880 * @param ctx context for application to store data for this ego
881 * (during the lifetime of this process, initially NULL)
882 * @param identifier identifier assigned by the user for this ego,
883 * NULL if the user just deleted the ego and it
884 * must thus no longer be used
888 struct GNUNET_IDENTITY_Ego *ego,
890 const char *identifier)
892 struct RequestHandle *handle = cls;
893 struct EgoEntry *ego_entry;
894 struct GNUNET_CRYPTO_EcdsaPublicKey pk;
896 if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
898 handle->state = ID_REST_STATE_POST_INIT;
902 if (ID_REST_STATE_INIT == handle->state) {
903 ego_entry = GNUNET_new (struct EgoEntry);
904 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
905 ego_entry->keystring =
906 GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
907 ego_entry->ego = ego;
908 GNUNET_asprintf (&ego_entry->identifier, "%s", identifier);
909 GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry);
915 * Function processing the REST call
917 * @param method HTTP method
918 * @param url URL of the HTTP request
919 * @param data body of the HTTP request (optional)
920 * @param data_size length of the body
921 * @param proc callback function for the result
922 * @param proc_cls closure for callback function
923 * @return GNUNET_OK if request accepted
926 rest_identity_process_request(struct GNUNET_REST_RequestHandle *conndata_handle,
927 GNUNET_REST_ResultProcessor proc,
930 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
934 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
935 handle->response_code = MHD_HTTP_OK;
936 handle->proc_cls = proc_cls;
938 handle->state = ID_REST_STATE_INIT;
939 handle->conndata_handle = conndata_handle;
940 handle->data = conndata_handle->data;
941 handle->data_size = conndata_handle->data_size;
942 handle->method = conndata_handle->method;
943 GNUNET_asprintf (&handle->url, "%s", conndata_handle->url);
944 if (handle->url[strlen (handle->url)-1] == '/')
945 handle->url[strlen (handle->url)-1] = '\0';
946 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
948 handle->identity_handle = GNUNET_IDENTITY_connect (cfg,
951 handle->timeout_task =
952 GNUNET_SCHEDULER_add_delayed (handle->timeout,
957 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
962 * Entry point for the plugin.
964 * @param cls Config info
965 * @return NULL on error, otherwise the plugin context
968 libgnunet_plugin_rest_identity_init (void *cls)
970 static struct Plugin plugin;
971 struct GNUNET_REST_Plugin *api;
974 if (NULL != plugin.cfg)
975 return NULL; /* can only initialize once! */
976 memset (&plugin, 0, sizeof (struct Plugin));
978 api = GNUNET_new (struct GNUNET_REST_Plugin);
980 api->name = GNUNET_REST_API_NS_IDENTITY;
981 api->process_request = &rest_identity_process_request;
982 GNUNET_asprintf (&allow_methods,
983 "%s, %s, %s, %s, %s",
985 MHD_HTTP_METHOD_POST,
987 MHD_HTTP_METHOD_DELETE,
988 MHD_HTTP_METHOD_OPTIONS);
990 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
991 _("Identity REST API initialized\n"));
997 * Exit point from the plugin.
999 * @param cls the plugin context (as returned by "init")
1000 * @return always NULL
1003 libgnunet_plugin_rest_identity_done (void *cls)
1005 struct GNUNET_REST_Plugin *api = cls;
1006 struct Plugin *plugin = api->cls;
1009 GNUNET_free_non_null (allow_methods);
1011 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1012 "Identity REST plugin is finished\n");
1016 /* end of plugin_rest_gns.c */