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