handle errors without crashing
[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  * Iteration over all results finished, build final
392  * response.
393  *
394  * @param cls the `struct RequestHandle`
395  */
396 static void
397 namestore_list_finished (void *cls)
398 {
399   struct RequestHandle *handle = cls;
400   char *result;
401   struct MHD_Response *resp;
402
403   handle->list_it = NULL;
404   if (GNUNET_SYSERR ==
405       GNUNET_JSONAPI_document_serialize (handle->resp_object,
406                                          &result))
407   {
408     do_error (handle);
409     return;
410   }
411   resp = GNUNET_REST_create_response (result);
412   handle->proc (handle->proc_cls,
413                 resp,
414                 MHD_HTTP_OK);
415   GNUNET_free_non_null (result);
416   GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed,
417                             handle);
418 }
419
420
421
422 /**
423  * Create a response with requested records
424  *
425  * @param handle the RequestHandle
426  */
427 static void
428 namestore_list_response (void *cls,
429                          const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
430                          const char *rname,
431                          unsigned int rd_len,
432                          const struct GNUNET_GNSRECORD_Data *rd)
433 {
434   struct RequestHandle *handle = cls;
435   struct GNUNET_JSONAPI_Resource *json_resource;
436   json_t *result_array;
437   json_t *record_obj;
438   int i;
439
440   if (NULL == handle->resp_object)
441     handle->resp_object = GNUNET_JSONAPI_document_new ();
442
443   if ( (NULL != handle->name) &&
444        (0 != strcmp (handle->name, rname)) )
445   {
446     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
447                 "%s does not match %s\n", rname, handle->name);
448     GNUNET_NAMESTORE_zone_iterator_next (handle->list_it);
449     return;
450   }
451
452   result_array = json_array ();
453   for (i=0; i<rd_len; i++)
454   {
455     if ( (GNUNET_GNSRECORD_TYPE_NICK == rd[i].record_type) &&
456          (0 != strcmp (rname, "+")) )
457       continue;
458
459     if ( (rd[i].record_type != handle->type) &&
460          (GNUNET_GNSRECORD_TYPE_ANY != handle->type) )
461       continue;
462     record_obj = gnsrecord_to_json (&(rd[i]));
463     json_array_append (result_array, record_obj);
464     json_decref (record_obj);
465   }
466
467   if (0 < json_array_size(result_array))
468   {
469     json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_NAMESTORE_TYPEINFO,
470                                                       rname);
471     GNUNET_JSONAPI_resource_add_attr (json_resource,
472                                            GNUNET_REST_JSONAPI_NAMESTORE_RECORD,
473                                            result_array);
474     GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
475   }
476
477   json_decref (result_array);
478   GNUNET_NAMESTORE_zone_iterator_next (handle->list_it);
479 }
480
481
482 static void
483 create_finished (void *cls, int32_t success, const char *emsg)
484 {
485   struct RequestHandle *handle = cls;
486   struct MHD_Response *resp;
487
488   handle->add_qe = NULL;
489   if (GNUNET_YES != success)
490   {
491     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
492                 "Error storing records%s%s\n",
493                 (NULL == emsg) ? "" : ": ",
494                 (NULL == emsg) ? "" : emsg);
495     GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
496     return;
497   }
498   resp = GNUNET_REST_create_response (NULL);
499   handle->proc (handle->proc_cls, resp, MHD_HTTP_NO_CONTENT);
500   GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
501 }
502
503
504 /**
505  * We're storing a new record; this requires
506  * that no record already exists
507  *
508  * @param cls closure, unused
509  * @param zone_key private key of the zone
510  * @param rec_name name that is being mapped (at most 255 characters long)
511  * @param rd_count number of entries in @a rd array
512  * @param rd array of records with data to store
513  */
514 static void
515 create_new_record_cont (void *cls,
516                         const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
517                         const char *rec_name,
518                         unsigned int rd_count,
519                         const struct GNUNET_GNSRECORD_Data *rd)
520 {
521   struct RequestHandle *handle = cls;
522
523   handle->add_qe = NULL;
524   if (0 != strcmp (rec_name, handle->name))
525   {
526     GNUNET_break (0);
527     do_error (handle);
528     return;
529   }
530
531   if (0 != rd_count)
532   {
533     handle->proc (handle->proc_cls,
534                   GNUNET_REST_create_response (NULL),
535                   MHD_HTTP_CONFLICT);
536     GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
537     return;
538   }
539
540   GNUNET_assert (NULL != handle->name);
541   handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
542                                                    &handle->zone_pkey,
543                                                    handle->name,
544                                                    handle->rd_count,
545                                                    handle->rd,
546                                                    &create_finished,
547                                                    handle);
548 }
549
550
551 static void
552 del_finished (void *cls,
553               int32_t success,
554               const char *emsg)
555 {
556   struct RequestHandle *handle = cls;
557
558   handle->add_qe = NULL;
559   if (GNUNET_NO == success)
560   {
561     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
562                 _("Deleting record failed, record does not exist%s%s\n"),
563                 (NULL != emsg) ? ": " : "",
564                 (NULL != emsg) ? emsg : "");
565     GNUNET_SCHEDULER_add_now (&do_error, handle); //do_not_found TODO
566     return;
567   }
568   if (GNUNET_SYSERR == success)
569   {
570     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
571                 _("Deleting record failed%s%s\n"),
572                 (NULL != emsg) ? ": " : "",
573                 (NULL != emsg) ? emsg : "");
574     GNUNET_SCHEDULER_add_now (&do_error, handle);
575     return;
576   }
577   handle->proc (handle->proc_cls,
578                 GNUNET_REST_create_response (NULL),
579                 MHD_HTTP_NO_CONTENT);
580   GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
581 }
582
583
584 static void
585 del_cont (void *cls,
586           const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
587           const char *label,
588           unsigned int rd_count,
589           const struct GNUNET_GNSRECORD_Data *rd)
590 {
591   struct RequestHandle *handle = cls;
592
593   handle->add_qe = NULL;
594   if (0 == rd_count)
595   {
596     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
597                 _("There are no records under label `%s' that could be deleted.\n"),
598                 label);
599     do_error (handle);
600     return;
601   }
602
603   handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
604                                                    &handle->zone_pkey,
605                                                    handle->name,
606                                                    0, NULL,
607                                                    &del_finished,
608                                                    handle);
609 }
610
611
612 static void
613 namestore_delete_cont (struct GNUNET_REST_RequestHandle *con,
614                        const char *url,
615                        void *cls)
616 {
617   struct RequestHandle *handle = cls;
618
619   if (NULL == handle->name)
620   {
621     GNUNET_SCHEDULER_add_now (&do_error, handle);
622     return;
623   }
624
625   handle->add_qe = GNUNET_NAMESTORE_records_lookup (handle->ns_handle,
626                                                     &handle->zone_pkey,
627                                                     handle->name,
628                                                     &do_error,
629                                                     handle,
630                                                     &del_cont,
631                                                     handle);
632 }
633
634
635 static int
636 json_to_gnsrecord (const json_t *records_json,
637                    struct GNUNET_GNSRECORD_Data **rd,
638                    unsigned int *rd_count)
639 {
640   struct GNUNET_TIME_Relative etime_rel;
641   struct GNUNET_TIME_Absolute etime_abs;
642   char *value;
643   void *rdata;
644   size_t rdata_size;
645   const char *typestring;
646   const char *expirationstring;
647   int i;
648   json_t *type_json;
649   json_t *value_json;
650   json_t *record_json;
651   json_t *exp_json;
652
653   *rd_count = json_array_size (records_json);
654   *rd = GNUNET_malloc (sizeof (struct GNUNET_GNSRECORD_Data) * *rd_count);
655   for (i = 0; i < *rd_count; i++)
656   {
657     memset (&((*rd)[i]), 0, sizeof (struct GNUNET_GNSRECORD_Data));
658     record_json = json_array_get (records_json, i);
659     type_json = json_object_get (record_json,
660                                  GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE);
661     if (!json_is_string (type_json))
662     {
663       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
664                   "Type property is no string\n");
665       return GNUNET_SYSERR;
666     }
667     typestring = json_string_value (type_json);
668     (*rd)[i].record_type = GNUNET_GNSRECORD_typename_to_number (typestring);
669     if (UINT32_MAX == (*rd)[i].record_type)
670     {
671       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Unsupported type `%s'\n"),
672                   json_string_value (type_json));
673       return GNUNET_SYSERR;
674     }
675     value_json = json_object_get (record_json,
676                                   GNUNET_REST_JSONAPI_NAMESTORE_VALUE);
677     if (!json_is_string (value_json))
678     {
679       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
680                   "Value property is no string\n");
681       return GNUNET_SYSERR;
682     }
683     value = GNUNET_strdup (json_string_value (value_json));
684     if (GNUNET_OK != GNUNET_GNSRECORD_string_to_value ((*rd)[i].record_type,
685                                                        value,
686                                                        &rdata,
687                                                        &rdata_size))
688     {
689       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Value `%s' invalid for record type `%s'\n"),
690                   value, typestring);
691       return GNUNET_SYSERR;
692     }
693     (*rd)[i].data = rdata;
694     (*rd)[i].data_size = rdata_size;
695     /**TODO
696      * if (1 == handle->is_shadow)
697      rde->flags |= GNUNET_GNSRECORD_RF_SHADOW_RECORD;
698      if (1 != handle->is_public)
699      rde->flags |= GNUNET_GNSRECORD_RF_PRIVATE;
700      */
701     exp_json = json_object_get (record_json,
702                                 GNUNET_REST_JSONAPI_NAMESTORE_EXPIRATION);
703     if (!json_is_string (exp_json))
704     {
705       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
706                   "Expiration property is no string\n");
707       return GNUNET_SYSERR;
708     }
709     expirationstring = json_string_value (exp_json);
710     if (0 == strcmp (expirationstring, "never"))
711     {
712       (*rd)[i].expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
713     }
714     else if (GNUNET_OK ==
715              GNUNET_STRINGS_fancy_time_to_relative (expirationstring,
716                                                     &etime_rel))
717     {
718       (*rd)[i].expiration_time = etime_rel.rel_value_us;
719       (*rd)[i].flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
720     }
721     else if (GNUNET_OK ==
722              GNUNET_STRINGS_fancy_time_to_absolute (expirationstring,
723                                                     &etime_abs))
724     {
725       (*rd)[i].expiration_time = etime_abs.abs_value_us;
726     }
727     else
728     {
729       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Value `%s' invalid for record type `%s'\n"),
730                   value, typestring);
731       return GNUNET_SYSERR;
732     }
733   }
734   return GNUNET_OK;
735 }
736
737
738 static void
739 namestore_create_cont (struct GNUNET_REST_RequestHandle *con,
740                        const char *url,
741                        void *cls)
742 {
743   struct RequestHandle *handle = cls;
744   struct MHD_Response *resp;
745   struct GNUNET_JSONAPI_Document *json_obj;
746   struct GNUNET_JSONAPI_Resource *json_res;
747   json_t *records_json;
748   json_t *data_js;
749   json_error_t err;
750   char term_data[handle->rest_handle->data_size+1];
751   struct GNUNET_JSON_Specification docspec[] = {
752     GNUNET_JSON_spec_jsonapi_document (&json_obj),
753     GNUNET_JSON_spec_end()
754   };
755
756   if (strlen (GNUNET_REST_API_NS_NAMESTORE) != strlen (handle->url))
757   {
758     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
759                 "Cannot create under %s\n", handle->url);
760     GNUNET_SCHEDULER_add_now (&do_error, handle);
761     return;
762   }
763   if (0 >= handle->rest_handle->data_size)
764   {
765     GNUNET_SCHEDULER_add_now (&do_error, handle);
766     return;
767   }
768   term_data[handle->rest_handle->data_size] = '\0';
769   GNUNET_memcpy (term_data,
770           handle->rest_handle->data,
771           handle->rest_handle->data_size);
772   data_js = json_loads (term_data,
773                         JSON_DECODE_ANY,
774                         &err);
775   GNUNET_assert (GNUNET_OK ==
776                  GNUNET_JSON_parse (data_js, docspec,
777                                     NULL, NULL));
778   json_decref (data_js);
779   if (NULL == json_obj)
780   {
781     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
782                 "Unable to parse JSONAPI Object from %s\n",
783                 term_data);
784     GNUNET_SCHEDULER_add_now (&do_error, handle);
785     return;
786   }
787   if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
788   {
789     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
790                 "Cannot create more than 1 resource! (Got %d)\n",
791                 GNUNET_JSONAPI_document_resource_count (json_obj));
792     GNUNET_JSONAPI_document_delete (json_obj);
793     GNUNET_SCHEDULER_add_now (&do_error, handle);
794     return;
795   }
796   json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
797   if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res,
798                                                        GNUNET_REST_JSONAPI_NAMESTORE_RECORD))
799   {
800     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
801                 "Unsupported JSON data type\n");
802     GNUNET_JSONAPI_document_delete (json_obj);
803     resp = GNUNET_REST_create_response (NULL);
804     handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
805     cleanup_handle (handle);
806     return;
807   }
808   handle->name = GNUNET_strdup (GNUNET_JSONAPI_resource_get_id (json_res));
809   records_json = GNUNET_JSONAPI_resource_read_attr (json_res,
810                                                     GNUNET_REST_JSONAPI_NAMESTORE_RECORD);
811   if (NULL == records_json)
812   {
813     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
814                 "No records given\n");
815     GNUNET_JSONAPI_document_delete (json_obj);
816     GNUNET_SCHEDULER_add_now (&do_error, handle);
817     return;
818   }
819   if (GNUNET_SYSERR == json_to_gnsrecord (records_json, &handle->rd, &handle->rd_count))
820   {
821     GNUNET_JSONAPI_document_delete (json_obj);
822     GNUNET_SCHEDULER_add_now (&do_error, handle);
823     return;
824   }
825   GNUNET_JSONAPI_document_delete (json_obj);
826
827   handle->add_qe = GNUNET_NAMESTORE_records_lookup (handle->ns_handle,
828                                                     &handle->zone_pkey,
829                                                     handle->name,
830                                                     &do_error,
831                                                     handle,
832                                                     &create_new_record_cont,
833                                                     handle);
834 }
835
836
837 static void
838 namestore_zkey_response (void *cls,
839                          const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
840                          const char *label,
841                          unsigned int rd_count,
842                          const struct GNUNET_GNSRECORD_Data *rd)
843 {
844   struct RequestHandle *handle = cls;
845   struct MHD_Response *resp;
846   struct GNUNET_JSONAPI_Document *json_obj;
847   struct GNUNET_JSONAPI_Resource *json_res;
848   json_t *name_json;
849   char* result;
850
851   handle->reverse_qe = NULL;
852   json_obj = GNUNET_JSONAPI_document_new ();
853   if (NULL != label)
854   {
855     name_json = json_string (label);
856     json_res = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_NAMESTORE_REVINFO,
857                                             handle->zkey_str);
858     GNUNET_JSONAPI_resource_add_attr (json_res,
859                                       GNUNET_REST_JSONAPI_NAMESTORE_NAME,
860                                       name_json);
861     GNUNET_JSONAPI_document_resource_add (json_obj, json_res);
862     json_decref (name_json);
863   }
864   //Handle response
865   if (GNUNET_SYSERR == GNUNET_JSONAPI_document_serialize (json_obj, &result))
866   {
867     GNUNET_JSONAPI_document_delete (json_obj);
868     GNUNET_SCHEDULER_add_now (&do_error, handle);
869     return;
870   }
871   resp = GNUNET_REST_create_response (result);
872   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
873   GNUNET_JSONAPI_document_delete (json_obj);
874   GNUNET_free (result);
875   GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
876 }
877
878
879 static void
880 namestore_zkey_cont (struct GNUNET_REST_RequestHandle *con,
881                      const char *url,
882                      void *cls)
883 {
884   struct RequestHandle *handle = cls;
885   struct GNUNET_HashCode key;
886   struct GNUNET_CRYPTO_EcdsaPublicKey pubkey;
887
888   GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_NAMESTORE_ZKEY,
889                       strlen (GNUNET_REST_JSONAPI_NAMESTORE_ZKEY),
890                       &key);
891   if ( GNUNET_NO ==
892        GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
893                                                &key) )
894   {
895     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
896                 "No zkey given %s\n", handle->url);
897     GNUNET_SCHEDULER_add_now (&do_error, handle);
898     return;
899   }
900   handle->zkey_str = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
901                                                         &key);
902   if (GNUNET_OK !=
903       GNUNET_CRYPTO_ecdsa_public_key_from_string (handle->zkey_str,
904                                                   strlen (handle->zkey_str),
905                                                   &pubkey))
906   {
907     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
908                 "Zkey invalid %s\n", handle->zkey_str);
909     GNUNET_SCHEDULER_add_now (&do_error, handle);
910     return;
911   }
912   handle->reverse_qe = GNUNET_NAMESTORE_zone_to_name (handle->ns_handle,
913                                                       &handle->zone_pkey,
914                                                       &pubkey,
915                                                       &do_error,
916                                                       handle,
917                                                       &namestore_zkey_response,
918                                                       handle);
919 }
920
921
922 static void
923 namestore_info_cont (struct GNUNET_REST_RequestHandle *con,
924                      const char *url,
925                      void *cls)
926 {
927   struct RequestHandle *handle = cls;
928
929   handle->list_it = GNUNET_NAMESTORE_zone_iteration_start (handle->ns_handle,
930                                                            &handle->zone_pkey,
931                                                            &do_error,
932                                                            handle,
933                                                            &namestore_list_response,
934                                                            handle,
935                                                            &namestore_list_finished,
936                                                            handle);
937 }
938
939
940 static char*
941 get_name_from_url (const char* url)
942 {
943   if (strlen (url) <= strlen (GNUNET_REST_API_NS_NAMESTORE))
944     return NULL;
945   return (char*)url + strlen (GNUNET_REST_API_NS_NAMESTORE) + 1;
946 }
947
948 /**
949  * Respond to OPTIONS request
950  *
951  * @param con_handle the connection handle
952  * @param url the url
953  * @param cls the RequestHandle
954  */
955 static void
956 options_cont (struct GNUNET_REST_RequestHandle *con_handle,
957               const char* url,
958               void *cls)
959 {
960   struct MHD_Response *resp;
961   struct RequestHandle *handle = cls;
962
963   //For now, independent of path return all options
964   resp = GNUNET_REST_create_response (NULL);
965   MHD_add_response_header (resp,
966                            "Access-Control-Allow-Methods",
967                            allow_methods);
968   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
969   cleanup_handle (handle);
970 }
971
972
973 /**
974  * Callback invoked from identity service with ego information.
975  * An @a ego of NULL means the ego was not found.
976  *
977  * @param cls closure with the configuration
978  * @param ego an ego known to identity service, or NULL
979  */
980 static void
981 identity_cb (void *cls,
982              const struct GNUNET_IDENTITY_Ego *ego)
983 {
984   struct RequestHandle *handle = cls;
985   struct MHD_Response *resp;
986   struct GNUNET_REST_RequestHandlerError err;
987   static const struct GNUNET_REST_RequestHandler handlers[] = {
988     {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_NAMESTORE_ZKEY, &namestore_zkey_cont}, //reverse
989     {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_NAMESTORE, &namestore_info_cont}, //list
990     {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_NAMESTORE, &namestore_create_cont}, //create
991     //    {MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_NAMESTORE, &namestore_edit_cont}, //update. TODO this shoul be PATCH
992     {MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_NAMESTORE, &namestore_delete_cont}, //delete
993     {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_NAMESTORE, &options_cont},
994     GNUNET_REST_HANDLER_END
995   };
996
997   handle->ego_lookup = NULL;
998   if (NULL == ego)
999   {
1000     if (NULL != handle->ego_name)
1001     {
1002       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1003                   _("Ego `%s' not known to identity service\n"),
1004                   handle->ego_name);
1005     }
1006     resp = GNUNET_REST_create_response (NULL);
1007     handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
1008     cleanup_handle (handle);
1009     return;
1010   }
1011   handle->zone_pkey = *GNUNET_IDENTITY_ego_get_private_key (ego);
1012   handle->ns_handle = GNUNET_NAMESTORE_connect (cfg);
1013   if (NULL == handle->ns_handle)
1014   {
1015     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1016                 _("Failed to connect to namestore\n"));
1017     GNUNET_SCHEDULER_add_now (&do_error, handle);
1018     return;
1019   }
1020
1021   if (GNUNET_OK !=
1022       GNUNET_JSONAPI_handle_request (handle->rest_handle,
1023                                      handlers,
1024                                      &err,
1025                                      handle))
1026   {
1027     handle->response_code = err.error_code;
1028     GNUNET_SCHEDULER_add_now (&do_error,
1029                               (void *) handle);
1030   }
1031 }
1032
1033
1034 static void
1035 default_ego_cb (void *cls,
1036                 struct GNUNET_IDENTITY_Ego *ego,
1037                 void **ctx,
1038                 const char *name)
1039 {
1040   struct RequestHandle *handle = cls;
1041   struct MHD_Response *resp;
1042   handle->get_default = NULL;
1043   if (NULL == ego)
1044   {
1045     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1046                 _("No default ego configured in identity service\n"));
1047     resp = GNUNET_REST_create_response (NULL);
1048     handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
1049     cleanup_handle (handle);
1050     return;
1051   }
1052   else
1053   {
1054     identity_cb (cls, ego);
1055   }
1056 }
1057
1058 static void
1059 id_connect_cb (void *cls,
1060                struct GNUNET_IDENTITY_Ego *ego,
1061                void **ctx,
1062                const char *name)
1063 {
1064   struct RequestHandle *handle = cls;
1065   if (NULL == ego)
1066   {
1067     handle->get_default = GNUNET_IDENTITY_get (handle->identity_handle,
1068                                                "namestore",
1069                                                &default_ego_cb, handle);
1070   }
1071 }
1072
1073
1074 /**
1075  * Function processing the REST call
1076  *
1077  * @param method HTTP method
1078  * @param url URL of the HTTP request
1079  * @param data body of the HTTP request (optional)
1080  * @param data_size length of the body
1081  * @param proc callback function for the result
1082  * @param proc_cls closure for callback function
1083  * @return #GNUNET_OK if request accepted
1084  */
1085 static void
1086 rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle,
1087                               GNUNET_REST_ResultProcessor proc,
1088                               void *proc_cls)
1089 {
1090   struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1091   struct MHD_Response *resp;
1092   struct GNUNET_HashCode key;
1093   char *ego;
1094   char *name;
1095   char *type;
1096
1097   handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1098   handle->proc_cls = proc_cls;
1099   handle->proc = proc;
1100   handle->rest_handle = rest_handle;
1101   handle->url = GNUNET_strdup (rest_handle->url);
1102   if (handle->url[strlen (handle->url)-1] == '/')
1103     handle->url[strlen (handle->url)-1] = '\0';
1104   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1105               "Connecting...\n");
1106   handle->cfg = cfg;
1107   ego = NULL;
1108   GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_NAMESTORE_EGO,
1109                       strlen (GNUNET_REST_JSONAPI_NAMESTORE_EGO),
1110                       &key);
1111   if ( GNUNET_YES ==
1112        GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1113                                                &key) )
1114   {
1115     ego = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
1116                                              &key);
1117   }
1118
1119   handle->type = GNUNET_GNSRECORD_TYPE_ANY;
1120   GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE,
1121                       strlen (GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE),
1122                       &key);
1123   if ( GNUNET_YES ==
1124        GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1125                                                &key) )
1126   {
1127     type = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
1128                                               &key);
1129
1130     handle->type = GNUNET_GNSRECORD_typename_to_number (type);
1131   }
1132   name = get_name_from_url (handle->url);
1133   if (NULL != ego)
1134     handle->ego_name = GNUNET_strdup (ego);
1135   if (NULL != name)
1136     handle->name = GNUNET_strdup (name);
1137   if (NULL == handle->ego_name)
1138   {
1139     handle->identity_handle = GNUNET_IDENTITY_connect (handle->cfg, &id_connect_cb, handle);
1140     if (NULL == handle->identity_handle)
1141     {
1142       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Cannot connect to identity service\n"));
1143       resp = GNUNET_REST_create_response (NULL);
1144       handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
1145       cleanup_handle (handle);
1146     }
1147     return;
1148   }
1149   handle->ego_lookup = GNUNET_IDENTITY_ego_lookup (cfg,
1150                                                    handle->ego_name,
1151                                                    &identity_cb,
1152                                                    handle);
1153   handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout,
1154                                                        &do_timeout,
1155                                                        handle);
1156 }
1157
1158 /**
1159  * Entry point for the plugin.
1160  *
1161  * @param cls Config info
1162  * @return NULL on error, otherwise the plugin context
1163  */
1164 void *
1165 libgnunet_plugin_rest_namestore_init (void *cls)
1166 {
1167   static struct Plugin plugin;
1168   cfg = cls;
1169   struct GNUNET_REST_Plugin *api;
1170
1171   if (NULL != plugin.cfg)
1172     return NULL;                /* can only initialize once! */
1173   memset (&plugin, 0, sizeof (struct Plugin));
1174   plugin.cfg = cfg;
1175   api = GNUNET_new (struct GNUNET_REST_Plugin);
1176   api->cls = &plugin;
1177   api->name = GNUNET_REST_API_NS_NAMESTORE;
1178   api->process_request = &rest_identity_process_request;
1179   GNUNET_asprintf (&allow_methods,
1180                    "%s, %s, %s, %s, %s",
1181                    MHD_HTTP_METHOD_GET,
1182                    MHD_HTTP_METHOD_POST,
1183                    MHD_HTTP_METHOD_PUT,
1184                    MHD_HTTP_METHOD_DELETE,
1185                    MHD_HTTP_METHOD_OPTIONS);
1186   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1187               _("Namestore REST API initialized\n"));
1188   return api;
1189 }
1190
1191
1192 /**
1193  * Exit point from the plugin.
1194  *
1195  * @param cls the plugin context (as returned by "init")
1196  * @return always NULL
1197  */
1198 void *
1199 libgnunet_plugin_rest_namestore_done (void *cls)
1200 {
1201   struct GNUNET_REST_Plugin *api = cls;
1202   struct Plugin *plugin = api->cls;
1203
1204   plugin->cfg = NULL;
1205   GNUNET_free (api);
1206   GNUNET_free_non_null (allow_methods);
1207   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1208               "Namestore REST plugin is finished\n");
1209   return NULL;
1210 }
1211
1212 /* end of plugin_rest_namestore.c */