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