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