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