fix single label get
[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 it
6    under the terms of the GNU Affero General Public License as published
7    by the Free Software Foundation, either version 3 of the License,
8    or (at your 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    Affero General Public License for more details.
14
15    You should have received a copy of the GNU Affero General Public License
16    along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18      SPDX-License-Identifier: AGPL3.0-or-later
19  */
20 /**
21  * @author Martin Schanzenbach
22  * @author Philippe Buschmann
23  * @file namestore/plugin_rest_namestore.c
24  * @brief GNUnet Namestore REST plugin
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_json_lib.h"
34 #include "microhttpd.h"
35 #include <jansson.h>
36
37 /**
38  * Namestore Namespace
39  */
40 #define GNUNET_REST_API_NS_NAMESTORE "/namestore"
41
42 /**
43  * Error message Unknown Error
44  */
45 #define GNUNET_REST_NAMESTORE_ERROR_UNKNOWN "Unknown Error"
46
47 /**
48  * Error message No identity found
49  */
50 #define GNUNET_REST_IDENTITY_NOT_FOUND "No identity found"
51
52
53 /**
54  * Error message Failed request
55  */
56 #define GNUNET_REST_NAMESTORE_FAILED "Namestore action failed"
57
58 /**
59  * Error message invalid data
60  */
61 #define GNUNET_REST_NAMESTORE_INVALID_DATA "Data invalid"
62
63 /**
64  * Error message No data
65  */
66 #define GNUNET_REST_NAMESTORE_NO_DATA "No data"
67
68 /**
69  * State while collecting all egos
70  */
71 #define ID_REST_STATE_INIT 0
72
73 /**
74  * Done collecting egos
75  */
76 #define ID_REST_STATE_POST_INIT 1
77 /**
78  * The configuration handle
79  */
80 const struct GNUNET_CONFIGURATION_Handle *cfg;
81
82 /**
83  * HTTP methods allows for this plugin
84  */
85 static char *allow_methods;
86
87 /**
88  * @brief struct returned by the initialization function of the plugin
89  */
90 struct Plugin
91 {
92   const struct GNUNET_CONFIGURATION_Handle *cfg;
93 };
94
95 /**
96  * The default namestore ego
97  */
98 struct EgoEntry
99 {
100   /**
101    * DLL
102    */
103   struct EgoEntry *next;
104
105   /**
106    * DLL
107    */
108   struct EgoEntry *prev;
109
110   /**
111    * Ego Identifier
112    */
113   char *identifier;
114
115   /**
116    * Public key string
117    */
118   char *keystring;
119
120   /**
121    * The Ego
122    */
123   struct GNUNET_IDENTITY_Ego *ego;
124 };
125
126
127 enum UpdateStrategy
128 {
129   UPDATE_STRATEGY_REPLACE,
130   UPDATE_STRATEGY_APPEND
131 };
132
133 /**
134  * The request handle
135  */
136 struct RequestHandle
137 {
138   /**
139    * Records to store
140    */
141   char *record_name;
142
143   /**
144    * Record type filter
145    */
146   uint32_t record_type;
147
148   /**
149    * How to update the record set
150    */
151   enum UpdateStrategy update_strategy;
152
153   /**
154    * Records to store
155    */
156   struct GNUNET_GNSRECORD_Data *rd;
157
158   /**
159    * Number of records in rd
160    */
161   unsigned int rd_count;
162
163   /**
164    * NAMESTORE Operation
165    */
166   struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
167
168   /**
169    * Response object
170    */
171   json_t *resp_object;
172
173   /**
174    * The processing state
175    */
176   int state;
177
178   /**
179    * Handle to NAMESTORE
180    */
181   struct GNUNET_NAMESTORE_Handle *ns_handle;
182
183   /**
184    * Handle to NAMESTORE it
185    */
186   struct GNUNET_NAMESTORE_ZoneIterator *list_it;
187
188   /**
189    * Private key for the zone
190    */
191   const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_pkey;
192
193   /**
194    * IDENTITY Operation
195    */
196   struct EgoEntry *ego_entry;
197
198   /**
199    * Ego list
200    */
201   struct EgoEntry *ego_head;
202
203   /**
204    * Ego list
205    */
206   struct EgoEntry *ego_tail;
207
208   /**
209    * IDENTITY Operation
210    */
211   struct GNUNET_IDENTITY_Operation *op;
212
213   /**
214    * Handle to Identity service.
215    */
216   struct GNUNET_IDENTITY_Handle *identity_handle;
217
218   /**
219    * Rest connection
220    */
221   struct GNUNET_REST_RequestHandle *rest_handle;
222
223   /**
224    * Desired timeout for the lookup (default is no timeout).
225    */
226   struct GNUNET_TIME_Relative timeout;
227
228   /**
229    * ID of a task associated with the resolution process.
230    */
231   struct GNUNET_SCHEDULER_Task *timeout_task;
232
233   /**
234    * The plugin result processor
235    */
236   GNUNET_REST_ResultProcessor proc;
237
238   /**
239    * The closure of the result processor
240    */
241   void *proc_cls;
242
243   /**
244    * The url
245    */
246   char *url;
247
248   /**
249    * Error response message
250    */
251   char *emsg;
252
253   /**
254    * Response code
255    */
256   int response_code;
257 };
258
259 /**
260  * Cleanup lookup handle
261  * @param handle Handle to clean up
262  */
263 static void
264 cleanup_handle (void *cls)
265 {
266   struct RequestHandle *handle = cls;
267   struct EgoEntry *ego_entry;
268   struct EgoEntry *ego_tmp;
269
270   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
271   if (NULL != handle->timeout_task)
272   {
273     GNUNET_SCHEDULER_cancel (handle->timeout_task);
274     handle->timeout_task = NULL;
275   }
276   if (NULL != handle->record_name)
277     GNUNET_free (handle->record_name);
278   if (NULL != handle->url)
279     GNUNET_free (handle->url);
280   if (NULL != handle->emsg)
281     GNUNET_free (handle->emsg);
282   if (NULL != handle->rd)
283   {
284     for (int i = 0; i < handle->rd_count; i++)
285     {
286       if (NULL != handle->rd[i].data)
287         GNUNET_free_nz ((void *) handle->rd[i].data);
288     }
289     GNUNET_free (handle->rd);
290   }
291   if (NULL != handle->timeout_task)
292     GNUNET_SCHEDULER_cancel (handle->timeout_task);
293   if (NULL != handle->list_it)
294     GNUNET_NAMESTORE_zone_iteration_stop (handle->list_it);
295   if (NULL != handle->ns_qe)
296     GNUNET_NAMESTORE_cancel (handle->ns_qe);
297   if (NULL != handle->identity_handle)
298     GNUNET_IDENTITY_disconnect (handle->identity_handle);
299   if (NULL != handle->ns_handle)
300   {
301     GNUNET_NAMESTORE_disconnect (handle->ns_handle);
302   }
303
304   for (ego_entry = handle->ego_head; NULL != ego_entry;)
305   {
306     ego_tmp = ego_entry;
307     ego_entry = ego_entry->next;
308     GNUNET_free (ego_tmp->identifier);
309     GNUNET_free (ego_tmp->keystring);
310     GNUNET_free (ego_tmp);
311   }
312
313   if (NULL != handle->resp_object)
314   {
315     json_decref (handle->resp_object);
316   }
317
318   GNUNET_free (handle);
319 }
320
321
322 /**
323  * Task run on errors.  Reports an error and cleans up everything.
324  *
325  * @param cls the `struct RequestHandle`
326  */
327 static void
328 do_error (void *cls)
329 {
330   struct RequestHandle *handle = cls;
331   struct MHD_Response *resp;
332   json_t *json_error = json_object ();
333   char *response;
334
335   if (NULL == handle->emsg)
336     handle->emsg = GNUNET_strdup (GNUNET_REST_NAMESTORE_ERROR_UNKNOWN);
337
338   json_object_set_new (json_error, "error", json_string (handle->emsg));
339
340   if (0 == handle->response_code)
341     handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
342   response = json_dumps (json_error, 0);
343   resp = GNUNET_REST_create_response (response);
344   MHD_add_response_header (resp, "Content-Type", "application/json");
345   handle->proc (handle->proc_cls, resp, handle->response_code);
346   json_decref (json_error);
347   GNUNET_free (response);
348   GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
349 }
350
351
352 /**
353  * Get EgoEntry from list with either a public key or a name
354  * If public key and name are not NULL, it returns the public key result first
355  *
356  * @param handle the RequestHandle
357  * @param pubkey the public key of an identity (only one can be NULL)
358  * @param name the name of an identity (only one can be NULL)
359  * @return EgoEntry or NULL if not found
360  */
361 struct EgoEntry *
362 get_egoentry_namestore (struct RequestHandle *handle, char *name)
363 {
364   struct EgoEntry *ego_entry;
365   char *copy = GNUNET_strdup (name);
366   char *tmp;
367
368   if (NULL == name)
369     return NULL;
370   tmp = strtok (copy, "/");
371   for (ego_entry = handle->ego_head; NULL != ego_entry;
372        ego_entry = ego_entry->next)
373   {
374     if (0 != strcasecmp (tmp, ego_entry->identifier))
375       continue;
376     GNUNET_free (copy);
377     return ego_entry;
378   }
379   GNUNET_free (copy);
380   return NULL;
381 }
382
383
384 /**
385  * Does internal server error when iteration failed.
386  *
387  * @param cls the `struct RequestHandle`
388  */
389 static void
390 namestore_iteration_error (void *cls)
391 {
392   struct RequestHandle *handle = cls;
393
394   handle->emsg = GNUNET_strdup (GNUNET_REST_NAMESTORE_FAILED);
395   GNUNET_SCHEDULER_add_now (&do_error, handle);
396   return;
397 }
398
399
400 /**
401  * Create finished callback
402  *
403  * @param cls the `struct RequestHandle`
404  * @param success the success indicating integer, GNUNET_OK on success
405  * @param emsg the error message (can be NULL)
406  */
407 static void
408 create_finished (void *cls, int32_t success, const char *emsg)
409 {
410   struct RequestHandle *handle = cls;
411   struct MHD_Response *resp;
412
413   handle->ns_qe = NULL;
414   if (GNUNET_YES != success)
415   {
416     if (NULL != emsg)
417     {
418       handle->emsg = GNUNET_strdup (emsg);
419       GNUNET_SCHEDULER_add_now (&do_error, handle);
420       return;
421     }
422     handle->emsg = GNUNET_strdup ("Error storing records");
423     GNUNET_SCHEDULER_add_now (&do_error, handle);
424     return;
425   }
426   resp = GNUNET_REST_create_response (NULL);
427   handle->proc (handle->proc_cls, resp, MHD_HTTP_NO_CONTENT);
428   GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
429 }
430
431
432 /**
433  * Delete finished callback
434  *
435  * @param cls the `struct RequestHandle`
436  * @param success the success indicating integer, GNUNET_OK on success
437  * @param emsg the error message (can be NULL)
438  */
439 static void
440 del_finished (void *cls, int32_t success, const char *emsg)
441 {
442   struct RequestHandle *handle = cls;
443
444   handle->ns_qe = NULL;
445   if (GNUNET_NO == success)
446   {
447     handle->response_code = MHD_HTTP_NOT_FOUND;
448     handle->emsg = GNUNET_strdup ("No record found");
449     GNUNET_SCHEDULER_add_now (&do_error, handle);
450     return;
451   }
452   if (GNUNET_SYSERR == success)
453   {
454     if (NULL != emsg)
455     {
456       handle->emsg = GNUNET_strdup (emsg);
457       GNUNET_SCHEDULER_add_now (&do_error, handle);
458       return;
459     }
460     handle->emsg = GNUNET_strdup ("Deleting record failed");
461     GNUNET_SCHEDULER_add_now (&do_error, handle);
462     return;
463   }
464   handle->proc (handle->proc_cls,
465                 GNUNET_REST_create_response (NULL),
466                 MHD_HTTP_NO_CONTENT);
467   GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
468 }
469
470
471 /**
472  * Iteration over all results finished, build final
473  * response.
474  *
475  * @param cls the `struct RequestHandle`
476  */
477 static void
478 namestore_list_finished (void *cls)
479 {
480   struct RequestHandle *handle = cls;
481   char *result_str;
482   struct MHD_Response *resp;
483
484   handle->list_it = NULL;
485
486   if (NULL == handle->resp_object)
487     handle->resp_object = json_array ();
488
489   result_str = json_dumps (handle->resp_object, 0);
490   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
491   resp = GNUNET_REST_create_response (result_str);
492   MHD_add_response_header (resp, "Content-Type", "application/json");
493   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
494   GNUNET_free_non_null (result_str);
495   GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
496 }
497
498
499 /**
500  * Create a response with requested records
501  *
502  * @param handle the RequestHandle
503  */
504 static void
505 namestore_list_iteration (void *cls,
506                           const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
507                           const char *rname,
508                           unsigned int rd_len,
509                           const struct GNUNET_GNSRECORD_Data *rd)
510 {
511   struct RequestHandle *handle = cls;
512   struct GNUNET_GNSRECORD_Data rd_filtered[rd_len];
513   json_t *record_obj;
514   int i = 0;
515   int j = 0;
516
517   if (NULL == handle->resp_object)
518     handle->resp_object = json_array ();
519   for (i = 0; i < rd_len; i++)
520   {
521     if ((GNUNET_GNSRECORD_TYPE_ANY != handle->record_type) &&
522         (rd[i].record_type != handle->record_type))
523       continue; /* Apply filter */
524     rd_filtered[j] = rd[i];
525     rd_filtered[j].data = rd[i].data;
526     j++;
527   }
528   /** Only add if not empty **/
529   if (j > 0)
530   {
531     record_obj = GNUNET_JSON_from_gnsrecord (rname,
532                                              rd_filtered,
533                                              j);
534     json_array_append_new (handle->resp_object, record_obj);
535   }
536   GNUNET_NAMESTORE_zone_iterator_next (handle->list_it, 1);
537 }
538
539 /**
540  * Handle lookup error
541  *
542  * @param cls the request handle
543  */
544 static void
545 ns_lookup_error_cb (void *cls)
546 {
547   struct RequestHandle *handle = cls;
548
549   handle->emsg = GNUNET_strdup (GNUNET_REST_NAMESTORE_FAILED);
550   GNUNET_SCHEDULER_add_now (&do_error, handle);
551 }
552
553
554 static void
555 ns_get_lookup_cb (void *cls,
556               const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
557               const char *label,
558               unsigned int rd_len,
559               const struct GNUNET_GNSRECORD_Data *rd)
560 {
561   struct RequestHandle *handle = cls;
562   struct GNUNET_GNSRECORD_Data rd_filtered[rd_len];
563   json_t *record_obj;
564   int i = 0;
565   int j = 0;
566
567   handle->ns_qe = NULL;
568   if (NULL == handle->resp_object)
569     handle->resp_object = json_array ();
570   for (i = 0; i < rd_len; i++)
571   {
572     if ((GNUNET_GNSRECORD_TYPE_ANY != handle->record_type) &&
573         (rd[i].record_type != handle->record_type))
574       continue; /* Apply filter */
575     rd_filtered[j] = rd[i];
576     rd_filtered[j].data = rd[i].data;
577     j++;
578   }
579   /** Only add if not empty **/
580   if (j > 0)
581   {
582     record_obj = GNUNET_JSON_from_gnsrecord (label,
583                                              rd_filtered,
584                                              j);
585     json_array_append_new (handle->resp_object, record_obj);
586   }
587   GNUNET_SCHEDULER_add_now (&namestore_list_finished, handle);
588 }
589
590
591
592
593 /**
594  * Handle namestore GET request
595  *
596  * @param con_handle the connection handle
597  * @param url the url
598  * @param cls the RequestHandle
599  */
600 void
601 namestore_get (struct GNUNET_REST_RequestHandle *con_handle,
602                const char *url,
603                void *cls)
604 {
605   struct RequestHandle *handle = cls;
606   struct EgoEntry *ego_entry;
607   struct GNUNET_HashCode key;
608   char *egoname;
609   char *labelname;
610   char *typename;
611
612   egoname = NULL;
613   ego_entry = NULL;
614
615   // set zone to name if given
616   if (strlen (GNUNET_REST_API_NS_NAMESTORE) + 1  >= strlen (handle->url))
617   {
618     handle->response_code = MHD_HTTP_NOT_FOUND;
619     handle->emsg = GNUNET_strdup (GNUNET_REST_IDENTITY_NOT_FOUND);
620     GNUNET_SCHEDULER_add_now (&do_error, handle);
621     return;
622   }
623   egoname = &handle->url[strlen (GNUNET_REST_API_NS_NAMESTORE) + 1];
624   ego_entry = get_egoentry_namestore (handle, egoname);
625   if (NULL == ego_entry)
626   {
627     handle->response_code = MHD_HTTP_NOT_FOUND;
628     handle->emsg = GNUNET_strdup (GNUNET_REST_IDENTITY_NOT_FOUND);
629     GNUNET_SCHEDULER_add_now (&do_error, handle);
630     return;
631   }
632   handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
633
634   GNUNET_CRYPTO_hash ("record_type", strlen ("record_type"), &key);
635   if (GNUNET_NO ==
636       GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map, &key))
637   {
638     handle->record_type = GNUNET_GNSRECORD_TYPE_ANY;
639   }
640   else
641   {
642     typename = GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map,
643                                                   &key);
644     handle->record_type = GNUNET_GNSRECORD_typename_to_number (typename);
645   }
646   labelname = &egoname[strlen (ego_entry->identifier)];
647   // set zone to name if given
648   if (1 >= strlen (labelname))
649   {
650     handle->list_it =
651       GNUNET_NAMESTORE_zone_iteration_start (handle->ns_handle,
652                                              handle->zone_pkey,
653                                              &namestore_iteration_error,
654                                              handle,
655                                              &namestore_list_iteration,
656                                              handle,
657                                              &namestore_list_finished,
658                                              handle);
659     if (NULL == handle->list_it)
660     {
661       handle->emsg = GNUNET_strdup (GNUNET_REST_NAMESTORE_FAILED);
662       GNUNET_SCHEDULER_add_now (&do_error, handle);
663       return;
664     }
665     return;
666   }
667   handle->record_name = GNUNET_strdup (labelname + 1);
668   handle->ns_qe = GNUNET_NAMESTORE_records_lookup (handle->ns_handle,
669                                                     handle->zone_pkey,
670                                                     handle->record_name,
671                                                     &ns_lookup_error_cb,
672                                                     handle,
673                                                     &ns_get_lookup_cb,
674                                                     handle);
675   if (NULL == handle->ns_qe)
676   {
677     handle->emsg = GNUNET_strdup (GNUNET_REST_NAMESTORE_FAILED);
678     GNUNET_SCHEDULER_add_now (&do_error, handle);
679     return;
680   }
681 }
682
683
684
685 static void
686 ns_lookup_cb (void *cls,
687               const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
688               const char *label,
689               unsigned int rd_count,
690               const struct GNUNET_GNSRECORD_Data *rd)
691 {
692   struct RequestHandle *handle = cls;
693   struct GNUNET_GNSRECORD_Data rd_new[rd_count + handle->rd_count];
694   int i = 0;
695   int j = 0;
696
697   if (UPDATE_STRATEGY_APPEND == handle->update_strategy)
698   {
699     for (i = 0; i < rd_count; i++)
700       rd_new[i] = rd[i];
701   }
702   for (j = 0; j < handle->rd_count; j++)
703     rd_new[i + j] = handle->rd[j];
704   handle->ns_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
705                                                    handle->zone_pkey,
706                                                    handle->record_name,
707                                                    i + j,
708                                                    rd_new,
709                                                    &create_finished,
710                                                    handle);
711   if (NULL == handle->ns_qe)
712   {
713     handle->emsg = GNUNET_strdup (GNUNET_REST_NAMESTORE_FAILED);
714     GNUNET_SCHEDULER_add_now (&do_error, handle);
715     return;
716   }
717 }
718
719
720 /**
721  * Handle namestore POST/PUT request
722  *
723  * @param con_handle the connection handle
724  * @param url the url
725  * @param cls the RequestHandle
726  */
727 void
728 namestore_add_or_update (struct GNUNET_REST_RequestHandle *con_handle,
729                          const char *url,
730                          void *cls)
731 {
732   struct RequestHandle *handle = cls;
733   struct EgoEntry *ego_entry;
734   char *egoname;
735   json_t *data_js;
736   json_error_t err;
737
738   char term_data[handle->rest_handle->data_size + 1];
739
740   if (0 >= handle->rest_handle->data_size)
741   {
742     handle->response_code = MHD_HTTP_BAD_REQUEST;
743     handle->emsg = GNUNET_strdup (GNUNET_REST_NAMESTORE_NO_DATA);
744     GNUNET_SCHEDULER_add_now (&do_error, handle);
745     return;
746   }
747   term_data[handle->rest_handle->data_size] = '\0';
748   GNUNET_memcpy (term_data,
749                  handle->rest_handle->data,
750                  handle->rest_handle->data_size);
751   data_js = json_loads (term_data, JSON_DECODE_ANY, &err);
752   struct GNUNET_JSON_Specification gnsspec[] =
753   { GNUNET_JSON_spec_gnsrecord (&handle->rd, &handle->rd_count,
754                                 &handle->record_name),
755     GNUNET_JSON_spec_end () };
756   if (GNUNET_OK != GNUNET_JSON_parse (data_js, gnsspec, NULL, NULL))
757   {
758     handle->emsg = GNUNET_strdup (GNUNET_REST_NAMESTORE_INVALID_DATA);
759     GNUNET_SCHEDULER_add_now (&do_error, handle);
760     json_decref (data_js);
761     return;
762   }
763   GNUNET_JSON_parse_free (gnsspec);
764   if (0 >= strlen (handle->record_name))
765   {
766     handle->response_code = MHD_HTTP_BAD_REQUEST;
767     handle->emsg = GNUNET_strdup (GNUNET_REST_NAMESTORE_INVALID_DATA);
768     GNUNET_SCHEDULER_add_now (&do_error, handle);
769     json_decref (data_js);
770     return;
771   }
772   json_decref (data_js);
773
774   egoname = NULL;
775   ego_entry = NULL;
776
777   // set zone to name if given
778   if (strlen (GNUNET_REST_API_NS_NAMESTORE) + 1 >= strlen (handle->url))
779   {
780     handle->response_code = MHD_HTTP_NOT_FOUND;
781     handle->emsg = GNUNET_strdup (GNUNET_REST_IDENTITY_NOT_FOUND);
782     GNUNET_SCHEDULER_add_now (&do_error, handle);
783     return;
784   }
785   egoname = &handle->url[strlen (GNUNET_REST_API_NS_NAMESTORE) + 1];
786   ego_entry = get_egoentry_namestore (handle, egoname);
787
788   if (NULL == ego_entry)
789   {
790     handle->response_code = MHD_HTTP_NOT_FOUND;
791     handle->emsg = GNUNET_strdup (GNUNET_REST_IDENTITY_NOT_FOUND);
792     GNUNET_SCHEDULER_add_now (&do_error, handle);
793     return;
794   }
795   handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
796   handle->ns_qe = GNUNET_NAMESTORE_records_lookup (handle->ns_handle,
797                                                     handle->zone_pkey,
798                                                     handle->record_name,
799                                                     &ns_lookup_error_cb,
800                                                     handle,
801                                                     &ns_lookup_cb,
802                                                     handle);
803   if (NULL == handle->ns_qe)
804   {
805     handle->emsg = GNUNET_strdup (GNUNET_REST_NAMESTORE_FAILED);
806     GNUNET_SCHEDULER_add_now (&do_error, handle);
807     return;
808   }
809 }
810
811
812 /**
813  * Handle namestore PUT request
814  *
815  * @param con_handle the connection handle
816  * @param url the url
817  * @param cls the RequestHandle
818  */
819 void
820 namestore_update (struct GNUNET_REST_RequestHandle *con_handle,
821                   const char *url,
822                   void *cls)
823 {
824   struct RequestHandle *handle = cls;
825   handle->update_strategy = UPDATE_STRATEGY_REPLACE;
826   namestore_add_or_update (con_handle, url, cls);
827 }
828
829
830 /**
831  * Handle namestore POST request
832  *
833  * @param con_handle the connection handle
834  * @param url the url
835  * @param cls the RequestHandle
836  */
837 void
838 namestore_add (struct GNUNET_REST_RequestHandle *con_handle,
839                const char *url,
840                void *cls)
841 {
842   struct RequestHandle *handle = cls;
843   handle->update_strategy = UPDATE_STRATEGY_APPEND;
844   namestore_add_or_update (con_handle, url, cls);
845 }
846
847
848 /**
849  * Handle namestore DELETE request
850  *
851  * @param con_handle the connection handle
852  * @param url the url
853  * @param cls the RequestHandle
854  */
855 void
856 namestore_delete (struct GNUNET_REST_RequestHandle *con_handle,
857                   const char *url,
858                   void *cls)
859 {
860   struct RequestHandle *handle = cls;
861   struct EgoEntry *ego_entry;
862   char *egoname;
863   char *labelname;
864
865   egoname = NULL;
866   ego_entry = NULL;
867
868   // set zone to name if given
869   if (strlen (GNUNET_REST_API_NS_NAMESTORE) + 1 >= strlen (handle->url))
870   {
871     handle->response_code = MHD_HTTP_NOT_FOUND;
872     handle->emsg = GNUNET_strdup (GNUNET_REST_IDENTITY_NOT_FOUND);
873     GNUNET_SCHEDULER_add_now (&do_error, handle);
874     return;
875   }
876   egoname = &handle->url[strlen (GNUNET_REST_API_NS_NAMESTORE) + 1];
877   ego_entry = get_egoentry_namestore (handle, egoname);
878   if (NULL == ego_entry)
879   {
880     handle->response_code = MHD_HTTP_NOT_FOUND;
881     handle->emsg = GNUNET_strdup (GNUNET_REST_IDENTITY_NOT_FOUND);
882     GNUNET_SCHEDULER_add_now (&do_error, handle);
883     return;
884   }
885   handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
886   labelname = &egoname[strlen (ego_entry->identifier)];
887   // set zone to name if given
888   if (1 >= strlen (labelname))
889   {
890     /* label is only "/" */
891     handle->response_code = MHD_HTTP_BAD_REQUEST;
892     handle->emsg = GNUNET_strdup ("Label missing");
893     GNUNET_SCHEDULER_add_now (&do_error, handle);
894   }
895
896   handle->record_name = GNUNET_strdup (labelname + 1);
897   handle->ns_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
898                                                   handle->zone_pkey,
899                                                   handle->record_name,
900                                                   0,
901                                                    NULL,
902                                                    &del_finished,
903                                                    handle);
904   if (NULL == handle->ns_qe)
905   {
906     handle->emsg = GNUNET_strdup (GNUNET_REST_NAMESTORE_FAILED);
907     GNUNET_SCHEDULER_add_now (&do_error, handle);
908     return;
909   }
910 }
911
912
913 /**
914  * Respond to OPTIONS request
915  *
916  * @param con_handle the connection handle
917  * @param url the url
918  * @param cls the RequestHandle
919  */
920 static void
921 options_cont (struct GNUNET_REST_RequestHandle *con_handle,
922               const char *url,
923               void *cls)
924 {
925   struct MHD_Response *resp;
926   struct RequestHandle *handle = cls;
927
928   // independent of path return all options
929   resp = GNUNET_REST_create_response (NULL);
930   MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods);
931   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
932   GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
933   return;
934 }
935
936
937 /**
938  * Handle rest request
939  *
940  * @param handle the request handle
941  */
942 static void
943 init_cont (struct RequestHandle *handle)
944 {
945   struct GNUNET_REST_RequestHandlerError err;
946   static const struct GNUNET_REST_RequestHandler handlers[] =
947   { { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_NAMESTORE, &namestore_get },
948     { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_NAMESTORE, &namestore_add },
949     { MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_NAMESTORE, &namestore_update },
950     { MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_NAMESTORE, &namestore_delete },
951     { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_NAMESTORE, &options_cont },
952     GNUNET_REST_HANDLER_END };
953
954   if (GNUNET_NO ==
955       GNUNET_REST_handle_request (handle->rest_handle, handlers, &err, handle))
956   {
957     handle->response_code = err.error_code;
958     GNUNET_SCHEDULER_add_now (&do_error, handle);
959   }
960 }
961
962
963 /**
964  * This function is initially called for all egos and then again
965  * whenever a ego's identifier changes or if it is deleted.  At the
966  * end of the initial pass over all egos, the function is once called
967  * with 'NULL' for 'ego'. That does NOT mean that the callback won't
968  * be invoked in the future or that there was an error.
969  *
970  * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
971  * this function is only called ONCE, and 'NULL' being passed in
972  * 'ego' does indicate an error (i.e. name is taken or no default
973  * value is known).  If 'ego' is non-NULL and if '*ctx'
974  * is set in those callbacks, the value WILL be passed to a subsequent
975  * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
976  * that one was not NULL).
977  *
978  * When an identity is renamed, this function is called with the
979  * (known) ego but the NEW identifier.
980  *
981  * When an identity is deleted, this function is called with the
982  * (known) ego and "NULL" for the 'identifier'.  In this case,
983  * the 'ego' is henceforth invalid (and the 'ctx' should also be
984  * cleaned up).
985  *
986  * @param cls closure
987  * @param ego ego handle
988  * @param ctx context for application to store data for this ego
989  *                 (during the lifetime of this process, initially NULL)
990  * @param name identifier assigned by the user for this ego,
991  *                   NULL if the user just deleted the ego and it
992  *                   must thus no longer be used
993  */
994 static void
995 id_connect_cb (void *cls,
996                struct GNUNET_IDENTITY_Ego *ego,
997                void **ctx,
998                const char *name)
999 {
1000   struct RequestHandle *handle = cls;
1001   struct EgoEntry *ego_entry;
1002   struct GNUNET_CRYPTO_EcdsaPublicKey pk;
1003
1004   if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
1005   {
1006     handle->state = ID_REST_STATE_POST_INIT;
1007     init_cont (handle);
1008     return;
1009   }
1010   if (ID_REST_STATE_INIT == handle->state)
1011   {
1012     ego_entry = GNUNET_new (struct EgoEntry);
1013     GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
1014     ego_entry->keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
1015     ego_entry->ego = ego;
1016     GNUNET_asprintf (&ego_entry->identifier, "%s", name);
1017     GNUNET_CONTAINER_DLL_insert_tail (handle->ego_head,
1018                                       handle->ego_tail,
1019                                       ego_entry);
1020   }
1021 }
1022
1023
1024 /**
1025  * Function processing the REST call
1026  *
1027  * @param method HTTP method
1028  * @param url URL of the HTTP request
1029  * @param data body of the HTTP request (optional)
1030  * @param data_size length of the body
1031  * @param proc callback function for the result
1032  * @param proc_cls closure for callback function
1033  * @return GNUNET_OK if request accepted
1034  */
1035 static void
1036 rest_process_request (struct GNUNET_REST_RequestHandle *rest_handle,
1037                       GNUNET_REST_ResultProcessor proc,
1038                       void *proc_cls)
1039 {
1040   struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1041
1042   handle->response_code = 0;
1043   handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1044   handle->proc_cls = proc_cls;
1045   handle->proc = proc;
1046   handle->rest_handle = rest_handle;
1047   handle->zone_pkey = NULL;
1048
1049   handle->url = GNUNET_strdup (rest_handle->url);
1050   if (handle->url[strlen (handle->url) - 1] == '/')
1051     handle->url[strlen (handle->url) - 1] = '\0';
1052   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n");
1053
1054   handle->ns_handle = GNUNET_NAMESTORE_connect (cfg);
1055   handle->identity_handle =
1056     GNUNET_IDENTITY_connect (cfg, &id_connect_cb, handle);
1057   handle->timeout_task =
1058     GNUNET_SCHEDULER_add_delayed (handle->timeout, &do_error, handle);
1059
1060   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected\n");
1061 }
1062
1063
1064 /**
1065  * Entry point for the plugin.
1066  *
1067  * @param cls Config info
1068  * @return NULL on error, otherwise the plugin context
1069  */
1070 void *
1071 libgnunet_plugin_rest_namestore_init (void *cls)
1072 {
1073   static struct Plugin plugin;
1074   struct GNUNET_REST_Plugin *api;
1075
1076   cfg = cls;
1077   if (NULL != plugin.cfg)
1078     return NULL; /* can only initialize once! */
1079   memset (&plugin, 0, sizeof(struct Plugin));
1080   plugin.cfg = cfg;
1081   api = GNUNET_new (struct GNUNET_REST_Plugin);
1082   api->cls = &plugin;
1083   api->name = GNUNET_REST_API_NS_NAMESTORE;
1084   api->process_request = &rest_process_request;
1085   GNUNET_asprintf (&allow_methods,
1086                    "%s, %s, %s, %s, %s",
1087                    MHD_HTTP_METHOD_GET,
1088                    MHD_HTTP_METHOD_POST,
1089                    MHD_HTTP_METHOD_PUT,
1090                    MHD_HTTP_METHOD_DELETE,
1091                    MHD_HTTP_METHOD_OPTIONS);
1092
1093   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _ ("Namestore REST API initialized\n"));
1094   return api;
1095 }
1096
1097
1098 /**
1099  * Exit point from the plugin.
1100  *
1101  * @param cls the plugin context (as returned by "init")
1102  * @return always NULL
1103  */
1104 void *
1105 libgnunet_plugin_rest_namestore_done (void *cls)
1106 {
1107   struct GNUNET_REST_Plugin *api = cls;
1108   struct Plugin *plugin = api->cls;
1109
1110   plugin->cfg = NULL;
1111
1112   GNUNET_free_non_null (allow_methods);
1113   GNUNET_free (api);
1114   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Namestore REST plugin is finished\n");
1115   return NULL;
1116 }
1117
1118
1119 /* end of plugin_rest_namestore.c */