error handling
[oweals/gnunet.git] / src / namestore / plugin_rest_namestore.c
1 /*
2    This file is part of GNUnet.
3    Copyright (C) 2012-2015 GNUnet e.V.
4
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.
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    Affero General Public License for more details.
14
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/>.
17
18      SPDX-License-Identifier: AGPL3.0-or-later
19  */
20 /**
21  * @author Martin Schanzenbach
22  * @author Philippe Buschmann
23  * @file namestore/plugin_rest_namestore.c
24  * @brief GNUnet Namestore REST plugin
25  */
26
27 #include "platform.h"
28 #include "gnunet_rest_plugin.h"
29 #include "gnunet_gns_service.h"
30 #include "gnunet_namestore_service.h"
31 #include "gnunet_identity_service.h"
32 #include "gnunet_rest_lib.h"
33 #include "gnunet_json_lib.h"
34 #include "microhttpd.h"
35 #include <jansson.h>
36
37 /**
38  * Namestore Namespace
39  */
40 #define GNUNET_REST_API_NS_NAMESTORE "/namestore"
41
42 /**
43  * Error message Unknown Error
44  */
45 #define GNUNET_REST_NAMESTORE_ERROR_UNKNOWN "Unknown Error"
46
47 /**
48  * Error message No identity found
49  */
50 #define GNUNET_REST_IDENTITY_NOT_FOUND "No identity found"
51
52
53 /**
54  * Error message Failed request
55  */
56 #define GNUNET_REST_NAMESTORE_FAILED "Namestore action failed"
57
58 /**
59  * Error message invalid data
60  */
61 #define GNUNET_REST_NAMESTORE_INVALID_DATA "Data invalid"
62
63 /**
64  * Error message No data
65  */
66 #define GNUNET_REST_NAMESTORE_NO_DATA "No data"
67
68 /**
69  * State while collecting all egos
70  */
71 #define ID_REST_STATE_INIT 0
72
73 /**
74  * Done collecting egos
75  */
76 #define ID_REST_STATE_POST_INIT 1
77 /**
78  * The configuration handle
79  */
80 const struct GNUNET_CONFIGURATION_Handle *cfg;
81
82 /**
83  * HTTP methods allows for this plugin
84  */
85 static char *allow_methods;
86
87 /**
88  * @brief struct returned by the initialization function of the plugin
89  */
90 struct Plugin
91 {
92   const struct GNUNET_CONFIGURATION_Handle *cfg;
93 };
94
95 /**
96  * The default namestore ego
97  */
98 struct EgoEntry
99 {
100   /**
101    * DLL
102    */
103   struct EgoEntry *next;
104
105   /**
106    * DLL
107    */
108   struct EgoEntry *prev;
109
110   /**
111    * Ego Identifier
112    */
113   char *identifier;
114
115   /**
116    * Public key string
117    */
118   char *keystring;
119
120   /**
121    * The Ego
122    */
123   struct GNUNET_IDENTITY_Ego *ego;
124 };
125
126 /**
127  * The request handle
128  */
129 struct RequestHandle
130 {
131   /**
132    * Records to store
133    */
134   char *record_name;
135
136   /**
137    * Records to store
138    */
139   struct GNUNET_GNSRECORD_Data *rd;
140
141   /**
142    * Number of records in rd
143    */
144   unsigned int rd_count;
145
146   /**
147    * NAMESTORE Operation
148    */
149   struct GNUNET_NAMESTORE_QueueEntry *add_qe;
150
151   /**
152    * Response object
153    */
154   json_t *resp_object;
155
156   /**
157    * The processing state
158    */
159   int state;
160
161   /**
162    * Handle to NAMESTORE
163    */
164   struct GNUNET_NAMESTORE_Handle *ns_handle;
165
166   /**
167    * Handle to NAMESTORE it
168    */
169   struct GNUNET_NAMESTORE_ZoneIterator *list_it;
170
171   /**
172    * Private key for the zone
173    */
174   const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_pkey;
175
176   /**
177    * IDENTITY Operation
178    */
179   struct EgoEntry *ego_entry;
180
181   /**
182    * Ego list
183    */
184   struct EgoEntry *ego_head;
185
186   /**
187    * Ego list
188    */
189   struct EgoEntry *ego_tail;
190
191   /**
192    * IDENTITY Operation
193    */
194   struct GNUNET_IDENTITY_Operation *op;
195
196   /**
197    * Handle to Identity service.
198    */
199   struct GNUNET_IDENTITY_Handle *identity_handle;
200
201   /**
202    * Rest connection
203    */
204   struct GNUNET_REST_RequestHandle *rest_handle;
205
206   /**
207    * Desired timeout for the lookup (default is no timeout).
208    */
209   struct GNUNET_TIME_Relative timeout;
210
211   /**
212    * ID of a task associated with the resolution process.
213    */
214   struct GNUNET_SCHEDULER_Task *timeout_task;
215
216   /**
217    * The plugin result processor
218    */
219   GNUNET_REST_ResultProcessor proc;
220
221   /**
222    * The closure of the result processor
223    */
224   void *proc_cls;
225
226   /**
227    * The url
228    */
229   char *url;
230
231   /**
232    * Error response message
233    */
234   char *emsg;
235
236   /**
237    * Response code
238    */
239   int response_code;
240 };
241
242 /**
243  * Cleanup lookup handle
244  * @param handle Handle to clean up
245  */
246 static void
247 cleanup_handle (void *cls)
248 {
249   struct RequestHandle *handle = cls;
250   struct EgoEntry *ego_entry;
251   struct EgoEntry *ego_tmp;
252
253   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
254   if (NULL != handle->timeout_task)
255   {
256     GNUNET_SCHEDULER_cancel (handle->timeout_task);
257     handle->timeout_task = NULL;
258   }
259   if (NULL != handle->record_name)
260     GNUNET_free (handle->record_name);
261   if (NULL != handle->url)
262     GNUNET_free (handle->url);
263   if (NULL != handle->emsg)
264     GNUNET_free (handle->emsg);
265   if (NULL != handle->rd)
266   {
267     for (int i = 0; i < handle->rd_count; i++)
268     {
269       if (NULL != handle->rd[i].data)
270         GNUNET_free ((void *) handle->rd[i].data);
271     }
272     GNUNET_free (handle->rd);
273   }
274   if (NULL != handle->timeout_task)
275     GNUNET_SCHEDULER_cancel (handle->timeout_task);
276   if (NULL != handle->list_it)
277     GNUNET_NAMESTORE_zone_iteration_stop (handle->list_it);
278   if (NULL != handle->add_qe)
279     GNUNET_NAMESTORE_cancel (handle->add_qe);
280   if (NULL != handle->identity_handle)
281     GNUNET_IDENTITY_disconnect (handle->identity_handle);
282   if (NULL != handle->ns_handle)
283   {
284     GNUNET_NAMESTORE_disconnect (handle->ns_handle);
285   }
286
287   for (ego_entry = handle->ego_head; NULL != ego_entry;)
288   {
289     ego_tmp = ego_entry;
290     ego_entry = ego_entry->next;
291     GNUNET_free (ego_tmp->identifier);
292     GNUNET_free (ego_tmp->keystring);
293     GNUNET_free (ego_tmp);
294   }
295
296   if (NULL != handle->resp_object)
297   {
298     json_decref (handle->resp_object);
299   }
300
301   GNUNET_free (handle);
302 }
303
304
305 /**
306  * Task run on errors.  Reports an error and cleans up everything.
307  *
308  * @param cls the `struct RequestHandle`
309  */
310 static void
311 do_error (void *cls)
312 {
313   struct RequestHandle *handle = cls;
314   struct MHD_Response *resp;
315   json_t *json_error = json_object ();
316   char *response;
317
318   if (NULL == handle->emsg)
319     handle->emsg = GNUNET_strdup (GNUNET_REST_NAMESTORE_ERROR_UNKNOWN);
320
321   json_object_set_new (json_error, "error", json_string (handle->emsg));
322
323   if (0 == handle->response_code)
324     handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
325   response = json_dumps (json_error, 0);
326   resp = GNUNET_REST_create_response (response);
327   handle->proc (handle->proc_cls, resp, handle->response_code);
328   json_decref (json_error);
329   GNUNET_free (response);
330   GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
331 }
332
333
334 /**
335  * Get EgoEntry from list with either a public key or a name
336  * If public key and name are not NULL, it returns the public key result first
337  *
338  * @param handle the RequestHandle
339  * @param pubkey the public key of an identity (only one can be NULL)
340  * @param name the name of an identity (only one can be NULL)
341  * @return EgoEntry or NULL if not found
342  */
343 struct EgoEntry *
344 get_egoentry_namestore (struct RequestHandle *handle, char *name)
345 {
346   struct EgoEntry *ego_entry;
347
348   if (NULL != name)
349   {
350     for (ego_entry = handle->ego_head; NULL != ego_entry;
351          ego_entry = ego_entry->next)
352     {
353       if (0 != strcasecmp (name, ego_entry->identifier))
354         continue;
355       return ego_entry;
356     }
357   }
358   return NULL;
359 }
360
361
362 /**
363  * Does internal server error when iteration failed.
364  *
365  * @param cls the `struct RequestHandle`
366  */
367 static void
368 namestore_iteration_error (void *cls)
369 {
370   struct RequestHandle *handle = cls;
371
372   handle->emsg = GNUNET_strdup (GNUNET_REST_NAMESTORE_FAILED);
373   GNUNET_SCHEDULER_add_now (&do_error, handle);
374   return;
375 }
376
377
378 /**
379  * Create finished callback
380  *
381  * @param cls the `struct RequestHandle`
382  * @param success the success indicating integer, GNUNET_OK on success
383  * @param emsg the error message (can be NULL)
384  */
385 static void
386 create_finished (void *cls, int32_t success, const char *emsg)
387 {
388   struct RequestHandle *handle = cls;
389   struct MHD_Response *resp;
390
391   handle->add_qe = NULL;
392   if (GNUNET_YES != success)
393   {
394     if (NULL != emsg)
395     {
396       handle->emsg = GNUNET_strdup (emsg);
397       GNUNET_SCHEDULER_add_now (&do_error, handle);
398       return;
399     }
400     handle->emsg = GNUNET_strdup ("Error storing records");
401     GNUNET_SCHEDULER_add_now (&do_error, handle);
402     return;
403   }
404   resp = GNUNET_REST_create_response (NULL);
405   handle->proc (handle->proc_cls, resp, MHD_HTTP_NO_CONTENT);
406   GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
407 }
408
409
410 /**
411  * Delete finished callback
412  *
413  * @param cls the `struct RequestHandle`
414  * @param success the success indicating integer, GNUNET_OK on success
415  * @param emsg the error message (can be NULL)
416  */
417 static void
418 del_finished (void *cls, int32_t success, const char *emsg)
419 {
420   struct RequestHandle *handle = cls;
421
422   handle->add_qe = NULL;
423   if (GNUNET_NO == success)
424   {
425     handle->response_code = MHD_HTTP_NOT_FOUND;
426     handle->emsg = GNUNET_strdup ("No record found");
427     GNUNET_SCHEDULER_add_now (&do_error, handle);
428     return;
429   }
430   if (GNUNET_SYSERR == success)
431   {
432     if (NULL != emsg)
433     {
434       handle->emsg = GNUNET_strdup (emsg);
435       GNUNET_SCHEDULER_add_now (&do_error, handle);
436       return;
437     }
438     handle->emsg = GNUNET_strdup ("Deleting record failed");
439     GNUNET_SCHEDULER_add_now (&do_error, handle);
440     return;
441   }
442   handle->proc (handle->proc_cls,
443                 GNUNET_REST_create_response (NULL),
444                 MHD_HTTP_NO_CONTENT);
445   GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
446 }
447
448
449 /**
450  * Iteration over all results finished, build final
451  * response.
452  *
453  * @param cls the `struct RequestHandle`
454  */
455 static void
456 namestore_list_finished (void *cls)
457 {
458   struct RequestHandle *handle = cls;
459   char *result_str;
460   struct MHD_Response *resp;
461
462   handle->list_it = NULL;
463
464   if (NULL == handle->resp_object)
465     handle->resp_object = json_array ();
466
467   result_str = json_dumps (handle->resp_object, 0);
468   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
469   resp = GNUNET_REST_create_response (result_str);
470   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
471   GNUNET_free_non_null (result_str);
472   GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
473 }
474
475
476 /**
477  * Create a response with requested records
478  *
479  * @param handle the RequestHandle
480  */
481 static void
482 namestore_list_iteration (void *cls,
483                           const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
484                           const char *rname,
485                           unsigned int rd_len,
486                           const struct GNUNET_GNSRECORD_Data *rd)
487 {
488   struct RequestHandle *handle = cls;
489   json_t *record_obj;
490
491   if (NULL == handle->resp_object)
492     handle->resp_object = json_array ();
493   record_obj = GNUNET_JSON_from_gnsrecord (rname,
494                                            rd,
495                                            rd_len);
496   json_array_append_new (handle->resp_object, record_obj);
497   GNUNET_NAMESTORE_zone_iterator_next (handle->list_it, 1);
498 }
499
500
501 /**
502  * Handle namestore GET request
503  *
504  * @param con_handle the connection handle
505  * @param url the url
506  * @param cls the RequestHandle
507  */
508 void
509 namestore_get (struct GNUNET_REST_RequestHandle *con_handle,
510                const char *url,
511                void *cls)
512 {
513   struct RequestHandle *handle = cls;
514   struct EgoEntry *ego_entry;
515   char *egoname;
516
517   egoname = NULL;
518   ego_entry = NULL;
519
520   // set zone to name if given
521   if (strlen (GNUNET_REST_API_NS_NAMESTORE) < strlen (handle->url))
522   {
523     egoname = &handle->url[strlen (GNUNET_REST_API_NS_NAMESTORE) + 1];
524     ego_entry = get_egoentry_namestore (handle, egoname);
525
526     if (NULL == ego_entry)
527     {
528       handle->response_code = MHD_HTTP_NOT_FOUND;
529       handle->emsg = GNUNET_strdup (GNUNET_REST_IDENTITY_NOT_FOUND);
530       GNUNET_SCHEDULER_add_now (&do_error, handle);
531       return;
532     }
533   }
534   if (NULL != ego_entry)
535     handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
536
537   handle->list_it =
538     GNUNET_NAMESTORE_zone_iteration_start (handle->ns_handle,
539                                            handle->zone_pkey,
540                                            &namestore_iteration_error,
541                                            handle,
542                                            &namestore_list_iteration,
543                                            handle,
544                                            &namestore_list_finished,
545                                            handle);
546   if (NULL == handle->list_it)
547   {
548     handle->emsg = GNUNET_strdup (GNUNET_REST_NAMESTORE_FAILED);
549     GNUNET_SCHEDULER_add_now (&do_error, handle);
550     return;
551   }
552 }
553
554
555 static void
556 ns_lookup_error_cb (void *cls)
557 {
558   struct RequestHandle *handle = cls;
559
560   handle->emsg = GNUNET_strdup (GNUNET_REST_NAMESTORE_FAILED);
561   GNUNET_SCHEDULER_add_now (&do_error, handle);
562 }
563
564
565 static void
566 ns_lookup_cb (void *cls,
567               const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
568               const char *label,
569               unsigned int rd_count,
570               const struct GNUNET_GNSRECORD_Data *rd)
571 {
572   struct RequestHandle *handle = cls;
573   struct GNUNET_GNSRECORD_Data rd_new[rd_count + handle->rd_count];
574
575   for (int i = 0; i < rd_count; i++)
576     rd_new[i] = rd[i];
577   for (int j = 0; j < handle->rd_count; j++)
578     rd_new[rd_count + j] = handle->rd[j];
579   handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
580                                                    handle->zone_pkey,
581                                                    handle->record_name,
582                                                    rd_count + handle->rd_count,
583                                                    rd_new,
584                                                    &create_finished,
585                                                    handle);
586   if (NULL == handle->add_qe)
587   {
588     handle->emsg = GNUNET_strdup (GNUNET_REST_NAMESTORE_FAILED);
589     GNUNET_SCHEDULER_add_now (&do_error, handle);
590     return;
591   }
592 }
593
594
595 /**
596  * Handle namestore POST request
597  *
598  * @param con_handle the connection handle
599  * @param url the url
600  * @param cls the RequestHandle
601  */
602 void
603 namestore_add (struct GNUNET_REST_RequestHandle *con_handle,
604                const char *url,
605                void *cls)
606 {
607   struct RequestHandle *handle = cls;
608   struct EgoEntry *ego_entry;
609   char *egoname;
610   json_t *data_js;
611   json_error_t err;
612
613   char term_data[handle->rest_handle->data_size + 1];
614
615   if (0 >= handle->rest_handle->data_size)
616   {
617     handle->emsg = GNUNET_strdup (GNUNET_REST_NAMESTORE_NO_DATA);
618     GNUNET_SCHEDULER_add_now (&do_error, handle);
619     return;
620   }
621   term_data[handle->rest_handle->data_size] = '\0';
622   GNUNET_memcpy (term_data,
623                  handle->rest_handle->data,
624                  handle->rest_handle->data_size);
625   data_js = json_loads (term_data, JSON_DECODE_ANY, &err);
626   struct GNUNET_JSON_Specification gnsspec[] =
627   { GNUNET_JSON_spec_gnsrecord (&handle->rd, &handle->rd_count,
628                                 &handle->record_name),
629     GNUNET_JSON_spec_end () };
630   if (GNUNET_OK != GNUNET_JSON_parse (data_js, gnsspec, NULL, NULL))
631   {
632     handle->emsg = GNUNET_strdup (GNUNET_REST_NAMESTORE_INVALID_DATA);
633     GNUNET_SCHEDULER_add_now (&do_error, handle);
634     json_decref (data_js);
635     return;
636   }
637   GNUNET_JSON_parse_free (gnsspec);
638   if (0 >= strlen (handle->record_name))
639   {
640     handle->emsg = GNUNET_strdup (GNUNET_REST_NAMESTORE_INVALID_DATA);
641     GNUNET_SCHEDULER_add_now (&do_error, handle);
642     json_decref (data_js);
643     return;
644   }
645   json_decref (data_js);
646
647   egoname = NULL;
648   ego_entry = NULL;
649
650   // set zone to name if given
651   if (strlen (GNUNET_REST_API_NS_NAMESTORE) < strlen (handle->url))
652   {
653     egoname = &handle->url[strlen (GNUNET_REST_API_NS_NAMESTORE) + 1];
654     ego_entry = get_egoentry_namestore (handle, egoname);
655
656     if (NULL == ego_entry)
657     {
658       handle->response_code = MHD_HTTP_NOT_FOUND;
659       handle->emsg = GNUNET_strdup (GNUNET_REST_IDENTITY_NOT_FOUND);
660       GNUNET_SCHEDULER_add_now (&do_error, handle);
661       return;
662     }
663   }
664   if (NULL != ego_entry)
665     handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
666   handle->add_qe = GNUNET_NAMESTORE_records_lookup (handle->ns_handle,
667                                                     handle->zone_pkey,
668                                                     handle->record_name,
669                                                     &ns_lookup_error_cb,
670                                                     handle,
671                                                     &ns_lookup_cb,
672                                                     handle);
673   if (NULL == handle->add_qe)
674   {
675     handle->emsg = GNUNET_strdup (GNUNET_REST_NAMESTORE_FAILED);
676     GNUNET_SCHEDULER_add_now (&do_error, handle);
677     return;
678   }
679 }
680
681
682 /**
683  * Handle namestore DELETE request
684  *
685  * @param con_handle the connection handle
686  * @param url the url
687  * @param cls the RequestHandle
688  */
689 void
690 namestore_delete (struct GNUNET_REST_RequestHandle *con_handle,
691                   const char *url,
692                   void *cls)
693 {
694   struct RequestHandle *handle = cls;
695   struct GNUNET_HashCode key;
696   struct EgoEntry *ego_entry;
697   char *egoname;
698
699   egoname = NULL;
700   ego_entry = NULL;
701
702   // set zone to name if given
703   if (strlen (GNUNET_REST_API_NS_NAMESTORE) < strlen (handle->url))
704   {
705     egoname = &handle->url[strlen (GNUNET_REST_API_NS_NAMESTORE) + 1];
706     ego_entry = get_egoentry_namestore (handle, egoname);
707
708     if (NULL == ego_entry)
709     {
710       handle->response_code = MHD_HTTP_NOT_FOUND;
711       handle->emsg = GNUNET_strdup (GNUNET_REST_IDENTITY_NOT_FOUND);
712       GNUNET_SCHEDULER_add_now (&do_error, handle);
713       return;
714     }
715   }
716   if (NULL != ego_entry)
717     handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
718
719   GNUNET_CRYPTO_hash ("record_name", strlen ("record_name"), &key);
720   if (GNUNET_NO ==
721       GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map, &key))
722   {
723     handle->emsg = GNUNET_strdup (GNUNET_REST_NAMESTORE_INVALID_DATA);
724     GNUNET_SCHEDULER_add_now (&do_error, handle);
725     return;
726   }
727   handle->record_name = GNUNET_strdup (
728     GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map, &key));
729
730   handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
731                                                    handle->zone_pkey,
732                                                    handle->record_name,
733                                                    0,
734                                                    NULL,
735                                                    &del_finished,
736                                                    handle);
737   if (NULL == handle->add_qe)
738   {
739     handle->emsg = GNUNET_strdup (GNUNET_REST_NAMESTORE_FAILED);
740     GNUNET_SCHEDULER_add_now (&do_error, handle);
741     return;
742   }
743 }
744
745
746 /**
747  * Respond to OPTIONS request
748  *
749  * @param con_handle the connection handle
750  * @param url the url
751  * @param cls the RequestHandle
752  */
753 static void
754 options_cont (struct GNUNET_REST_RequestHandle *con_handle,
755               const char *url,
756               void *cls)
757 {
758   struct MHD_Response *resp;
759   struct RequestHandle *handle = cls;
760
761   // independent of path return all options
762   resp = GNUNET_REST_create_response (NULL);
763   MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods);
764   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
765   GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
766   return;
767 }
768
769
770 /**
771  * Handle rest request
772  *
773  * @param handle the request handle
774  */
775 static void
776 init_cont (struct RequestHandle *handle)
777 {
778   struct GNUNET_REST_RequestHandlerError err;
779   static const struct GNUNET_REST_RequestHandler handlers[] =
780   { { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_NAMESTORE, &namestore_get },
781     { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_NAMESTORE, &namestore_add },
782     { MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_NAMESTORE, &namestore_delete },
783     { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_NAMESTORE, &options_cont },
784     GNUNET_REST_HANDLER_END };
785
786   if (GNUNET_NO ==
787       GNUNET_REST_handle_request (handle->rest_handle, handlers, &err, handle))
788   {
789     handle->response_code = err.error_code;
790     GNUNET_SCHEDULER_add_now (&do_error, handle);
791   }
792 }
793
794
795 /**
796  * This function is initially called for all egos and then again
797  * whenever a ego's identifier changes or if it is deleted.  At the
798  * end of the initial pass over all egos, the function is once called
799  * with 'NULL' for 'ego'. That does NOT mean that the callback won't
800  * be invoked in the future or that there was an error.
801  *
802  * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
803  * this function is only called ONCE, and 'NULL' being passed in
804  * 'ego' does indicate an error (i.e. name is taken or no default
805  * value is known).  If 'ego' is non-NULL and if '*ctx'
806  * is set in those callbacks, the value WILL be passed to a subsequent
807  * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
808  * that one was not NULL).
809  *
810  * When an identity is renamed, this function is called with the
811  * (known) ego but the NEW identifier.
812  *
813  * When an identity is deleted, this function is called with the
814  * (known) ego and "NULL" for the 'identifier'.  In this case,
815  * the 'ego' is henceforth invalid (and the 'ctx' should also be
816  * cleaned up).
817  *
818  * @param cls closure
819  * @param ego ego handle
820  * @param ctx context for application to store data for this ego
821  *                 (during the lifetime of this process, initially NULL)
822  * @param name identifier assigned by the user for this ego,
823  *                   NULL if the user just deleted the ego and it
824  *                   must thus no longer be used
825  */
826 static void
827 id_connect_cb (void *cls,
828                struct GNUNET_IDENTITY_Ego *ego,
829                void **ctx,
830                const char *name)
831 {
832   struct RequestHandle *handle = cls;
833   struct EgoEntry *ego_entry;
834   struct GNUNET_CRYPTO_EcdsaPublicKey pk;
835
836   if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
837   {
838     handle->state = ID_REST_STATE_POST_INIT;
839     init_cont (handle);
840     return;
841   }
842   if (ID_REST_STATE_INIT == handle->state)
843   {
844     ego_entry = GNUNET_new (struct EgoEntry);
845     GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
846     ego_entry->keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
847     ego_entry->ego = ego;
848     GNUNET_asprintf (&ego_entry->identifier, "%s", name);
849     GNUNET_CONTAINER_DLL_insert_tail (handle->ego_head,
850                                       handle->ego_tail,
851                                       ego_entry);
852   }
853 }
854
855
856 /**
857  * Function processing the REST call
858  *
859  * @param method HTTP method
860  * @param url URL of the HTTP request
861  * @param data body of the HTTP request (optional)
862  * @param data_size length of the body
863  * @param proc callback function for the result
864  * @param proc_cls closure for callback function
865  * @return GNUNET_OK if request accepted
866  */
867 static void
868 rest_process_request (struct GNUNET_REST_RequestHandle *rest_handle,
869                       GNUNET_REST_ResultProcessor proc,
870                       void *proc_cls)
871 {
872   struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
873
874   handle->response_code = 0;
875   handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
876   handle->proc_cls = proc_cls;
877   handle->proc = proc;
878   handle->rest_handle = rest_handle;
879   handle->zone_pkey = NULL;
880
881   handle->url = GNUNET_strdup (rest_handle->url);
882   if (handle->url[strlen (handle->url) - 1] == '/')
883     handle->url[strlen (handle->url) - 1] = '\0';
884   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n");
885
886   handle->ns_handle = GNUNET_NAMESTORE_connect (cfg);
887   handle->identity_handle =
888     GNUNET_IDENTITY_connect (cfg, &id_connect_cb, handle);
889   handle->timeout_task =
890     GNUNET_SCHEDULER_add_delayed (handle->timeout, &do_error, handle);
891
892   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected\n");
893 }
894
895
896 /**
897  * Entry point for the plugin.
898  *
899  * @param cls Config info
900  * @return NULL on error, otherwise the plugin context
901  */
902 void *
903 libgnunet_plugin_rest_namestore_init (void *cls)
904 {
905   static struct Plugin plugin;
906   struct GNUNET_REST_Plugin *api;
907
908   cfg = cls;
909   if (NULL != plugin.cfg)
910     return NULL; /* can only initialize once! */
911   memset (&plugin, 0, sizeof(struct Plugin));
912   plugin.cfg = cfg;
913   api = GNUNET_new (struct GNUNET_REST_Plugin);
914   api->cls = &plugin;
915   api->name = GNUNET_REST_API_NS_NAMESTORE;
916   api->process_request = &rest_process_request;
917   GNUNET_asprintf (&allow_methods,
918                    "%s, %s, %s, %s, %s",
919                    MHD_HTTP_METHOD_GET,
920                    MHD_HTTP_METHOD_POST,
921                    MHD_HTTP_METHOD_PUT,
922                    MHD_HTTP_METHOD_DELETE,
923                    MHD_HTTP_METHOD_OPTIONS);
924
925   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _ ("Namestore REST API initialized\n"));
926   return api;
927 }
928
929
930 /**
931  * Exit point from the plugin.
932  *
933  * @param cls the plugin context (as returned by "init")
934  * @return always NULL
935  */
936 void *
937 libgnunet_plugin_rest_namestore_done (void *cls)
938 {
939   struct GNUNET_REST_Plugin *api = cls;
940   struct Plugin *plugin = api->cls;
941
942   plugin->cfg = NULL;
943
944   GNUNET_free_non_null (allow_methods);
945   GNUNET_free (api);
946   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Namestore REST plugin is finished\n");
947   return NULL;
948 }
949
950
951 /* end of plugin_rest_namestore.c */