rps: keep track of valid peers in peermap
[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
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., 51 Franklin Street, Fifth Floor,
18    Boston, MA 02110-1301, USA.
19    */
20 /**
21  * @author Martin Schanzenbach
22  * @file namestore/plugin_rest_namestore.c
23  * @brief GNUnet Namestore REST plugin
24  *
25  */
26
27 #include "platform.h"
28 #include "gnunet_rest_plugin.h"
29 #include "gnunet_namestore_service.h"
30 #include "gnunet_identity_service.h"
31 #include "gnunet_rest_lib.h"
32 #include "gnunet_jsonapi_lib.h"
33 #include "gnunet_jsonapi_util.h"
34 #include "microhttpd.h"
35 #include <jansson.h>
36
37 #define GNUNET_REST_API_NS_NAMESTORE "/names"
38
39 #define GNUNET_REST_API_NS_NAMESTORE_ZKEY "/names/zkey"
40
41 #define GNUNET_REST_JSONAPI_NAMESTORE_TYPEINFO "record"
42
43 #define GNUNET_REST_JSONAPI_NAMESTORE_NAME "name"
44
45 #define GNUNET_REST_JSONAPI_NAMESTORE_REVINFO "revinfo"
46
47 #define GNUNET_REST_JSONAPI_NAMESTORE_RECORD GNUNET_REST_JSONAPI_NAMESTORE_TYPEINFO
48
49 #define GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE "record_type"
50
51 #define GNUNET_REST_JSONAPI_NAMESTORE_VALUE "value"
52
53 #define GNUNET_REST_JSONAPI_NAMESTORE_PUBLIC "public"
54
55 #define GNUNET_REST_JSONAPI_NAMESTORE_SHADOW "shadow"
56
57 #define GNUNET_REST_JSONAPI_NAMESTORE_PKEY "pkey"
58
59 #define GNUNET_REST_JSONAPI_NAMESTORE_ZKEY "zkey"
60
61 #define GNUNET_REST_JSONAPI_NAMESTORE_EXPIRATION "expiration"
62
63 #define GNUNET_REST_JSONAPI_NAMESTORE_EGO "ego"
64
65 /**
66  * @brief struct returned by the initialization function of the plugin
67  */
68 struct Plugin
69 {
70   const struct GNUNET_CONFIGURATION_Handle *cfg;
71 };
72
73
74 /**
75  * HTTP methods allows for this plugin
76  */
77 static char* allow_methods;
78
79 const struct GNUNET_CONFIGURATION_Handle *cfg;
80
81 struct RecordEntry
82 {
83   /**
84    * DLL
85    */
86   struct RecordEntry *next;
87
88   /**
89    * DLL
90    */
91   struct RecordEntry *prev;
92
93 };
94
95 struct RequestHandle
96 {
97   /**
98    * Ego list
99    */
100   struct RecordEntry *record_head;
101
102   /**
103    * Ego list
104    */
105   struct record_entry *record_tail;
106
107   /**
108    * JSON response object
109    */
110   struct GNUNET_JSONAPI_Document *resp_object;
111
112   /**
113    * Rest connection
114    */
115   struct GNUNET_REST_RequestHandle *rest_handle;
116
117   /**
118    * Handle to GNS service.
119    */
120   struct GNUNET_IDENTITY_Handle *identity_handle;
121
122   /**
123    * Handle to NAMESTORE
124    */
125   struct GNUNET_NAMESTORE_Handle *ns_handle;
126
127   /**
128    * Handle to NAMESTORE it
129    */
130   struct GNUNET_NAMESTORE_ZoneIterator *list_it;
131
132   /**
133    * Private key for the zone
134    */
135   struct GNUNET_CRYPTO_EcdsaPrivateKey zone_pkey;
136
137   /**
138    * Handle to identity lookup
139    */
140   struct GNUNET_IDENTITY_EgoLookup *ego_lookup;
141
142   /**
143    * Default Ego operation
144    */
145   struct GNUNET_IDENTITY_Operation *get_default;
146
147   /**
148    * Name of the ego
149    */
150   char *ego_name;
151
152   /**
153    * Record is public
154    */
155   int is_public;
156
157   /**
158    * Shadow record
159    */
160   int is_shadow;
161
162   /**
163    * Name of the record to modify
164    */
165   char *name;
166
167   /**
168    * Value of the record
169    */
170   char *value;
171
172   /**
173    * Zkey string
174    */
175   const char* zkey_str;
176
177   /**
178    * record type
179    */
180   uint32_t type;
181
182   /**
183    * Records to store
184    */
185   struct GNUNET_GNSRECORD_Data *rd;
186
187   /**
188    * record count
189    */
190   unsigned int rd_count;
191
192   /**
193    * NAMESTORE Operation
194    */
195   struct GNUNET_NAMESTORE_QueueEntry *add_qe;
196
197   /**
198    * NAMESTORE Operation
199    */
200   struct GNUNET_NAMESTORE_QueueEntry *reverse_qe;
201
202   /**
203    * Desired timeout for the lookup (default is no timeout).
204    */
205   struct GNUNET_TIME_Relative timeout;
206
207   /**
208    * ID of a task associated with the resolution process.
209    */
210   struct GNUNET_SCHEDULER_Task * timeout_task;
211
212   /**
213    * The plugin result processor
214    */
215   GNUNET_REST_ResultProcessor proc;
216
217   /**
218    * The closure of the result processor
219    */
220   void *proc_cls;
221
222   /**
223    * The url
224    */
225   char *url;
226
227   /**
228    * Cfg
229    */
230   const struct GNUNET_CONFIGURATION_Handle *cfg;
231
232   /**
233    * HTTP response code
234    */
235   int response_code;
236
237 };
238
239
240 /**
241  * Cleanup lookup handle
242  *
243  * @param handle Handle to clean up
244  */
245 static void
246 cleanup_handle (struct RequestHandle *handle)
247 {
248   struct RecordEntry *record_entry;
249   struct RecordEntry *record_tmp;
250   int i;
251
252   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
253               "Cleaning up\n");
254   if (NULL != handle->resp_object)
255     GNUNET_JSONAPI_document_delete (handle->resp_object);
256   if (NULL != handle->name)
257     GNUNET_free (handle->name);
258   if (NULL != handle->timeout_task)
259     GNUNET_SCHEDULER_cancel (handle->timeout_task);
260   if (NULL != handle->ego_lookup)
261     GNUNET_IDENTITY_ego_lookup_cancel (handle->ego_lookup);
262   if (NULL != handle->get_default)
263     GNUNET_IDENTITY_cancel (handle->get_default);
264   if (NULL != handle->list_it)
265     GNUNET_NAMESTORE_zone_iteration_stop (handle->list_it);
266   if (NULL != handle->add_qe)
267     GNUNET_NAMESTORE_cancel (handle->add_qe);
268   if (NULL != handle->identity_handle)
269     GNUNET_IDENTITY_disconnect (handle->identity_handle);
270   if (NULL != handle->ns_handle)
271     GNUNET_NAMESTORE_disconnect (handle->ns_handle);
272   if (NULL != handle->url)
273     GNUNET_free (handle->url);
274   if (NULL != handle->value)
275     GNUNET_free (handle->value);
276   if (NULL != handle->rd)
277   {
278     for (i = 0; i < handle->rd_count; i++)
279     {
280       if (NULL != handle->rd[i].data)
281         GNUNET_free ((void*)handle->rd[i].data);
282     }
283     GNUNET_free (handle->rd);
284   }
285   if (NULL != handle->ego_name)
286     GNUNET_free (handle->ego_name);
287   for (record_entry = handle->record_head;
288        NULL != record_entry;)
289   {
290     record_tmp = record_entry;
291     record_entry = record_entry->next;
292     GNUNET_free (record_tmp);
293   }
294   GNUNET_free (handle);
295 }
296
297
298 /**
299  * Create json representation of a GNSRECORD
300  *
301  * @param rd the GNSRECORD_Data
302  */
303 static json_t *
304 gnsrecord_to_json (const struct GNUNET_GNSRECORD_Data *rd)
305 {
306   const char *typename;
307   char *string_val;
308   const char *exp_str;
309   json_t *record_obj;
310
311   typename = GNUNET_GNSRECORD_number_to_typename (rd->record_type);
312   string_val = GNUNET_GNSRECORD_value_to_string (rd->record_type,
313                                                  rd->data,
314                                                  rd->data_size);
315
316   if (NULL == string_val)
317   {
318     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
319                 "Record of type %d malformed, skipping\n",
320                 (int) rd->record_type);
321     return NULL;
322   }
323   record_obj = json_object();
324   json_object_set_new (record_obj,
325                        GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE,
326                        json_string (typename));
327   json_object_set_new (record_obj,
328                        GNUNET_REST_JSONAPI_NAMESTORE_VALUE,
329                        json_string (string_val));
330   GNUNET_free (string_val);
331
332   if (GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION & rd->flags)
333   {
334     struct GNUNET_TIME_Relative time_rel;
335     time_rel.rel_value_us = rd->expiration_time;
336     exp_str = GNUNET_STRINGS_relative_time_to_string (time_rel, 1);
337   }
338   else
339   {
340     struct GNUNET_TIME_Absolute time_abs;
341     time_abs.abs_value_us = rd->expiration_time;
342     exp_str = GNUNET_STRINGS_absolute_time_to_string (time_abs);
343   }
344   json_object_set_new (record_obj, GNUNET_REST_JSONAPI_NAMESTORE_EXPIRATION, json_string (exp_str));
345
346   json_object_set_new (record_obj, "expired",
347                        json_boolean (GNUNET_YES == GNUNET_GNSRECORD_is_expired (rd)));
348   return record_obj;
349 }
350
351
352 /**
353  * Task run on error.  Generates error response and cleans up.
354  *
355  * @param cls the request to generate an error response for
356  */
357 static void
358 do_error (void *cls)
359 {
360   struct RequestHandle *handle = cls;
361   struct MHD_Response *resp = GNUNET_REST_create_json_response (NULL);
362
363   handle->proc (handle->proc_cls, resp, handle->response_code);
364   cleanup_handle (handle);
365 }
366
367
368 /**
369  * Task run on timeout.
370  *
371  * @param cls the request to time out
372  */
373 static void
374 do_timeout (void *cls)
375 {
376   struct RequestHandle *handle = cls;
377
378   handle->timeout_task = NULL;
379   do_error (handle);
380 }
381
382
383 static void
384 cleanup_handle_delayed (void *cls)
385 {
386   cleanup_handle (cls);
387 }
388
389
390 /**
391  * Create a response with requested records
392  *
393  * @param handle the RequestHandle
394  */
395 static void
396 namestore_list_response (void *cls,
397                          const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
398                          const char *rname,
399                          unsigned int rd_len,
400                          const struct GNUNET_GNSRECORD_Data *rd)
401 {
402   struct RequestHandle *handle = cls;
403   struct GNUNET_JSONAPI_Resource *json_resource;
404   struct MHD_Response *resp;
405   json_t *result_array;
406   json_t *record_obj;
407   int i;
408   char *result;
409
410   if (NULL == handle->resp_object)
411     handle->resp_object = GNUNET_JSONAPI_document_new ();
412
413   if (NULL == rname)
414   {
415     handle->list_it = NULL;
416     //Handle response
417     if (GNUNET_SYSERR == GNUNET_JSONAPI_document_serialize (handle->resp_object, &result))
418     {
419       GNUNET_SCHEDULER_add_now (&do_error, handle);
420       return;
421     }
422     resp = GNUNET_REST_create_json_response (result);
423     handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
424     GNUNET_free (result);
425     GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
426     return;
427   }
428
429   if ( (NULL != handle->name) &&
430        (0 != strcmp (handle->name, rname)) )
431   {
432     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
433                 "%s does not match %s\n", rname, handle->name);
434     GNUNET_NAMESTORE_zone_iterator_next (handle->list_it);
435     return;
436   }
437
438   result_array = json_array ();
439   for (i=0; i<rd_len; i++)
440   {
441     if ( (GNUNET_GNSRECORD_TYPE_NICK == rd[i].record_type) &&
442          (0 != strcmp (rname, "+")) )
443       continue;
444
445     if ( (rd[i].record_type != handle->type) &&
446          (GNUNET_GNSRECORD_TYPE_ANY != handle->type) )
447       continue;
448     record_obj = gnsrecord_to_json (&(rd[i]));
449     json_array_append (result_array, record_obj);
450     json_decref (record_obj);
451   }
452
453   if (0 < json_array_size(result_array))
454   {
455     json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_NAMESTORE_TYPEINFO,
456                                                       rname);
457     GNUNET_JSONAPI_resource_add_attr (json_resource,
458                                            GNUNET_REST_JSONAPI_NAMESTORE_RECORD,
459                                            result_array);
460     GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
461   }
462
463   json_decref (result_array);
464   GNUNET_NAMESTORE_zone_iterator_next (handle->list_it);
465 }
466
467 static void
468 create_finished (void *cls, int32_t success, const char *emsg)
469 {
470   struct RequestHandle *handle = cls;
471   struct MHD_Response *resp;
472
473   handle->add_qe = NULL;
474   if (GNUNET_YES != success)
475   {
476     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
477                 "Error storing records%s%s\n",
478                 (NULL == emsg) ? "" : ": ",
479                 (NULL == emsg) ? "" : emsg);
480     GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
481     return;
482   }
483   resp = GNUNET_REST_create_json_response (NULL);
484   handle->proc (handle->proc_cls, resp, MHD_HTTP_NO_CONTENT);
485   GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
486 }
487
488
489 /**
490  * We're storing a new record; this requires
491  * that no record already exists
492  *
493  * @param cls closure, unused
494  * @param zone_key private key of the zone
495  * @param rec_name name that is being mapped (at most 255 characters long)
496  * @param rd_count number of entries in @a rd array
497  * @param rd array of records with data to store
498  */
499 static void
500 create_new_record_cont (void *cls,
501                         const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
502                         const char *rec_name,
503                         unsigned int rd_count,
504                         const struct GNUNET_GNSRECORD_Data *rd)
505 {
506   struct RequestHandle *handle = cls;
507
508   handle->add_qe = NULL;
509   if ( (NULL != zone_key) &&
510        (0 != strcmp (rec_name, handle->name)) )
511   {
512     GNUNET_break (0);
513     GNUNET_SCHEDULER_add_now (&do_error, handle);
514     return;
515   }
516
517   if (0 != rd_count)
518   {
519     handle->proc (handle->proc_cls,
520                   GNUNET_REST_create_json_response (NULL),
521                   MHD_HTTP_CONFLICT);
522     GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
523     return;
524   }
525
526   GNUNET_assert (NULL != handle->name);
527   handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
528                                                    &handle->zone_pkey,
529                                                    handle->name,
530                                                    handle->rd_count,
531                                                    handle->rd,
532                                                    &create_finished,
533                                                    handle);
534 }
535
536 static void
537 del_finished (void *cls,
538               int32_t success,
539               const char *emsg)
540 {
541   struct RequestHandle *handle = cls;
542
543   handle->add_qe = NULL;
544   if (GNUNET_NO == success)
545   {
546     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
547                 _("Deleting record failed, record does not exist%s%s\n"),
548                 (NULL != emsg) ? ": " : "",
549                 (NULL != emsg) ? emsg : "");
550     GNUNET_SCHEDULER_add_now (&do_error, handle); //do_not_found TODO
551     return;
552   }
553   if (GNUNET_SYSERR == success)
554   {
555     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
556                 _("Deleting record failed%s%s\n"),
557                 (NULL != emsg) ? ": " : "",
558                 (NULL != emsg) ? emsg : "");
559     GNUNET_SCHEDULER_add_now (&do_error, handle);
560     return;
561   }
562   handle->proc (handle->proc_cls,
563                 GNUNET_REST_create_json_response (NULL),
564                 MHD_HTTP_NO_CONTENT);
565   GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
566 }
567
568 static void
569 del_cont (void *cls,
570           const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
571           const char *label,
572           unsigned int rd_count,
573           const struct GNUNET_GNSRECORD_Data *rd)
574 {
575   struct RequestHandle *handle = cls;
576   handle->add_qe = NULL;
577   if (0 == rd_count)
578   {
579     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
580                 _("There are no records under label `%s' that could be deleted.\n"),
581                 label);
582     GNUNET_SCHEDULER_add_now (&do_error, handle);
583     return;
584   }
585
586   handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
587                                                    &handle->zone_pkey,
588                                                    handle->name,
589                                                    0, NULL,
590                                                    &del_finished,
591                                                    handle);
592 }
593
594 static void
595 namestore_delete_cont (struct GNUNET_REST_RequestHandle *con,
596                        const char *url,
597                        void *cls)
598 {
599   struct RequestHandle *handle = cls;
600
601   if (NULL == handle->name)
602   {
603     GNUNET_SCHEDULER_add_now (&do_error, handle);
604     return;
605   }
606
607   handle->add_qe = GNUNET_NAMESTORE_records_lookup (handle->ns_handle,
608                                                     &handle->zone_pkey,
609                                                     handle->name,
610                                                     &del_cont,
611                                                     handle);
612 }
613
614 static int
615 json_to_gnsrecord (const json_t *records_json,
616                    struct GNUNET_GNSRECORD_Data **rd,
617                    unsigned int *rd_count)
618 {
619   struct GNUNET_TIME_Relative etime_rel;
620   struct GNUNET_TIME_Absolute etime_abs;
621   char *value;
622   void *rdata;
623   size_t rdata_size;
624   const char *typestring;
625   const char *expirationstring;
626   int i;
627   json_t *type_json;
628   json_t *value_json;
629   json_t *record_json;
630   json_t *exp_json;
631
632   *rd_count = json_array_size (records_json);
633   *rd = GNUNET_malloc (sizeof (struct GNUNET_GNSRECORD_Data) * *rd_count);
634   for (i = 0; i < *rd_count; i++)
635   {
636     memset (&((*rd)[i]), 0, sizeof (struct GNUNET_GNSRECORD_Data));
637     record_json = json_array_get (records_json, i);
638     type_json = json_object_get (record_json,
639                                  GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE);
640     if (!json_is_string (type_json))
641     {
642       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
643                   "Type property is no string\n");
644       return GNUNET_SYSERR;
645     }
646     typestring = json_string_value (type_json);
647     (*rd)[i].record_type = GNUNET_GNSRECORD_typename_to_number (typestring);
648     if (UINT32_MAX == (*rd)[i].record_type)
649     {
650       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Unsupported type `%s'\n"),
651                   json_string_value (type_json));
652       return GNUNET_SYSERR;
653     }
654     value_json = json_object_get (record_json,
655                                   GNUNET_REST_JSONAPI_NAMESTORE_VALUE);
656     if (!json_is_string (value_json))
657     {
658       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
659                   "Value property is no string\n");
660       return GNUNET_SYSERR;
661     }
662     value = GNUNET_strdup (json_string_value (value_json));
663     if (GNUNET_OK != GNUNET_GNSRECORD_string_to_value ((*rd)[i].record_type,
664                                                        value,
665                                                        &rdata,
666                                                        &rdata_size))
667     {
668       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Value `%s' invalid for record type `%s'\n"),
669                   value, typestring);
670       return GNUNET_SYSERR;
671     }
672     (*rd)[i].data = rdata;
673     (*rd)[i].data_size = rdata_size;
674     /**TODO
675      * if (1 == handle->is_shadow)
676      rde->flags |= GNUNET_GNSRECORD_RF_SHADOW_RECORD;
677      if (1 != handle->is_public)
678      rde->flags |= GNUNET_GNSRECORD_RF_PRIVATE;
679      */
680     exp_json = json_object_get (record_json,
681                                 GNUNET_REST_JSONAPI_NAMESTORE_EXPIRATION);
682     if (!json_is_string (exp_json))
683     {
684       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
685                   "Expiration property is no string\n");
686       return GNUNET_SYSERR;
687     }
688     expirationstring = json_string_value (exp_json);
689     if (0 == strcmp (expirationstring, "never"))
690     {
691       (*rd)[i].expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
692     }
693     else if (GNUNET_OK ==
694              GNUNET_STRINGS_fancy_time_to_relative (expirationstring,
695                                                     &etime_rel))
696     {
697       (*rd)[i].expiration_time = etime_rel.rel_value_us;
698       (*rd)[i].flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
699     }
700     else if (GNUNET_OK ==
701              GNUNET_STRINGS_fancy_time_to_absolute (expirationstring,
702                                                     &etime_abs))
703     {
704       (*rd)[i].expiration_time = etime_abs.abs_value_us;
705     }
706     else
707     {
708       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Value `%s' invalid for record type `%s'\n"),
709                   value, typestring);
710       return GNUNET_SYSERR;
711     }
712   }
713   return GNUNET_OK;
714 }
715
716 static void
717 namestore_create_cont (struct GNUNET_REST_RequestHandle *con,
718                        const char *url,
719                        void *cls)
720 {
721   struct RequestHandle *handle = cls;
722   struct MHD_Response *resp;
723   struct GNUNET_JSONAPI_Document *json_obj;
724   struct GNUNET_JSONAPI_Resource *json_res;
725   json_t *records_json;
726   char term_data[handle->rest_handle->data_size+1];
727
728   if (strlen (GNUNET_REST_API_NS_NAMESTORE) != strlen (handle->url))
729   {
730     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
731                 "Cannot create under %s\n", handle->url);
732     GNUNET_SCHEDULER_add_now (&do_error, handle);
733     return;
734   }
735   if (0 >= handle->rest_handle->data_size)
736   {
737     GNUNET_SCHEDULER_add_now (&do_error, handle);
738     return;
739   }
740   term_data[handle->rest_handle->data_size] = '\0';
741   memcpy (term_data,
742           handle->rest_handle->data,
743           handle->rest_handle->data_size);
744   GNUNET_assert (GNUNET_OK == GNUNET_JSONAPI_document_parse (term_data,
745                                                            &json_obj));
746   if (NULL == json_obj)
747   {
748     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
749                 "Unable to parse JSONAPI Object from %s\n",
750                 term_data);
751     GNUNET_SCHEDULER_add_now (&do_error, handle);
752     return;
753   }
754   if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
755   {
756     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
757                 "Cannot create more than 1 resource! (Got %d)\n",
758                 GNUNET_JSONAPI_document_resource_count (json_obj));
759     GNUNET_JSONAPI_document_delete (json_obj);
760     GNUNET_SCHEDULER_add_now (&do_error, handle);
761     return;
762   }
763   json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
764   if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res,
765                                                             GNUNET_REST_JSONAPI_NAMESTORE_RECORD))
766   {
767     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
768                 "Unsupported JSON data type\n");
769     GNUNET_JSONAPI_document_delete (json_obj);
770     resp = GNUNET_REST_create_json_response (NULL);
771     handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
772     cleanup_handle (handle);
773     return;
774   }
775   handle->name = GNUNET_strdup (GNUNET_JSONAPI_resource_get_id (json_res));
776   records_json = GNUNET_JSONAPI_resource_read_attr (json_res,
777                                                          GNUNET_REST_JSONAPI_NAMESTORE_RECORD);
778   if (NULL == records_json)
779   {
780     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
781                 "No records given\n");
782     GNUNET_JSONAPI_document_delete (json_obj);
783     GNUNET_SCHEDULER_add_now (&do_error, handle);
784     return;
785   }
786   if (GNUNET_SYSERR == json_to_gnsrecord (records_json, &handle->rd, &handle->rd_count))
787   {
788     GNUNET_JSONAPI_document_delete (json_obj);
789     GNUNET_SCHEDULER_add_now (&do_error, handle);
790     return;
791   }
792   GNUNET_JSONAPI_document_delete (json_obj);
793
794   handle->add_qe = GNUNET_NAMESTORE_records_lookup (handle->ns_handle,
795                                                     &handle->zone_pkey,
796                                                     handle->name,
797                                                     &create_new_record_cont, handle );
798 }
799
800 static void
801 namestore_zkey_response (void *cls,
802                          const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
803                          const char *label,
804                          unsigned int rd_count,
805                          const struct GNUNET_GNSRECORD_Data *rd)
806 {
807   struct RequestHandle *handle = cls;
808   struct MHD_Response *resp;
809   struct GNUNET_JSONAPI_Document *json_obj;
810   struct GNUNET_JSONAPI_Resource *json_res;
811   json_t *name_json;
812   char* result;
813
814   handle->reverse_qe = NULL;
815   json_obj = GNUNET_JSONAPI_document_new ();
816   if (NULL != label)
817   {
818     name_json = json_string (label);
819     json_res = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_NAMESTORE_REVINFO,
820                                                  handle->zkey_str);
821     GNUNET_JSONAPI_resource_add_attr (json_res,
822                                            GNUNET_REST_JSONAPI_NAMESTORE_NAME,
823                                            name_json);
824     GNUNET_JSONAPI_document_resource_add (json_obj, json_res);
825     json_decref (name_json);
826   }
827   //Handle response
828   if (GNUNET_SYSERR == GNUNET_JSONAPI_document_serialize (json_obj, &result))
829   {
830     GNUNET_JSONAPI_document_delete (json_obj);
831     GNUNET_SCHEDULER_add_now (&do_error, handle);
832     return;
833   }
834   resp = GNUNET_REST_create_json_response (result);
835   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
836   GNUNET_JSONAPI_document_delete (json_obj);
837   GNUNET_free (result);
838   GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
839   return;
840
841 }
842
843 static void
844 namestore_zkey_cont (struct GNUNET_REST_RequestHandle *con,
845                      const char *url,
846                      void *cls)
847 {
848   struct RequestHandle *handle = cls;
849   struct GNUNET_HashCode key;
850   struct GNUNET_CRYPTO_EcdsaPublicKey pubkey;
851
852   GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_NAMESTORE_ZKEY,
853                       strlen (GNUNET_REST_JSONAPI_NAMESTORE_ZKEY),
854                       &key);
855   if ( GNUNET_NO ==
856        GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
857                                                &key) )
858   {
859     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
860                 "No zkey given %s\n", handle->url);
861     GNUNET_SCHEDULER_add_now (&do_error, handle);
862     return;
863   }
864   handle->zkey_str = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
865                                             &key);
866   if (GNUNET_OK !=
867       GNUNET_CRYPTO_ecdsa_public_key_from_string (handle->zkey_str,
868                                                   strlen (handle->zkey_str),
869                                                   &pubkey))
870   {
871     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
872                 "Zkey invalid %s\n", handle->zkey_str);
873     GNUNET_SCHEDULER_add_now (&do_error, handle);
874     return;
875   }
876   handle->reverse_qe = GNUNET_NAMESTORE_zone_to_name (handle->ns_handle,
877                                                       &handle->zone_pkey,
878                                                       &pubkey,
879                                                       &namestore_zkey_response,
880                                                       handle);
881 }
882
883 static void
884 namestore_info_cont (struct GNUNET_REST_RequestHandle *con,
885                      const char *url,
886                      void *cls)
887 {
888   struct RequestHandle *handle = cls;
889   handle->list_it = GNUNET_NAMESTORE_zone_iteration_start (handle->ns_handle,
890                                                            &handle->zone_pkey,
891                                                            &namestore_list_response,
892                                                            handle);
893 }
894
895 static char*
896 get_name_from_url (const char* url)
897 {
898   if (strlen (url) <= strlen (GNUNET_REST_API_NS_NAMESTORE))
899     return NULL;
900   return (char*)url + strlen (GNUNET_REST_API_NS_NAMESTORE) + 1;
901 }
902
903 /**
904  * Respond to OPTIONS request
905  *
906  * @param con_handle the connection handle
907  * @param url the url
908  * @param cls the RequestHandle
909  */
910 static void
911 options_cont (struct GNUNET_REST_RequestHandle *con_handle,
912               const char* url,
913               void *cls)
914 {
915   struct MHD_Response *resp;
916   struct RequestHandle *handle = cls;
917
918   //For now, independent of path return all options
919   resp = GNUNET_REST_create_json_response (NULL);
920   MHD_add_response_header (resp,
921                            "Access-Control-Allow-Methods",
922                            allow_methods);
923   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
924   cleanup_handle (handle);
925   return;
926 }
927
928 /**
929  * Function called with the result from the check if the namestore
930  * service is actually running.  If it is, we start the actual
931  * operation.
932  *
933  * @param cls closure with our configuration
934  * @param result #GNUNET_YES if the namestore service is running
935  */
936 static void
937 testservice_task (void *cls,
938                   int result)
939 {
940   struct RequestHandle *handle = cls;
941   struct GNUNET_REST_RequestHandlerError err;
942   static const struct GNUNET_REST_RequestHandler handlers[] = {
943     {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_NAMESTORE_ZKEY, &namestore_zkey_cont}, //reverse
944     {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_NAMESTORE, &namestore_info_cont}, //list
945     {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_NAMESTORE, &namestore_create_cont}, //create
946     //    {MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_NAMESTORE, &namestore_edit_cont}, //update. TODO this shoul be PATCH
947     {MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_NAMESTORE, &namestore_delete_cont}, //delete
948     {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_NAMESTORE, &options_cont},
949     GNUNET_REST_HANDLER_END
950   };
951
952   if (GNUNET_YES != result)
953   {
954     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Service `%s' is not running\n"),
955                 "namestore");
956     GNUNET_SCHEDULER_add_now (&do_error, handle);
957     return;
958   }
959   handle->ns_handle = GNUNET_NAMESTORE_connect (cfg);
960   if (NULL == handle->ns_handle)
961   {
962     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
963                 _("Failed to connect to namestore\n"));
964     GNUNET_SCHEDULER_add_now (&do_error, handle);
965     return;
966   }
967
968   if (GNUNET_OK != GNUNET_JSONAPI_handle_request (handle->rest_handle,
969                                                   handlers,
970                                                   &err,
971                                                   handle))
972   {
973     handle->response_code = err.error_code;
974     GNUNET_SCHEDULER_add_now (&do_error, (void*) handle);
975   }
976
977 }
978
979 /**
980  * Callback invoked from identity service with ego information.
981  * An @a ego of NULL means the ego was not found.
982  *
983  * @param cls closure with the configuration
984  * @param ego an ego known to identity service, or NULL
985  */
986 static void
987 identity_cb (void *cls,
988              const struct GNUNET_IDENTITY_Ego *ego)
989 {
990   struct RequestHandle *handle = cls;
991   struct MHD_Response *resp;
992
993   handle->ego_lookup = NULL;
994   if (NULL == ego)
995   {
996     if (NULL != handle->ego_name)
997     {
998       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
999                   _("Ego `%s' not known to identity service\n"),
1000                   handle->ego_name);
1001     }
1002     resp = GNUNET_REST_create_json_response (NULL);
1003     handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
1004     cleanup_handle (handle);
1005     return;
1006   }
1007   handle->zone_pkey = *GNUNET_IDENTITY_ego_get_private_key (ego);
1008   GNUNET_CLIENT_service_test ("namestore", handle->cfg,
1009                               GNUNET_TIME_UNIT_SECONDS,
1010                               &testservice_task,
1011                               (void *) handle);
1012 }
1013
1014 static void
1015 default_ego_cb (void *cls,
1016                 struct GNUNET_IDENTITY_Ego *ego,
1017                 void **ctx,
1018                 const char *name)
1019 {
1020   struct RequestHandle *handle = cls;
1021   struct MHD_Response *resp;
1022   handle->get_default = NULL;
1023   if (NULL == ego)
1024   {
1025     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1026                 _("No default ego configured in identity service\n"));
1027     resp = GNUNET_REST_create_json_response (NULL);
1028     handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
1029     cleanup_handle (handle);
1030     return;
1031   }
1032   else
1033   {
1034     identity_cb (cls, ego);
1035   }
1036 }
1037
1038 static void
1039 id_connect_cb (void *cls,
1040                struct GNUNET_IDENTITY_Ego *ego,
1041                void **ctx,
1042                const char *name)
1043 {
1044   struct RequestHandle *handle = cls;
1045   if (NULL == ego)
1046   {
1047     handle->get_default = GNUNET_IDENTITY_get (handle->identity_handle,
1048                                                "namestore",
1049                                                &default_ego_cb, handle);
1050   }
1051 }
1052
1053 static void
1054 testservice_id_task (void *cls, int result)
1055 {
1056   struct RequestHandle *handle = cls;
1057   struct MHD_Response *resp;
1058   struct GNUNET_HashCode key;
1059   char *ego;
1060   char *name;
1061   char *type;
1062
1063   if (result != GNUNET_YES)
1064   {
1065     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1066                 _("Identity service is not running\n"));
1067     resp = GNUNET_REST_create_json_response (NULL);
1068     handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
1069     cleanup_handle (handle);
1070     return;
1071   }
1072   ego = NULL;
1073   GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_NAMESTORE_EGO,
1074                       strlen (GNUNET_REST_JSONAPI_NAMESTORE_EGO),
1075                       &key);
1076   if ( GNUNET_YES ==
1077        GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1078                                                &key) )
1079   {
1080     ego = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
1081                                              &key);
1082   }
1083
1084   handle->type = GNUNET_GNSRECORD_TYPE_ANY;
1085   GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE,
1086                       strlen (GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE),
1087                       &key);
1088   if ( GNUNET_YES ==
1089        GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1090                                                &key) )
1091   {
1092     type = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
1093                                               &key);
1094
1095     handle->type = GNUNET_GNSRECORD_typename_to_number (type);
1096   }
1097   name = get_name_from_url (handle->url);
1098   if (NULL != ego)
1099     handle->ego_name = GNUNET_strdup (ego);
1100   if (NULL != name)
1101     handle->name = GNUNET_strdup (name);
1102   if (NULL == handle->ego_name)
1103   {
1104     handle->identity_handle = GNUNET_IDENTITY_connect (handle->cfg, &id_connect_cb, handle);
1105     if (NULL == handle->identity_handle)
1106     {
1107       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Cannot connect to identity service\n"));
1108       resp = GNUNET_REST_create_json_response (NULL);
1109       handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
1110       cleanup_handle (handle);
1111     }
1112     return;
1113   }
1114   handle->ego_lookup = GNUNET_IDENTITY_ego_lookup (cfg,
1115                                                    handle->ego_name,
1116                                                    &identity_cb,
1117                                                    handle);
1118 }
1119
1120 /**
1121  * Function processing the REST call
1122  *
1123  * @param method HTTP method
1124  * @param url URL of the HTTP request
1125  * @param data body of the HTTP request (optional)
1126  * @param data_size length of the body
1127  * @param proc callback function for the result
1128  * @param proc_cls closure for callback function
1129  * @return GNUNET_OK if request accepted
1130  */
1131 static void
1132 rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle,
1133                               GNUNET_REST_ResultProcessor proc,
1134                               void *proc_cls)
1135 {
1136   struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1137
1138   handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1139   handle->proc_cls = proc_cls;
1140   handle->proc = proc;
1141   handle->rest_handle = rest_handle;
1142   handle->url = GNUNET_strdup (rest_handle->url);
1143   if (handle->url[strlen (handle->url)-1] == '/')
1144     handle->url[strlen (handle->url)-1] = '\0';
1145   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1146               "Connecting...\n");
1147   handle->cfg = cfg;
1148   GNUNET_CLIENT_service_test ("identity",
1149                               cfg,
1150                               GNUNET_TIME_UNIT_SECONDS,
1151                               &testservice_id_task,
1152                               handle);
1153   handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout,
1154                                                        &do_timeout,
1155                                                        handle);
1156 }
1157
1158 /**
1159  * Entry point for the plugin.
1160  *
1161  * @param cls Config info
1162  * @return NULL on error, otherwise the plugin context
1163  */
1164 void *
1165 libgnunet_plugin_rest_namestore_init (void *cls)
1166 {
1167   static struct Plugin plugin;
1168   cfg = cls;
1169   struct GNUNET_REST_Plugin *api;
1170
1171   if (NULL != plugin.cfg)
1172     return NULL;                /* can only initialize once! */
1173   memset (&plugin, 0, sizeof (struct Plugin));
1174   plugin.cfg = cfg;
1175   api = GNUNET_new (struct GNUNET_REST_Plugin);
1176   api->cls = &plugin;
1177   api->name = GNUNET_REST_API_NS_NAMESTORE;
1178   api->process_request = &rest_identity_process_request;
1179   GNUNET_asprintf (&allow_methods,
1180                    "%s, %s, %s, %s, %s",
1181                    MHD_HTTP_METHOD_GET,
1182                    MHD_HTTP_METHOD_POST,
1183                    MHD_HTTP_METHOD_PUT,
1184                    MHD_HTTP_METHOD_DELETE,
1185                    MHD_HTTP_METHOD_OPTIONS);
1186   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1187               _("Namestore REST API initialized\n"));
1188   return api;
1189 }
1190
1191
1192 /**
1193  * Exit point from the plugin.
1194  *
1195  * @param cls the plugin context (as returned by "init")
1196  * @return always NULL
1197  */
1198 void *
1199 libgnunet_plugin_rest_namestore_done (void *cls)
1200 {
1201   struct GNUNET_REST_Plugin *api = cls;
1202   struct Plugin *plugin = api->cls;
1203
1204   plugin->cfg = NULL;
1205   GNUNET_free (api);
1206   GNUNET_free_non_null (allow_methods);
1207   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1208               "Namestore REST plugin is finished\n");
1209   return NULL;
1210 }
1211
1212 /* end of plugin_rest_namestore.c */