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