-more REST
[oweals/gnunet.git] / src / identity / plugin_rest_identity.c
1 /*
2    This file is part of GNUnet.
3    Copyright (C) 2012-2015 Christian Grothoff (and other contributing authors)
4
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.
9
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.
14
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., 59 Temple Place - Suite 330,
18    Boston, MA 02111-1307, USA.
19    */
20 /**
21  * @author Martin Schanzenbach
22  * @file identity/plugin_rest_identity.c
23  * @brief GNUnet Namestore REST plugin
24  *
25  */
26
27 #include "platform.h"
28 #include "gnunet_rest_plugin.h"
29 #include "gnunet_identity_service.h"
30 #include "gnunet_rest_lib.h"
31 #include "microhttpd.h"
32 #include <jansson.h>
33
34 #define API_NAMESPACE "/identity"
35
36 #define EGO_NAMESPACE "/identity/egos"
37
38 #define ID_REST_STATE_INIT 0
39
40 #define ID_REST_STATE_POST_INIT 1
41
42 #define URL_PARAM_SUBSYS "service"
43
44 #define GNUNET_REST_JSONAPI_IDENTITY_EGO "ego"
45
46 #define GNUNET_REST_JSONAPI_IDENTITY_KEY "key"
47
48 #define GNUNET_REST_JSONAPI_IDENTITY_SUBSYSTEM "subsystem"
49
50 /**
51  * @brief struct returned by the initialization function of the plugin
52  */
53 struct Plugin
54 {
55   const struct GNUNET_CONFIGURATION_Handle *cfg;
56 };
57
58 const struct GNUNET_CONFIGURATION_Handle *cfg;
59
60 struct EgoEntry
61 {
62   /**
63    * DLL
64    */
65   struct EgoEntry *next;
66   
67   /**
68    * DLL
69    */
70   struct EgoEntry *prev;
71   
72   /**
73    * Ego Identifier
74    */
75   char *identifier;
76   
77   /**
78    * Ego Pkey
79    */
80   struct GNUNET_CRYPTO_EcdsaPublicKey pk;
81
82   /**
83    * The Ego
84    */
85   struct GNUNET_IDENTITY_Ego *ego;
86 };
87
88 struct RequestHandle
89 {
90   /**
91    * Ego list
92    */
93   struct EgoEntry *ego_head;
94
95   /**
96    * Ego list
97    */
98   struct EgoEntry *ego_tail;
99
100   struct RestConnectionDataHandle *conndata_handle;
101   
102   /**
103    * The processing state
104    */
105   int state;
106
107   /**
108    * Handle to GNS service.
109    */
110   struct GNUNET_IDENTITY_Handle *identity_handle;
111
112   /**
113    * IDENTITY Operation
114    */
115   struct GNUNET_IDENTITY_Operation *op;
116
117   /**
118    * Desired timeout for the lookup (default is no timeout).
119    */
120   struct GNUNET_TIME_Relative timeout;
121
122   /**
123    * ID of a task associated with the resolution process.
124    */
125   struct GNUNET_SCHEDULER_Task * timeout_task;    
126
127   /**
128    * The root of the received JSON or NULL
129    */
130   json_t *json_root;
131
132   /**
133    * The plugin result processor
134    */
135   GNUNET_REST_ResultProcessor proc;
136
137   /**
138    * The closure of the result processor
139    */
140   void *proc_cls;
141
142   /**
143    * The name to look up
144    */
145   char *name;
146
147   /**
148    * The subsystem set from REST
149    */
150   char *subsys;
151
152   /**
153    * The url
154    */
155   char *url;
156
157   /**
158    * The data from the REST request
159    */
160   const char* data;
161
162   /**
163    * the length of the REST data
164    */
165   size_t data_size;
166
167   /**
168    * HTTP method
169    */
170   const char* method;
171
172 };
173
174
175 /**
176  * Cleanup lookup handle
177  * @praram handle Handle to clean up
178  */
179 void
180 cleanup_handle (struct RequestHandle *handle)
181 {
182   struct EgoEntry *ego_entry;
183   struct EgoEntry *ego_tmp;
184   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
185               "Cleaning up\n");
186   if (NULL != handle->json_root)
187     json_decref (handle->json_root);
188   if (NULL != handle->name)
189     GNUNET_free (handle->name);
190   if (NULL != handle->timeout_task)
191     GNUNET_SCHEDULER_cancel (handle->timeout_task);
192   if (NULL != handle->identity_handle)
193     GNUNET_IDENTITY_disconnect (handle->identity_handle);
194   if (NULL != handle->subsys)
195     GNUNET_free (handle->subsys);
196   if (NULL != handle->url)
197     GNUNET_free (handle->url);
198   for (ego_entry = handle->ego_head;
199        NULL != ego_entry;)
200   {
201     ego_tmp = ego_entry;
202     ego_entry = ego_entry->next;
203     GNUNET_free (ego_tmp->identifier);
204     GNUNET_free (ego_tmp);
205   }
206   GNUNET_free (handle);
207 }
208
209
210 /**
211  * Task run on shutdown.  Cleans up everything.
212  *
213  * @param cls unused
214  * @param tc scheduler context
215  */
216 static void
217 do_error (void *cls,
218           const struct GNUNET_SCHEDULER_TaskContext *tc)
219 {
220   struct RequestHandle *handle = cls;
221   struct MHD_Response *resp = GNUNET_REST_create_json_response (NULL);
222   handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
223   cleanup_handle (handle);
224 }
225
226 /**
227  * Callback for IDENTITY_get()
228  *
229  * @param cls the RequestHandle
230  * @param ego the Ego found
231  * @param ctx the context
232  * @param name the id of the ego
233  */
234 void
235 get_ego_for_subsys (void *cls,
236                     struct GNUNET_IDENTITY_Ego *ego,
237                     void **ctx,
238                     const char *name)
239 {
240   struct RequestHandle *handle = cls;
241   struct JsonApiObject *json_object;
242   struct JsonApiResource *json_resource;
243   struct EgoEntry *ego_entry;
244   struct MHD_Response *resp;
245   json_t *key_json;
246   char *result_str;
247   char *keystring;
248
249   json_object = GNUNET_REST_jsonapi_object_new ();
250   
251   for (ego_entry = handle->ego_head;
252        NULL != ego_entry;
253        ego_entry = ego_entry->next)
254   {
255     if ( (NULL != name) && (0 != strcmp (name, ego_entry->identifier)) )
256       continue;
257     if (NULL == name)
258       continue;
259     json_resource = GNUNET_REST_jsonapi_resource_new (GNUNET_REST_JSONAPI_IDENTITY_EGO, ego_entry->identifier);
260     keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&ego_entry->pk);
261     key_json = json_string (keystring);
262     GNUNET_REST_jsonapi_resource_add_attr (json_resource, GNUNET_REST_JSONAPI_IDENTITY_KEY, key_json);
263     json_decref (key_json);
264     GNUNET_free (keystring);
265     GNUNET_REST_jsonapi_object_resource_add (json_object, json_resource);
266     break;
267   }
268   if (0 == GNUNET_REST_jsonapi_object_resource_count (json_object))
269   {
270     GNUNET_REST_jsonapi_object_delete (json_object);
271     GNUNET_SCHEDULER_add_now (&do_error, handle);
272     return;
273   }
274   GNUNET_REST_jsonapi_data_serialize (json_object, &result_str);
275   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
276   resp = GNUNET_REST_create_json_response (result_str);
277   GNUNET_REST_jsonapi_object_delete (json_object);
278   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
279   GNUNET_free (result_str);
280   cleanup_handle (handle);
281 }
282
283 /**
284  * Create a response with requested ego(s)
285  *
286  * @param handle the RequestHandle
287  */
288 void
289 ego_info_response (struct RestConnectionDataHandle *con,
290                    const char *url,
291                    void *cls)
292 {
293   const char *egoname;
294   char *keystring;
295   char *result_str;
296   char *subsys_val;
297   struct RequestHandle *handle = cls;
298   struct EgoEntry *ego_entry;
299   struct GNUNET_HashCode key;
300   struct MHD_Response *resp;
301   struct JsonApiObject *json_object;
302   struct JsonApiResource *json_resource;
303   json_t *key_str;
304
305   if (GNUNET_NO == GNUNET_REST_namespace_match (handle->url, EGO_NAMESPACE))
306   {
307     resp = GNUNET_REST_create_json_response (NULL);
308     handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
309     cleanup_handle (handle);
310     GNUNET_break (0);
311     return;
312   }
313   if ( (strlen (EGO_NAMESPACE) == strlen (handle->url) )) {
314     GNUNET_CRYPTO_hash (URL_PARAM_SUBSYS, strlen (URL_PARAM_SUBSYS), &key);
315     if ( GNUNET_YES ==
316          GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
317                                                  &key) )
318     {
319       subsys_val = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
320                                                       &key);
321       if (NULL != subsys_val)
322       {
323         GNUNET_asprintf (&handle->subsys, "%s", subsys_val);
324         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Looking for %s's ego\n", subsys_val);
325         handle->op = GNUNET_IDENTITY_get (handle->identity_handle,
326                                           handle->subsys,
327                                           &get_ego_for_subsys,
328                                           handle);
329         return;
330       }
331     }
332   }
333   json_object = GNUNET_REST_jsonapi_object_new ();
334   egoname = &handle->url[strlen (EGO_NAMESPACE)+1];
335
336   if (strlen (EGO_NAMESPACE) == strlen (handle->url))
337   {
338     egoname = NULL;
339   }
340
341   //Return all egos
342   for (ego_entry = handle->ego_head;
343        NULL != ego_entry;
344        ego_entry = ego_entry->next)
345   {
346     if ( (NULL != egoname) && (0 != strcmp (egoname, ego_entry->identifier)) )
347       continue;
348     keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&ego_entry->pk);
349     json_resource = GNUNET_REST_jsonapi_resource_new (GNUNET_REST_JSONAPI_IDENTITY_EGO, ego_entry->identifier);
350     key_str = json_string (keystring);
351     GNUNET_REST_jsonapi_resource_add_attr (json_resource,
352                                            GNUNET_REST_JSONAPI_IDENTITY_KEY,
353                                            key_str);
354     json_decref (key_str);
355     GNUNET_free (keystring);
356     GNUNET_REST_jsonapi_object_resource_add (json_object, json_resource);
357   }
358
359   GNUNET_REST_jsonapi_data_serialize (json_object, &result_str);
360   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
361   resp = GNUNET_REST_create_json_response (result_str);
362   GNUNET_REST_jsonapi_object_delete (json_object);
363   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
364   GNUNET_free (result_str);
365   cleanup_handle (handle);
366 }
367
368 static void
369 do_finished (void *cls, const char *emsg)
370 {
371   struct RequestHandle *handle = cls;
372   struct MHD_Response *resp;
373
374   handle->op = NULL;
375   if (NULL != emsg)
376   {
377     GNUNET_SCHEDULER_add_now (&do_error, handle);
378     return;
379   }
380   resp = GNUNET_REST_create_json_response (NULL);
381   handle->proc (handle->proc_cls, resp, MHD_HTTP_NO_CONTENT);
382   cleanup_handle (handle);
383 }
384
385 static void
386 set_finished (void *cls, const char *emsg)
387 {
388   struct RequestHandle *handle = cls;
389   struct MHD_Response *resp;
390
391   handle->op = NULL;
392   if (NULL != emsg)
393   {
394     GNUNET_SCHEDULER_add_now (&do_error, handle);
395     return;
396   }
397   resp = GNUNET_REST_create_json_response (NULL);
398   handle->proc (handle->proc_cls, resp, MHD_HTTP_NO_CONTENT);
399   cleanup_handle (handle);
400 }
401
402 static void
403 create_finished (void *cls, const char *emsg)
404 {
405   struct RequestHandle *handle = cls;
406   struct MHD_Response *resp;
407
408   handle->op = NULL;
409   if (NULL != emsg)
410   {
411     GNUNET_SCHEDULER_add_now (&do_error, handle);
412     return;
413   }
414   resp = GNUNET_REST_create_json_response (NULL);
415   handle->proc (handle->proc_cls, resp, MHD_HTTP_NO_CONTENT);
416   cleanup_handle (handle);
417 }
418
419 static void
420 ego_create_cont (struct RestConnectionDataHandle *con,
421                  const char *url,
422                  void *cls)
423 {
424   struct RequestHandle *handle = cls;
425   struct EgoEntry *ego_entry;
426   struct MHD_Response *resp;
427   struct JsonApiObject *json_obj;
428   struct JsonApiResource *json_res;
429   json_t *egoname_json;
430   char term_data[handle->data_size+1];
431   const char* egoname;
432
433   if (strlen (API_NAMESPACE) != strlen (handle->url))
434   {
435     GNUNET_SCHEDULER_add_now (&do_error, handle);
436     return;
437   }
438   if (0 >= handle->data_size)
439   {
440     GNUNET_SCHEDULER_add_now (&do_error, handle);
441     return;
442   }
443   term_data[handle->data_size] = '\0';
444   memcpy (term_data, handle->data, handle->data_size);
445   json_obj = GNUNET_REST_jsonapi_object_parse (term_data);
446
447   if (NULL == json_obj)
448   {
449     GNUNET_SCHEDULER_add_now (&do_error, handle);
450     return;
451   }
452   if (1 != GNUNET_REST_jsonapi_object_resource_count (json_obj))
453   {
454     GNUNET_REST_jsonapi_object_delete (json_obj);
455     GNUNET_SCHEDULER_add_now (&do_error, handle);
456     return;
457   }
458
459   json_res = GNUNET_REST_jsonapi_object_get_resource (json_obj, 0);
460   if (GNUNET_NO == GNUNET_REST_jsonapi_resource_check_type (json_res, GNUNET_REST_JSONAPI_IDENTITY_EGO))
461   {
462     GNUNET_REST_jsonapi_object_delete (json_obj);
463     resp = GNUNET_REST_create_json_response (NULL);
464     handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
465     cleanup_handle (handle);
466     return;
467   }
468   
469   egoname_json = GNUNET_REST_jsonapi_resource_read_attr (json_res, GNUNET_REST_JSONAPI_KEY_ID);
470   if (!json_is_string (egoname_json))
471   {
472     GNUNET_REST_jsonapi_object_delete (json_obj); 
473     GNUNET_SCHEDULER_add_now (&do_error, handle);
474     return;
475   }
476   egoname = json_string_value (egoname_json);
477   for (ego_entry = handle->ego_head;
478        NULL != ego_entry;
479        ego_entry = ego_entry->next)
480   {
481     if (0 == strcasecmp (egoname, ego_entry->identifier))
482     {
483       json_decref (egoname_json);
484       GNUNET_REST_jsonapi_object_delete (json_obj);
485       resp = GNUNET_REST_create_json_response (NULL);
486       handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
487       cleanup_handle (handle);
488       return;
489     }
490   }
491   GNUNET_asprintf (&handle->name, "%s", egoname);
492   json_decref (egoname_json);
493   GNUNET_REST_jsonapi_object_delete (json_obj);
494   handle->op = GNUNET_IDENTITY_create (handle->identity_handle,
495                                        handle->name,
496                                        &create_finished,
497                                        handle);
498 }
499
500 void 
501 subsys_set_cont (struct RestConnectionDataHandle *con,
502                  const char *url,
503                  void *cls)
504 {
505   struct JsonApiObject *json_obj;
506   struct JsonApiResource *json_res;
507   const char *egoname;
508   const char *subsys;
509   struct RequestHandle *handle = cls;
510   char term_data[handle->data_size+1];
511   struct EgoEntry *ego_entry;
512   struct MHD_Response *resp;
513   int ego_exists = GNUNET_NO;
514   json_t *subsys_json;
515   
516   if (strlen (API_NAMESPACE) > strlen (handle->url))
517   {
518     GNUNET_SCHEDULER_add_now (&do_error, handle);
519     return;
520   }
521
522   egoname = &handle->url[strlen(EGO_NAMESPACE)+1];
523   for (ego_entry = handle->ego_head;
524        NULL != ego_entry;
525        ego_entry = ego_entry->next)
526   {
527     if (0 == strcasecmp (egoname, ego_entry->identifier))
528     {
529       ego_exists = GNUNET_YES;
530       break;
531     }
532   }
533   if (GNUNET_NO == ego_exists)
534   {
535     resp = GNUNET_REST_create_json_response (NULL);
536     handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
537     cleanup_handle (handle);
538     return;
539   }
540
541   if (0 >= handle->data_size)
542   {
543     GNUNET_SCHEDULER_add_now (&do_error, handle);
544     return;
545   }
546
547   term_data[handle->data_size] = '\0';
548   memcpy (term_data, handle->data, handle->data_size);
549   json_obj = GNUNET_REST_jsonapi_object_parse (term_data);
550
551   if (NULL == json_obj)
552   {
553     GNUNET_SCHEDULER_add_now (&do_error, handle);
554     return;
555   }
556   if (1 != GNUNET_REST_jsonapi_object_resource_count (json_obj))
557   {
558     GNUNET_REST_jsonapi_object_delete (json_obj);
559     GNUNET_SCHEDULER_add_now (&do_error, handle);
560     return;
561   }
562
563   json_res = GNUNET_REST_jsonapi_object_get_resource (json_obj, 0);
564   if (GNUNET_NO == GNUNET_REST_jsonapi_resource_check_id (json_res, egoname))
565   {
566     GNUNET_REST_jsonapi_object_delete (json_obj);
567     GNUNET_SCHEDULER_add_now (&do_error, handle);
568     return;
569   }
570   
571   if (GNUNET_NO == GNUNET_REST_jsonapi_resource_check_id (json_res, GNUNET_REST_JSONAPI_IDENTITY_EGO))
572   {
573     GNUNET_REST_jsonapi_object_delete (json_obj);
574     GNUNET_SCHEDULER_add_now (&do_error, handle);
575     return;
576   }
577
578   subsys_json = GNUNET_REST_jsonapi_resource_read_attr (json_res, GNUNET_REST_JSONAPI_IDENTITY_SUBSYSTEM);
579   if (!json_is_string (subsys_json))
580   {
581     json_decref (subsys_json);
582     GNUNET_REST_jsonapi_object_delete (json_obj);
583     GNUNET_SCHEDULER_add_now (&do_error, handle);
584     return;
585   }
586   subsys = json_string_value (subsys_json);
587   GNUNET_asprintf (&handle->subsys, "%s", subsys);
588   json_decref (subsys_json);
589   GNUNET_REST_jsonapi_object_delete (json_obj);
590   handle->op = GNUNET_IDENTITY_set (handle->identity_handle,
591                                     handle->subsys,
592                                     ego_entry->ego,
593                                     &set_finished,
594                                     handle);
595 }
596
597 void 
598 ego_delete_cont (struct RestConnectionDataHandle *con_handle,
599                  const char* url,
600                  void *cls)
601 {
602   const char *egoname;
603   struct EgoEntry *ego_entry;
604   struct MHD_Response *resp;
605   struct RequestHandle *handle = cls;
606   int ego_exists = GNUNET_NO;
607
608   if (strlen (API_NAMESPACE) >= strlen (handle->url))
609   {
610     GNUNET_SCHEDULER_add_now (&do_error, handle);
611     return;
612   }
613
614   egoname = &handle->url[strlen(API_NAMESPACE)+1];
615   for (ego_entry = handle->ego_head;
616        NULL != ego_entry;
617        ego_entry = ego_entry->next)
618   {
619     if (0 == strcasecmp (egoname, ego_entry->identifier))
620     {
621       ego_exists = GNUNET_YES;
622       break;
623     }
624   }
625   if (GNUNET_NO == ego_exists)
626   {
627     resp = GNUNET_REST_create_json_response (NULL);
628     handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
629     cleanup_handle (handle);
630     return;
631   }
632   handle->op = GNUNET_IDENTITY_delete (handle->identity_handle,
633                                        egoname,
634                                        &do_finished,
635                                        handle);
636
637 }
638
639 void
640 init_cont (struct RequestHandle *handle)
641 {
642   static const struct GNUNET_REST_RestConnectionHandler handlers[] = {
643     {MHD_HTTP_METHOD_GET, API_NAMESPACE, &ego_info_response},
644     {MHD_HTTP_METHOD_POST, API_NAMESPACE, &ego_create_cont},
645     {MHD_HTTP_METHOD_PUT, API_NAMESPACE, &subsys_set_cont},
646     {MHD_HTTP_METHOD_DELETE, API_NAMESPACE, &ego_delete_cont},
647     GNUNET_REST_HANDLER_END
648   };
649
650   if (GNUNET_NO == GNUNET_REST_handle_request (handle->conndata_handle, handlers, handle))
651     GNUNET_SCHEDULER_add_now (&do_error, handle);
652 }
653
654 /**
655  * If listing is enabled, prints information about the egos.
656  *
657  * This function is initially called for all egos and then again
658  * whenever a ego's identifier changes or if it is deleted.  At the
659  * end of the initial pass over all egos, the function is once called
660  * with 'NULL' for 'ego'. That does NOT mean that the callback won't
661  * be invoked in the future or that there was an error.
662  *
663  * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
664  * this function is only called ONCE, and 'NULL' being passed in
665  * 'ego' does indicate an error (i.e. name is taken or no default
666  * value is known).  If 'ego' is non-NULL and if '*ctx'
667  * is set in those callbacks, the value WILL be passed to a subsequent
668  * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
669  * that one was not NULL).
670  *
671  * When an identity is renamed, this function is called with the
672  * (known) ego but the NEW identifier.
673  *
674  * When an identity is deleted, this function is called with the
675  * (known) ego and "NULL" for the 'identifier'.  In this case,
676  * the 'ego' is henceforth invalid (and the 'ctx' should also be
677  * cleaned up).
678  *
679  * @param cls closure
680  * @param ego ego handle
681  * @param ctx context for application to store data for this ego
682  *                 (during the lifetime of this process, initially NULL)
683  * @param identifier identifier assigned by the user for this ego,
684  *                   NULL if the user just deleted the ego and it
685  *                   must thus no longer be used
686  */
687 static void
688 list_ego (void *cls,
689           struct GNUNET_IDENTITY_Ego *ego,
690           void **ctx,
691           const char *identifier)
692 {
693   struct RequestHandle *handle = cls;
694   struct EgoEntry *ego_entry;
695
696   if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
697   {
698     handle->state = ID_REST_STATE_POST_INIT;
699     init_cont (handle);
700     return;
701   }
702   if (ID_REST_STATE_INIT == handle->state) {
703     ego_entry = GNUNET_new (struct EgoEntry);
704     GNUNET_IDENTITY_ego_get_public_key (ego, &(ego_entry->pk));
705     ego_entry->ego = ego;
706     GNUNET_asprintf (&ego_entry->identifier, "%s", identifier);
707     GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry);
708   }
709
710 }
711
712 /**
713  * Function processing the REST call
714  *
715  * @param method HTTP method
716  * @param url URL of the HTTP request
717  * @param data body of the HTTP request (optional)
718  * @param data_size length of the body
719  * @param proc callback function for the result
720  * @param proc_cls closure for callback function
721  * @return GNUNET_OK if request accepted
722  */
723 void
724 rest_identity_process_request(struct RestConnectionDataHandle *conndata_handle,
725                               GNUNET_REST_ResultProcessor proc,
726                               void *proc_cls)
727 {
728   struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
729
730
731
732   handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
733
734   handle->proc_cls = proc_cls;
735   handle->proc = proc;
736   handle->state = ID_REST_STATE_INIT;
737   handle->conndata_handle = conndata_handle;
738   handle->data = conndata_handle->data;
739   handle->data_size = conndata_handle->data_size;
740   handle->method = conndata_handle->method;
741   GNUNET_asprintf (&handle->url, "%s", conndata_handle->url);
742   if (handle->url[strlen (handle->url)-1] == '/')
743     handle->url[strlen (handle->url)-1] = '\0';
744   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
745               "Connecting...\n");
746   handle->identity_handle = GNUNET_IDENTITY_connect (cfg,
747                                                      &list_ego,
748                                                      handle); 
749   handle->timeout_task =
750     GNUNET_SCHEDULER_add_delayed (handle->timeout,
751                                   &do_error,
752                                   handle);
753
754
755   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
756               "Connected\n");
757 }
758
759 /**
760  * Entry point for the plugin.
761  *
762  * @param cls Config info
763  * @return NULL on error, otherwise the plugin context
764  */
765 void *
766 libgnunet_plugin_rest_identity_init (void *cls)
767 {
768   static struct Plugin plugin;
769   cfg = cls;
770   struct GNUNET_REST_Plugin *api;
771
772   if (NULL != plugin.cfg)
773     return NULL;                /* can only initialize once! */
774   memset (&plugin, 0, sizeof (struct Plugin));
775   plugin.cfg = cfg;
776   api = GNUNET_new (struct GNUNET_REST_Plugin);
777   api->cls = &plugin;
778   api->name = API_NAMESPACE;
779   api->process_request = &rest_identity_process_request;
780   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
781               _("Identity REST API initialized\n"));
782   return api;
783 }
784
785
786 /**
787  * Exit point from the plugin.
788  *
789  * @param cls the plugin context (as returned by "init")
790  * @return always NULL
791  */
792 void *
793 libgnunet_plugin_rest_identity_done (void *cls)
794 {
795   struct GNUNET_REST_Plugin *api = cls;
796   struct Plugin *plugin = api->cls;
797
798   plugin->cfg = NULL;
799   GNUNET_free (api);
800   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
801               "Identity REST plugin is finished\n");
802   return NULL;
803 }
804
805 /* end of plugin_rest_gns.c */