modify zoneimport to deal with non-TLD zones due to difference in zone cuts between...
[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_gns_service.h"
30 #include "gnunet_namestore_service.h"
31 #include "gnunet_identity_service.h"
32 #include "gnunet_rest_lib.h"
33 #include "gnunet_jsonapi_lib.h"
34 #include "gnunet_jsonapi_util.h"
35 #include "microhttpd.h"
36 #include <jansson.h>
37
38 #define GNUNET_REST_API_NS_NAMESTORE "/names"
39
40 #define GNUNET_REST_API_NS_NAMESTORE_ZKEY "/names/zkey"
41
42 #define GNUNET_REST_JSONAPI_NAMESTORE_TYPEINFO "record"
43
44 #define GNUNET_REST_JSONAPI_NAMESTORE_NAME "name"
45
46 #define GNUNET_REST_JSONAPI_NAMESTORE_REVINFO "revinfo"
47
48 #define GNUNET_REST_JSONAPI_NAMESTORE_RECORD GNUNET_REST_JSONAPI_NAMESTORE_TYPEINFO
49
50 #define GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE "record_type"
51
52 #define GNUNET_REST_JSONAPI_NAMESTORE_VALUE "value"
53
54 #define GNUNET_REST_JSONAPI_NAMESTORE_PUBLIC "public"
55
56 #define GNUNET_REST_JSONAPI_NAMESTORE_SHADOW "shadow"
57
58 #define GNUNET_REST_JSONAPI_NAMESTORE_PKEY "pkey"
59
60 #define GNUNET_REST_JSONAPI_NAMESTORE_ZKEY "zkey"
61
62 #define GNUNET_REST_JSONAPI_NAMESTORE_EXPIRATION "expiration"
63
64 #define GNUNET_REST_JSONAPI_NAMESTORE_EGO "ego"
65
66 /**
67  * @brief struct returned by the initialization function of the plugin
68  */
69 struct Plugin
70 {
71   const struct GNUNET_CONFIGURATION_Handle *cfg;
72 };
73
74
75 /**
76  * HTTP methods allows for this plugin
77  */
78 static char* allow_methods;
79
80 const struct GNUNET_CONFIGURATION_Handle *cfg;
81
82 struct RecordEntry
83 {
84   /**
85    * DLL
86    */
87   struct RecordEntry *next;
88
89   /**
90    * DLL
91    */
92   struct RecordEntry *prev;
93
94 };
95
96 struct RequestHandle
97 {
98   /**
99    * Ego list
100    */
101   struct RecordEntry *record_head;
102
103   /**
104    * Ego list
105    */
106   struct record_entry *record_tail;
107
108   /**
109    * JSON response object
110    */
111   struct GNUNET_JSONAPI_Document *resp_object;
112
113   /**
114    * Rest connection
115    */
116   struct GNUNET_REST_RequestHandle *rest_handle;
117
118   /**
119    * Handle to GNS service.
120    */
121   struct GNUNET_IDENTITY_Handle *identity_handle;
122
123   /**
124    * Handle to NAMESTORE
125    */
126   struct GNUNET_NAMESTORE_Handle *ns_handle;
127
128   /**
129    * Handle to NAMESTORE it
130    */
131   struct GNUNET_NAMESTORE_ZoneIterator *list_it;
132
133   /**
134    * Private key for the zone
135    */
136   struct GNUNET_CRYPTO_EcdsaPrivateKey zone_pkey;
137
138   /**
139    * Handle to identity lookup
140    */
141   struct GNUNET_IDENTITY_EgoLookup *ego_lookup;
142
143   /**
144    * Default Ego operation
145    */
146   struct GNUNET_IDENTITY_Operation *get_default;
147
148   /**
149    * Name of the ego
150    */
151   char *ego_name;
152
153   /**
154    * Record is public
155    */
156   int is_public;
157
158   /**
159    * Shadow record
160    */
161   int is_shadow;
162
163   /**
164    * Name of the record to modify
165    */
166   char *name;
167
168   /**
169    * Value of the record
170    */
171   char *value;
172
173   /**
174    * Zkey string
175    */
176   const char* zkey_str;
177
178   /**
179    * record type
180    */
181   uint32_t type;
182
183   /**
184    * Records to store
185    */
186   struct GNUNET_GNSRECORD_Data *rd;
187
188   /**
189    * record count
190    */
191   unsigned int rd_count;
192
193   /**
194    * NAMESTORE Operation
195    */
196   struct GNUNET_NAMESTORE_QueueEntry *add_qe;
197
198   /**
199    * NAMESTORE Operation
200    */
201   struct GNUNET_NAMESTORE_QueueEntry *reverse_qe;
202
203   /**
204    * Desired timeout for the lookup (default is no timeout).
205    */
206   struct GNUNET_TIME_Relative timeout;
207
208   /**
209    * ID of a task associated with the resolution process.
210    */
211   struct GNUNET_SCHEDULER_Task * timeout_task;
212
213   /**
214    * The plugin result processor
215    */
216   GNUNET_REST_ResultProcessor proc;
217
218   /**
219    * The closure of the result processor
220    */
221   void *proc_cls;
222
223   /**
224    * The url
225    */
226   char *url;
227
228   /**
229    * Cfg
230    */
231   const struct GNUNET_CONFIGURATION_Handle *cfg;
232
233   /**
234    * HTTP response code
235    */
236   int response_code;
237
238 };
239
240
241 /**
242  * Cleanup lookup handle
243  *
244  * @param handle Handle to clean up
245  */
246 static void
247 cleanup_handle (struct RequestHandle *handle)
248 {
249   struct RecordEntry *record_entry;
250   struct RecordEntry *record_tmp;
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 (unsigned int 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
444   if (NULL == handle->resp_object)
445     handle->resp_object = GNUNET_JSONAPI_document_new ();
446
447   if ( (NULL != handle->name) &&
448        (0 != strcmp (handle->name,
449                      rname)) )
450   {
451     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
452                 "%s does not match %s\n",
453                 rname,
454                 handle->name);
455     GNUNET_NAMESTORE_zone_iterator_next (handle->list_it);
456     return;
457   }
458
459   result_array = json_array ();
460   for (unsigned int i=0; i<rd_len; i++)
461   {
462     if ( (GNUNET_GNSRECORD_TYPE_NICK == rd[i].record_type) &&
463          (0 != strcmp (rname, GNUNET_GNS_MASTERZONE_STR)) )
464       continue;
465
466     if ( (rd[i].record_type != handle->type) &&
467          (GNUNET_GNSRECORD_TYPE_ANY != handle->type) )
468       continue;
469     record_obj = gnsrecord_to_json (&rd[i]);
470     json_array_append (result_array,
471                        record_obj);
472     json_decref (record_obj);
473   }
474
475   if (0 < json_array_size(result_array))
476   {
477     json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_NAMESTORE_TYPEINFO,
478                                                  rname);
479     GNUNET_JSONAPI_resource_add_attr (json_resource,
480                                       GNUNET_REST_JSONAPI_NAMESTORE_RECORD,
481                                       result_array);
482     GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
483   }
484
485   json_decref (result_array);
486   GNUNET_NAMESTORE_zone_iterator_next (handle->list_it);
487 }
488
489
490 static void
491 create_finished (void *cls, int32_t success, const char *emsg)
492 {
493   struct RequestHandle *handle = cls;
494   struct MHD_Response *resp;
495
496   handle->add_qe = NULL;
497   if (GNUNET_YES != success)
498   {
499     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
500                 "Error storing records%s%s\n",
501                 (NULL == emsg) ? "" : ": ",
502                 (NULL == emsg) ? "" : emsg);
503     GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
504     return;
505   }
506   resp = GNUNET_REST_create_response (NULL);
507   handle->proc (handle->proc_cls, resp, MHD_HTTP_NO_CONTENT);
508   GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
509 }
510
511
512 /**
513  * We're storing a new record; this requires
514  * that no record already exists
515  *
516  * @param cls closure, unused
517  * @param zone_key private key of the zone
518  * @param rec_name name that is being mapped (at most 255 characters long)
519  * @param rd_count number of entries in @a rd array
520  * @param rd array of records with data to store
521  */
522 static void
523 create_new_record_cont (void *cls,
524                         const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
525                         const char *rec_name,
526                         unsigned int rd_count,
527                         const struct GNUNET_GNSRECORD_Data *rd)
528 {
529   struct RequestHandle *handle = cls;
530
531   handle->add_qe = NULL;
532   if (0 != strcmp (rec_name, handle->name))
533   {
534     GNUNET_break (0);
535     do_error (handle);
536     return;
537   }
538
539   if (0 != rd_count)
540   {
541     handle->proc (handle->proc_cls,
542                   GNUNET_REST_create_response (NULL),
543                   MHD_HTTP_CONFLICT);
544     GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
545     return;
546   }
547
548   GNUNET_assert (NULL != handle->name);
549   handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
550                                                    &handle->zone_pkey,
551                                                    handle->name,
552                                                    handle->rd_count,
553                                                    handle->rd,
554                                                    &create_finished,
555                                                    handle);
556 }
557
558
559 static void
560 del_finished (void *cls,
561               int32_t success,
562               const char *emsg)
563 {
564   struct RequestHandle *handle = cls;
565
566   handle->add_qe = NULL;
567   if (GNUNET_NO == success)
568   {
569     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
570                 _("Deleting record failed, record does not exist%s%s\n"),
571                 (NULL != emsg) ? ": " : "",
572                 (NULL != emsg) ? emsg : "");
573     GNUNET_SCHEDULER_add_now (&do_error, handle); //do_not_found TODO
574     return;
575   }
576   if (GNUNET_SYSERR == success)
577   {
578     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
579                 _("Deleting record failed%s%s\n"),
580                 (NULL != emsg) ? ": " : "",
581                 (NULL != emsg) ? emsg : "");
582     GNUNET_SCHEDULER_add_now (&do_error, handle);
583     return;
584   }
585   handle->proc (handle->proc_cls,
586                 GNUNET_REST_create_response (NULL),
587                 MHD_HTTP_NO_CONTENT);
588   GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
589 }
590
591
592 static void
593 del_cont (void *cls,
594           const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
595           const char *label,
596           unsigned int rd_count,
597           const struct GNUNET_GNSRECORD_Data *rd)
598 {
599   struct RequestHandle *handle = cls;
600
601   handle->add_qe = NULL;
602   if (0 == rd_count)
603   {
604     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
605                 _("There are no records under label `%s' that could be deleted.\n"),
606                 label);
607     do_error (handle);
608     return;
609   }
610
611   handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
612                                                    &handle->zone_pkey,
613                                                    handle->name,
614                                                    0, NULL,
615                                                    &del_finished,
616                                                    handle);
617 }
618
619
620 static void
621 namestore_delete_cont (struct GNUNET_REST_RequestHandle *con,
622                        const char *url,
623                        void *cls)
624 {
625   struct RequestHandle *handle = cls;
626
627   if (NULL == handle->name)
628   {
629     GNUNET_SCHEDULER_add_now (&do_error, handle);
630     return;
631   }
632
633   handle->add_qe = GNUNET_NAMESTORE_records_lookup (handle->ns_handle,
634                                                     &handle->zone_pkey,
635                                                     handle->name,
636                                                     &do_error,
637                                                     handle,
638                                                     &del_cont,
639                                                     handle);
640 }
641
642
643 static int
644 json_to_gnsrecord (const json_t *records_json,
645                    struct GNUNET_GNSRECORD_Data **rd,
646                    unsigned int *rd_count)
647 {
648   struct GNUNET_TIME_Relative etime_rel;
649   struct GNUNET_TIME_Absolute etime_abs;
650   char *value;
651   void *rdata;
652   size_t rdata_size;
653   const char *typestring;
654   const char *expirationstring;
655   json_t *type_json;
656   json_t *value_json;
657   json_t *record_json;
658   json_t *exp_json;
659
660   *rd_count = json_array_size (records_json);
661   *rd = GNUNET_new_array (*rd_count,
662                            struct GNUNET_GNSRECORD_Data);
663   for (unsigned int i = 0; i < *rd_count; i++)
664   {
665     memset (&(*rd)[i],
666             0,
667             sizeof (struct GNUNET_GNSRECORD_Data));
668     record_json = json_array_get (records_json,
669                                   i);
670     type_json = json_object_get (record_json,
671                                  GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE);
672     if (! json_is_string (type_json))
673     {
674       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
675                   "Type property is no string\n");
676       return GNUNET_SYSERR;
677     }
678     typestring = json_string_value (type_json);
679     (*rd)[i].record_type = GNUNET_GNSRECORD_typename_to_number (typestring);
680     if (UINT32_MAX == (*rd)[i].record_type)
681     {
682       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Unsupported type `%s'\n"),
683                   json_string_value (type_json));
684       return GNUNET_SYSERR;
685     }
686     value_json = json_object_get (record_json,
687                                   GNUNET_REST_JSONAPI_NAMESTORE_VALUE);
688     if (! json_is_string (value_json))
689     {
690       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
691                   "Value property is no string\n");
692       return GNUNET_SYSERR;
693     }
694     value = GNUNET_strdup (json_string_value (value_json));
695     if (GNUNET_OK !=
696         GNUNET_GNSRECORD_string_to_value ((*rd)[i].record_type,
697                                           value,
698                                           &rdata,
699                                           &rdata_size))
700     {
701       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
702                   _("Value `%s' invalid for record type `%s'\n"),
703                   value,
704                   typestring);
705       return GNUNET_SYSERR;
706     }
707     (*rd)[i].data = rdata;
708     (*rd)[i].data_size = rdata_size;
709     /**TODO
710      * if (1 == handle->is_shadow)
711      rde->flags |= GNUNET_GNSRECORD_RF_SHADOW_RECORD;
712      if (1 != handle->is_public)
713      rde->flags |= GNUNET_GNSRECORD_RF_PRIVATE;
714      */
715     exp_json = json_object_get (record_json,
716                                 GNUNET_REST_JSONAPI_NAMESTORE_EXPIRATION);
717     if (! json_is_string (exp_json))
718     {
719       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
720                   "Expiration property is no string\n");
721       return GNUNET_SYSERR;
722     }
723     expirationstring = json_string_value (exp_json);
724     if (0 == strcmp (expirationstring, "never"))
725     {
726       (*rd)[i].expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
727     }
728     else if (GNUNET_OK ==
729              GNUNET_STRINGS_fancy_time_to_relative (expirationstring,
730                                                     &etime_rel))
731     {
732       (*rd)[i].expiration_time = etime_rel.rel_value_us;
733       (*rd)[i].flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
734     }
735     else if (GNUNET_OK ==
736              GNUNET_STRINGS_fancy_time_to_absolute (expirationstring,
737                                                     &etime_abs))
738     {
739       (*rd)[i].expiration_time = etime_abs.abs_value_us;
740     }
741     else
742     {
743       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
744                   _("Value `%s' invalid for record type `%s'\n"),
745                   value,
746                   typestring);
747       return GNUNET_SYSERR;
748     }
749   }
750   return GNUNET_OK;
751 }
752
753
754 static void
755 namestore_create_cont (struct GNUNET_REST_RequestHandle *con,
756                        const char *url,
757                        void *cls)
758 {
759   struct RequestHandle *handle = cls;
760   struct MHD_Response *resp;
761   struct GNUNET_JSONAPI_Document *json_obj;
762   struct GNUNET_JSONAPI_Resource *json_res;
763   json_t *records_json;
764   json_t *data_js;
765   json_error_t err;
766   char term_data[handle->rest_handle->data_size+1];
767   struct GNUNET_JSON_Specification docspec[] = {
768     GNUNET_JSON_spec_jsonapi_document (&json_obj),
769     GNUNET_JSON_spec_end()
770   };
771
772   if (strlen (GNUNET_REST_API_NS_NAMESTORE) != strlen (handle->url))
773   {
774     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
775                 "Cannot create under %s\n", handle->url);
776     GNUNET_SCHEDULER_add_now (&do_error, handle);
777     return;
778   }
779   if (0 >= handle->rest_handle->data_size)
780   {
781     GNUNET_SCHEDULER_add_now (&do_error, handle);
782     return;
783   }
784   term_data[handle->rest_handle->data_size] = '\0';
785   GNUNET_memcpy (term_data,
786                  handle->rest_handle->data,
787                  handle->rest_handle->data_size);
788   data_js = json_loads (term_data,
789                         JSON_DECODE_ANY,
790                         &err);
791   GNUNET_assert (GNUNET_OK ==
792                  GNUNET_JSON_parse (data_js, docspec,
793                                     NULL, NULL));
794   json_decref (data_js);
795   if (NULL == json_obj)
796   {
797     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
798                 "Unable to parse JSONAPI Object from %s\n",
799                 term_data);
800     GNUNET_SCHEDULER_add_now (&do_error, handle);
801     return;
802   }
803   if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
804   {
805     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
806                 "Cannot create more than 1 resource! (Got %d)\n",
807                 GNUNET_JSONAPI_document_resource_count (json_obj));
808     GNUNET_JSONAPI_document_delete (json_obj);
809     GNUNET_SCHEDULER_add_now (&do_error, handle);
810     return;
811   }
812   json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
813   if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res,
814                                                        GNUNET_REST_JSONAPI_NAMESTORE_RECORD))
815   {
816     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
817                 "Unsupported JSON data type\n");
818     GNUNET_JSONAPI_document_delete (json_obj);
819     resp = GNUNET_REST_create_response (NULL);
820     handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
821     cleanup_handle (handle);
822     return;
823   }
824   handle->name = GNUNET_strdup (GNUNET_JSONAPI_resource_get_id (json_res));
825   records_json = GNUNET_JSONAPI_resource_read_attr (json_res,
826                                                     GNUNET_REST_JSONAPI_NAMESTORE_RECORD);
827   if (NULL == records_json)
828   {
829     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
830                 "No records given\n");
831     GNUNET_JSONAPI_document_delete (json_obj);
832     GNUNET_SCHEDULER_add_now (&do_error, handle);
833     return;
834   }
835   if (GNUNET_SYSERR == json_to_gnsrecord (records_json, &handle->rd, &handle->rd_count))
836   {
837     GNUNET_JSONAPI_document_delete (json_obj);
838     GNUNET_SCHEDULER_add_now (&do_error, handle);
839     return;
840   }
841   GNUNET_JSONAPI_document_delete (json_obj);
842
843   handle->add_qe = GNUNET_NAMESTORE_records_lookup (handle->ns_handle,
844                                                     &handle->zone_pkey,
845                                                     handle->name,
846                                                     &do_error,
847                                                     handle,
848                                                     &create_new_record_cont,
849                                                     handle);
850 }
851
852
853 static void
854 namestore_zkey_response (void *cls,
855                          const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
856                          const char *label,
857                          unsigned int rd_count,
858                          const struct GNUNET_GNSRECORD_Data *rd)
859 {
860   struct RequestHandle *handle = cls;
861   struct MHD_Response *resp;
862   struct GNUNET_JSONAPI_Document *json_obj;
863   struct GNUNET_JSONAPI_Resource *json_res;
864   json_t *name_json;
865   char* result;
866
867   handle->reverse_qe = NULL;
868   json_obj = GNUNET_JSONAPI_document_new ();
869   if (NULL != label)
870   {
871     name_json = json_string (label);
872     json_res = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_NAMESTORE_REVINFO,
873                                             handle->zkey_str);
874     GNUNET_JSONAPI_resource_add_attr (json_res,
875                                       GNUNET_REST_JSONAPI_NAMESTORE_NAME,
876                                       name_json);
877     GNUNET_JSONAPI_document_resource_add (json_obj, json_res);
878     json_decref (name_json);
879   }
880   //Handle response
881   if (GNUNET_SYSERR == GNUNET_JSONAPI_document_serialize (json_obj, &result))
882   {
883     GNUNET_JSONAPI_document_delete (json_obj);
884     GNUNET_SCHEDULER_add_now (&do_error, handle);
885     return;
886   }
887   resp = GNUNET_REST_create_response (result);
888   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
889   GNUNET_JSONAPI_document_delete (json_obj);
890   GNUNET_free (result);
891   GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
892 }
893
894
895 static void
896 namestore_zkey_cont (struct GNUNET_REST_RequestHandle *con,
897                      const char *url,
898                      void *cls)
899 {
900   struct RequestHandle *handle = cls;
901   struct GNUNET_HashCode key;
902   struct GNUNET_CRYPTO_EcdsaPublicKey pubkey;
903
904   GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_NAMESTORE_ZKEY,
905                       strlen (GNUNET_REST_JSONAPI_NAMESTORE_ZKEY),
906                       &key);
907   if ( GNUNET_NO ==
908        GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
909                                                &key) )
910   {
911     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
912                 "No zkey given %s\n", handle->url);
913     GNUNET_SCHEDULER_add_now (&do_error, handle);
914     return;
915   }
916   handle->zkey_str = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
917                                                         &key);
918   if ((NULL == handle->zkey_str) ||
919       (GNUNET_OK !=
920        GNUNET_CRYPTO_ecdsa_public_key_from_string (handle->zkey_str,
921                                                    strlen (handle->zkey_str),
922                                                    &pubkey)))
923   {
924     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
925                 "Zkey invalid %s\n", handle->zkey_str);
926     GNUNET_SCHEDULER_add_now (&do_error, handle);
927     return;
928   }
929   handle->reverse_qe = GNUNET_NAMESTORE_zone_to_name (handle->ns_handle,
930                                                       &handle->zone_pkey,
931                                                       &pubkey,
932                                                       &do_error,
933                                                       handle,
934                                                       &namestore_zkey_response,
935                                                       handle);
936 }
937
938
939 static void
940 namestore_info_cont (struct GNUNET_REST_RequestHandle *con,
941                      const char *url,
942                      void *cls)
943 {
944   struct RequestHandle *handle = cls;
945
946   handle->list_it = GNUNET_NAMESTORE_zone_iteration_start (handle->ns_handle,
947                                                            &handle->zone_pkey,
948                                                            &do_error,
949                                                            handle,
950                                                            &namestore_list_response,
951                                                            handle,
952                                                            &namestore_list_finished,
953                                                            handle);
954 }
955
956
957 static char*
958 get_name_from_url (const char* url)
959 {
960   if (strlen (url) <= strlen (GNUNET_REST_API_NS_NAMESTORE))
961     return NULL;
962   return (char*)url + strlen (GNUNET_REST_API_NS_NAMESTORE) + 1;
963 }
964
965 /**
966  * Respond to OPTIONS request
967  *
968  * @param con_handle the connection handle
969  * @param url the url
970  * @param cls the RequestHandle
971  */
972 static void
973 options_cont (struct GNUNET_REST_RequestHandle *con_handle,
974               const char* url,
975               void *cls)
976 {
977   struct MHD_Response *resp;
978   struct RequestHandle *handle = cls;
979
980   //For now, independent of path return all options
981   resp = GNUNET_REST_create_response (NULL);
982   MHD_add_response_header (resp,
983                            "Access-Control-Allow-Methods",
984                            allow_methods);
985   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
986   cleanup_handle (handle);
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   struct GNUNET_REST_RequestHandlerError err;
1004   static const struct GNUNET_REST_RequestHandler handlers[] = {
1005     {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_NAMESTORE_ZKEY, &namestore_zkey_cont}, //reverse
1006     {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_NAMESTORE, &namestore_info_cont}, //list
1007     {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_NAMESTORE, &namestore_create_cont}, //create
1008     //    {MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_NAMESTORE, &namestore_edit_cont}, //update. TODO this shoul be PATCH
1009     {MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_NAMESTORE, &namestore_delete_cont}, //delete
1010     {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_NAMESTORE, &options_cont},
1011     GNUNET_REST_HANDLER_END
1012   };
1013
1014   handle->ego_lookup = NULL;
1015   if (NULL == ego)
1016   {
1017     if (NULL != handle->ego_name)
1018     {
1019       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1020                   _("Ego `%s' not known to identity service\n"),
1021                   handle->ego_name);
1022     }
1023     resp = GNUNET_REST_create_response (NULL);
1024     handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
1025     cleanup_handle (handle);
1026     return;
1027   }
1028   handle->zone_pkey = *GNUNET_IDENTITY_ego_get_private_key (ego);
1029   handle->ns_handle = GNUNET_NAMESTORE_connect (cfg);
1030   if (NULL == handle->ns_handle)
1031   {
1032     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1033                 _("Failed to connect to namestore\n"));
1034     GNUNET_SCHEDULER_add_now (&do_error, handle);
1035     return;
1036   }
1037
1038   if (GNUNET_OK !=
1039       GNUNET_JSONAPI_handle_request (handle->rest_handle,
1040                                      handlers,
1041                                      &err,
1042                                      handle))
1043   {
1044     handle->response_code = err.error_code;
1045     GNUNET_SCHEDULER_add_now (&do_error,
1046                               (void *) handle);
1047   }
1048 }
1049
1050
1051 static void
1052 default_ego_cb (void *cls,
1053                 struct GNUNET_IDENTITY_Ego *ego,
1054                 void **ctx,
1055                 const char *name)
1056 {
1057   struct RequestHandle *handle = cls;
1058   struct MHD_Response *resp;
1059   handle->get_default = NULL;
1060   if (NULL == ego)
1061   {
1062     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1063                 _("No default ego configured in identity service\n"));
1064     resp = GNUNET_REST_create_response (NULL);
1065     handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
1066     cleanup_handle (handle);
1067     return;
1068   }
1069   else
1070   {
1071     identity_cb (cls, ego);
1072   }
1073 }
1074
1075 static void
1076 id_connect_cb (void *cls,
1077                struct GNUNET_IDENTITY_Ego *ego,
1078                void **ctx,
1079                const char *name)
1080 {
1081   struct RequestHandle *handle = cls;
1082   if (NULL == ego)
1083   {
1084     handle->get_default = GNUNET_IDENTITY_get (handle->identity_handle,
1085                                                "namestore",
1086                                                &default_ego_cb, handle);
1087   }
1088 }
1089
1090
1091 /**
1092  * Function processing the REST call
1093  *
1094  * @param method HTTP method
1095  * @param url URL of the HTTP request
1096  * @param data body of the HTTP request (optional)
1097  * @param data_size length of the body
1098  * @param proc callback function for the result
1099  * @param proc_cls closure for callback function
1100  * @return #GNUNET_OK if request accepted
1101  */
1102 static void
1103 rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle,
1104                               GNUNET_REST_ResultProcessor proc,
1105                               void *proc_cls)
1106 {
1107   struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1108   struct MHD_Response *resp;
1109   struct GNUNET_HashCode key;
1110   char *ego;
1111   char *name;
1112   char *type;
1113
1114   handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1115   handle->proc_cls = proc_cls;
1116   handle->proc = proc;
1117   handle->rest_handle = rest_handle;
1118   handle->url = GNUNET_strdup (rest_handle->url);
1119   if (handle->url[strlen (handle->url)-1] == '/')
1120     handle->url[strlen (handle->url)-1] = '\0';
1121   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1122               "Connecting...\n");
1123   handle->cfg = cfg;
1124   ego = NULL;
1125   GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_NAMESTORE_EGO,
1126                       strlen (GNUNET_REST_JSONAPI_NAMESTORE_EGO),
1127                       &key);
1128   if ( GNUNET_YES ==
1129        GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1130                                                &key) )
1131   {
1132     ego = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
1133                                              &key);
1134   }
1135
1136   handle->type = GNUNET_GNSRECORD_TYPE_ANY;
1137   GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE,
1138                       strlen (GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE),
1139                       &key);
1140   if ( GNUNET_YES ==
1141        GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1142                                                &key) )
1143   {
1144     type = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
1145                                               &key);
1146     if (NULL != type)
1147       handle->type = GNUNET_GNSRECORD_typename_to_number (type);
1148   }
1149   name = get_name_from_url (handle->url);
1150   if (NULL != ego)
1151     handle->ego_name = GNUNET_strdup (ego);
1152   if (NULL != name)
1153     handle->name = GNUNET_strdup (name);
1154   if (NULL == handle->ego_name)
1155   {
1156     handle->identity_handle = GNUNET_IDENTITY_connect (handle->cfg, &id_connect_cb, handle);
1157     if (NULL == handle->identity_handle)
1158     {
1159       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Cannot connect to identity service\n"));
1160       resp = GNUNET_REST_create_response (NULL);
1161       handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
1162       cleanup_handle (handle);
1163     }
1164     return;
1165   }
1166   handle->ego_lookup = GNUNET_IDENTITY_ego_lookup (cfg,
1167                                                    handle->ego_name,
1168                                                    &identity_cb,
1169                                                    handle);
1170   handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout,
1171                                                        &do_timeout,
1172                                                        handle);
1173 }
1174
1175 /**
1176  * Entry point for the plugin.
1177  *
1178  * @param cls Config info
1179  * @return NULL on error, otherwise the plugin context
1180  */
1181 void *
1182 libgnunet_plugin_rest_namestore_init (void *cls)
1183 {
1184   static struct Plugin plugin;
1185   cfg = cls;
1186   struct GNUNET_REST_Plugin *api;
1187
1188   if (NULL != plugin.cfg)
1189     return NULL;                /* can only initialize once! */
1190   memset (&plugin, 0, sizeof (struct Plugin));
1191   plugin.cfg = cfg;
1192   api = GNUNET_new (struct GNUNET_REST_Plugin);
1193   api->cls = &plugin;
1194   api->name = GNUNET_REST_API_NS_NAMESTORE;
1195   api->process_request = &rest_identity_process_request;
1196   GNUNET_asprintf (&allow_methods,
1197                    "%s, %s, %s, %s, %s",
1198                    MHD_HTTP_METHOD_GET,
1199                    MHD_HTTP_METHOD_POST,
1200                    MHD_HTTP_METHOD_PUT,
1201                    MHD_HTTP_METHOD_DELETE,
1202                    MHD_HTTP_METHOD_OPTIONS);
1203   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1204               _("Namestore REST API initialized\n"));
1205   return api;
1206 }
1207
1208
1209 /**
1210  * Exit point from the plugin.
1211  *
1212  * @param cls the plugin context (as returned by "init")
1213  * @return always NULL
1214  */
1215 void *
1216 libgnunet_plugin_rest_namestore_done (void *cls)
1217 {
1218   struct GNUNET_REST_Plugin *api = cls;
1219   struct Plugin *plugin = api->cls;
1220
1221   plugin->cfg = NULL;
1222   GNUNET_free (api);
1223   GNUNET_free_non_null (allow_methods);
1224   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1225               "Namestore REST plugin is finished\n");
1226   return NULL;
1227 }
1228
1229 /* end of plugin_rest_namestore.c */