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