implementing new scheduler shutdown semantics
[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 "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  *
246  * @param handle Handle to clean up
247  */
248 static void
249 cleanup_handle (struct RequestHandle *handle)
250 {
251   struct RecordEntry *record_entry;
252   struct RecordEntry *record_tmp;
253   int i;
254
255   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
256               "Cleaning up\n");
257   if (NULL != handle->resp_object)
258     GNUNET_REST_jsonapi_object_delete (handle->resp_object);
259   if (NULL != handle->name)
260     GNUNET_free (handle->name);
261   if (NULL != handle->timeout_task)
262     GNUNET_SCHEDULER_cancel (handle->timeout_task);
263   if (NULL != handle->ego_lookup)
264     GNUNET_IDENTITY_ego_lookup_cancel (handle->ego_lookup);
265   if (NULL != handle->get_default)
266     GNUNET_IDENTITY_cancel (handle->get_default);
267   if (NULL != handle->list_it)
268     GNUNET_NAMESTORE_zone_iteration_stop (handle->list_it);
269   if (NULL != handle->add_qe)
270     GNUNET_NAMESTORE_cancel (handle->add_qe);
271   if (NULL != handle->identity_handle)
272     GNUNET_IDENTITY_disconnect (handle->identity_handle);
273   if (NULL != handle->ns_handle)
274     GNUNET_NAMESTORE_disconnect (handle->ns_handle);
275   if (NULL != handle->url)
276     GNUNET_free (handle->url);
277   if (NULL != handle->value)
278     GNUNET_free (handle->value);
279   if (NULL != handle->rd)
280   {
281     for (i = 0; i < handle->rd_count; i++)
282     {
283       if (NULL != handle->rd[i].data)
284         GNUNET_free ((void*)handle->rd[i].data);
285     }
286     GNUNET_free (handle->rd);
287   }
288   if (NULL != handle->ego_name)
289     GNUNET_free (handle->ego_name);
290   for (record_entry = handle->record_head;
291        NULL != record_entry;)
292   {
293     record_tmp = record_entry;
294     record_entry = record_entry->next;
295     GNUNET_free (record_tmp);
296   }
297   GNUNET_free (handle);
298 }
299
300
301 /**
302  * Create json representation of a GNSRECORD
303  *
304  * @param rd the GNSRECORD_Data
305  */
306 static json_t *
307 gnsrecord_to_json (const struct GNUNET_GNSRECORD_Data *rd)
308 {
309   const char *typename;
310   char *string_val;
311   const char *exp_str;
312   json_t *record_obj;
313
314   typename = GNUNET_GNSRECORD_number_to_typename (rd->record_type);
315   string_val = GNUNET_GNSRECORD_value_to_string (rd->record_type,
316                                                  rd->data,
317                                                  rd->data_size);
318
319   if (NULL == string_val)
320   {
321     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
322                 "Record of type %d malformed, skipping\n",
323                 (int) rd->record_type);
324     return NULL;
325   }
326   record_obj = json_object();
327   json_object_set_new (record_obj,
328                        GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE,
329                        json_string (typename));
330   json_object_set_new (record_obj,
331                        GNUNET_REST_JSONAPI_NAMESTORE_VALUE,
332                        json_string (string_val));
333   GNUNET_free (string_val);
334
335   if (GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION & rd->flags)
336   {
337     struct GNUNET_TIME_Relative time_rel;
338     time_rel.rel_value_us = rd->expiration_time;
339     exp_str = GNUNET_STRINGS_relative_time_to_string (time_rel, 1);
340   }
341   else
342   {
343     struct GNUNET_TIME_Absolute time_abs;
344     time_abs.abs_value_us = rd->expiration_time;
345     exp_str = GNUNET_STRINGS_absolute_time_to_string (time_abs);
346   }
347   json_object_set_new (record_obj, GNUNET_REST_JSONAPI_NAMESTORE_EXPIRATION, json_string (exp_str));
348
349   json_object_set_new (record_obj, "expired",
350                        json_boolean (GNUNET_YES == GNUNET_GNSRECORD_is_expired (rd)));
351   return record_obj;
352 }
353
354
355 /**
356  * Task run on error.  Generates error response and cleans up.
357  *
358  * @param cls the request to generate an error response for
359  */
360 static void
361 do_error (void *cls)
362 {
363   struct RequestHandle *handle = cls;
364   struct MHD_Response *resp = GNUNET_REST_create_json_response (NULL);
365
366   handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
367   cleanup_handle (handle);
368 }
369
370
371 /**
372  * Task run on timeout.
373  *
374  * @param cls the request to time out
375  */
376 static void
377 do_timeout (void *cls)
378 {
379   struct RequestHandle *handle = cls;
380
381   handle->timeout_task = NULL;
382   do_error (handle);
383 }
384
385
386 static void
387 cleanup_handle_delayed (void *cls)
388 {
389   cleanup_handle (cls);
390 }
391
392
393 /**
394  * Create a response with requested records
395  *
396  * @param handle the RequestHandle
397  */
398 static void
399 namestore_list_response (void *cls,
400                          const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
401                          const char *rname,
402                          unsigned int rd_len,
403                          const struct GNUNET_GNSRECORD_Data *rd)
404 {
405   struct RequestHandle *handle = cls;
406   struct JsonApiResource *json_resource;
407   struct MHD_Response *resp;
408   json_t *result_array;
409   json_t *record_obj;
410   int i;
411   char *result;
412
413   if (NULL == handle->resp_object)
414     handle->resp_object = GNUNET_REST_jsonapi_object_new ();
415
416   if (NULL == rname)
417   {
418     handle->list_it = NULL;
419     //Handle response
420     if (GNUNET_SYSERR == GNUNET_REST_jsonapi_data_serialize (handle->resp_object, &result))
421     {
422       GNUNET_SCHEDULER_add_now (&do_error, handle);
423       return;
424     }
425     resp = GNUNET_REST_create_json_response (result);
426     handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
427     GNUNET_free (result);
428     GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
429     return;
430   }
431
432   if ( (NULL != handle->name) &&
433        (0 != strcmp (handle->name, rname)) )
434   {
435     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
436                 "%s does not match %s\n", rname, handle->name);
437     GNUNET_NAMESTORE_zone_iterator_next (handle->list_it);
438     return;
439   }
440
441   result_array = json_array ();
442   for (i=0; i<rd_len; i++)
443   {
444     if ( (GNUNET_GNSRECORD_TYPE_NICK == rd[i].record_type) &&
445          (0 != strcmp (rname, "+")) )
446       continue;
447
448     if ( (rd[i].record_type != handle->type) &&
449          (GNUNET_GNSRECORD_TYPE_ANY != handle->type) )
450       continue;
451     record_obj = gnsrecord_to_json (&(rd[i]));
452     json_array_append (result_array, record_obj);
453     json_decref (record_obj);
454   }
455
456   if (0 < json_array_size(result_array))
457   {
458     json_resource = GNUNET_REST_jsonapi_resource_new (GNUNET_REST_JSONAPI_NAMESTORE_TYPEINFO,
459                                                       rname);
460     GNUNET_REST_jsonapi_resource_add_attr (json_resource,
461                                            GNUNET_REST_JSONAPI_NAMESTORE_RECORD,
462                                            result_array);
463     GNUNET_REST_jsonapi_object_resource_add (handle->resp_object, json_resource);
464   }
465
466   json_decref (result_array);
467   GNUNET_NAMESTORE_zone_iterator_next (handle->list_it);
468 }
469
470 static void
471 create_finished (void *cls, int32_t success, const char *emsg)
472 {
473   struct RequestHandle *handle = cls;
474   struct MHD_Response *resp;
475
476   handle->add_qe = NULL;
477   if (GNUNET_YES != success)
478   {
479     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
480                 "Error storing records%s%s\n",
481                 (NULL == emsg) ? "" : ": ",
482                 (NULL == emsg) ? "" : emsg);
483     GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
484     return;
485   }
486   resp = GNUNET_REST_create_json_response (NULL);
487   handle->proc (handle->proc_cls, resp, MHD_HTTP_NO_CONTENT);
488   GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
489 }
490
491
492 /**
493  * We're storing a new record; this requires
494  * that no record already exists
495  *
496  * @param cls closure, unused
497  * @param zone_key private key of the zone
498  * @param rec_name name that is being mapped (at most 255 characters long)
499  * @param rd_count number of entries in @a rd array
500  * @param rd array of records with data to store
501  */
502 static void
503 create_new_record_cont (void *cls,
504                         const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
505                         const char *rec_name,
506                         unsigned int rd_count,
507                         const struct GNUNET_GNSRECORD_Data *rd)
508 {
509   struct RequestHandle *handle = cls;
510
511   handle->add_qe = NULL;
512   if ( (NULL != zone_key) &&
513        (0 != strcmp (rec_name, handle->name)) )
514   {
515     GNUNET_break (0);
516     GNUNET_SCHEDULER_add_now (&do_error, handle);
517     return;
518   }
519
520   if (0 != rd_count)
521   {
522     handle->proc (handle->proc_cls,
523                   GNUNET_REST_create_json_response (NULL),
524                   MHD_HTTP_CONFLICT);
525     GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
526     return;
527   }
528
529   GNUNET_assert (NULL != handle->name);
530   handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
531                                                    &handle->zone_pkey,
532                                                    handle->name,
533                                                    handle->rd_count,
534                                                    handle->rd,
535                                                    &create_finished,
536                                                    handle);
537 }
538
539 static void
540 del_finished (void *cls,
541               int32_t success,
542               const char *emsg)
543 {
544   struct RequestHandle *handle = cls;
545
546   handle->add_qe = NULL;
547   if (GNUNET_NO == success)
548   {
549     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
550                 _("Deleting record failed, record does not exist%s%s\n"),
551                 (NULL != emsg) ? ": " : "",
552                 (NULL != emsg) ? emsg : "");
553     GNUNET_SCHEDULER_add_now (&do_error, handle); //do_not_found TODO
554     return;
555   }
556   if (GNUNET_SYSERR == success)
557   {
558     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
559                 _("Deleting record failed%s%s\n"),
560                 (NULL != emsg) ? ": " : "",
561                 (NULL != emsg) ? emsg : "");
562     GNUNET_SCHEDULER_add_now (&do_error, handle);
563     return;
564   }
565   handle->proc (handle->proc_cls,
566                 GNUNET_REST_create_json_response (NULL),
567                 MHD_HTTP_NO_CONTENT);
568   GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
569 }
570
571 static void
572 del_cont (void *cls,
573           const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
574           const char *label,
575           unsigned int rd_count,
576           const struct GNUNET_GNSRECORD_Data *rd)
577 {
578   struct RequestHandle *handle = cls;
579   handle->add_qe = NULL;
580   if (0 == rd_count)
581   {
582     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
583                 _("There are no records under label `%s' that could be deleted.\n"),
584                 label);
585     GNUNET_SCHEDULER_add_now (&do_error, handle);
586     return;
587   }
588
589   handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
590                                                    &handle->zone_pkey,
591                                                    handle->name,
592                                                    0, NULL,
593                                                    &del_finished,
594                                                    handle);
595 }
596
597 static void
598 namestore_delete_cont (struct RestConnectionDataHandle *con,
599                        const char *url,
600                        void *cls)
601 {
602   struct RequestHandle *handle = cls;
603
604   if (NULL == handle->name)
605   {
606     GNUNET_SCHEDULER_add_now (&do_error, handle);
607     return;
608   }
609
610   handle->add_qe = GNUNET_NAMESTORE_records_lookup (handle->ns_handle,
611                                                     &handle->zone_pkey,
612                                                     handle->name,
613                                                     &del_cont,
614                                                     handle);
615 }
616
617 static int
618 json_to_gnsrecord (const json_t *records_json,
619                    struct GNUNET_GNSRECORD_Data **rd,
620                    unsigned int *rd_count)
621 {
622   struct GNUNET_TIME_Relative etime_rel;
623   struct GNUNET_TIME_Absolute etime_abs;
624   char *value;
625   void *rdata;
626   size_t rdata_size;
627   const char *typestring;
628   const char *expirationstring;
629   int i;
630   json_t *type_json;
631   json_t *value_json;
632   json_t *record_json;
633   json_t *exp_json;
634
635   *rd_count = json_array_size (records_json);
636   *rd = GNUNET_malloc (sizeof (struct GNUNET_GNSRECORD_Data) * *rd_count);
637   for (i = 0; i < *rd_count; i++)
638   {
639     memset (&((*rd)[i]), 0, sizeof (struct GNUNET_GNSRECORD_Data));
640     record_json = json_array_get (records_json, i);
641     type_json = json_object_get (record_json,
642                                  GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE);
643     if (!json_is_string (type_json))
644     {
645       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
646                   "Type property is no string\n");
647       return GNUNET_SYSERR;
648     }
649     typestring = json_string_value (type_json);
650     (*rd)[i].record_type = GNUNET_GNSRECORD_typename_to_number (typestring);
651     if (UINT32_MAX == (*rd)[i].record_type)
652     {
653       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Unsupported type `%s'\n"),
654                   json_string_value (type_json));
655       return GNUNET_SYSERR;
656     }
657     value_json = json_object_get (record_json,
658                                   GNUNET_REST_JSONAPI_NAMESTORE_VALUE);
659     if (!json_is_string (value_json))
660     {
661       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
662                   "Value property is no string\n");
663       return GNUNET_SYSERR;
664     }
665     GNUNET_asprintf (&value, "%s", json_string_value (value_json));
666     if (GNUNET_OK != GNUNET_GNSRECORD_string_to_value ((*rd)[i].record_type,
667                                                        value,
668                                                        &rdata,
669                                                        &rdata_size))
670     {
671       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Value `%s' invalid for record type `%s'\n"),
672                   value, typestring);
673       return GNUNET_SYSERR;
674     }
675     (*rd)[i].data = rdata;
676     (*rd)[i].data_size = rdata_size;
677     /**TODO
678      * if (1 == handle->is_shadow)
679      rde->flags |= GNUNET_GNSRECORD_RF_SHADOW_RECORD;
680      if (1 != handle->is_public)
681      rde->flags |= GNUNET_GNSRECORD_RF_PRIVATE;
682      */
683     exp_json = json_object_get (record_json,
684                                 GNUNET_REST_JSONAPI_NAMESTORE_EXPIRATION);
685     if (!json_is_string (exp_json))
686     {
687       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
688                   "Expiration property is no string\n");
689       return GNUNET_SYSERR;
690     }
691     expirationstring = json_string_value (exp_json);
692     if (0 == strcmp (expirationstring, "never"))
693     {
694       (*rd)[i].expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
695     }
696     else if (GNUNET_OK ==
697              GNUNET_STRINGS_fancy_time_to_relative (expirationstring,
698                                                     &etime_rel))
699     {
700       (*rd)[i].expiration_time = etime_rel.rel_value_us;
701       (*rd)[i].flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
702     }
703     else if (GNUNET_OK ==
704              GNUNET_STRINGS_fancy_time_to_absolute (expirationstring,
705                                                     &etime_abs))
706     {
707       (*rd)[i].expiration_time = etime_abs.abs_value_us;
708     }
709     else
710     {
711       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Value `%s' invalid for record type `%s'\n"),
712                   value, typestring);
713       return GNUNET_SYSERR;
714     }
715   }
716   return GNUNET_OK;
717 }
718
719 static void
720 namestore_create_cont (struct RestConnectionDataHandle *con,
721                        const char *url,
722                        void *cls)
723 {
724   struct RequestHandle *handle = cls;
725   struct MHD_Response *resp;
726   struct JsonApiObject *json_obj;
727   struct JsonApiResource *json_res;
728   json_t *name_json;
729   json_t *records_json;
730   char term_data[handle->data_size+1];
731
732   if (strlen (GNUNET_REST_API_NS_NAMESTORE) != strlen (handle->url))
733   {
734     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
735                 "Cannot create under %s\n", handle->url);
736     GNUNET_SCHEDULER_add_now (&do_error, handle);
737     return;
738   }
739   if (0 >= handle->data_size)
740   {
741     GNUNET_SCHEDULER_add_now (&do_error, handle);
742     return;
743   }
744   term_data[handle->data_size] = '\0';
745   memcpy (term_data, handle->data, handle->data_size);
746   json_obj = GNUNET_REST_jsonapi_object_parse (term_data);
747   if (NULL == json_obj)
748   {
749     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
750                 "Unable to parse JSONAPI Object from %s\n",
751                 term_data);
752     GNUNET_SCHEDULER_add_now (&do_error, handle);
753     return;
754   }
755   if (1 != GNUNET_REST_jsonapi_object_resource_count (json_obj))
756   {
757     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
758                 "Cannot create more than 1 resource! (Got %d)\n",
759                 GNUNET_REST_jsonapi_object_resource_count (json_obj));
760     GNUNET_REST_jsonapi_object_delete (json_obj);
761     GNUNET_SCHEDULER_add_now (&do_error, handle);
762     return;
763   }
764   json_res = GNUNET_REST_jsonapi_object_get_resource (json_obj, 0);
765   if (GNUNET_NO == GNUNET_REST_jsonapi_resource_check_type (json_res,
766                                                             GNUNET_REST_JSONAPI_NAMESTORE_RECORD))
767   {
768     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
769                 "Unsupported JSON data type\n");
770     GNUNET_REST_jsonapi_object_delete (json_obj);
771     resp = GNUNET_REST_create_json_response (NULL);
772     handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
773     cleanup_handle (handle);
774     return;
775   }
776   name_json = GNUNET_REST_jsonapi_resource_read_attr (json_res, GNUNET_REST_JSONAPI_KEY_ID);
777   if (!json_is_string (name_json))
778   {
779     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
780                 "Name property is no string\n");
781     GNUNET_REST_jsonapi_object_delete (json_obj);
782     GNUNET_SCHEDULER_add_now (&do_error, handle);
783     return;
784   }
785   GNUNET_asprintf (&handle->name, "%s", json_string_value (name_json));
786   records_json = GNUNET_REST_jsonapi_resource_read_attr (json_res,
787                                                          GNUNET_REST_JSONAPI_NAMESTORE_RECORD);
788   if (NULL == records_json)
789   {
790     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
791                 "No records given\n");
792     GNUNET_REST_jsonapi_object_delete (json_obj);
793     GNUNET_SCHEDULER_add_now (&do_error, handle);
794     return;
795   }
796   if (GNUNET_SYSERR == json_to_gnsrecord (records_json, &handle->rd, &handle->rd_count))
797   {
798     GNUNET_REST_jsonapi_object_delete (json_obj);
799     GNUNET_SCHEDULER_add_now (&do_error, handle);
800     return;
801   }
802   GNUNET_REST_jsonapi_object_delete (json_obj);
803
804   handle->add_qe = GNUNET_NAMESTORE_records_lookup (handle->ns_handle,
805                                                     &handle->zone_pkey,
806                                                     handle->name,
807                                                     &create_new_record_cont, handle );
808 }
809
810 static void
811 namestore_zkey_response (void *cls,
812                          const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
813                          const char *label,
814                          unsigned int rd_count,
815                          const struct GNUNET_GNSRECORD_Data *rd)
816 {
817   struct RequestHandle *handle = cls;
818   struct MHD_Response *resp;
819   struct JsonApiObject *json_obj;
820   struct JsonApiResource *json_res;
821   json_t *name_json;
822   char* result;
823
824   handle->reverse_qe = NULL;
825   json_obj = GNUNET_REST_jsonapi_object_new ();
826   if (NULL != label)
827   {
828     name_json = json_string (label);
829     json_res = GNUNET_REST_jsonapi_resource_new (GNUNET_REST_JSONAPI_NAMESTORE_REVINFO,
830                                                  handle->zkey_str);
831     GNUNET_REST_jsonapi_resource_add_attr (json_res,
832                                            GNUNET_REST_JSONAPI_NAMESTORE_NAME,
833                                            name_json);
834     GNUNET_REST_jsonapi_object_resource_add (json_obj, json_res);
835     json_decref (name_json);
836   }
837   //Handle response
838   if (GNUNET_SYSERR == GNUNET_REST_jsonapi_data_serialize (json_obj, &result))
839   {
840     GNUNET_REST_jsonapi_object_delete (json_obj);
841     GNUNET_SCHEDULER_add_now (&do_error, handle);
842     return;
843   }
844   resp = GNUNET_REST_create_json_response (result);
845   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
846   GNUNET_REST_jsonapi_object_delete (json_obj);
847   GNUNET_free (result);
848   GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
849   return;
850
851 }
852
853 static void
854 namestore_zkey_cont (struct RestConnectionDataHandle *con,
855                      const char *url,
856                      void *cls)
857 {
858   struct RequestHandle *handle = cls;
859   struct GNUNET_HashCode key;
860   struct GNUNET_CRYPTO_EcdsaPublicKey pubkey;
861
862   GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_NAMESTORE_ZKEY,
863                       strlen (GNUNET_REST_JSONAPI_NAMESTORE_ZKEY),
864                       &key);
865   if ( GNUNET_NO ==
866        GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
867                                                &key) )
868   {
869     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
870                 "No zkey given %s\n", handle->url);
871     GNUNET_SCHEDULER_add_now (&do_error, handle);
872     return;
873   }
874   handle->zkey_str = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
875                                             &key);
876   if (GNUNET_OK !=
877       GNUNET_CRYPTO_ecdsa_public_key_from_string (handle->zkey_str,
878                                                   strlen (handle->zkey_str),
879                                                   &pubkey))
880   {
881     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
882                 "Zkey invalid %s\n", handle->zkey_str);
883     GNUNET_SCHEDULER_add_now (&do_error, handle);
884     return;
885   }
886   handle->reverse_qe = GNUNET_NAMESTORE_zone_to_name (handle->ns_handle,
887                                                       &handle->zone_pkey,
888                                                       &pubkey,
889                                                       &namestore_zkey_response,
890                                                       handle);
891 }
892
893 static void
894 namestore_info_cont (struct RestConnectionDataHandle *con,
895                      const char *url,
896                      void *cls)
897 {
898   struct RequestHandle *handle = cls;
899   handle->list_it = GNUNET_NAMESTORE_zone_iteration_start (handle->ns_handle,
900                                                            &handle->zone_pkey,
901                                                            &namestore_list_response,
902                                                            handle);
903 }
904
905 static char*
906 get_name_from_url (const char* url)
907 {
908   if (strlen (url) <= strlen (GNUNET_REST_API_NS_NAMESTORE))
909     return NULL;
910   return (char*)url + strlen (GNUNET_REST_API_NS_NAMESTORE) + 1;
911 }
912
913 /**
914  * Respond to OPTIONS request
915  *
916  * @param con_handle the connection handle
917  * @param url the url
918  * @param cls the RequestHandle
919  */
920 static void
921 options_cont (struct RestConnectionDataHandle *con_handle,
922               const char* url,
923               void *cls)
924 {
925   struct MHD_Response *resp;
926   struct RequestHandle *handle = cls;
927
928   //For now, independent of path return all options
929   resp = GNUNET_REST_create_json_response (NULL);
930   MHD_add_response_header (resp,
931                            "Access-Control-Allow-Methods",
932                            allow_methods);
933   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
934   cleanup_handle (handle);
935   return;
936 }
937
938 /**
939  * Function called with the result from the check if the namestore
940  * service is actually running.  If it is, we start the actual
941  * operation.
942  *
943  * @param cls closure with our configuration
944  * @param result #GNUNET_YES if the namestore service is running
945  */
946 static void
947 testservice_task (void *cls,
948                   int result)
949 {
950   struct RequestHandle *handle = cls;
951   static const struct GNUNET_REST_RestConnectionHandler 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_NO == GNUNET_REST_handle_request (handle->conndata_handle, handlers, handle))
978     GNUNET_SCHEDULER_add_now (&do_error, (void*) handle);
979
980 }
981
982 /**
983  * Callback invoked from identity service with ego information.
984  * An @a ego of NULL means the ego was not found.
985  *
986  * @param cls closure with the configuration
987  * @param ego an ego known to identity service, or NULL
988  */
989 static void
990 identity_cb (void *cls,
991              const struct GNUNET_IDENTITY_Ego *ego)
992 {
993   struct RequestHandle *handle = cls;
994   struct MHD_Response *resp;
995
996   handle->ego_lookup = NULL;
997   if (NULL == ego)
998   {
999     if (NULL != handle->ego_name)
1000     {
1001       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1002                   _("Ego `%s' not known to identity service\n"),
1003                   handle->ego_name);
1004     }
1005     resp = GNUNET_REST_create_json_response (NULL);
1006     handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
1007     cleanup_handle (handle);
1008     return;
1009   }
1010   handle->zone_pkey = *GNUNET_IDENTITY_ego_get_private_key (ego);
1011   GNUNET_CLIENT_service_test ("namestore", handle->cfg,
1012                               GNUNET_TIME_UNIT_SECONDS,
1013                               &testservice_task,
1014                               (void *) handle);
1015 }
1016
1017 static void
1018 default_ego_cb (void *cls,
1019                 struct GNUNET_IDENTITY_Ego *ego,
1020                 void **ctx,
1021                 const char *name)
1022 {
1023   struct RequestHandle *handle = cls;
1024   struct MHD_Response *resp;
1025   handle->get_default = NULL;
1026   if (NULL == ego)
1027   {
1028     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1029                 _("No default ego configured in identity service\n"));
1030     resp = GNUNET_REST_create_json_response (NULL);
1031     handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
1032     cleanup_handle (handle);
1033     return;
1034   }
1035   else
1036   {
1037     identity_cb (cls, ego);
1038   }
1039 }
1040
1041 static void
1042 id_connect_cb (void *cls,
1043                struct GNUNET_IDENTITY_Ego *ego,
1044                void **ctx,
1045                const char *name)
1046 {
1047   struct RequestHandle *handle = cls;
1048   if (NULL == ego)
1049   {
1050     handle->get_default = GNUNET_IDENTITY_get (handle->identity_handle,
1051                                                "namestore",
1052                                                &default_ego_cb, handle);
1053   }
1054 }
1055
1056 static void
1057 testservice_id_task (void *cls, int result)
1058 {
1059   struct RequestHandle *handle = cls;
1060   struct MHD_Response *resp;
1061   struct GNUNET_HashCode key;
1062   char *ego;
1063   char *name;
1064   char *type;
1065
1066   if (result != GNUNET_YES)
1067   {
1068     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1069                 _("Identity service is not running\n"));
1070     resp = GNUNET_REST_create_json_response (NULL);
1071     handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
1072     cleanup_handle (handle);
1073     return;
1074   }
1075   ego = NULL;
1076   GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_NAMESTORE_EGO,
1077                       strlen (GNUNET_REST_JSONAPI_NAMESTORE_EGO),
1078                       &key);
1079   if ( GNUNET_YES ==
1080        GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
1081                                                &key) )
1082   {
1083     ego = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
1084                                              &key);
1085   }
1086
1087   handle->type = GNUNET_GNSRECORD_TYPE_ANY;
1088   GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE,
1089                       strlen (GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE),
1090                       &key);
1091   if ( GNUNET_YES ==
1092        GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
1093                                                &key) )
1094   {
1095     type = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
1096                                               &key);
1097
1098     handle->type = GNUNET_GNSRECORD_typename_to_number (type);
1099   }
1100   name = get_name_from_url (handle->url);
1101   if (NULL != ego)
1102     GNUNET_asprintf (&handle->ego_name, "%s", ego);
1103   if (NULL != name)
1104     GNUNET_asprintf (&handle->name, "%s", name);
1105   if (NULL == handle->ego_name)
1106   {
1107     handle->identity_handle = GNUNET_IDENTITY_connect (handle->cfg, &id_connect_cb, handle);
1108     if (NULL == handle->identity_handle)
1109     {
1110       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Cannot connect to identity service\n"));
1111       resp = GNUNET_REST_create_json_response (NULL);
1112       handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
1113       cleanup_handle (handle);
1114     }
1115     return;
1116   }
1117   handle->ego_lookup = GNUNET_IDENTITY_ego_lookup (cfg,
1118                                                    handle->ego_name,
1119                                                    &identity_cb,
1120                                                    handle);
1121 }
1122
1123 /**
1124  * Function processing the REST call
1125  *
1126  * @param method HTTP method
1127  * @param url URL of the HTTP request
1128  * @param data body of the HTTP request (optional)
1129  * @param data_size length of the body
1130  * @param proc callback function for the result
1131  * @param proc_cls closure for callback function
1132  * @return GNUNET_OK if request accepted
1133  */
1134 static void
1135 rest_identity_process_request(struct RestConnectionDataHandle *conndata_handle,
1136                               GNUNET_REST_ResultProcessor proc,
1137                               void *proc_cls)
1138 {
1139   struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1140
1141   handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1142   handle->proc_cls = proc_cls;
1143   handle->proc = proc;
1144   handle->conndata_handle = conndata_handle;
1145   handle->data = conndata_handle->data;
1146   handle->data_size = conndata_handle->data_size;
1147   GNUNET_asprintf (&handle->url, "%s", conndata_handle->url);
1148   if (handle->url[strlen (handle->url)-1] == '/')
1149     handle->url[strlen (handle->url)-1] = '\0';
1150   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1151               "Connecting...\n");
1152   handle->cfg = cfg;
1153   GNUNET_CLIENT_service_test ("identity",
1154                               cfg,
1155                               GNUNET_TIME_UNIT_SECONDS,
1156                               &testservice_id_task,
1157                               handle);
1158   handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout,
1159                                                        &do_timeout,
1160                                                        handle);
1161 }
1162
1163 /**
1164  * Entry point for the plugin.
1165  *
1166  * @param cls Config info
1167  * @return NULL on error, otherwise the plugin context
1168  */
1169 void *
1170 libgnunet_plugin_rest_namestore_init (void *cls)
1171 {
1172   static struct Plugin plugin;
1173   cfg = cls;
1174   struct GNUNET_REST_Plugin *api;
1175
1176   if (NULL != plugin.cfg)
1177     return NULL;                /* can only initialize once! */
1178   memset (&plugin, 0, sizeof (struct Plugin));
1179   plugin.cfg = cfg;
1180   api = GNUNET_new (struct GNUNET_REST_Plugin);
1181   api->cls = &plugin;
1182   api->name = GNUNET_REST_API_NS_NAMESTORE;
1183   api->process_request = &rest_identity_process_request;
1184   GNUNET_asprintf (&allow_methods,
1185                    "%s, %s, %s, %s, %s",
1186                    MHD_HTTP_METHOD_GET,
1187                    MHD_HTTP_METHOD_POST,
1188                    MHD_HTTP_METHOD_PUT,
1189                    MHD_HTTP_METHOD_DELETE,
1190                    MHD_HTTP_METHOD_OPTIONS);
1191   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1192               _("Namestore REST API initialized\n"));
1193   return api;
1194 }
1195
1196
1197 /**
1198  * Exit point from the plugin.
1199  *
1200  * @param cls the plugin context (as returned by "init")
1201  * @return always NULL
1202  */
1203 void *
1204 libgnunet_plugin_rest_namestore_done (void *cls)
1205 {
1206   struct GNUNET_REST_Plugin *api = cls;
1207   struct Plugin *plugin = api->cls;
1208
1209   plugin->cfg = NULL;
1210   GNUNET_free (api);
1211   GNUNET_free_non_null (allow_methods);
1212   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1213               "Namestore REST plugin is finished\n");
1214   return NULL;
1215 }
1216
1217 /* end of plugin_rest_namestore.c */