aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSchanzenbach, Martin <martin.schanzenbach@aisec.fraunhofer.de>2018-08-09 23:57:14 +0200
committerSchanzenbach, Martin <martin.schanzenbach@aisec.fraunhofer.de>2018-08-09 23:57:14 +0200
commit08c410658159c0975ad87d7b7582259cd2ac6ee4 (patch)
treef567c9020be2505f1c16a7249020e3e965ba7194
parent389f4939845a0cb00e5ce0d8ea3ab7fc0541fd1c (diff)
parent1ad7b69834fffc95e05354983009e435030c0861 (diff)
downloadgnunet-08c410658159c0975ad87d7b7582259cd2ac6ee4.tar.gz
gnunet-08c410658159c0975ad87d7b7582259cd2ac6ee4.zip
Merge branch 'gsoc2018/rest_api'
-rw-r--r--src/gns/plugin_rest_gns.c674
-rwxr-xr-xsrc/gns/test_plugin_rest_gns.sh50
-rw-r--r--src/gnsrecord/gnsrecord.c3
-rw-r--r--src/identity/Makefile.am2
-rw-r--r--src/identity/plugin_rest_identity.c1057
-rwxr-xr-xsrc/identity/test_plugin_rest_identity.sh159
-rw-r--r--src/include/gnunet_json_lib.h23
-rw-r--r--src/json/Makefile.am4
-rw-r--r--src/json/json_generator.c35
-rw-r--r--src/json/json_gnsrecord.c177
-rw-r--r--src/namestore/Makefile.am4
-rw-r--r--src/namestore/plugin_rest_namestore.c1276
-rwxr-xr-xsrc/namestore/test_plugin_rest_namestore.sh208
-rw-r--r--src/peerinfo/Makefile.am22
-rw-r--r--src/peerinfo/plugin_rest_peerinfo.c801
15 files changed, 2819 insertions, 1676 deletions
diff --git a/src/gns/plugin_rest_gns.c b/src/gns/plugin_rest_gns.c
index e76a5d116..fd2469577 100644
--- a/src/gns/plugin_rest_gns.c
+++ b/src/gns/plugin_rest_gns.c
@@ -11,42 +11,42 @@
11 WITHOUT ANY WARRANTY; without even the implied warranty of 11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details. 13 Affero General Public License for more details.
14 14
15 You should have received a copy of the GNU Affero General Public License 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/>. 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */ 17 */
18/** 18/**
19 * @author Martin Schanzenbach 19 * @author Philippe Buschmann
20 * @file gns/plugin_rest_gns.c 20 * @file gns/plugin_rest_gns.c
21 * @brief GNUnet GNS REST plugin 21 * @brief GNUnet Gns REST plugin
22 *
23 */ 22 */
24 23
25#include "platform.h" 24#include "platform.h"
26#include "gnunet_rest_plugin.h" 25#include "gnunet_rest_plugin.h"
27#include <gnunet_dnsparser_lib.h> 26#include "gnunet_rest_lib.h"
28#include <gnunet_identity_service.h> 27#include "gnunet_json_lib.h"
29#include <gnunet_gnsrecord_lib.h> 28#include "gnunet_gnsrecord_lib.h"
30#include <gnunet_namestore_service.h> 29#include "gnunet_gns_service.h"
31#include <gnunet_gns_service.h> 30#include "microhttpd.h"
32#include <gnunet_rest_lib.h>
33#include <gnunet_jsonapi_lib.h>
34#include <gnunet_jsonapi_util.h>
35#include <jansson.h> 31#include <jansson.h>
36 32
37#define GNUNET_REST_API_NS_GNS "/gns" 33#define GNUNET_REST_API_NS_GNS "/gns"
38 34
39#define GNUNET_REST_JSONAPI_GNS_RECORD_TYPE "record_type"
40
41#define GNUNET_REST_JSONAPI_GNS_TYPEINFO "gns_name"
42 35
43#define GNUNET_REST_JSONAPI_GNS_RECORD "records" 36#define GNUNET_REST_GNS_PARAM_NAME "name"
44 37
45#define GNUNET_REST_JSONAPI_GNS_EGO "ego" 38#define GNUNET_REST_GNS_PARAM_RECORD_TYPE "record_type"
39#define GNUNET_REST_GNS_ERROR_UNKNOWN "Unknown Error"
46 40
47#define GNUNET_REST_JSONAPI_GNS_PKEY "pkey" 41/**
42 * The configuration handle
43 */
44const struct GNUNET_CONFIGURATION_Handle *cfg;
48 45
49#define GNUNET_REST_JSONAPI_GNS_OPTIONS "options" 46/**
47 * HTTP methods allows for this plugin
48 */
49static char* allow_methods;
50 50
51/** 51/**
52 * @brief struct returned by the initialization function of the plugin 52 * @brief struct returned by the initialization function of the plugin
@@ -56,54 +56,44 @@ struct Plugin
56 const struct GNUNET_CONFIGURATION_Handle *cfg; 56 const struct GNUNET_CONFIGURATION_Handle *cfg;
57}; 57};
58 58
59const struct GNUNET_CONFIGURATION_Handle *cfg;
60 59
61struct LookupHandle 60struct RequestHandle
62{ 61{
63 /**
64 * Handle to GNS service.
65 */
66 struct GNUNET_GNS_Handle *gns;
67 62
68 /** 63 /**
69 * Desired timeout for the lookup (default is no timeout). 64 * Connection to GNS
70 */ 65 */
71 struct GNUNET_TIME_Relative timeout; 66 struct GNUNET_GNS_Handle *gns;
72 67
73 /** 68 /**
74 * Handle to lookup request 69 * Active GNS lookup
75 */ 70 */
76 struct GNUNET_GNS_LookupRequest *lookup_request; 71 struct GNUNET_GNS_LookupWithTldRequest *gns_lookup;
77 72
78 /** 73 /**
79 * Handle to rest request 74 * Name to look up
80 */ 75 */
81 struct GNUNET_REST_RequestHandle *rest_handle; 76 char *name;
82 77
83 /** 78 /**
84 * Lookup an ego with the identity service. 79 * Record type to look up
85 */ 80 */
86 struct GNUNET_IDENTITY_EgoLookup *el; 81 int record_type;
87 82
88 /** 83 /**
89 * Handle for identity service. 84 * Rest connection
90 */ 85 */
91 struct GNUNET_IDENTITY_Handle *identity; 86 struct GNUNET_REST_RequestHandle *rest_handle;
92 87
93 /** 88 /**
94 * Active operation on identity service. 89 * Desired timeout for the lookup (default is no timeout).
95 */ 90 */
96 struct GNUNET_IDENTITY_Operation *id_op; 91 struct GNUNET_TIME_Relative timeout;
97 92
98 /** 93 /**
99 * ID of a task associated with the resolution process. 94 * ID of a task associated with the resolution process.
100 */ 95 */
101 struct GNUNET_SCHEDULER_Task * timeout_task; 96 struct GNUNET_SCHEDULER_Task *timeout_task;
102
103 /**
104 * The root of the received JSON or NULL
105 */
106 json_t *json_root;
107 97
108 /** 98 /**
109 * The plugin result processor 99 * The plugin result processor
@@ -116,49 +106,17 @@ struct LookupHandle
116 void *proc_cls; 106 void *proc_cls;
117 107
118 /** 108 /**
119 * The name to look up 109 * The url
120 */
121 char *name;
122
123 /**
124 * The ego to use
125 * In string representation from JSON
126 */
127 const char *ego_str;
128
129 /**
130 * The Pkey to use
131 * In string representation from JSON
132 */
133 const char *pkey_str;
134
135 /**
136 * The record type
137 */ 110 */
138 int type; 111 char *url;
139 112
140 /** 113 /**
141 * The public key of to use for lookup 114 * Error response message
142 */ 115 */
143 struct GNUNET_CRYPTO_EcdsaPublicKey pkey; 116 char *emsg;
144 117
145 /** 118 /**
146 * The public key to use for lookup 119 * Reponse code
147 */
148 struct GNUNET_CRYPTO_EcdsaPublicKey pkeym;
149
150 /**
151 * The resolver options
152 */
153 enum GNUNET_GNS_LocalOptions options;
154
155 /**
156 * the shorten key
157 */
158 struct GNUNET_CRYPTO_EcdsaPrivateKey shorten_key;
159
160 /**
161 * HTTP response code
162 */ 120 */
163 int response_code; 121 int response_code;
164 122
@@ -166,39 +124,20 @@ struct LookupHandle
166 124
167 125
168/** 126/**
169 * Cleanup lookup handle. 127 * Cleanup lookup handle
170 *
171 * @param handle Handle to clean up 128 * @param handle Handle to clean up
172 */ 129 */
173static void 130static void
174cleanup_handle (struct LookupHandle *handle) 131cleanup_handle (void *cls)
175{ 132{
133 struct RequestHandle *handle = cls;
176 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 134 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
177 "Cleaning up\n"); 135 "Cleaning up\n");
178 if (NULL != handle->json_root)
179 json_decref (handle->json_root);
180 136
181 if (NULL != handle->name) 137 if (NULL != handle->gns_lookup)
182 GNUNET_free (handle->name);
183 if (NULL != handle->el)
184 {
185 GNUNET_IDENTITY_ego_lookup_cancel (handle->el);
186 handle->el = NULL;
187 }
188 if (NULL != handle->id_op)
189 {
190 GNUNET_IDENTITY_cancel (handle->id_op);
191 handle->id_op = NULL;
192 }
193 if (NULL != handle->lookup_request)
194 {
195 GNUNET_GNS_lookup_cancel (handle->lookup_request);
196 handle->lookup_request = NULL;
197 }
198 if (NULL != handle->identity)
199 { 138 {
200 GNUNET_IDENTITY_disconnect (handle->identity); 139 GNUNET_GNS_lookup_with_tld_cancel (handle->gns_lookup);
201 handle->identity = NULL; 140 handle->gns_lookup = NULL;
202 } 141 }
203 if (NULL != handle->gns) 142 if (NULL != handle->gns)
204 { 143 {
@@ -209,387 +148,181 @@ cleanup_handle (struct LookupHandle *handle)
209 if (NULL != handle->timeout_task) 148 if (NULL != handle->timeout_task)
210 { 149 {
211 GNUNET_SCHEDULER_cancel (handle->timeout_task); 150 GNUNET_SCHEDULER_cancel (handle->timeout_task);
151 handle->timeout_task = NULL;
212 } 152 }
153 if (NULL != handle->url)
154 GNUNET_free (handle->url);
155 if (NULL != handle->name)
156 GNUNET_free (handle->name);
157 if (NULL != handle->emsg)
158 GNUNET_free (handle->emsg);
159
213 GNUNET_free (handle); 160 GNUNET_free (handle);
214} 161}
215 162
216 163
217/** 164/**
218 * Task run on shutdown. Cleans up everything. 165 * Task run on errors. Reports an error and cleans up everything.
219 * 166 *
220 * @param cls unused 167 * @param cls the `struct RequestHandle`
221 * @param tc scheduler context
222 */ 168 */
223static void 169static void
224do_error (void *cls) 170do_error (void *cls)
225{ 171{
226 struct LookupHandle *handle = cls; 172 struct RequestHandle *handle = cls;
227 struct MHD_Response *resp; 173 struct MHD_Response *resp;
174 json_t *json_error = json_object();
175 char *response;
228 176
229 resp = GNUNET_REST_create_response (NULL); 177 if (NULL == handle->emsg)
230 handle->proc (handle->proc_cls, resp, handle->response_code); 178 handle->emsg = GNUNET_strdup(GNUNET_REST_GNS_ERROR_UNKNOWN);
231 cleanup_handle (handle);
232}
233
234 179
235/** 180 json_object_set_new(json_error,"error", json_string(handle->emsg));
236 * Create json representation of a GNSRECORD
237 *
238 * @param rd the GNSRECORD_Data
239 */
240static json_t *
241gnsrecord_to_json (const struct GNUNET_GNSRECORD_Data *rd)
242{
243 const char *typename;
244 char *string_val;
245 const char *exp_str;
246 json_t *record_obj;
247
248 typename = GNUNET_GNSRECORD_number_to_typename (rd->record_type);
249 string_val = GNUNET_GNSRECORD_value_to_string (rd->record_type,
250 rd->data,
251 rd->data_size);
252 181
253 if (NULL == string_val) 182 if (0 == handle->response_code)
254 { 183 handle->response_code = MHD_HTTP_OK;
255 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 184 response = json_dumps (json_error, 0);
256 "Record of type %d malformed, skipping\n", 185 resp = GNUNET_REST_create_response (response);
257 (int) rd->record_type); 186 handle->proc (handle->proc_cls, resp, handle->response_code);
258 return NULL; 187 json_decref(json_error);
259 } 188 GNUNET_free(response);
260 record_obj = json_object (); 189 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
261 json_object_set_new (record_obj, "type", json_string (typename));
262 json_object_set_new (record_obj, "value", json_string (string_val));
263 GNUNET_free (string_val);
264
265 if (GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION & rd->flags)
266 {
267 struct GNUNET_TIME_Relative time_rel;
268 time_rel.rel_value_us = rd->expiration_time;
269 exp_str = GNUNET_STRINGS_relative_time_to_string (time_rel, 1);
270 }
271 else
272 {
273 struct GNUNET_TIME_Absolute time_abs;
274 time_abs.abs_value_us = rd->expiration_time;
275 exp_str = GNUNET_STRINGS_absolute_time_to_string (time_abs);
276 }
277 json_object_set_new (record_obj, "expiration_time", json_string (exp_str));
278
279 json_object_set_new (record_obj, "expired",
280 json_boolean (GNUNET_YES == GNUNET_GNSRECORD_is_expired (rd)));
281 return record_obj;
282}
283
284
285static void
286do_cleanup (void *cls)
287{
288 struct LookupHandle *handle = cls;
289 cleanup_handle (handle);
290} 190}
291 191
292 192
293/** 193/**
294 * Function called with the result of a GNS lookup. 194 * Iterator called on obtained result for a GNS lookup.
295 * 195 *
296 * @param cls the 'const char *' name that was resolved 196 * @param cls closure with the object
297 * @param rd_count number of records returned 197 * @param was_gns #GNUNET_NO if name was not a GNS name
298 * @param rd array of @a rd_count records with the results 198 * @param rd_count number of records in @a rd
199 * @param rd the records in reply
299 */ 200 */
300static void 201static void
301process_lookup_result (void *cls, uint32_t rd_count, 202handle_gns_response (void *cls,
302 const struct GNUNET_GNSRECORD_Data *rd) 203 int was_gns,
204 uint32_t rd_count,
205 const struct GNUNET_GNSRECORD_Data *rd)
303{ 206{
304 struct LookupHandle *handle = cls; 207 struct RequestHandle *handle = cls;
305 struct MHD_Response *resp; 208 struct MHD_Response *resp;
306 struct GNUNET_JSONAPI_Document *json_document;
307 struct GNUNET_JSONAPI_Resource *json_resource;
308 uint32_t i;
309 char *result;
310 json_t *result_array; 209 json_t *result_array;
311 json_t *record_obj; 210 json_t *record_obj;
211 char *result;
212
213 handle->gns_lookup = NULL;
214
215 if (GNUNET_NO == was_gns)
216 {
217 handle->emsg = GNUNET_strdup("Name not found in GNS");
218 GNUNET_SCHEDULER_add_now (&do_error, handle);
219 return;
220 }
312 221
313 result_array = json_array(); 222 result_array = json_array();
314 json_document = GNUNET_JSONAPI_document_new (); 223 for (uint32_t i=0;i<rd_count;i++)
315 json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_GNS_TYPEINFO, handle->name);
316 handle->lookup_request = NULL;
317 for (i=0; i<rd_count; i++)
318 { 224 {
319 if ( (rd[i].record_type != handle->type) && 225 if ((rd[i].record_type != handle->record_type) &&
320 (GNUNET_GNSRECORD_TYPE_ANY != handle->type) ) 226 (GNUNET_GNSRECORD_TYPE_ANY != handle->record_type) )
227 {
321 continue; 228 continue;
322 record_obj = gnsrecord_to_json (&(rd[i])); 229 }
230
231 record_obj = GNUNET_JSON_from_gns_record(NULL,&rd[i]);
323 json_array_append (result_array, record_obj); 232 json_array_append (result_array, record_obj);
324 json_decref (record_obj); 233 json_decref (record_obj);
325 } 234 }
326 GNUNET_JSONAPI_resource_add_attr (json_resource, 235
327 GNUNET_REST_JSONAPI_GNS_RECORD, 236 result = json_dumps(result_array, 0);
328 result_array);
329 GNUNET_JSONAPI_document_resource_add (json_document, json_resource);
330 GNUNET_JSONAPI_document_serialize (json_document, &result);
331 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result); 237 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result);
332 json_decref (result_array);
333 GNUNET_JSONAPI_document_delete (json_document);
334 resp = GNUNET_REST_create_response (result); 238 resp = GNUNET_REST_create_response (result);
335 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); 239 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
336 GNUNET_free (result); 240 GNUNET_free (result);
337 GNUNET_SCHEDULER_add_now (&do_cleanup, handle); 241 json_decref (result_array);
242 GNUNET_SCHEDULER_add_now(&cleanup_handle, handle);
338} 243}
339 244
340 245
341/** 246/**
342 * Perform the actual resolution, starting with the zone 247 * Handle gns GET request
343 * identified by the given public key and the shorten zone.
344 * 248 *
345 * @param pkey public key to use for the zone, can be NULL 249 * @param con_handle the connection handle
250 * @param url the url
251 * @param cls the RequestHandle
346 */ 252 */
347static void 253void
348lookup_with_public_key (struct LookupHandle *handle) 254get_gns_cont (struct GNUNET_REST_RequestHandle *con_handle,
255 const char* url,
256 void *cls)
349{ 257{
350 if (UINT32_MAX == handle->type) 258 struct RequestHandle *handle = cls;
351 { 259 struct GNUNET_HashCode key;
352 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 260 char *record_type;
353 _("Invalid typename specified, assuming `ANY'\n")); 261 char *name;
354 handle->type = GNUNET_GNSRECORD_TYPE_ANY; 262
355 } 263 GNUNET_CRYPTO_hash (GNUNET_REST_GNS_PARAM_NAME,
356 if (NULL != handle->name) 264 strlen (GNUNET_REST_GNS_PARAM_NAME),
357 { 265 &key);
358 handle->lookup_request = GNUNET_GNS_lookup (handle->gns, 266 if ( GNUNET_NO
359 handle->name, 267 == GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map,
360 &handle->pkey, 268 &key))
361 handle->type,
362 handle->options,
363 &process_lookup_result,
364 handle);
365 }
366 else
367 { 269 {
270 handle->emsg = GNUNET_strdup("Parameter name is missing");
368 GNUNET_SCHEDULER_add_now (&do_error, handle); 271 GNUNET_SCHEDULER_add_now (&do_error, handle);
369 return; 272 return;
370 } 273 }
371} 274 name = GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map,&key);
372 275 if(0 >= strlen (name))
373
374/**
375 * Method called to with the ego we are to use for the lookup,
376 * when the ego is determined by a name.
377 *
378 * @param cls closure (NULL, unused)
379 * @param ego ego handle, NULL if not found
380 */
381static void
382identity_zone_cb (void *cls,
383 const struct GNUNET_IDENTITY_Ego *ego)
384{
385 struct LookupHandle *handle = cls;
386
387 handle->el = NULL;
388 if (NULL == ego)
389 { 276 {
390 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 277 handle->emsg = GNUNET_strdup("Length of parameter name is zero");
391 _("Ego for not found, cannot perform lookup.\n"));
392 GNUNET_SCHEDULER_add_now (&do_error, handle); 278 GNUNET_SCHEDULER_add_now (&do_error, handle);
393 return; 279 return;
394 } 280 }
395 else 281 handle->name = GNUNET_strdup(name);
396 {
397 GNUNET_IDENTITY_ego_get_public_key (ego, &handle->pkey);
398 lookup_with_public_key (handle);
399 }
400 json_decref(handle->json_root);
401}
402
403 282
404/** 283 handle->record_type = UINT32_MAX;
405 * Method called to with the ego we are to use for the lookup, 284 GNUNET_CRYPTO_hash (GNUNET_REST_GNS_PARAM_RECORD_TYPE,
406 * when the ego is the one for the default master zone. 285 strlen (GNUNET_REST_GNS_PARAM_RECORD_TYPE),
407 * 286 &key);
408 * @param cls closure (NULL, unused) 287 if ( GNUNET_YES
409 * @param ego ego handle, NULL if not found 288 == GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map,
410 * @param ctx context for application to store data for this ego 289 &key))
411 * (during the lifetime of this process, initially NULL)
412 * @param name name assigned by the user for this ego,
413 * NULL if the user just deleted the ego and it
414 * must thus no longer be used
415 */
416static void
417identity_master_cb (void *cls,
418 struct GNUNET_IDENTITY_Ego *ego,
419 void **ctx,
420 const char *name)
421{
422 const char *dot;
423 struct LookupHandle *handle = cls;
424
425 handle->id_op = NULL;
426 if (NULL == ego)
427 { 290 {
428 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 291 record_type = GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map, &key);
429 _("Ego for `gns-master' not found, cannot perform lookup. Did you run gnunet-gns-import.sh?\n")); 292 handle->record_type = GNUNET_GNSRECORD_typename_to_number(record_type);
430 GNUNET_SCHEDULER_add_now (&do_error, handle);
431 return;
432 } 293 }
433 GNUNET_IDENTITY_ego_get_public_key (ego,
434 &handle->pkey);
435 /* main name is our own master zone, do no look for that in the DHT */
436 handle->options = GNUNET_GNS_LO_LOCAL_MASTER;
437 /* if the name is of the form 'label.gnu', never go to the DHT */
438 dot = NULL;
439 if (NULL != handle->name)
440 dot = strchr (handle->name, '.');
441 if ( (NULL != dot) &&
442 (0 == strcasecmp (dot, ".gnu")) )
443 handle->options = GNUNET_GNS_LO_NO_DHT;
444 lookup_with_public_key (handle);
445}
446
447/**
448 * Parse REST uri for name and record type
449 *
450 * @param url Url to parse
451 * @param handle lookup handle to populate
452 * @return GNUNET_SYSERR on error
453 */
454static int
455parse_url (const char *url, struct LookupHandle *handle)
456{
457 char *name;
458 char tmp_url[strlen(url)+1];
459 char *tok;
460
461 strcpy (tmp_url, url);
462 tok = strtok ((char*)tmp_url, "/");
463 if (NULL == tok)
464 return GNUNET_SYSERR;
465 name = strtok (NULL, "/");
466 if (NULL == name)
467 return GNUNET_SYSERR;
468 GNUNET_asprintf (&handle->name,
469 "%s",
470 name);
471 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
472 "Got name: %s\n", handle->name);
473 return GNUNET_OK;
474}
475
476 294
477static void
478get_gns_cont (struct GNUNET_REST_RequestHandle *conndata_handle,
479 const char* url,
480 void *cls)
481{
482 struct LookupHandle *handle = cls;
483 struct GNUNET_HashCode key;
484 295
485 //parse name and type from url 296 if(UINT32_MAX == handle->record_type)
486 if (GNUNET_OK != parse_url (url, handle))
487 { 297 {
488 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error parsing url...\n"); 298 handle->record_type = GNUNET_GNSRECORD_TYPE_ANY;
489 GNUNET_SCHEDULER_add_now (&do_error, handle);
490 return;
491 } 299 }
492 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 300
493 "Connecting...\n");
494 handle->gns = GNUNET_GNS_connect (cfg); 301 handle->gns = GNUNET_GNS_connect (cfg);
495 handle->identity = GNUNET_IDENTITY_connect (cfg, NULL, NULL);
496 handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout,
497 &do_error, handle);
498 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
499 "Connected\n");
500 if (NULL == handle->gns) 302 if (NULL == handle->gns)
501 { 303 {
502 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 304 handle->emsg = GNUNET_strdup ("GNS not available");
503 "Connecting to GNS failed\n");
504 GNUNET_SCHEDULER_add_now (&do_error, handle); 305 GNUNET_SCHEDULER_add_now (&do_error, handle);
505 return; 306 return;
506 } 307 }
507 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_GNS_OPTIONS,
508 strlen (GNUNET_REST_JSONAPI_GNS_OPTIONS),
509 &key);
510 handle->options = GNUNET_GNS_LO_DEFAULT;
511 if ( GNUNET_YES ==
512 GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map,
513 &key) )
514 {
515 handle->options = GNUNET_GNS_LO_DEFAULT;//TODO(char*) GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map,
516 //&key);
517 }
518 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_GNS_RECORD_TYPE,
519 strlen (GNUNET_REST_JSONAPI_GNS_RECORD_TYPE),
520 &key);
521 if ( GNUNET_YES ==
522 GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map,
523 &key) )
524 {
525 handle->type = GNUNET_GNSRECORD_typename_to_number
526 (GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map,
527 &key));
528 }
529 else
530 handle->type = GNUNET_GNSRECORD_TYPE_ANY;
531 308
532 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_GNS_PKEY, 309 handle->gns_lookup = GNUNET_GNS_lookup_with_tld (handle->gns,
533 strlen (GNUNET_REST_JSONAPI_GNS_PKEY), 310 handle->name,
534 &key); 311 handle->record_type,
535 if ( GNUNET_YES == 312 GNUNET_NO,
536 GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map, 313 &handle_gns_response,
537 &key) ) 314 handle);
538 { 315 return;
539 handle->pkey_str = GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map,
540 &key);
541 GNUNET_assert (NULL != handle->pkey_str);
542 if (GNUNET_OK !=
543 GNUNET_CRYPTO_ecdsa_public_key_from_string (handle->pkey_str,
544 strlen(handle->pkey_str),
545 &(handle->pkey)))
546 {
547 GNUNET_SCHEDULER_add_now (&do_error, handle);
548 return;
549 }
550 lookup_with_public_key (handle);
551 return;
552 }
553 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_GNS_EGO,
554 strlen (GNUNET_REST_JSONAPI_GNS_EGO),
555 &key);
556 if ( GNUNET_YES ==
557 GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map,
558 &key) )
559 {
560 handle->ego_str = GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map,
561 &key);
562 handle->el = GNUNET_IDENTITY_ego_lookup (cfg,
563 handle->ego_str,
564 &identity_zone_cb,
565 handle);
566 return;
567 }
568 if ( (NULL != handle->name) &&
569 (strlen (handle->name) > 4) &&
570 (0 == strcmp (".zkey",
571 &handle->name[strlen (handle->name) - 4])) )
572 {
573 GNUNET_CRYPTO_ecdsa_key_get_public
574 (GNUNET_CRYPTO_ecdsa_key_get_anonymous (),
575 &(handle->pkey));
576 lookup_with_public_key (handle);
577 }
578 else
579 {
580 GNUNET_break (NULL == handle->id_op);
581 handle->id_op = GNUNET_IDENTITY_get (handle->identity,
582 "gns-master",
583 &identity_master_cb,
584 handle);
585 GNUNET_assert (NULL != handle->id_op);
586 }
587} 316}
588 317
318
319
589/** 320/**
590 * Handle rest request 321 * Respond to OPTIONS request
591 * 322 *
592 * @param handle the lookup handle 323 * @param con_handle the connection handle
324 * @param url the url
325 * @param cls the RequestHandle
593 */ 326 */
594static void 327static void
595options_cont (struct GNUNET_REST_RequestHandle *con_handle, 328options_cont (struct GNUNET_REST_RequestHandle *con_handle,
@@ -597,53 +330,38 @@ options_cont (struct GNUNET_REST_RequestHandle *con_handle,
597 void *cls) 330 void *cls)
598{ 331{
599 struct MHD_Response *resp; 332 struct MHD_Response *resp;
600 struct LookupHandle *handle = cls; 333 struct RequestHandle *handle = cls;
601 334
602 //For GNS, independent of path return all options 335 //independent of path return all options
603 resp = GNUNET_REST_create_response (NULL); 336 resp = GNUNET_REST_create_response (NULL);
604 MHD_add_response_header (resp, 337 MHD_add_response_header (resp,
605 "Access-Control-Allow-Methods", 338 "Access-Control-Allow-Methods",
606 MHD_HTTP_METHOD_GET); 339 allow_methods);
607 handle->proc (handle->proc_cls, 340 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
608 resp, 341 GNUNET_SCHEDULER_add_now(&cleanup_handle, handle);
609 MHD_HTTP_OK); 342 return;
610 cleanup_handle (handle);
611} 343}
612 344
613 345
614/** 346/**
615 * Function processing the REST call 347 * Handle rest request
616 * 348 *
617 * @param method HTTP method 349 * @param handle the request handle
618 * @param url URL of the HTTP request
619 * @param data body of the HTTP request (optional)
620 * @param data_size length of the body
621 * @param proc callback function for the result
622 * @param proc_cls closure for @a proc
623 * @return #GNUNET_OK if request accepted
624 */ 350 */
625static void 351static void
626rest_gns_process_request (struct GNUNET_REST_RequestHandle *conndata_handle, 352init_cont (struct RequestHandle *handle)
627 GNUNET_REST_ResultProcessor proc,
628 void *proc_cls)
629{ 353{
354 struct GNUNET_REST_RequestHandlerError err;
630 static const struct GNUNET_REST_RequestHandler handlers[] = { 355 static const struct GNUNET_REST_RequestHandler handlers[] = {
631 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_GNS, &get_gns_cont}, 356 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_GNS, &get_gns_cont},
632 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_GNS, &options_cont}, 357 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_GNS, &options_cont},
633 GNUNET_REST_HANDLER_END 358 GNUNET_REST_HANDLER_END
634 }; 359 };
635 struct LookupHandle *handle = GNUNET_new (struct LookupHandle);
636 struct GNUNET_REST_RequestHandlerError err;
637
638 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
639 handle->proc_cls = proc_cls;
640 handle->proc = proc;
641 handle->rest_handle = conndata_handle;
642 360
643 if (GNUNET_NO == GNUNET_JSONAPI_handle_request (conndata_handle, 361 if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle,
644 handlers, 362 handlers,
645 &err, 363 &err,
646 handle)) 364 handle))
647 { 365 {
648 handle->response_code = err.error_code; 366 handle->response_code = err.error_code;
649 GNUNET_SCHEDULER_add_now (&do_error, handle); 367 GNUNET_SCHEDULER_add_now (&do_error, handle);
@@ -652,18 +370,58 @@ rest_gns_process_request (struct GNUNET_REST_RequestHandle *conndata_handle,
652 370
653 371
654/** 372/**
373 * Function processing the REST call
374 *
375 * @param method HTTP method
376 * @param url URL of the HTTP request
377 * @param data body of the HTTP request (optional)
378 * @param data_size length of the body
379 * @param proc callback function for the result
380 * @param proc_cls closure for callback function
381 * @return GNUNET_OK if request accepted
382 */
383static void
384rest_process_request(struct GNUNET_REST_RequestHandle *rest_handle,
385 GNUNET_REST_ResultProcessor proc,
386 void *proc_cls)
387{
388 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
389
390 handle->response_code = 0;
391 handle->timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60);
392 handle->proc_cls = proc_cls;
393 handle->proc = proc;
394 handle->rest_handle = rest_handle;
395
396 handle->url = GNUNET_strdup (rest_handle->url);
397 if (handle->url[strlen (handle->url)-1] == '/')
398 handle->url[strlen (handle->url)-1] = '\0';
399 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n");
400
401 init_cont(handle);
402
403 handle->timeout_task =
404 GNUNET_SCHEDULER_add_delayed (handle->timeout,
405 &do_error,
406 handle);
407
408 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected\n");
409}
410
411
412/**
655 * Entry point for the plugin. 413 * Entry point for the plugin.
656 * 414 *
657 * @param cls the "struct GNUNET_NAMESTORE_PluginEnvironment*" 415 * @param cls Config info
658 * @return NULL on error, otherwise the plugin context 416 * @return NULL on error, otherwise the plugin context
659 */ 417 */
660void * 418void *
661libgnunet_plugin_rest_gns_init (void *cls) 419libgnunet_plugin_rest_gns_init (void *cls)
662{ 420{
663 static struct Plugin plugin; 421 static struct Plugin plugin;
664 cfg = cls;
665 struct GNUNET_REST_Plugin *api; 422 struct GNUNET_REST_Plugin *api;
666 423
424 cfg = cls;
667 if (NULL != plugin.cfg) 425 if (NULL != plugin.cfg)
668 return NULL; /* can only initialize once! */ 426 return NULL; /* can only initialize once! */
669 memset (&plugin, 0, sizeof (struct Plugin)); 427 memset (&plugin, 0, sizeof (struct Plugin));
@@ -671,9 +429,17 @@ libgnunet_plugin_rest_gns_init (void *cls)
671 api = GNUNET_new (struct GNUNET_REST_Plugin); 429 api = GNUNET_new (struct GNUNET_REST_Plugin);
672 api->cls = &plugin; 430 api->cls = &plugin;
673 api->name = GNUNET_REST_API_NS_GNS; 431 api->name = GNUNET_REST_API_NS_GNS;
674 api->process_request = &rest_gns_process_request; 432 api->process_request = &rest_process_request;
675 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 433 GNUNET_asprintf (&allow_methods,
676 _("GNS REST API initialized\n")); 434 "%s, %s, %s, %s, %s",
435 MHD_HTTP_METHOD_GET,
436 MHD_HTTP_METHOD_POST,
437 MHD_HTTP_METHOD_PUT,
438 MHD_HTTP_METHOD_DELETE,
439 MHD_HTTP_METHOD_OPTIONS);
440
441 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
442 _("Gns REST API initialized\n"));
677 return api; 443 return api;
678} 444}
679 445
@@ -689,12 +455,14 @@ libgnunet_plugin_rest_gns_done (void *cls)
689{ 455{
690 struct GNUNET_REST_Plugin *api = cls; 456 struct GNUNET_REST_Plugin *api = cls;
691 struct Plugin *plugin = api->cls; 457 struct Plugin *plugin = api->cls;
692
693 plugin->cfg = NULL; 458 plugin->cfg = NULL;
459
460 GNUNET_free_non_null (allow_methods);
694 GNUNET_free (api); 461 GNUNET_free (api);
695 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 462 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
696 "GNS REST plugin is finished\n"); 463 "Gns REST plugin is finished\n");
697 return NULL; 464 return NULL;
698} 465}
699 466
700/* end of plugin_rest_gns.c */ 467/* end of plugin_rest_gns.c */
468
diff --git a/src/gns/test_plugin_rest_gns.sh b/src/gns/test_plugin_rest_gns.sh
new file mode 100755
index 000000000..7ede44501
--- /dev/null
+++ b/src/gns/test_plugin_rest_gns.sh
@@ -0,0 +1,50 @@
1#!/usr/bin/bash
2
3#First, start gnunet-arm and the rest-service.
4#Exit 0 means success, exit 1 means failed test
5
6gns_link="http://localhost:7776/gns"
7wrong_link="http://localhost:7776/gnsandmore"
8
9curl_get () {
10 #$1 is link
11 #$2 is grep
12 cache="$(curl -v "$1" 2>&1 | grep "$2")"
13 #echo $cache
14 if [ "" == "$cache" ]
15 then
16 exit 1
17 fi
18}
19
20gnunet-identity -D "test_plugin_rest_gns" > /dev/null 2>&1
21
22curl_get "$gns_link?name=www.test_plugin_rest_gns" "error"
23
24gnunet-identity -C "test_plugin_rest_gns"
25
26curl_get "$gns_link?name=www.test_plugin_rest_gns" "\[\]"
27
28gnunet-namestore -z "test_plugin_rest_gns" -p -a -n www -e 1d -V 1.1.1.1 -t A
29
30curl_get "$gns_link?name=www.test_plugin_rest_gns" "1.1.1.1"
31
32gnunet-namestore -z "test_plugin_rest_gns" -p -a -n www -e 1d -V 1::1 -t AAAA
33
34curl_get "$gns_link?name=www.test_plugin_rest_gns" "1::1.*1.1.1.1"
35
36gnunet-namestore -z "test_plugin_rest_gns" -p -a -n www -e 1d -V 1.1.1.2 -t A
37
38curl_get "$gns_link?name=www.test_plugin_rest_gns" "1.1.1.2.*1::1.*1.1.1.1"
39curl_get "$gns_link?name=www.test_plugin_rest_gns&record_type=A" "1.1.1.2.*1.1.1.1"
40curl_get "$gns_link?name=www.test_plugin_rest_gns&record_type=AAAA" "1::1"
41curl_get "$gns_link?name=www.test_plugin_rest_gns&record_type=WRONG_TYPE" "1.1.1.2.*1::1.*1.1.1.1"
42
43gnunet-namestore -z "test_plugin_rest_gns" -p -a -n www1 -e 1d -V 1.1.1.1 -t A
44curl_get "$gns_link?name=www1.test_plugin_rest_gns" "1.1.1.1"
45
46gnunet-identity -D "test_plugin_rest_gns"
47
48curl_get "$gns_link?name=www1.test_plugin_rest_gns" "error"
49
50exit 0
diff --git a/src/gnsrecord/gnsrecord.c b/src/gnsrecord/gnsrecord.c
index da34846e7..b80d86073 100644
--- a/src/gnsrecord/gnsrecord.c
+++ b/src/gnsrecord/gnsrecord.c
@@ -28,7 +28,9 @@
28#include "gnunet_constants.h" 28#include "gnunet_constants.h"
29#include "gnunet_gnsrecord_lib.h" 29#include "gnunet_gnsrecord_lib.h"
30#include "gnunet_gnsrecord_plugin.h" 30#include "gnunet_gnsrecord_plugin.h"
31#include "gnunet_json_lib.h"
31#include "gnunet_tun_lib.h" 32#include "gnunet_tun_lib.h"
33#include <jansson.h>
32 34
33 35
34#define LOG(kind,...) GNUNET_log_from (kind, "gnsrecord",__VA_ARGS__) 36#define LOG(kind,...) GNUNET_log_from (kind, "gnsrecord",__VA_ARGS__)
@@ -245,5 +247,4 @@ GNUNET_GNSRECORD_number_to_typename (uint32_t type)
245 return NULL; 247 return NULL;
246} 248}
247 249
248
249/* end of gnsrecord.c */ 250/* end of gnsrecord.c */
diff --git a/src/identity/Makefile.am b/src/identity/Makefile.am
index b8e70fffb..e7104f0c3 100644
--- a/src/identity/Makefile.am
+++ b/src/identity/Makefile.am
@@ -60,8 +60,6 @@ libgnunet_plugin_rest_identity_la_SOURCES = \
60libgnunet_plugin_rest_identity_la_LIBADD = \ 60libgnunet_plugin_rest_identity_la_LIBADD = \
61 libgnunetidentity.la \ 61 libgnunetidentity.la \
62 $(top_builddir)/src/rest/libgnunetrest.la \ 62 $(top_builddir)/src/rest/libgnunetrest.la \
63 $(top_builddir)/src/jsonapi/libgnunetjsonapi.la \
64 $(top_builddir)/src/jsonapi/libgnunetjsonapiutils.la \
65 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \ 63 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \
66 $(LTLIBINTL) -ljansson -lmicrohttpd 64 $(LTLIBINTL) -ljansson -lmicrohttpd
67libgnunet_plugin_rest_identity_la_LDFLAGS = \ 65libgnunet_plugin_rest_identity_la_LDFLAGS = \
diff --git a/src/identity/plugin_rest_identity.c b/src/identity/plugin_rest_identity.c
index 355d75fd9..a518a74cc 100644
--- a/src/identity/plugin_rest_identity.c
+++ b/src/identity/plugin_rest_identity.c
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 Copyright (C) 2012-2015 GNUnet e.V. 3 Copyright (C) 2012-2015 GNUnet e.V.
4 4
5 GNUnet is free software: you can redistribute it and/or modify it 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 6 under the terms of the GNU Affero General Public License as published
@@ -11,74 +11,51 @@
11 WITHOUT ANY WARRANTY; without even the implied warranty of 11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details. 13 Affero General Public License for more details.
14 14
15 You should have received a copy of the GNU Affero General Public License 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/>. 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */ 17 */
18/** 18/**
19 * @author Martin Schanzenbach 19 * @author Martin Schanzenbach
20 * @author Philippe Buschmann
20 * @file identity/plugin_rest_identity.c 21 * @file identity/plugin_rest_identity.c
21 * @brief GNUnet Namestore REST plugin 22 * @brief GNUnet Identity REST plugin
22 *
23 */ 23 */
24 24
25#include "platform.h" 25#include "platform.h"
26#include "gnunet_rest_plugin.h" 26#include "gnunet_rest_plugin.h"
27#include "gnunet_identity_service.h" 27#include "gnunet_identity_service.h"
28#include "gnunet_rest_lib.h" 28#include "gnunet_rest_lib.h"
29#include "gnunet_jsonapi_lib.h"
30#include "gnunet_jsonapi_util.h"
31#include "microhttpd.h" 29#include "microhttpd.h"
32#include <jansson.h> 30#include <jansson.h>
33#include "gnunet_signatures.h"
34 31
35/**
36 * REST root namespace
37 */
38#define GNUNET_REST_API_NS_IDENTITY "/identity" 32#define GNUNET_REST_API_NS_IDENTITY "/identity"
39 33
40/** 34/**
41 * State while collecting all egos 35 * Parameter names
42 */
43#define ID_REST_STATE_INIT 0
44
45/**
46 * Done collecting egos
47 */
48#define ID_REST_STATE_POST_INIT 1
49
50/**
51 * Resource type
52 */
53#define GNUNET_REST_JSONAPI_IDENTITY_EGO "ego"
54
55/**
56 * Name attribute
57 */
58#define GNUNET_REST_JSONAPI_IDENTITY_NAME "name"
59
60/**
61 * Attribute to rename "name" TODO we changed id to the pubkey
62 * so this can be unified with "name"
63 */
64#define GNUNET_REST_JSONAPI_IDENTITY_NEWNAME "newname"
65
66/**
67 * URL parameter to change the subsytem for ego
68 */ 36 */
69#define GNUNET_REST_JSONAPI_IDENTITY_SUBSYSTEM "subsystem" 37#define GNUNET_REST_PARAM_PUBKEY "pubkey"
70 38#define GNUNET_REST_PARAM_SUBSYSTEM "subsystem"
39#define GNUNET_REST_PARAM_NAME "name"
40#define GNUNET_REST_PARAM_NEWNAME "newname"
71 41
72/** 42/**
73 * Error messages 43 * Error messages
74 */ 44 */
45#define GNUNET_REST_IDENTITY_ERROR_UNKNOWN "Unknown Error"
75#define GNUNET_REST_ERROR_RESOURCE_INVALID "Resource location invalid" 46#define GNUNET_REST_ERROR_RESOURCE_INVALID "Resource location invalid"
76#define GNUNET_REST_ERROR_NO_DATA "No data" 47#define GNUNET_REST_ERROR_NO_DATA "No data"
48#define GNUNET_REST_ERROR_DATA_INVALID "Data invalid"
77 49
78/** 50/**
79 * GNUid token lifetime 51 * State while collecting all egos
80 */ 52 */
81#define GNUNET_GNUID_TOKEN_EXPIRATION_MICROSECONDS 300000000 53#define ID_REST_STATE_INIT 0
54
55/**
56 * Done collecting egos
57 */
58#define ID_REST_STATE_POST_INIT 1
82 59
83/** 60/**
84 * The configuration handle 61 * The configuration handle
@@ -129,28 +106,37 @@ struct EgoEntry
129 struct GNUNET_IDENTITY_Ego *ego; 106 struct GNUNET_IDENTITY_Ego *ego;
130}; 107};
131 108
132
133struct RequestHandle 109struct RequestHandle
134{ 110{
135 /** 111 /**
136 * Ego list 112 * The data from the REST request
137 */ 113 */
138 struct EgoEntry *ego_head; 114 const char* data;
139 115
140 /** 116 /**
141 * Ego list 117 * The name to look up
142 */ 118 */
143 struct EgoEntry *ego_tail; 119 char *name;
144 120
145 /** 121 /**
146 * Handle to the rest connection 122 * the length of the REST data
147 */ 123 */
148 struct GNUNET_REST_RequestHandle *conndata_handle; 124 size_t data_size;
149 125
150 /** 126 /**
151 * response code 127 * Requested Subsystem
152 */ 128 */
153 int response_code; 129 char *subsystem;
130
131 /**
132 * Ego list
133 */
134 struct EgoEntry *ego_head;
135
136 /**
137 * Ego list
138 */
139 struct EgoEntry *ego_tail;
154 140
155 /** 141 /**
156 * The processing state 142 * The processing state
@@ -158,7 +144,7 @@ struct RequestHandle
158 int state; 144 int state;
159 145
160 /** 146 /**
161 * Handle to GNS service. 147 * Handle to Identity service.
162 */ 148 */
163 struct GNUNET_IDENTITY_Handle *identity_handle; 149 struct GNUNET_IDENTITY_Handle *identity_handle;
164 150
@@ -168,6 +154,11 @@ struct RequestHandle
168 struct GNUNET_IDENTITY_Operation *op; 154 struct GNUNET_IDENTITY_Operation *op;
169 155
170 /** 156 /**
157 * Rest connection
158 */
159 struct GNUNET_REST_RequestHandle *rest_handle;
160
161 /**
171 * Desired timeout for the lookup (default is no timeout). 162 * Desired timeout for the lookup (default is no timeout).
172 */ 163 */
173 struct GNUNET_TIME_Relative timeout; 164 struct GNUNET_TIME_Relative timeout;
@@ -175,7 +166,7 @@ struct RequestHandle
175 /** 166 /**
176 * ID of a task associated with the resolution process. 167 * ID of a task associated with the resolution process.
177 */ 168 */
178 struct GNUNET_SCHEDULER_Task * timeout_task; 169 struct GNUNET_SCHEDULER_Task *timeout_task;
179 170
180 /** 171 /**
181 * The plugin result processor 172 * The plugin result processor
@@ -188,81 +179,63 @@ struct RequestHandle
188 void *proc_cls; 179 void *proc_cls;
189 180
190 /** 181 /**
191 * The name to look up
192 */
193 char *name;
194
195 /**
196 * The subsystem set from REST
197 */
198 char *subsys;
199
200 /**
201 * The url 182 * The url
202 */ 183 */
203 char *url; 184 char *url;
204 185
205 /** 186 /**
206 * The data from the REST request 187 * Error response message
207 */
208 const char* data;
209
210 /**
211 * the length of the REST data
212 */
213 size_t data_size;
214
215 /**
216 * HTTP method
217 */ 188 */
218 const char* method; 189 char *emsg;
219 190
220 /** 191 /**
221 * Error response message 192 * Reponse code
222 */ 193 */
223 char *emsg; 194 int response_code;
224 195
225}; 196};
226 197
227
228/** 198/**
229 * Cleanup lookup handle 199 * Cleanup lookup handle
230 * @param handle Handle to clean up 200 * @param handle Handle to clean up
231 */ 201 */
232static void 202static void
233cleanup_handle (struct RequestHandle *handle) 203cleanup_handle (void *cls)
234{ 204{
205 struct RequestHandle *handle = cls;
235 struct EgoEntry *ego_entry; 206 struct EgoEntry *ego_entry;
236 struct EgoEntry *ego_tmp; 207 struct EgoEntry *ego_tmp;
237 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 208
238 "Cleaning up\n"); 209 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
239 if (NULL != handle->name)
240 GNUNET_free (handle->name);
241 if (NULL != handle->timeout_task) 210 if (NULL != handle->timeout_task)
242 { 211 {
243 GNUNET_SCHEDULER_cancel (handle->timeout_task); 212 GNUNET_SCHEDULER_cancel (handle->timeout_task);
244 handle->timeout_task = NULL; 213 handle->timeout_task = NULL;
245 } 214 }
246 if (NULL != handle->identity_handle) 215
247 GNUNET_IDENTITY_disconnect (handle->identity_handle); 216 if (NULL != handle->subsystem)
248 if (NULL != handle->subsys) 217 GNUNET_free(handle->subsystem);
249 GNUNET_free (handle->subsys);
250 if (NULL != handle->url) 218 if (NULL != handle->url)
251 GNUNET_free (handle->url); 219 GNUNET_free(handle->url);
252 if (NULL != handle->emsg) 220 if (NULL != handle->emsg)
253 GNUNET_free (handle->emsg); 221 GNUNET_free(handle->emsg);
222 if (NULL != handle->name)
223 GNUNET_free (handle->name);
224 if (NULL != handle->identity_handle)
225 GNUNET_IDENTITY_disconnect (handle->identity_handle);
226
254 for (ego_entry = handle->ego_head; 227 for (ego_entry = handle->ego_head;
255 NULL != ego_entry;) 228 NULL != ego_entry;)
256 { 229 {
257 ego_tmp = ego_entry; 230 ego_tmp = ego_entry;
258 ego_entry = ego_entry->next; 231 ego_entry = ego_entry->next;
259 GNUNET_free (ego_tmp->identifier); 232 GNUNET_free(ego_tmp->identifier);
260 GNUNET_free (ego_tmp->keystring); 233 GNUNET_free(ego_tmp->keystring);
261 GNUNET_free (ego_tmp); 234 GNUNET_free(ego_tmp);
262 } 235 }
263 GNUNET_free (handle);
264}
265 236
237 GNUNET_free(handle);
238}
266 239
267/** 240/**
268 * Task run on errors. Reports an error and cleans up everything. 241 * Task run on errors. Reports an error and cleans up everything.
@@ -274,23 +247,67 @@ do_error (void *cls)
274{ 247{
275 struct RequestHandle *handle = cls; 248 struct RequestHandle *handle = cls;
276 struct MHD_Response *resp; 249 struct MHD_Response *resp;
277 char *json_error; 250 json_t *json_error = json_object();
278 251 char *response;
279 GNUNET_asprintf (&json_error, 252
280 "{Error while processing request: %s}", 253 if (NULL == handle->emsg)
281 &handle->emsg); 254 handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_ERROR_UNKNOWN);
282 255
283 resp = GNUNET_REST_create_response (json_error); 256 json_object_set_new(json_error,"error", json_string(handle->emsg));
284 handle->proc (handle->proc_cls, 257
285 resp, 258 if (0 == handle->response_code)
286 handle->response_code); 259 handle->response_code = MHD_HTTP_OK;
287 cleanup_handle (handle); 260 response = json_dumps (json_error, 0);
288 GNUNET_free (json_error); 261 resp = GNUNET_REST_create_response (response);
262 handle->proc (handle->proc_cls, resp, handle->response_code);
263 json_decref(json_error);
264 GNUNET_free(response);
265 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
289} 266}
290 267
291 268
269
292/** 270/**
293 * Callback for IDENTITY_get() 271 * Get EgoEntry from list with either a public key or a name
272 * If public key and name are not NULL, it returns the public key result first
273 *
274 * @param handle the RequestHandle
275 * @param pubkey the public key of an identity (only one can be NULL)
276 * @param name the name of an identity (only one can be NULL)
277 * @return EgoEntry or NULL if not found
278 */
279struct EgoEntry*
280get_egoentry(struct RequestHandle *handle, char* pubkey, char *name)
281{
282 struct EgoEntry *ego_entry;
283 if (NULL != pubkey)
284 {
285 for (ego_entry = handle->ego_head;
286 NULL != ego_entry;
287 ego_entry = ego_entry->next)
288 {
289 if (0 != strcasecmp (pubkey, ego_entry->keystring))
290 continue;
291 return ego_entry;
292 }
293 }
294 if (NULL != name)
295 {
296 for (ego_entry = handle->ego_head;
297 NULL != ego_entry;
298 ego_entry = ego_entry->next)
299 {
300 if (0 != strcasecmp (name, ego_entry->identifier))
301 continue;
302 return ego_entry;
303 }
304 }
305 return NULL;
306}
307
308
309/**
310 * Callback for GET Request with subsystem
294 * 311 *
295 * @param cls the RequestHandle 312 * @param cls the RequestHandle
296 * @param ego the Ego found 313 * @param ego the Ego found
@@ -298,153 +315,177 @@ do_error (void *cls)
298 * @param name the id of the ego 315 * @param name the id of the ego
299 */ 316 */
300static void 317static void
301get_ego_for_subsys (void *cls, 318ego_get_for_subsystem (void *cls, struct GNUNET_IDENTITY_Ego *ego, void **ctx,
302 struct GNUNET_IDENTITY_Ego *ego, 319 const char *name)
303 void **ctx,
304 const char *name)
305{ 320{
306 struct RequestHandle *handle = cls; 321 struct RequestHandle *handle = cls;
307 struct GNUNET_JSONAPI_Document *json_document;
308 struct GNUNET_JSONAPI_Resource *json_resource;
309 struct EgoEntry *ego_entry;
310 struct MHD_Response *resp; 322 struct MHD_Response *resp;
311 json_t *name_json; 323 struct GNUNET_CRYPTO_EcdsaPublicKey public_key;
324 json_t *json_root;
312 char *result_str; 325 char *result_str;
326 char *public_key_string;
313 327
314 json_document = GNUNET_JSONAPI_document_new (); 328 if(NULL == ego)
315
316 for (ego_entry = handle->ego_head;
317 NULL != ego_entry;
318 ego_entry = ego_entry->next)
319 { 329 {
320 if ( (NULL != name) && (0 != strcmp (name, ego_entry->identifier)) ) 330 handle->emsg = GNUNET_strdup("No identity found for subsystem");
321 continue;
322 if (NULL == name)
323 continue;
324 json_resource = GNUNET_JSONAPI_resource_new
325 (GNUNET_REST_JSONAPI_IDENTITY_EGO, ego_entry->keystring);
326 name_json = json_string (ego_entry->identifier);
327 GNUNET_JSONAPI_resource_add_attr (json_resource,
328 GNUNET_REST_JSONAPI_IDENTITY_NAME,
329 name_json);
330 json_decref (name_json);
331 GNUNET_JSONAPI_document_resource_add (json_document, json_resource);
332 break;
333 }
334 if (0 == GNUNET_JSONAPI_document_resource_count (json_document))
335 {
336 GNUNET_JSONAPI_document_delete (json_document);
337 handle->emsg = GNUNET_strdup("No identity matches results!");
338 GNUNET_SCHEDULER_add_now (&do_error, handle); 331 GNUNET_SCHEDULER_add_now (&do_error, handle);
339 return; 332 return;
340 } 333 }
341 GNUNET_JSONAPI_document_serialize (json_document, &result_str); 334
342 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str); 335 GNUNET_IDENTITY_ego_get_public_key(ego,&public_key);
336 public_key_string = GNUNET_CRYPTO_ecdsa_public_key_to_string(&public_key);
337
338 // create json with subsystem identity
339 json_root = json_object ();
340 json_object_set_new (json_root, GNUNET_REST_PARAM_PUBKEY, json_string(public_key_string));
341 json_object_set_new (json_root, GNUNET_REST_PARAM_NAME, json_string(name));
342
343 result_str = json_dumps (json_root, 0);
344 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
343 resp = GNUNET_REST_create_response (result_str); 345 resp = GNUNET_REST_create_response (result_str);
344 GNUNET_JSONAPI_document_delete (json_document); 346
347 json_decref (json_root);
345 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); 348 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
346 GNUNET_free (result_str); 349 GNUNET_free(result_str);
347 cleanup_handle (handle); 350 GNUNET_free(public_key_string);
351 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
348} 352}
349 353
350/** 354/**
351 * Create a response with requested ego(s) 355 * Handle identity GET request
352 * 356 *
353 * @param con the Rest handle 357 * @param con_handle the connection handle
354 * @param url the requested url 358 * @param url the url
355 * @param cls the request handle 359 * @param cls the RequestHandle
356 */ 360 */
357static void 361void
358ego_info_response (struct GNUNET_REST_RequestHandle *con, 362ego_get (struct GNUNET_REST_RequestHandle *con_handle, const char* url,
359 const char *url, 363 void *cls)
360 void *cls)
361{ 364{
362 const char *egoname;
363 char *result_str;
364 char *subsys_val;
365 char *keystring;
366 struct RequestHandle *handle = cls; 365 struct RequestHandle *handle = cls;
367 struct EgoEntry *ego_entry; 366 struct EgoEntry *ego_entry;
368 struct GNUNET_HashCode key; 367 struct GNUNET_HashCode key;
369 struct MHD_Response *resp; 368 struct MHD_Response *resp;
370 struct GNUNET_JSONAPI_Document *json_document; 369 char *keystring;
371 struct GNUNET_JSONAPI_Resource *json_resource; 370 char *egoname;
372 json_t *name_str; 371 json_t *json_root;
372 json_t *json_ego;
373 char *result_str;
373 374
374 if (GNUNET_NO == GNUNET_REST_namespace_match (handle->url, GNUNET_REST_API_NS_IDENTITY)) 375 //requested default identity of subsystem
376 GNUNET_CRYPTO_hash (GNUNET_REST_PARAM_SUBSYSTEM,
377 strlen (GNUNET_REST_PARAM_SUBSYSTEM), &key);
378 if ( GNUNET_YES
379 == GNUNET_CONTAINER_multihashmap_contains (
380 handle->rest_handle->url_param_map, &key))
375 { 381 {
376 resp = GNUNET_REST_create_response (NULL); 382 handle->subsystem = GNUNET_strdup(
377 handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST); 383 GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
378 cleanup_handle (handle); 384 &key));
385 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Looking for %s's ego\n",
386 handle->subsystem);
387
388 handle->op = GNUNET_IDENTITY_get (handle->identity_handle,
389 handle->subsystem,
390 &ego_get_for_subsystem,
391 handle);
392 if (NULL == handle->op)
393 {
394 handle->emsg = GNUNET_strdup("No identity found for subsystem");
395 GNUNET_SCHEDULER_add_now (&do_error, handle);
396 return;
397 }
379 return; 398 return;
380 } 399 }
381 egoname = NULL; 400 egoname = NULL;
382 keystring = NULL; 401 keystring = NULL;
383 if (strlen (GNUNET_REST_API_NS_IDENTITY) < strlen (handle->url)) 402
403 //one identity requested with key
404 GNUNET_CRYPTO_hash (GNUNET_REST_PARAM_PUBKEY,
405 strlen (GNUNET_REST_PARAM_PUBKEY),
406 &key);
407 if ( GNUNET_YES
408 == GNUNET_CONTAINER_multihashmap_contains (
409 handle->rest_handle->url_param_map, &key))
384 { 410 {
385 keystring = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY)+1]; 411 keystring = GNUNET_CONTAINER_multihashmap_get (
386 //Return all egos 412 handle->rest_handle->url_param_map, &key);
387 for (ego_entry = handle->ego_head; 413
388 NULL != ego_entry; 414 ego_entry = get_egoentry(handle, keystring, NULL);
389 ego_entry = ego_entry->next) 415 if (NULL == ego_entry)
390 { 416 {
391 if ( (NULL != keystring) && (0 != strcmp (keystring, ego_entry->keystring)) ) 417 handle->emsg = GNUNET_strdup("No identity found for public key");
392 continue; 418 GNUNET_SCHEDULER_add_now (&do_error, handle);
393 egoname = ego_entry->identifier; 419 return;
394 } 420 }
421 egoname = ego_entry->identifier;
395 } 422 }
396 423
397 if ( NULL == egoname ) { 424 //one identity requested with name
398 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_IDENTITY_SUBSYSTEM, 425 if (NULL == egoname)
399 strlen (GNUNET_REST_JSONAPI_IDENTITY_SUBSYSTEM), 426 {
400 &key); 427 GNUNET_CRYPTO_hash (GNUNET_REST_PARAM_NAME,
401 if ( GNUNET_YES == 428 strlen (GNUNET_REST_PARAM_NAME),
402 GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map, 429 &key);
403 &key) ) 430 if ( GNUNET_YES
431 == GNUNET_CONTAINER_multihashmap_contains (
432 handle->rest_handle->url_param_map, &key))
404 { 433 {
405 subsys_val = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map, 434 egoname = GNUNET_CONTAINER_multihashmap_get (
406 &key); 435 handle->rest_handle->url_param_map, &key);
407 if (NULL != subsys_val) 436 if (0 >= strlen(egoname))
408 { 437 {
409 GNUNET_asprintf (&handle->subsys, "%s", subsys_val); 438 handle->emsg = GNUNET_strdup("No identity found for name");
410 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Looking for %s's ego\n", subsys_val); 439 GNUNET_SCHEDULER_add_now (&do_error, handle);
411 handle->op = GNUNET_IDENTITY_get (handle->identity_handle,
412 handle->subsys,
413 &get_ego_for_subsys,
414 handle);
415 return; 440 return;
416 } 441 }
442 //LOWERCASE ego names?
443 GNUNET_STRINGS_utf8_tolower(egoname, egoname);
417 } 444 }
418 } 445 }
419 446
420 json_document = GNUNET_JSONAPI_document_new (); 447 json_root = json_array ();
421 448 //Return ego/egos
422 //Return all egos
423 for (ego_entry = handle->ego_head; 449 for (ego_entry = handle->ego_head;
424 NULL != ego_entry; 450 NULL != ego_entry; ego_entry = ego_entry->next)
425 ego_entry = ego_entry->next)
426 { 451 {
427 if ( (NULL != egoname) && (0 != strcmp (egoname, ego_entry->identifier)) ) 452 //if only one ego requested
428 continue; 453 if ((NULL != egoname)){
429 json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_EGO, 454 if(0 != strcmp (egoname, ego_entry->identifier)){
430 ego_entry->keystring); 455 continue;
431 name_str = json_string (ego_entry->identifier); 456 }
432 GNUNET_JSONAPI_resource_add_attr ( 457 }
433 json_resource, 458
434 GNUNET_REST_JSONAPI_IDENTITY_NAME, 459 json_ego = json_object ();
435 name_str); 460 json_object_set_new (json_ego,
436 json_decref (name_str); 461 GNUNET_REST_PARAM_PUBKEY,
437 GNUNET_JSONAPI_document_resource_add (json_document, json_resource); 462 json_string (ego_entry->keystring));
463 json_object_set_new (json_ego,
464 GNUNET_REST_PARAM_NAME,
465 json_string (ego_entry->identifier));
466 json_array_append (json_root, json_ego);
467 json_decref (json_ego);
468 }
469
470 if ((size_t) 0 == json_array_size (json_root))
471 {
472 json_decref (json_root);
473 handle->emsg = GNUNET_strdup("No identities found!");
474 GNUNET_SCHEDULER_add_now (&do_error, handle);
475 return;
438 } 476 }
439 GNUNET_JSONAPI_document_serialize (json_document, &result_str); 477
440 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str); 478 result_str = json_dumps (json_root, 0);
479 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
441 resp = GNUNET_REST_create_response (result_str); 480 resp = GNUNET_REST_create_response (result_str);
442 GNUNET_JSONAPI_document_delete (json_document); 481
482 json_decref (json_root);
443 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); 483 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
444 GNUNET_free (result_str); 484 GNUNET_free(result_str);
445 cleanup_handle (handle); 485 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
446} 486}
447 487
488
448/** 489/**
449 * Processing finished 490 * Processing finished
450 * 491 *
@@ -460,311 +501,363 @@ do_finished (void *cls, const char *emsg)
460 handle->op = NULL; 501 handle->op = NULL;
461 if (NULL != emsg) 502 if (NULL != emsg)
462 { 503 {
463 handle->emsg = GNUNET_strdup (emsg); 504 handle->emsg = GNUNET_strdup(emsg);
464 GNUNET_SCHEDULER_add_now (&do_error, handle); 505 GNUNET_SCHEDULER_add_now (&do_error, handle);
465 return; 506 return;
466 } 507 }
467 resp = GNUNET_REST_create_response (NULL); 508 resp = GNUNET_REST_create_response (NULL);
468 handle->proc (handle->proc_cls, resp, MHD_HTTP_NO_CONTENT); 509 handle->proc (handle->proc_cls, resp, handle->response_code);
469 cleanup_handle (handle); 510 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
470} 511}
471 512
513
472/** 514/**
473 * Create a new ego 515 * Handle identity PUT request
474 * 516 *
475 * @param con rest handle 517 * @param con_handle the connection handle
476 * @param url url 518 * @param url the url
477 * @param cls request handle 519 * @param cls the RequestHandle
478 */ 520 */
479static void 521void
480ego_create_cont (struct GNUNET_REST_RequestHandle *con, 522ego_edit (struct GNUNET_REST_RequestHandle *con_handle,
481 const char *url, 523 const char* url,
482 void *cls) 524 void *cls)
483{ 525{
484 struct RequestHandle *handle = cls; 526 struct RequestHandle *handle = cls;
485 struct EgoEntry *ego_entry; 527 struct EgoEntry *ego_entry;
528 struct EgoEntry *ego_entry_tmp;
486 struct MHD_Response *resp; 529 struct MHD_Response *resp;
487 struct GNUNET_JSONAPI_Document *json_obj; 530 int json_state;
488 struct GNUNET_JSONAPI_Resource *json_res;
489 json_t *egoname_json;
490 json_t *data_js; 531 json_t *data_js;
491 json_error_t err; 532 json_error_t err;
492 const char* egoname; 533 char *pubkey;
493 char term_data[handle->data_size+1]; 534 char *name;
494 struct GNUNET_JSON_Specification docspec[] = { 535 char *newsubsys;
495 GNUNET_JSON_spec_jsonapi_document (&json_obj), 536 char *newname;
496 GNUNET_JSON_spec_end() 537 char term_data[handle->data_size + 1];
497 }; 538
498 if (strlen (GNUNET_REST_API_NS_IDENTITY) != strlen (handle->url)) 539 //if no data
499 {
500 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_RESOURCE_INVALID);
501 GNUNET_SCHEDULER_add_now (&do_error, handle);
502 return;
503 }
504 if (0 >= handle->data_size) 540 if (0 >= handle->data_size)
505 { 541 {
506 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_NO_DATA); 542 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA);
507 GNUNET_SCHEDULER_add_now (&do_error, handle); 543 GNUNET_SCHEDULER_add_now (&do_error, handle);
508 return; 544 return;
509 } 545 }
546 //if not json
510 term_data[handle->data_size] = '\0'; 547 term_data[handle->data_size] = '\0';
511 GNUNET_memcpy (term_data, handle->data, handle->data_size); 548 GNUNET_memcpy(term_data, handle->data, handle->data_size);
512 data_js = json_loads (term_data, 549 data_js = json_loads (term_data,JSON_DECODE_ANY,&err);
513 JSON_DECODE_ANY,
514 &err);
515 GNUNET_assert (NULL != data_js);
516 GNUNET_assert (GNUNET_OK ==
517 GNUNET_JSON_parse (data_js, docspec,
518 NULL, NULL));
519 550
520 json_decref (data_js); 551 if (NULL == data_js)
521
522 if (NULL == json_obj)
523 { 552 {
553 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA);
524 GNUNET_SCHEDULER_add_now (&do_error, handle); 554 GNUNET_SCHEDULER_add_now (&do_error, handle);
525 return; 555 return;
526 } 556 }
527 if (1 != GNUNET_JSONAPI_document_resource_count (json_obj)) 557
528 { 558 ego_entry = NULL;
529 GNUNET_JSONAPI_document_delete (json_obj); 559 pubkey = NULL;
530 handle->emsg = GNUNET_strdup ("Provided resource count invalid"); 560 name = NULL;
531 GNUNET_SCHEDULER_add_now (&do_error, handle); 561 newname = NULL;
532 return; 562 //NEW NAME
533 } 563 json_state = 0;
534 json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0); 564 json_state = json_unpack(data_js,
535 if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res, GNUNET_REST_JSONAPI_IDENTITY_EGO)) 565 "{s:s,s?:s,s?:s}",
536 { 566 GNUNET_REST_PARAM_NEWNAME,
537 GNUNET_JSONAPI_document_delete (json_obj); 567 &newname,
538 resp = GNUNET_REST_create_response (NULL); 568 GNUNET_REST_PARAM_PUBKEY,
539 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT); 569 &pubkey,
540 cleanup_handle (handle); 570 GNUNET_REST_PARAM_NAME,
541 return; 571 &name);
542 } 572 //Change name with pubkey or name identifier
543 egoname_json = GNUNET_JSONAPI_resource_read_attr (json_res, GNUNET_REST_JSONAPI_IDENTITY_NAME); 573 if (0 == json_state)
544 if (!json_is_string (egoname_json))
545 { 574 {
546 GNUNET_JSONAPI_document_delete (json_obj); 575 if (NULL == newname)
547 handle->emsg = GNUNET_strdup ("No name provided"); 576 {
548 GNUNET_SCHEDULER_add_now (&do_error, handle); 577 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID);
578 GNUNET_SCHEDULER_add_now (&do_error, handle);
579 json_decref (data_js);
580 return;
581 }
582
583 if (0 >= strlen(newname))
584 {
585 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID);
586 GNUNET_SCHEDULER_add_now (&do_error, handle);
587 json_decref (data_js);
588 return;
589 }
590 //lower case name
591 GNUNET_STRINGS_utf8_tolower(newname,newname);
592
593 ego_entry = get_egoentry(handle,pubkey,name);
594
595 if (NULL == ego_entry)
596 {
597 resp = GNUNET_REST_create_response (NULL);
598 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
599 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
600 json_decref (data_js);
601 return;
602 }
603
604 for (ego_entry_tmp = handle->ego_head;
605 NULL != ego_entry_tmp; ego_entry_tmp = ego_entry_tmp->next)
606 {
607 if (0 == strcasecmp (newname, ego_entry_tmp->identifier))
608 {
609 //Ego with same name not allowed
610 resp = GNUNET_REST_create_response (NULL);
611 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
612 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
613 json_decref (data_js);
614 return;
615 }
616 }
617 handle->response_code = MHD_HTTP_NO_CONTENT;
618 handle->op = GNUNET_IDENTITY_rename (handle->identity_handle,
619 ego_entry->identifier, newname,
620 &do_finished, handle);
621 json_decref (data_js);
549 return; 622 return;
550 } 623 }
551 egoname = json_string_value (egoname_json); 624
552 for (ego_entry = handle->ego_head; 625 newsubsys = NULL;
553 NULL != ego_entry; 626 //SUBSYSTEM
554 ego_entry = ego_entry->next) 627 json_state = 0;
628 json_state = json_unpack(data_js,
629 "{s:s,s?:s,s?:s}",
630 GNUNET_REST_PARAM_SUBSYSTEM,
631 &newsubsys,
632 GNUNET_REST_PARAM_PUBKEY,
633 &pubkey,
634 GNUNET_REST_PARAM_NAME,
635 &name);
636 //Change subsystem with pubkey or name identifier
637 if (0 == json_state)
555 { 638 {
556 if (0 == strcasecmp (egoname, ego_entry->identifier)) 639 if (NULL == newsubsys || (NULL == pubkey && NULL == name))
557 { 640 {
558 GNUNET_JSONAPI_document_delete (json_obj); 641 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID);
559 resp = GNUNET_REST_create_response (NULL); 642 GNUNET_SCHEDULER_add_now (&do_error, handle);
560 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT); 643 json_decref (data_js);
561 cleanup_handle (handle); 644 return;
645 }
646
647 if (0 >= strlen(newsubsys))
648 {
649 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID);
650 GNUNET_SCHEDULER_add_now (&do_error, handle);
651 json_decref (data_js);
562 return; 652 return;
563 } 653 }
654
655 ego_entry = get_egoentry(handle, pubkey, name);
656
657 if (NULL == ego_entry)
658 {
659 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID);
660 GNUNET_SCHEDULER_add_now (&do_error, handle);
661 json_decref (data_js);
662 return;
663 }
664
665 handle->response_code = MHD_HTTP_NO_CONTENT;
666 handle->op = GNUNET_IDENTITY_set (handle->identity_handle,
667 newsubsys,
668 ego_entry->ego,
669 &do_finished,
670 handle);
671 json_decref (data_js);
672 return;
564 } 673 }
565 GNUNET_asprintf (&handle->name, "%s", egoname);
566 GNUNET_JSONAPI_document_delete (json_obj);
567 handle->op = GNUNET_IDENTITY_create (handle->identity_handle,
568 handle->name,
569 &do_finished,
570 handle);
571}
572 674
675 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID);
676 GNUNET_SCHEDULER_add_now (&do_error, handle);
677 json_decref (data_js);
678 return;
679}
573 680
574/** 681/**
575 * Handle ego edit request 682 * Handle identity POST request
576 * 683 *
577 * @param con rest connection handle 684 * @param con_handle the connection handle
578 * @param url the url that is requested 685 * @param url the url
579 * @param cls the RequestHandle 686 * @param cls the RequestHandle
580 */ 687 */
581static void 688void
582ego_edit_cont (struct GNUNET_REST_RequestHandle *con, 689ego_create (struct GNUNET_REST_RequestHandle *con_handle, const char* url,
583 const char *url, 690 void *cls)
584 void *cls)
585{ 691{
586 struct GNUNET_JSONAPI_Document *json_obj;
587 struct GNUNET_JSONAPI_Resource *json_res;
588 struct RequestHandle *handle = cls; 692 struct RequestHandle *handle = cls;
589 struct EgoEntry *ego_entry; 693 struct EgoEntry *ego_entry;
590 struct EgoEntry *ego_entry_tmp;
591 struct MHD_Response *resp; 694 struct MHD_Response *resp;
592 json_t *subsys_json;
593 json_t *name_json;
594 json_t *data_js; 695 json_t *data_js;
595 json_error_t err; 696 json_error_t err;
596 const char *keystring; 697 char* egoname;
597 const char *subsys; 698 int json_unpack_state;
598 const char *newname; 699 char term_data[handle->data_size + 1];
599 char term_data[handle->data_size+1];
600 int ego_exists = GNUNET_NO;
601 struct GNUNET_JSON_Specification docspec[] = {
602 GNUNET_JSON_spec_jsonapi_document (&json_obj),
603 GNUNET_JSON_spec_end()
604 };
605 700
606 if (strlen (GNUNET_REST_API_NS_IDENTITY) > strlen (handle->url)) 701 if (strlen (GNUNET_REST_API_NS_IDENTITY) != strlen (handle->url))
607 { 702 {
608 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_RESOURCE_INVALID); 703 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_RESOURCE_INVALID);
609 GNUNET_SCHEDULER_add_now (&do_error, handle); 704 GNUNET_SCHEDULER_add_now (&do_error, handle);
610 return; 705 return;
611 } 706 }
612 707
613 keystring = &handle->url[strlen(GNUNET_REST_API_NS_IDENTITY)+1];
614
615 for (ego_entry = handle->ego_head;
616 NULL != ego_entry;
617 ego_entry = ego_entry->next)
618 {
619 if (0 != strcasecmp (keystring, ego_entry->keystring))
620 continue;
621 ego_exists = GNUNET_YES;
622 break;
623 }
624
625 if (GNUNET_NO == ego_exists)
626 {
627 resp = GNUNET_REST_create_response (NULL);
628 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
629 cleanup_handle (handle);
630 return;
631 }
632
633 if (0 >= handle->data_size) 708 if (0 >= handle->data_size)
634 { 709 {
635 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_NO_DATA); 710 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA);
636 GNUNET_SCHEDULER_add_now (&do_error, handle); 711 GNUNET_SCHEDULER_add_now (&do_error, handle);
637 return; 712 return;
638 } 713 }
639
640 term_data[handle->data_size] = '\0'; 714 term_data[handle->data_size] = '\0';
641 GNUNET_memcpy (term_data, handle->data, handle->data_size); 715 GNUNET_memcpy(term_data, handle->data, handle->data_size);
642 data_js = json_loads (term_data, 716 data_js = json_loads (term_data,
643 JSON_DECODE_ANY, 717 JSON_DECODE_ANY,
644 &err); 718 &err);
645 GNUNET_assert (NULL != data_js); 719 if (NULL == data_js)
646 GNUNET_assert (GNUNET_OK ==
647 GNUNET_JSON_parse (data_js, docspec,
648 NULL, NULL));
649
650 json_decref (data_js);
651
652 if (NULL == json_obj)
653 { 720 {
654 handle->emsg = GNUNET_strdup ("Data invalid"); 721 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA);
655 GNUNET_SCHEDULER_add_now (&do_error, handle); 722 GNUNET_SCHEDULER_add_now (&do_error, handle);
723 json_decref (data_js);
656 return; 724 return;
657 } 725 }
658 726 json_unpack_state = 0;
659 if (1 != GNUNET_JSONAPI_document_resource_count (json_obj)) 727 json_unpack_state = json_unpack(data_js,
728 "{s:s!}",
729 GNUNET_REST_PARAM_NAME,
730 &egoname);
731 if (0 != json_unpack_state)
660 { 732 {
661 GNUNET_JSONAPI_document_delete (json_obj); 733 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID);
662 handle->emsg = GNUNET_strdup ("Resource amount invalid");
663 GNUNET_SCHEDULER_add_now (&do_error, handle); 734 GNUNET_SCHEDULER_add_now (&do_error, handle);
735 json_decref (data_js);
664 return; 736 return;
665 } 737 }
666 json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
667 738
668 if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res, GNUNET_REST_JSONAPI_IDENTITY_EGO)) 739 if (NULL == egoname)
669 { 740 {
670 GNUNET_JSONAPI_document_delete (json_obj); 741 handle->emsg = GNUNET_strdup("No name provided");
671 handle->emsg = GNUNET_strdup ("Resource type invalid");
672 GNUNET_SCHEDULER_add_now (&do_error, handle); 742 GNUNET_SCHEDULER_add_now (&do_error, handle);
743 json_decref (data_js);
673 return; 744 return;
674 } 745 }
675 746 if (0 >= strlen (egoname))
676 //This is a rename
677 name_json = GNUNET_JSONAPI_resource_read_attr (json_res,
678 GNUNET_REST_JSONAPI_IDENTITY_NEWNAME);
679 if ((NULL != name_json) && json_is_string (name_json))
680 { 747 {
681 newname = json_string_value (name_json); 748 json_decref (data_js);
682 for (ego_entry_tmp = handle->ego_head; 749 handle->emsg = GNUNET_strdup("No name provided");
683 NULL != ego_entry_tmp; 750 GNUNET_SCHEDULER_add_now (&do_error, handle);
684 ego_entry_tmp = ego_entry_tmp->next)
685 {
686 if (0 == strcasecmp (newname, ego_entry_tmp->identifier) &&
687 0 != strcasecmp (keystring, ego_entry_tmp->keystring))
688 {
689 //Ego with same name not allowed
690 GNUNET_JSONAPI_document_delete (json_obj);
691 resp = GNUNET_REST_create_response (NULL);
692 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
693 cleanup_handle (handle);
694 return;
695 }
696 }
697 handle->op = GNUNET_IDENTITY_rename (handle->identity_handle,
698 ego_entry->identifier,
699 newname,
700 &do_finished,
701 handle);
702 GNUNET_JSONAPI_document_delete (json_obj);
703 return; 751 return;
704 } 752 }
705 753 GNUNET_STRINGS_utf8_tolower(egoname, egoname);
706 //Set subsystem 754 for (ego_entry = handle->ego_head;
707 subsys_json = GNUNET_JSONAPI_resource_read_attr (json_res, GNUNET_REST_JSONAPI_IDENTITY_SUBSYSTEM); 755 NULL != ego_entry; ego_entry = ego_entry->next)
708 if ( (NULL != subsys_json) && json_is_string (subsys_json))
709 { 756 {
710 subsys = json_string_value (subsys_json); 757 if (0 == strcasecmp (egoname, ego_entry->identifier))
711 GNUNET_asprintf (&handle->subsys, "%s", subsys); 758 {
712 GNUNET_JSONAPI_document_delete (json_obj); 759 resp = GNUNET_REST_create_response (NULL);
713 handle->op = GNUNET_IDENTITY_set (handle->identity_handle, 760 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
714 handle->subsys, 761 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
715 ego_entry->ego, 762 json_decref (data_js);
716 &do_finished, 763 return;
717 handle); 764 }
718 return;
719 } 765 }
720 GNUNET_JSONAPI_document_delete (json_obj); 766 handle->name = GNUNET_strdup(egoname);
721 handle->emsg = GNUNET_strdup ("Subsystem not provided"); 767 json_decref (data_js);
722 GNUNET_SCHEDULER_add_now (&do_error, handle); 768 handle->response_code = MHD_HTTP_CREATED;
769 handle->op = GNUNET_IDENTITY_create (handle->identity_handle, handle->name,
770 &do_finished, handle);
723} 771}
724 772
773/**
774 * Handle identity DELETE request
775 *
776 * @param con_handle the connection handle
777 * @param url the url
778 * @param cls the RequestHandle
779 */
725void 780void
726ego_delete_cont (struct GNUNET_REST_RequestHandle *con_handle, 781ego_delete (struct GNUNET_REST_RequestHandle *con_handle, const char* url,
727 const char* url, 782 void *cls)
728 void *cls)
729{ 783{
730 const char *keystring; 784 struct RequestHandle *handle = cls;
731 struct EgoEntry *ego_entry; 785 struct EgoEntry *ego_entry;
786 struct GNUNET_HashCode key;
732 struct MHD_Response *resp; 787 struct MHD_Response *resp;
733 struct RequestHandle *handle = cls; 788 const char *keystring;
789 char *egoname;
734 int ego_exists = GNUNET_NO; 790 int ego_exists = GNUNET_NO;
735 791
736 if (strlen (GNUNET_REST_API_NS_IDENTITY) >= strlen (handle->url)) 792 keystring = NULL;
793 egoname = NULL;
794
795 //delete with pubkey
796 GNUNET_CRYPTO_hash (GNUNET_REST_PARAM_PUBKEY,
797 strlen (GNUNET_REST_PARAM_PUBKEY), &key);
798 if ( GNUNET_YES
799 == GNUNET_CONTAINER_multihashmap_contains (
800 handle->rest_handle->url_param_map, &key))
737 { 801 {
738 handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_RESOURCE_INVALID); 802 keystring = GNUNET_CONTAINER_multihashmap_get (
739 GNUNET_SCHEDULER_add_now (&do_error, handle); 803 handle->rest_handle->url_param_map,&key);
740 return;
741 } 804 }
742 805
743 keystring = &handle->url[strlen(GNUNET_REST_API_NS_IDENTITY)+1]; 806 GNUNET_CRYPTO_hash (GNUNET_REST_PARAM_NAME,
744 for (ego_entry = handle->ego_head; 807 strlen (GNUNET_REST_PARAM_NAME), &key);
745 NULL != ego_entry; 808 if ( GNUNET_YES
746 ego_entry = ego_entry->next) 809 == GNUNET_CONTAINER_multihashmap_contains (
810 handle->rest_handle->url_param_map, &key))
747 { 811 {
748 if (0 != strcasecmp (keystring, ego_entry->keystring)) 812 egoname = GNUNET_CONTAINER_multihashmap_get (
749 continue; 813 handle->rest_handle->url_param_map, &key);
750 ego_exists = GNUNET_YES; 814 //LOWERCASE ego names?
751 break; 815 //GNUNET_STRINGS_utf8_tolower(egoname, egoname);
752 } 816 }
817
818 if (NULL != keystring)
819 {
820 for (ego_entry = handle->ego_head;
821 NULL != ego_entry; ego_entry = ego_entry->next)
822 {
823 if (0 != strcasecmp (keystring, ego_entry->keystring))
824 continue;
825 ego_exists = GNUNET_YES;
826 break;
827 }
828 }
829 else if (NULL != egoname)
830 {
831 for (ego_entry = handle->ego_head;
832 NULL != ego_entry; ego_entry = ego_entry->next)
833 {
834 if (0 != strcmp (egoname, ego_entry->identifier))
835 continue;
836 ego_exists = GNUNET_YES;
837 break;
838 }
839 }
840 else
841 {
842 handle->emsg = GNUNET_strdup("Missing parameter pubkey or name");
843 GNUNET_SCHEDULER_add_now (&do_error, handle);
844 return;
845 }
846
753 if (GNUNET_NO == ego_exists) 847 if (GNUNET_NO == ego_exists)
754 { 848 {
755 resp = GNUNET_REST_create_response (NULL); 849 resp = GNUNET_REST_create_response (NULL);
756 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND); 850 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
757 cleanup_handle (handle); 851 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
758 return; 852 return;
759 } 853 }
854 handle->response_code = MHD_HTTP_NO_CONTENT;
760 handle->op = GNUNET_IDENTITY_delete (handle->identity_handle, 855 handle->op = GNUNET_IDENTITY_delete (handle->identity_handle,
761 ego_entry->identifier, 856 ego_entry->identifier, &do_finished,
762 &do_finished, 857 handle);
763 handle);
764 858
765} 859}
766 860
767
768/** 861/**
769 * Respond to OPTIONS request 862 * Respond to OPTIONS request
770 * 863 *
@@ -773,20 +866,17 @@ ego_delete_cont (struct GNUNET_REST_RequestHandle *con_handle,
773 * @param cls the RequestHandle 866 * @param cls the RequestHandle
774 */ 867 */
775static void 868static void
776options_cont (struct GNUNET_REST_RequestHandle *con_handle, 869options_cont (struct GNUNET_REST_RequestHandle *con_handle, const char* url,
777 const char* url, 870 void *cls)
778 void *cls)
779{ 871{
780 struct MHD_Response *resp; 872 struct MHD_Response *resp;
781 struct RequestHandle *handle = cls; 873 struct RequestHandle *handle = cls;
782 874
783 //For now, independent of path return all options 875 //For now, independent of path return all options
784 resp = GNUNET_REST_create_response (NULL); 876 resp = GNUNET_REST_create_response (NULL);
785 MHD_add_response_header (resp, 877 MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods);
786 "Access-Control-Allow-Methods",
787 allow_methods);
788 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); 878 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
789 cleanup_handle (handle); 879 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
790 return; 880 return;
791} 881}
792 882
@@ -800,18 +890,17 @@ init_cont (struct RequestHandle *handle)
800{ 890{
801 struct GNUNET_REST_RequestHandlerError err; 891 struct GNUNET_REST_RequestHandlerError err;
802 static const struct GNUNET_REST_RequestHandler handlers[] = { 892 static const struct GNUNET_REST_RequestHandler handlers[] = {
803 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY, &ego_info_response}, 893 { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY, &ego_get },
804 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY, &ego_create_cont}, 894 { MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_IDENTITY, &ego_edit },
805 {MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_IDENTITY, &ego_edit_cont}, 895 { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY, &ego_create },
806 {MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_IDENTITY, &ego_delete_cont}, 896 { MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_IDENTITY, &ego_delete },
807 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY, &options_cont}, 897 { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY, &options_cont },
808 GNUNET_REST_HANDLER_END 898 GNUNET_REST_HANDLER_END
809 }; 899 };
810 900
811 if (GNUNET_NO == GNUNET_JSONAPI_handle_request (handle->conndata_handle, 901 if (GNUNET_NO
812 handlers, 902 == GNUNET_REST_handle_request (handle->rest_handle, handlers, &err,
813 &err, 903 handle))
814 handle))
815 { 904 {
816 handle->response_code = err.error_code; 905 handle->response_code = err.error_code;
817 GNUNET_SCHEDULER_add_now (&do_error, handle); 906 GNUNET_SCHEDULER_add_now (&do_error, handle);
@@ -852,10 +941,8 @@ init_cont (struct RequestHandle *handle)
852 * must thus no longer be used 941 * must thus no longer be used
853 */ 942 */
854static void 943static void
855list_ego (void *cls, 944init_egos (void *cls, struct GNUNET_IDENTITY_Ego *ego, void **ctx,
856 struct GNUNET_IDENTITY_Ego *ego, 945 const char *identifier)
857 void **ctx,
858 const char *identifier)
859{ 946{
860 struct RequestHandle *handle = cls; 947 struct RequestHandle *handle = cls;
861 struct EgoEntry *ego_entry; 948 struct EgoEntry *ego_entry;
@@ -867,16 +954,16 @@ list_ego (void *cls,
867 init_cont (handle); 954 init_cont (handle);
868 return; 955 return;
869 } 956 }
870 if (ID_REST_STATE_INIT == handle->state) { 957 if (ID_REST_STATE_INIT == handle->state)
871 ego_entry = GNUNET_new (struct EgoEntry); 958 {
959 ego_entry = GNUNET_new(struct EgoEntry);
872 GNUNET_IDENTITY_ego_get_public_key (ego, &pk); 960 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
873 ego_entry->keystring = 961 ego_entry->keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
874 GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
875 ego_entry->ego = ego; 962 ego_entry->ego = ego;
876 GNUNET_asprintf (&ego_entry->identifier, "%s", identifier); 963 GNUNET_asprintf (&ego_entry->identifier, "%s", identifier);
877 GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry); 964 GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head, handle->ego_tail,
965 ego_entry);
878 } 966 }
879
880} 967}
881 968
882/** 969/**
@@ -891,39 +978,30 @@ list_ego (void *cls,
891 * @return GNUNET_OK if request accepted 978 * @return GNUNET_OK if request accepted
892 */ 979 */
893static void 980static void
894rest_identity_process_request(struct GNUNET_REST_RequestHandle *conndata_handle, 981rest_process_request (struct GNUNET_REST_RequestHandle *rest_handle,
895 GNUNET_REST_ResultProcessor proc, 982 GNUNET_REST_ResultProcessor proc, void *proc_cls)
896 void *proc_cls)
897{ 983{
898 struct RequestHandle *handle = GNUNET_new (struct RequestHandle); 984 struct RequestHandle *handle = GNUNET_new(struct RequestHandle);
899
900
901 985
986 handle->response_code = 0;
902 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL; 987 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
903
904 handle->proc_cls = proc_cls; 988 handle->proc_cls = proc_cls;
905 handle->proc = proc; 989 handle->proc = proc;
906 handle->state = ID_REST_STATE_INIT; 990 handle->rest_handle = rest_handle;
907 handle->conndata_handle = conndata_handle; 991 handle->data = rest_handle->data;
908 handle->data = conndata_handle->data; 992 handle->data_size = rest_handle->data_size;
909 handle->data_size = conndata_handle->data_size; 993
910 handle->method = conndata_handle->method; 994 handle->url = GNUNET_strdup(rest_handle->url);
911 GNUNET_asprintf (&handle->url, "%s", conndata_handle->url); 995 if (handle->url[strlen (handle->url) - 1] == '/')
912 if (handle->url[strlen (handle->url)-1] == '/') 996 handle->url[strlen (handle->url) - 1] = '\0';
913 handle->url[strlen (handle->url)-1] = '\0'; 997 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n");
914 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 998
915 "Connecting...\n"); 999 handle->identity_handle = GNUNET_IDENTITY_connect (cfg, &init_egos, handle);
916 handle->identity_handle = GNUNET_IDENTITY_connect (cfg, 1000
917 &list_ego, 1001 handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout,
918 handle); 1002 &do_error, handle);
919 handle->timeout_task = 1003
920 GNUNET_SCHEDULER_add_delayed (handle->timeout, 1004 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Connected\n");
921 &do_error,
922 handle);
923
924
925 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
926 "Connected\n");
927} 1005}
928 1006
929/** 1007/**
@@ -940,27 +1018,24 @@ libgnunet_plugin_rest_identity_init (void *cls)
940 1018
941 cfg = cls; 1019 cfg = cls;
942 if (NULL != plugin.cfg) 1020 if (NULL != plugin.cfg)
943 return NULL; /* can only initialize once! */ 1021 return NULL; /* can only initialize once! */
944 memset (&plugin, 0, sizeof (struct Plugin)); 1022 memset (&plugin, 0, sizeof(struct Plugin));
945 plugin.cfg = cfg; 1023 plugin.cfg = cfg;
946 api = GNUNET_new (struct GNUNET_REST_Plugin); 1024 api = GNUNET_new(struct GNUNET_REST_Plugin);
947 api->cls = &plugin; 1025 api->cls = &plugin;
948 api->name = GNUNET_REST_API_NS_IDENTITY; 1026 api->name = GNUNET_REST_API_NS_IDENTITY;
949 api->process_request = &rest_identity_process_request; 1027 api->process_request = &rest_process_request;
950 GNUNET_asprintf (&allow_methods, 1028 GNUNET_asprintf (&allow_methods, "%s, %s, %s, %s, %s",
951 "%s, %s, %s, %s, %s", 1029 MHD_HTTP_METHOD_GET,
952 MHD_HTTP_METHOD_GET, 1030 MHD_HTTP_METHOD_POST,
953 MHD_HTTP_METHOD_POST, 1031 MHD_HTTP_METHOD_PUT,
954 MHD_HTTP_METHOD_PUT, 1032 MHD_HTTP_METHOD_DELETE,
955 MHD_HTTP_METHOD_DELETE, 1033 MHD_HTTP_METHOD_OPTIONS);
956 MHD_HTTP_METHOD_OPTIONS); 1034
957 1035 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, _("Identity REST API initialized\n"));
958 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
959 _("Identity REST API initialized\n"));
960 return api; 1036 return api;
961} 1037}
962 1038
963
964/** 1039/**
965 * Exit point from the plugin. 1040 * Exit point from the plugin.
966 * 1041 *
@@ -972,13 +1047,13 @@ libgnunet_plugin_rest_identity_done (void *cls)
972{ 1047{
973 struct GNUNET_REST_Plugin *api = cls; 1048 struct GNUNET_REST_Plugin *api = cls;
974 struct Plugin *plugin = api->cls; 1049 struct Plugin *plugin = api->cls;
975
976 plugin->cfg = NULL; 1050 plugin->cfg = NULL;
977 GNUNET_free_non_null (allow_methods); 1051
978 GNUNET_free (api); 1052 GNUNET_free_non_null(allow_methods);
979 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1053 GNUNET_free(api);
980 "Identity REST plugin is finished\n"); 1054 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Identity REST plugin is finished\n");
981 return NULL; 1055 return NULL;
982} 1056}
983 1057
984/* end of plugin_rest_gns.c */ 1058/* end of plugin_rest_identity.c */
1059
diff --git a/src/identity/test_plugin_rest_identity.sh b/src/identity/test_plugin_rest_identity.sh
new file mode 100755
index 000000000..d9377500e
--- /dev/null
+++ b/src/identity/test_plugin_rest_identity.sh
@@ -0,0 +1,159 @@
1#!/usr/bin/bash
2
3#First, start gnunet-arm and the rest-service.
4#Exit 0 means success, exit 1 means failed test
5
6identity_link="http://localhost:7776/identity"
7wrong_link="http://localhost:7776/identityandmore"
8
9
10curl_get () {
11 #$1 is link
12 #$2 is grep
13 cache="$(curl -v "$1" 2>&1 | grep "$2")"
14 #echo $cache
15 if [ "" == "$cache" ]
16 then
17 exit 1
18 fi
19}
20
21curl_post () {
22 #$1 is link
23 #$2 is data
24 #$3 is grep
25 cache="$(curl -v -X "POST" "$1" --data "$2" 2>&1 | grep "$3")"
26 #echo $cache
27 if [ "" == "$cache" ]
28 then
29 exit 1
30 fi
31}
32
33curl_delete () {
34 #$1 is link
35 #$2 is grep
36 cache="$(curl -v -X "DELETE" "$1" 2>&1 | grep "$2")"
37 #echo $cache
38 if [ "" == "$cache" ]
39 then
40 exit 1
41 fi
42}
43
44curl_put () {
45 #$1 is link
46 #$2 is data
47 #$3 is grep
48 cache="$(curl -v -X "PUT" "$1" --data "$2" 2>&1 | grep "$3")"
49 #echo $cache
50 if [ "" == "$cache" ]
51 then
52 exit 1
53 fi
54}
55
56#Test GET
57test="$(gnunet-identity -d)"
58#if no identity exists
59if [ "" == "$test" ]
60then
61 curl_get "$identity_link" "error"
62 gnunet-identity -C "test_plugin_rest_identity"
63 name="$(gnunet-identity -d | awk 'NR==1{print $1}')"
64 public="$(gnunet-identity -d | awk 'NR==1{print $3}')"
65
66 curl_get "${identity_link}?name=$name" "$public"
67 curl_get "${identity_link}?name=" "error"
68 curl_get "${identity_link}?name=$public" "error"
69
70 curl_get "${identity_link}?pubkey=$public" "$name"
71 curl_get "${identity_link}?pubkey=$name" "error"
72 curl_get "${identity_link}?pubkey=" "error"
73
74 gnunet-identity -D "test_plugin_rest_identity"
75else
76 name="$(gnunet-identity -d | awk 'NR==1{print $1}')"
77 public="$(gnunet-identity -d | awk 'NR==1{print $3}')"
78
79 curl_get "${identity_link}?name=$name" "$public"
80 curl_get "${identity_link}?name=" "error"
81 curl_get "${identity_link}?name=$public" "error"
82
83 curl_get "${identity_link}?pubkey=$public" "$name"
84 curl_get "${identity_link}?pubkey=$name" "error"
85 curl_get "${identity_link}?pubkey=" "error"
86fi
87
88#Test POST
89gnunet-identity -D "test_plugin_rest_identity" > /dev/null 2>&1
90gnunet-identity -D "test_plugin_rest_identity1" > /dev/null 2>&1
91
92curl_post "${identity_link}" '{"name":"test_plugin_rest_identity"}' "HTTP/1.1 201 Created"
93curl_post "${identity_link}" '{"name":"test_plugin_rest_identity"}' "HTTP/1.1 409"
94curl_post "${identity_link}" '{"name":"Test_plugin_rest_identity"}' "HTTP/1.1 409"
95curl_post "${identity_link}" '{}' "error"
96curl_post "${identity_link}" '' "error"
97curl_post "${identity_link}" '{"name":""}' "error"
98curl_post "${identity_link}" '{"name":123}' "error"
99curl_post "${identity_link}" '{"name":[]}' "error"
100curl_post "${identity_link}" '{"name1":"test_plugin_rest_identity"}' "error"
101curl_post "${identity_link}" '{"other":""}' "error"
102curl_post "${identity_link}" '{"name":"test_plugin_rest_identity1", "other":"test_plugin_rest_identity2"}' "error"
103
104#Test PUT
105name="$(gnunet-identity -d | grep "test_plugin_rest_identity" | awk 'NR==1{print $1}')"
106public="$(gnunet-identity -d | grep "test_plugin_rest_identity" | awk 'NR==1{print $3}')"
107
108curl_put "${identity_link}" '{"newname":"test_plugin_rest_identity1","pubkey":"'$public'"}' "HTTP/1.1 204"
109curl_put "${identity_link}" '{"newname":"test_plugin_rest_identity1","pubkey":"'$public'"}' "HTTP/1.1 409"
110curl_put "${identity_link}" '{"newname":"test_plugin_rest_identity1","pubkey":"'$public'xx"}' "HTTP/1.1 404"
111curl_put "${identity_link}" '{"newname":"test_plugin_rest_identity1","pubkey":""}' "HTTP/1.1 404"
112curl_put "${identity_link}" '{"newname":"test_plugin_rest_identity1","pubke":""}' "HTTP/1.1 404"
113curl_put "${identity_link}" '{"newname":"test_plugin_rest_identity1","pubke":"","other":"sdfdsf"}' "HTTP/1.1 404"
114curl_put "${identity_link}" '{"newname":"test_plugin_rest_identity1","pubke":"","name":"sdfdsf"}' "HTTP/1.1 404"
115curl_put "${identity_link}" '{"newname":"test_plugin_rest_identity","pubke":"","name":"test_plugin_rest_identity1"}' "HTTP/1.1 204"
116curl_put "${identity_link}" '{"newnam":"test_plugin_rest_identity","pubkey":"'$public'"}' "error"
117curl_put "${identity_link}" '{"newname":"test_plugin_rest_identity1","name":"test_plugin_rest_identity"}' "HTTP/1.1 204"
118curl_put "${identity_link}" '{"newname":"TEST_plugin_rest_identity1","name":"test_plugin_rest_identity1"}' "HTTP/1.1 409"
119curl_put "${identity_link}" '{"newname":"test_plugin_rest_identity1","name":"test_plugin_rest_identity1"}' "HTTP/1.1 409"
120curl_put "${identity_link}" '{"newname":"test_plugin_rest_identity","name":"test_plugin_rest_identityxxx"}' "HTTP/1.1 404"
121curl_put "${identity_link}" '{"newname":"test_plugin_rest_identity","name":"test_plugin_rest_identity1"}' "HTTP/1.1 204"
122curl_put "${identity_link}" '{"newnam":"test_plugin_rest_identityfail","name":"test_plugin_rest_identity"}' "error"
123
124
125#Test subsystem
126curl_put "${identity_link}" '{"subsystem":"namestore","name":"test_plugin_rest_identity"}' "HTTP/1.1 204"
127curl_put "${identity_link}" '{"subsystem":"namestore","name":"test_plugin_rest_identity"}' "HTTP/1.1 204"
128curl_get "${identity_link}?subsystem=namestore" "test_plugin_rest_identity"
129curl_post "${identity_link}" '{"name":"test_plugin_rest_identity1"}' "HTTP/1.1 201 Created"
130public="$(gnunet-identity -d | grep "test_plugin_rest_identity" | awk 'NR==1{print $3}')"
131curl_put "${identity_link}" '{"subsystem":"namestore","pubkey":"'"$public"'"}' "HTTP/1.1 204"
132curl_get "${identity_link}?subsystem=namestore" "test_plugin_rest_identity1"
133curl_get "${identity_link}?subsystem=test_plugin_rest_identity_no_subsystem" "error"
134curl_put "${identity_link}" '{"subsystem":"test_plugin_rest_identity_no_subsystem","name":"test_plugin_rest_identity1"}' "HTTP/1.1 204"
135curl_get "${identity_link}?subsystem=test_plugin_rest_identity_no_subsystem" "test_plugin_rest_identity1"
136
137curl_put "${identity_link}" '{"subsyste":"test_plugin_rest_identity_no_subsystem","name":"test_plugin_rest_identity1"}' "error"
138curl_put "${identity_link}" '{"subsystem":"test_plugin_rest_identity_no_subsystem","name":"Test_plugin_rest_identity1"}' "HTTP/1.1 204"
139
140#Test DELETE
141curl_delete "${identity_link}?name=test_plugin_rest_identity" "HTTP/1.1 204"
142curl_get "${identity_link}?name=test_plugin_rest_identity" "error"
143curl_delete "${identity_link}?name=TEST_plugin_rest_identity1" "HTTP/1.1 404"
144curl_delete "${identity_link}?name=test_plugin_rest_identity1" "HTTP/1.1 204"
145curl_get "${identity_link}?name=test_plugin_rest_identity1" "error"
146curl_delete "${identity_link}?name=test_plugin_rest_identity_not_found" "HTTP/1.1 404"
147curl_post "${identity_link}" '{"name":"test_plugin_rest_identity1"}' "HTTP/1.1 201 Created"
148public="$(gnunet-identity -d | grep "test_plugin_rest_identity1" | awk 'NR==1{print $3}')"
149curl_delete "${identity_link}?pubkey=$public" "HTTP/1.1 204"
150curl_delete "${identity_link}?pubke=$public" "error"
151curl_delete "${identity_link}?pubkey=$public&other=232" "HTTP/1.1 404"
152
153#Test wrong_link
154curl_get "$wrong_link" "HTTP/1.1 404"
155curl_post "$wrong_link" '{"name":"test_plugin_rest_identity"}' "HTTP/1.1 404"
156curl_put "$wrong_link" '{"newname":"test_plugin_rest_identity1","name":"test_plugin_rest_identity"}' "HTTP/1.1 404"
157curl_delete "$wrong_link?name=test_plugin_rest_identity1" "HTTP/1.1 404"
158
159exit 0;
diff --git a/src/include/gnunet_json_lib.h b/src/include/gnunet_json_lib.h
index 06749590c..781d5698b 100644
--- a/src/include/gnunet_json_lib.h
+++ b/src/include/gnunet_json_lib.h
@@ -26,6 +26,7 @@
26#define GNUNET_JSON_LIB_H 26#define GNUNET_JSON_LIB_H
27 27
28#include "gnunet_util_lib.h" 28#include "gnunet_util_lib.h"
29#include "gnunet_gnsrecord_lib.h"
29#include <jansson.h> 30#include <jansson.h>
30 31
31 32
@@ -318,6 +319,17 @@ GNUNET_JSON_spec_rsa_signature (const char *name,
318 struct GNUNET_CRYPTO_RsaSignature **sig); 319 struct GNUNET_CRYPTO_RsaSignature **sig);
319 320
320 321
322
323/**
324 * JSON Specification for GNS Records.
325 *
326 * @param gnsrecord_object struct of GNUNET_GNSRECORD_Data to fill
327 * @return JSON Specification
328 */
329struct GNUNET_JSON_Specification
330GNUNET_JSON_spec_gnsrecord_data (struct GNUNET_GNSRECORD_Data **gnsrecord_object);
331
332
321/* ****************** Generic generator interface ******************* */ 333/* ****************** Generic generator interface ******************* */
322 334
323 335
@@ -393,6 +405,16 @@ GNUNET_JSON_from_rsa_public_key (const struct GNUNET_CRYPTO_RsaPublicKey *pk);
393json_t * 405json_t *
394GNUNET_JSON_from_rsa_signature (const struct GNUNET_CRYPTO_RsaSignature *sig); 406GNUNET_JSON_from_rsa_signature (const struct GNUNET_CRYPTO_RsaSignature *sig);
395 407
408/**
409 * Convert Gns record to JSON.
410 *
411 * @param rname name of record
412 * @param rd record data
413 * @return corresponding JSON encoding
414 */
415json_t *
416GNUNET_JSON_from_gns_record (const char* rname,
417 const struct GNUNET_GNSRECORD_Data *rd);
396 418
397/* ******************* Helpers for MHD upload handling ******************* */ 419/* ******************* Helpers for MHD upload handling ******************* */
398 420
@@ -479,7 +501,6 @@ GNUNET_JSON_getopt (char shortName,
479 const char *description, 501 const char *description,
480 json_t **json); 502 json_t **json);
481 503
482
483#endif 504#endif
484 505
485/* end of gnunet_json_lib.h */ 506/* end of gnunet_json_lib.h */
diff --git a/src/json/Makefile.am b/src/json/Makefile.am
index da19e7955..f3fa28d69 100644
--- a/src/json/Makefile.am
+++ b/src/json/Makefile.am
@@ -16,9 +16,11 @@ libgnunetjson_la_SOURCES = \
16 json.c \ 16 json.c \
17 json_mhd.c \ 17 json_mhd.c \
18 json_generator.c \ 18 json_generator.c \
19 json_helper.c 19 json_helper.c \
20 json_gnsrecord.c
20libgnunetjson_la_LIBADD = \ 21libgnunetjson_la_LIBADD = \
21 $(top_builddir)/src/util/libgnunetutil.la \ 22 $(top_builddir)/src/util/libgnunetutil.la \
23 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
22 -ljansson \ 24 -ljansson \
23 $(XLIB) 25 $(XLIB)
24 26
diff --git a/src/json/json_generator.c b/src/json/json_generator.c
index dd6df4f74..d8c82bc86 100644
--- a/src/json/json_generator.c
+++ b/src/json/json_generator.c
@@ -157,5 +157,40 @@ GNUNET_JSON_from_rsa_signature (const struct GNUNET_CRYPTO_RsaSignature *sig)
157 return ret; 157 return ret;
158} 158}
159 159
160/**
161 * Convert Gns record to JSON.
162 *
163 * @param rname name of record
164 * @param rd record data
165 * @return corresponding JSON encoding
166 */
167json_t *
168GNUNET_JSON_from_gns_record (const char* rname,
169 const struct GNUNET_GNSRECORD_Data *rd)
170{
171 struct GNUNET_TIME_Absolute expiration_time;
172 const char *expiration_time_str;
173 const char *record_type_str;
174 char *value_str;
175 json_t *ret;
176 int flags;
177
178 value_str = GNUNET_GNSRECORD_value_to_string(rd->record_type,rd->data,rd->data_size);
179 expiration_time = GNUNET_GNSRECORD_record_get_expiration_time(1, rd);
180 expiration_time_str = GNUNET_STRINGS_absolute_time_to_string(expiration_time);
181 flags = (int)rd->flags; //maybe necessary
182 record_type_str = GNUNET_GNSRECORD_number_to_typename(rd->record_type);
183
184 // ? for possible NULL values
185 ret = json_pack("{s:s?,s:s?,s:s?,s:i,s:s?}",
186 "value", value_str,
187 "type", record_type_str,
188 "expiration_time", expiration_time_str,
189 "flag", flags,
190 "label", rname);
191 GNUNET_free_non_null(value_str);
192 return ret;
193}
194
160 195
161/* End of json/json_generator.c */ 196/* End of json/json_generator.c */
diff --git a/src/json/json_gnsrecord.c b/src/json/json_gnsrecord.c
new file mode 100644
index 000000000..7bdf97f06
--- /dev/null
+++ b/src/json/json_gnsrecord.c
@@ -0,0 +1,177 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009-2013 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
19/**
20 * @file json/json_gnsrecord.c
21 * @brief JSON handling of GNS record data
22 * @author Philippe Buschmann
23 */
24#include "platform.h"
25#include "gnunet_util_lib.h"
26#include "gnunet_json_lib.h"
27
28#define GNUNET_JSON_GNSRECORD_VALUE "value"
29#define GNUNET_JSON_GNSRECORD_TYPE "type"
30#define GNUNET_JSON_GNSRECORD_EXPIRATION_TIME "expiration_time"
31#define GNUNET_JSON_GNSRECORD_FLAG "flag"
32#define GNUNET_JSON_GNSRECORD_LABEL "label"
33#define GNUNET_JSON_GNSRECORD_NEVER "never"
34
35
36/**
37 * Parse given JSON object to gns record
38 *
39 * @param cls closure, NULL
40 * @param root the json object representing data
41 * @param spec where to write the data
42 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
43 */
44static int
45parse_gnsrecordobject (void *cls,
46 json_t *root,
47 struct GNUNET_JSON_Specification *spec)
48{
49 struct GNUNET_GNSRECORD_Data *gnsrecord_object;
50 struct GNUNET_TIME_Absolute abs_expiration_time;
51 int unpack_state=0;
52 const char *value;
53 const char *expiration_time;
54 const char *record_type;
55 const char *label;
56 int flag;
57 void *rdata = NULL;
58 size_t rdata_size;
59
60 GNUNET_assert(NULL != root);
61 if(!json_is_object(root))
62 {
63 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
64 "Error json is not array nor object!\n");
65 return GNUNET_SYSERR;
66 }
67 //interpret single gns record
68 unpack_state = json_unpack(root,
69 "{s:s, s:s, s:s, s?:i, s:s!}",
70 GNUNET_JSON_GNSRECORD_VALUE, &value,
71 GNUNET_JSON_GNSRECORD_TYPE, &record_type,
72 GNUNET_JSON_GNSRECORD_EXPIRATION_TIME, &expiration_time,
73 GNUNET_JSON_GNSRECORD_FLAG, &flag,
74 GNUNET_JSON_GNSRECORD_LABEL, &label);
75 if (0 != unpack_state)
76 {
77 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
78 "Error json object has a wrong format!\n");
79 return GNUNET_SYSERR;
80 }
81 gnsrecord_object = GNUNET_new (struct GNUNET_GNSRECORD_Data);
82 gnsrecord_object->record_type = GNUNET_GNSRECORD_typename_to_number(record_type);
83 if (UINT32_MAX == gnsrecord_object->record_type)
84 {
85 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,"Unsupported type\n");
86 GNUNET_free(gnsrecord_object);
87 return GNUNET_SYSERR;
88 }
89 if (GNUNET_OK
90 != GNUNET_GNSRECORD_string_to_value (gnsrecord_object->record_type,
91 value,
92 &rdata,
93 &rdata_size))
94 {
95 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,"Value invalid for record type\n");
96 GNUNET_free(gnsrecord_object);
97 return GNUNET_SYSERR;
98 }
99
100 gnsrecord_object->data = rdata;
101 gnsrecord_object->data_size = rdata_size;
102
103 if (0 == strcmp (expiration_time, GNUNET_JSON_GNSRECORD_NEVER))
104 {
105 gnsrecord_object->expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
106 }
107 else if (GNUNET_OK
108 == GNUNET_STRINGS_fancy_time_to_absolute (expiration_time,
109 &abs_expiration_time))
110 {
111 gnsrecord_object->expiration_time = abs_expiration_time.abs_value_us;
112 }
113 else
114 {
115 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Expiration time invalid\n");
116 GNUNET_free_non_null(rdata);
117 GNUNET_free(gnsrecord_object);
118 return GNUNET_SYSERR;
119 }
120 // check if flag is a valid enum value
121 if ((GNUNET_GNSRECORD_RF_NONE != flag)
122 && (GNUNET_GNSRECORD_RF_PRIVATE != flag)
123 && (GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION != flag)
124 && (GNUNET_GNSRECORD_RF_SHADOW_RECORD) != flag)
125 {
126 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Flag invalid\n");
127 GNUNET_free_non_null(rdata);
128 GNUNET_free(gnsrecord_object);
129 return GNUNET_SYSERR;
130 }
131 gnsrecord_object->flags = (enum GNUNET_GNSRECORD_Flags)flag;
132 *(struct GNUNET_GNSRECORD_Data **) spec->ptr = gnsrecord_object;
133 return GNUNET_OK;
134}
135
136/**
137 * Cleanup data left from parsing RSA public key.
138 *
139 * @param cls closure, NULL
140 * @param[out] spec where to free the data
141 */
142static void
143clean_gnsrecordobject (void *cls, struct GNUNET_JSON_Specification *spec)
144{
145 struct GNUNET_GNSRECORD_Data **gnsrecord_object;
146 gnsrecord_object = (struct GNUNET_GNSRECORD_Data **) spec->ptr;
147 if (NULL != *gnsrecord_object)
148 {
149 if (NULL != (*gnsrecord_object)->data)
150 GNUNET_free((char*)(*gnsrecord_object)->data);
151
152 GNUNET_free(*gnsrecord_object);
153 *gnsrecord_object = NULL;
154 }
155}
156
157/**
158 * JSON Specification for GNS Records.
159 *
160 * @param gnsrecord_object struct of GNUNET_GNSRECORD_Data to fill
161 * @return JSON Specification
162 */
163struct GNUNET_JSON_Specification
164GNUNET_JSON_spec_gnsrecord_data (struct GNUNET_GNSRECORD_Data **gnsrecord_object)
165{
166 struct GNUNET_JSON_Specification ret = {
167 .parser = &parse_gnsrecordobject,
168 .cleaner = &clean_gnsrecordobject,
169 .cls = NULL,
170 .field = NULL,
171 .ptr = gnsrecord_object,
172 .ptr_size = 0,
173 .size_ptr = NULL
174 };
175 *gnsrecord_object = NULL;
176 return ret;
177}
diff --git a/src/namestore/Makefile.am b/src/namestore/Makefile.am
index 777e722c2..7f44c2a71 100644
--- a/src/namestore/Makefile.am
+++ b/src/namestore/Makefile.am
@@ -230,8 +230,8 @@ libgnunet_plugin_rest_namestore_la_LIBADD = \
230 libgnunetnamestore.la \ 230 libgnunetnamestore.la \
231 $(top_builddir)/src/rest/libgnunetrest.la \ 231 $(top_builddir)/src/rest/libgnunetrest.la \
232 $(top_builddir)/src/identity/libgnunetidentity.la \ 232 $(top_builddir)/src/identity/libgnunetidentity.la \
233 $(top_builddir)/src/jsonapi/libgnunetjsonapi.la \ 233 $(top_builddir)/src/json/libgnunetjson.la \
234 $(top_builddir)/src/jsonapi/libgnunetjsonapiutils.la \ 234 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
235 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \ 235 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \
236 $(LTLIBINTL) -ljansson -lmicrohttpd 236 $(LTLIBINTL) -ljansson -lmicrohttpd
237libgnunet_plugin_rest_namestore_la_LDFLAGS = \ 237libgnunet_plugin_rest_namestore_la_LDFLAGS = \
diff --git a/src/namestore/plugin_rest_namestore.c b/src/namestore/plugin_rest_namestore.c
index ec44046e0..f14707cce 100644
--- a/src/namestore/plugin_rest_namestore.c
+++ b/src/namestore/plugin_rest_namestore.c
@@ -11,15 +11,15 @@
11 WITHOUT ANY WARRANTY; without even the implied warranty of 11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details. 13 Affero General Public License for more details.
14 14
15 You should have received a copy of the GNU Affero General Public License 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/>. 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */ 17 */
18/** 18/**
19 * @author Martin Schanzenbach 19 * @author Martin Schanzenbach
20 * @author Philippe Buschmann
20 * @file namestore/plugin_rest_namestore.c 21 * @file namestore/plugin_rest_namestore.c
21 * @brief GNUnet Namestore REST plugin 22 * @brief GNUnet Namestore REST plugin
22 *
23 */ 23 */
24 24
25#include "platform.h" 25#include "platform.h"
@@ -28,38 +28,45 @@
28#include "gnunet_namestore_service.h" 28#include "gnunet_namestore_service.h"
29#include "gnunet_identity_service.h" 29#include "gnunet_identity_service.h"
30#include "gnunet_rest_lib.h" 30#include "gnunet_rest_lib.h"
31#include "gnunet_jsonapi_lib.h" 31#include "gnunet_json_lib.h"
32#include "gnunet_jsonapi_util.h"
33#include "microhttpd.h" 32#include "microhttpd.h"
34#include <jansson.h> 33#include <jansson.h>
35 34
36#define GNUNET_REST_API_NS_NAMESTORE "/names"
37
38#define GNUNET_REST_API_NS_NAMESTORE_ZKEY "/names/zkey"
39
40#define GNUNET_REST_JSONAPI_NAMESTORE_TYPEINFO "record"
41
42#define GNUNET_REST_JSONAPI_NAMESTORE_NAME "name"
43
44#define GNUNET_REST_JSONAPI_NAMESTORE_REVINFO "revinfo"
45 35
46#define GNUNET_REST_JSONAPI_NAMESTORE_RECORD GNUNET_REST_JSONAPI_NAMESTORE_TYPEINFO 36#define GNUNET_REST_API_NS_NAMESTORE "/namestore"
37#define GNUNET_REST_SUBSYSTEM_NAMESTORE "namestore"
47 38
48#define GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE "record_type" 39/**
49 40 * Parameter names
50#define GNUNET_REST_JSONAPI_NAMESTORE_VALUE "value" 41 */
51 42#define GNUNET_REST_API_PARAM_PUBKEY "pubkey"
52#define GNUNET_REST_JSONAPI_NAMESTORE_PUBLIC "public" 43#define GNUNET_REST_API_PARAM_NAME "name"
53 44
54#define GNUNET_REST_JSONAPI_NAMESTORE_SHADOW "shadow" 45/**
46 * Error messages
47 */
48#define GNUNET_REST_NAMESTORE_ERROR_UNKNOWN "Unknown Error"
55 49
56#define GNUNET_REST_JSONAPI_NAMESTORE_PKEY "pkey" 50#define GNUNET_REST_NAMESTORE_RD_COUNT 1
57 51
58#define GNUNET_REST_JSONAPI_NAMESTORE_ZKEY "zkey" 52/**
53 * State while collecting all egos
54 */
55#define ID_REST_STATE_INIT 0
59 56
60#define GNUNET_REST_JSONAPI_NAMESTORE_EXPIRATION "expiration" 57/**
58 * Done collecting egos
59 */
60#define ID_REST_STATE_POST_INIT 1
61/**
62 * The configuration handle
63 */
64const struct GNUNET_CONFIGURATION_Handle *cfg;
61 65
62#define GNUNET_REST_JSONAPI_NAMESTORE_EGO "ego" 66/**
67 * HTTP methods allows for this plugin
68 */
69static char* allow_methods;
63 70
64/** 71/**
65 * @brief struct returned by the initialization function of the plugin 72 * @brief struct returned by the initialization function of the plugin
@@ -69,135 +76,110 @@ struct Plugin
69 const struct GNUNET_CONFIGURATION_Handle *cfg; 76 const struct GNUNET_CONFIGURATION_Handle *cfg;
70}; 77};
71 78
72
73/** 79/**
74 * HTTP methods allows for this plugin 80 * The default namestore ego
75 */ 81 */
76static char* allow_methods; 82struct EgoEntry
77
78const struct GNUNET_CONFIGURATION_Handle *cfg;
79
80struct RecordEntry
81{ 83{
82 /** 84 /**
83 * DLL 85 * DLL
84 */ 86 */
85 struct RecordEntry *next; 87 struct EgoEntry *next;
86 88
87 /** 89 /**
88 * DLL 90 * DLL
89 */ 91 */
90 struct RecordEntry *prev; 92 struct EgoEntry *prev;
91
92};
93
94struct RequestHandle
95{
96 /**
97 * Ego list
98 */
99 struct RecordEntry *record_head;
100
101 /**
102 * Ego list
103 */
104 struct record_entry *record_tail;
105 93
106 /** 94 /**
107 * JSON response object 95 * Ego Identifier
108 */ 96 */
109 struct GNUNET_JSONAPI_Document *resp_object; 97 char *identifier;
110 98
111 /** 99 /**
112 * Rest connection 100 * Public key string
113 */ 101 */
114 struct GNUNET_REST_RequestHandle *rest_handle; 102 char *keystring;
115 103
116 /** 104 /**
117 * Handle to GNS service. 105 * The Ego
118 */
119 struct GNUNET_IDENTITY_Handle *identity_handle;
120
121 /**
122 * Handle to NAMESTORE
123 */ 106 */
124 struct GNUNET_NAMESTORE_Handle *ns_handle; 107 struct GNUNET_IDENTITY_Ego *ego;
108};
125 109
126 /**
127 * Handle to NAMESTORE it
128 */
129 struct GNUNET_NAMESTORE_ZoneIterator *list_it;
130 110
111struct RequestHandle
112{
131 /** 113 /**
132 * Private key for the zone 114 * Records to store
133 */ 115 */
134 struct GNUNET_CRYPTO_EcdsaPrivateKey zone_pkey; 116 char *label_name;
135 117
136 /** 118 /**
137 * Handle to identity lookup 119 * Records to store
138 */ 120 */
139 struct GNUNET_IDENTITY_EgoLookup *ego_lookup; 121 struct GNUNET_GNSRECORD_Data *rd;
140 122
141 /** 123 /**
142 * Default Ego operation 124 * NAMESTORE Operation
143 */ 125 */
144 struct GNUNET_IDENTITY_Operation *get_default; 126 struct GNUNET_NAMESTORE_QueueEntry *add_qe;
145 127
146 /** 128 /**
147 * Name of the ego 129 * Response object
148 */ 130 */
149 char *ego_name; 131 json_t *resp_object;
150 132
151 /** 133 /**
152 * Record is public 134 * The processing state
153 */ 135 */
154 int is_public; 136 int state;
155 137
156 /** 138 /**
157 * Shadow record 139 * Handle to NAMESTORE
158 */ 140 */
159 int is_shadow; 141 struct GNUNET_NAMESTORE_Handle *ns_handle;
160 142
161 /** 143 /**
162 * Name of the record to modify 144 * Handle to NAMESTORE it
163 */ 145 */
164 char *name; 146 struct GNUNET_NAMESTORE_ZoneIterator *list_it;
165 147
166 /** 148 /**
167 * Value of the record 149 * Private key for the zone
168 */ 150 */
169 char *value; 151 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_pkey;
170 152
171 /** 153 /**
172 * Zkey string 154 * IDENTITY Operation
173 */ 155 */
174 const char* zkey_str; 156 struct EgoEntry *ego_entry;
175 157
176 /** 158 /**
177 * record type 159 * Ego list
178 */ 160 */
179 uint32_t type; 161 struct EgoEntry *ego_head;
180 162
181 /** 163 /**
182 * Records to store 164 * Ego list
183 */ 165 */
184 struct GNUNET_GNSRECORD_Data *rd; 166 struct EgoEntry *ego_tail;
185 167
186 /** 168 /**
187 * record count 169 * IDENTITY Operation
188 */ 170 */
189 unsigned int rd_count; 171 struct GNUNET_IDENTITY_Operation *op;
190 172
191 /** 173 /**
192 * NAMESTORE Operation 174 * Handle to Identity service.
193 */ 175 */
194 struct GNUNET_NAMESTORE_QueueEntry *add_qe; 176 struct GNUNET_IDENTITY_Handle *identity_handle;
195 177
196 /** 178 /**
197 * NAMESTORE Operation 179 * Rest connection
198 */ 180 */
199 struct GNUNET_NAMESTORE_QueueEntry *reverse_qe; 181 struct GNUNET_REST_RequestHandle *rest_handle;
200 182
201 /** 183 /**
202 * Desired timeout for the lookup (default is no timeout). 184 * Desired timeout for the lookup (default is no timeout).
203 */ 185 */
@@ -206,7 +188,7 @@ struct RequestHandle
206 /** 188 /**
207 * ID of a task associated with the resolution process. 189 * ID of a task associated with the resolution process.
208 */ 190 */
209 struct GNUNET_SCHEDULER_Task * timeout_task; 191 struct GNUNET_SCHEDULER_Task *timeout_task;
210 192
211 /** 193 /**
212 * The plugin result processor 194 * The plugin result processor
@@ -224,164 +206,201 @@ struct RequestHandle
224 char *url; 206 char *url;
225 207
226 /** 208 /**
227 * Cfg 209 * Error response message
228 */ 210 */
229 const struct GNUNET_CONFIGURATION_Handle *cfg; 211 char *emsg;
230 212
231 /** 213 /**
232 * HTTP response code 214 * Reponse code
233 */ 215 */
234 int response_code; 216 int response_code;
235 217
236}; 218};
237 219
238
239/** 220/**
240 * Cleanup lookup handle 221 * Cleanup lookup handle
241 *
242 * @param handle Handle to clean up 222 * @param handle Handle to clean up
243 */ 223 */
244static void 224static void
245cleanup_handle (struct RequestHandle *handle) 225cleanup_handle (void *cls)
246{ 226{
247 struct RecordEntry *record_entry; 227 struct RequestHandle *handle = cls;
248 struct RecordEntry *record_tmp; 228 struct EgoEntry *ego_entry;
229 struct EgoEntry *ego_tmp;
249 230
250 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 231 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
251 "Cleaning up\n"); 232 "Cleaning up\n");
252 if (NULL != handle->resp_object)
253 GNUNET_JSONAPI_document_delete (handle->resp_object);
254 if (NULL != handle->name)
255 GNUNET_free (handle->name);
256 if (NULL != handle->timeout_task) 233 if (NULL != handle->timeout_task)
234 {
257 GNUNET_SCHEDULER_cancel (handle->timeout_task); 235 GNUNET_SCHEDULER_cancel (handle->timeout_task);
258 if (NULL != handle->ego_lookup) 236 handle->timeout_task = NULL;
259 GNUNET_IDENTITY_ego_lookup_cancel (handle->ego_lookup); 237 }
260 if (NULL != handle->get_default) 238 if (NULL != handle->label_name)
261 GNUNET_IDENTITY_cancel (handle->get_default); 239 GNUNET_free(handle->label_name);
240 if (NULL != handle->url)
241 GNUNET_free(handle->url);
242 if (NULL != handle->emsg)
243 GNUNET_free(handle->emsg);
244 if (NULL != handle->rd)
245 {
246 if (NULL != handle->rd->data)
247 GNUNET_free((void*)handle->rd->data);
248 GNUNET_free(handle->rd);
249 }
250 if (NULL != handle->timeout_task)
251 GNUNET_SCHEDULER_cancel(handle->timeout_task);
262 if (NULL != handle->list_it) 252 if (NULL != handle->list_it)
263 GNUNET_NAMESTORE_zone_iteration_stop (handle->list_it); 253 GNUNET_NAMESTORE_zone_iteration_stop(handle->list_it);
264 if (NULL != handle->add_qe) 254 if (NULL != handle->add_qe)
265 GNUNET_NAMESTORE_cancel (handle->add_qe); 255 GNUNET_NAMESTORE_cancel(handle->add_qe);
266 if (NULL != handle->identity_handle) 256 if (NULL != handle->identity_handle)
267 GNUNET_IDENTITY_disconnect (handle->identity_handle); 257 GNUNET_IDENTITY_disconnect(handle->identity_handle);
268 if (NULL != handle->ns_handle) 258 if (NULL != handle->ns_handle)
269 GNUNET_NAMESTORE_disconnect (handle->ns_handle);
270 if (NULL != handle->url)
271 GNUNET_free (handle->url);
272 if (NULL != handle->value)
273 GNUNET_free (handle->value);
274 if (NULL != handle->rd)
275 { 259 {
276 for (unsigned int i = 0; i < handle->rd_count; i++) 260 GNUNET_NAMESTORE_disconnect(handle->ns_handle);
277 {
278 if (NULL != handle->rd[i].data)
279 GNUNET_free ((void*)handle->rd[i].data);
280 }
281 GNUNET_free (handle->rd);
282 } 261 }
283 if (NULL != handle->ego_name) 262
284 GNUNET_free (handle->ego_name); 263 for (ego_entry = handle->ego_head;
285 for (record_entry = handle->record_head; 264 NULL != ego_entry;)
286 NULL != record_entry;)
287 { 265 {
288 record_tmp = record_entry; 266 ego_tmp = ego_entry;
289 record_entry = record_entry->next; 267 ego_entry = ego_entry->next;
290 GNUNET_free (record_tmp); 268 GNUNET_free(ego_tmp->identifier);
269 GNUNET_free(ego_tmp->keystring);
270 GNUNET_free(ego_tmp);
291 } 271 }
272
273 if(NULL != handle->resp_object)
274 {
275 json_decref(handle->resp_object);
276 }
277
292 GNUNET_free (handle); 278 GNUNET_free (handle);
293} 279}
294 280
295 281
296/** 282/**
297 * Create json representation of a GNSRECORD 283 * Task run on errors. Reports an error and cleans up everything.
298 * 284 *
299 * @param rd the GNSRECORD_Data 285 * @param cls the `struct RequestHandle`
300 */ 286 */
301static json_t * 287static void
302gnsrecord_to_json (const struct GNUNET_GNSRECORD_Data *rd) 288do_error (void *cls)
303{ 289{
304 const char *typename; 290 struct RequestHandle *handle = cls;
305 char *string_val; 291 struct MHD_Response *resp;
306 const char *exp_str; 292 json_t *json_error = json_object();
307 json_t *record_obj; 293 char *response;
308 294
309 typename = GNUNET_GNSRECORD_number_to_typename (rd->record_type); 295 if (NULL == handle->emsg)
310 string_val = GNUNET_GNSRECORD_value_to_string (rd->record_type, 296 handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_ERROR_UNKNOWN);
311 rd->data,
312 rd->data_size);
313 297
314 if (NULL == string_val) 298 json_object_set_new(json_error,"error", json_string(handle->emsg));
315 { 299
316 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 300 if (0 == handle->response_code)
317 "Record of type %d malformed, skipping\n", 301 handle->response_code = MHD_HTTP_OK;
318 (int) rd->record_type); 302 response = json_dumps (json_error, 0);
319 return NULL; 303 resp = GNUNET_REST_create_response (response);
320 } 304 handle->proc (handle->proc_cls, resp, handle->response_code);
321 record_obj = json_object(); 305 json_decref(json_error);
322 json_object_set_new (record_obj, 306 GNUNET_free(response);
323 GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE, 307 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
324 json_string (typename)); 308}
325 json_object_set_new (record_obj, 309
326 GNUNET_REST_JSONAPI_NAMESTORE_VALUE, 310
327 json_string (string_val)); 311/**
328 GNUNET_free (string_val); 312 * Get EgoEntry from list with either a public key or a name
329 313 * If public key and name are not NULL, it returns the public key result first
330 if (GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION & rd->flags) 314 *
315 * @param handle the RequestHandle
316 * @param pubkey the public key of an identity (only one can be NULL)
317 * @param name the name of an identity (only one can be NULL)
318 * @return EgoEntry or NULL if not found
319 */
320struct EgoEntry*
321get_egoentry(struct RequestHandle *handle, char* pubkey, char *name)
322{
323 struct EgoEntry *ego_entry;
324 if (NULL != pubkey)
331 { 325 {
332 struct GNUNET_TIME_Relative time_rel; 326 for (ego_entry = handle->ego_head;
333 time_rel.rel_value_us = rd->expiration_time; 327 NULL != ego_entry;
334 exp_str = GNUNET_STRINGS_relative_time_to_string (time_rel, 1); 328 ego_entry = ego_entry->next)
329 {
330 if (0 != strcasecmp (pubkey, ego_entry->keystring))
331 continue;
332 return ego_entry;
333 }
335 } 334 }
336 else 335 if (NULL != name)
337 { 336 {
338 struct GNUNET_TIME_Absolute time_abs; 337 for (ego_entry = handle->ego_head;
339 time_abs.abs_value_us = rd->expiration_time; 338 NULL != ego_entry;
340 exp_str = GNUNET_STRINGS_absolute_time_to_string (time_abs); 339 ego_entry = ego_entry->next)
340 {
341 if (0 != strcasecmp (name, ego_entry->identifier))
342 continue;
343 return ego_entry;
344 }
341 } 345 }
342 json_object_set_new (record_obj, GNUNET_REST_JSONAPI_NAMESTORE_EXPIRATION, json_string (exp_str)); 346 return NULL;
343
344 json_object_set_new (record_obj, "expired",
345 json_boolean (GNUNET_YES == GNUNET_GNSRECORD_is_expired (rd)));
346 return record_obj;
347} 347}
348 348
349 349
350/** 350/**
351 * Task run on error. Generates error response and cleans up. 351 * Does internal server error when iteration failed.
352 *
353 * @param cls the request to generate an error response for
354 */ 352 */
355static void 353static void
356do_error (void *cls) 354namestore_iteration_error (void *cls)
357{ 355{
358 struct RequestHandle *handle = cls; 356 struct RequestHandle *handle = cls;
359 struct MHD_Response *resp = GNUNET_REST_create_response (NULL); 357 struct MHD_Response *resp = GNUNET_REST_create_response (NULL);
360 358 handle->proc (handle->proc_cls, resp, MHD_HTTP_INTERNAL_SERVER_ERROR);
361 handle->proc (handle->proc_cls, resp, handle->response_code); 359 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
362 cleanup_handle (handle);
363} 360}
364 361
365 362
366/**
367 * Task run on timeout.
368 *
369 * @param cls the request to time out
370 */
371static void 363static void
372do_timeout (void *cls) 364create_finished (void *cls, int32_t success, const char *emsg)
373{ 365{
374 struct RequestHandle *handle = cls; 366 struct RequestHandle *handle = cls;
367 struct MHD_Response *resp;
375 368
376 handle->timeout_task = NULL; 369 handle->add_qe = NULL;
377 do_error (handle); 370 if (GNUNET_YES != success)
371 {
372 handle->emsg = GNUNET_strdup("Error storing records");
373 GNUNET_SCHEDULER_add_now (&do_error, handle);
374 return;
375 }
376 resp = GNUNET_REST_create_response (NULL);
377 handle->proc (handle->proc_cls, resp, MHD_HTTP_NO_CONTENT);
378 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
378} 379}
379 380
380 381
381static void 382static void
382cleanup_handle_delayed (void *cls) 383del_finished (void *cls, int32_t success, const char *emsg)
383{ 384{
384 cleanup_handle (cls); 385 struct RequestHandle *handle = cls;
386
387 handle->add_qe = NULL;
388 if (GNUNET_NO == success)
389 {
390 handle->emsg = GNUNET_strdup("Deleting record failed. Record does not exist");
391 GNUNET_SCHEDULER_add_now (&do_error, handle);
392 return;
393 }
394 if (GNUNET_SYSERR == success)
395 {
396 handle->emsg = GNUNET_strdup("Deleting record failed");
397 GNUNET_SCHEDULER_add_now (&do_error, handle);
398 return;
399 }
400 handle->proc (handle->proc_cls,
401 GNUNET_REST_create_response (NULL),
402 MHD_HTTP_NO_CONTENT);
403 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
385} 404}
386 405
387 406
@@ -395,31 +414,24 @@ static void
395namestore_list_finished (void *cls) 414namestore_list_finished (void *cls)
396{ 415{
397 struct RequestHandle *handle = cls; 416 struct RequestHandle *handle = cls;
398 char *result; 417 char *result_str;
399 struct MHD_Response *resp; 418 struct MHD_Response *resp;
400 419
401 handle->list_it = NULL; 420 handle->list_it = NULL;
402 if (NULL == handle->resp_object)
403 handle->resp_object = GNUNET_JSONAPI_document_new ();
404 421
405 if (GNUNET_SYSERR == 422 if (NULL == handle->resp_object)
406 GNUNET_JSONAPI_document_serialize (handle->resp_object,
407 &result))
408 { 423 {
409 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; 424 GNUNET_SCHEDULER_add_now (&do_error, handle);
410 GNUNET_SCHEDULER_add_now (&do_error,
411 handle);
412 return; 425 return;
413 } 426 }
414 resp = GNUNET_REST_create_response (result);
415 handle->proc (handle->proc_cls,
416 resp,
417 MHD_HTTP_OK);
418 GNUNET_free_non_null (result);
419 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed,
420 handle);
421}
422 427
428 result_str = json_dumps (handle->resp_object, 0);
429 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
430 resp = GNUNET_REST_create_response (result_str);
431 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
432 GNUNET_free_non_null (result_str);
433 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
434}
423 435
424 436
425/** 437/**
@@ -428,84 +440,111 @@ namestore_list_finished (void *cls)
428 * @param handle the RequestHandle 440 * @param handle the RequestHandle
429 */ 441 */
430static void 442static void
431namestore_list_response (void *cls, 443namestore_list_iteration (void *cls,
432 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key, 444 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
433 const char *rname, 445 const char *rname,
434 unsigned int rd_len, 446 unsigned int rd_len,
435 const struct GNUNET_GNSRECORD_Data *rd) 447 const struct GNUNET_GNSRECORD_Data *rd)
436{ 448{
437 struct RequestHandle *handle = cls; 449 struct RequestHandle *handle = cls;
438 struct GNUNET_JSONAPI_Resource *json_resource;
439 json_t *result_array;
440 json_t *record_obj; 450 json_t *record_obj;
441 451
442 if (NULL == handle->resp_object) 452 if (NULL == handle->resp_object)
443 handle->resp_object = GNUNET_JSONAPI_document_new (); 453 handle->resp_object = json_array();
444 454
445 if ( (NULL != handle->name) && 455 /*if ( (NULL != handle->ego_entry->identifier) &&
446 (0 != strcmp (handle->name, 456 (0 != strcmp (handle->ego_entry->identifier,
447 rname)) ) 457 rname)) )
448 { 458 {
449 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 459 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
450 "%s does not match %s\n", 460 "%s does not match %s\n", rname,
451 rname, 461 handle->ego_entry->identifier);
452 handle->name); 462 GNUNET_NAMESTORE_zone_iterator_next (handle->list_it, 1);
453 GNUNET_NAMESTORE_zone_iterator_next (handle->list_it,
454 1);
455 return; 463 return;
456 } 464 }*/
457 465
458 result_array = json_array (); 466 for (unsigned int i = 0; i < rd_len; i++)
459 for (unsigned int i=0; i<rd_len; i++)
460 { 467 {
461 if ( (GNUNET_GNSRECORD_TYPE_NICK == rd[i].record_type) && 468 if ( (GNUNET_GNSRECORD_TYPE_NICK == rd[i].record_type) &&
462 (0 != strcmp (rname, GNUNET_GNS_EMPTY_LABEL_AT)) ) 469 (0 != strcmp (rname, GNUNET_GNS_EMPTY_LABEL_AT)) )
463 continue; 470 continue;
464 471
465 if ( (rd[i].record_type != handle->type) && 472 record_obj = GNUNET_JSON_from_gns_record(rname,rd);
466 (GNUNET_GNSRECORD_TYPE_ANY != handle->type) ) 473
474 if(NULL == record_obj)
467 continue; 475 continue;
468 record_obj = gnsrecord_to_json (&rd[i]);
469 json_array_append (result_array,
470 record_obj);
471 json_decref (record_obj);
472 }
473 476
474 if (0 < json_array_size(result_array)) 477 json_array_append (handle->resp_object, record_obj);
475 { 478 json_decref (record_obj);
476 json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_NAMESTORE_TYPEINFO,
477 rname);
478 GNUNET_JSONAPI_resource_add_attr (json_resource,
479 GNUNET_REST_JSONAPI_NAMESTORE_RECORD,
480 result_array);
481 GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
482 } 479 }
483 480
484 json_decref (result_array); 481 GNUNET_NAMESTORE_zone_iterator_next (handle->list_it, 1);
485 GNUNET_NAMESTORE_zone_iterator_next (handle->list_it,
486 1);
487} 482}
488 483
489 484
490static void 485/**
491create_finished (void *cls, int32_t success, const char *emsg) 486 * Handle namestore GET request
487 *
488 * @param con_handle the connection handle
489 * @param url the url
490 * @param cls the RequestHandle
491 */
492void
493namestore_get (struct GNUNET_REST_RequestHandle *con_handle,
494 const char* url,
495 void *cls)
492{ 496{
493 struct RequestHandle *handle = cls; 497 struct RequestHandle *handle = cls;
494 struct MHD_Response *resp; 498 struct EgoEntry *ego_entry = NULL;
499 struct GNUNET_HashCode key;
500 char *pubkey = NULL;
501 char *name = NULL;
502
503 //change zone if pubkey or name specified
504 GNUNET_CRYPTO_hash (GNUNET_REST_API_PARAM_PUBKEY,
505 strlen (GNUNET_REST_API_PARAM_PUBKEY),
506 &key);
507 if ( GNUNET_YES
508 == GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map,
509 &key))
510 {
511 pubkey = GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map,
512 &key);
513 }
514 GNUNET_CRYPTO_hash (GNUNET_REST_API_PARAM_NAME,
515 strlen (GNUNET_REST_API_PARAM_NAME),
516 &key);
517 if ( GNUNET_YES
518 == GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map,
519 &key))
520 {
521 name = GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map,
522 &key);
523 }
495 524
496 handle->add_qe = NULL; 525 ego_entry = get_egoentry(handle,pubkey,name);
497 if (GNUNET_YES != success) 526 if (NULL == ego_entry)
498 { 527 {
499 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 528 if (NULL != pubkey || NULL != name)
500 "Error storing records%s%s\n", 529 {
501 (NULL == emsg) ? "" : ": ", 530 handle->emsg = GNUNET_strdup("Invalid identity");
502 (NULL == emsg) ? "" : emsg); 531 handle->response_code = MHD_HTTP_NOT_FOUND;
503 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); 532 GNUNET_SCHEDULER_add_now (&do_error, handle);
504 return; 533 return;
534 }
505 } 535 }
506 resp = GNUNET_REST_create_response (NULL); 536 if ( NULL != ego_entry )
507 handle->proc (handle->proc_cls, resp, MHD_HTTP_NO_CONTENT); 537 {
508 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); 538 handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key(ego_entry->ego);
539 }
540 handle->list_it = GNUNET_NAMESTORE_zone_iteration_start (handle->ns_handle,
541 handle->zone_pkey,
542 &namestore_iteration_error,
543 handle,
544 &namestore_list_iteration,
545 handle,
546 &namestore_list_finished,
547 handle);
509} 548}
510 549
511 550
@@ -529,10 +568,10 @@ create_new_record_cont (void *cls,
529 struct RequestHandle *handle = cls; 568 struct RequestHandle *handle = cls;
530 569
531 handle->add_qe = NULL; 570 handle->add_qe = NULL;
532 if (0 != strcmp (rec_name, handle->name)) 571 if (0 != strcmp (rec_name, handle->label_name))
533 { 572 {
534 GNUNET_break (0); 573 GNUNET_break (0);
535 do_error (handle); 574 GNUNET_SCHEDULER_add_now (&do_error, handle);
536 return; 575 return;
537 } 576 }
538 577
@@ -541,426 +580,262 @@ create_new_record_cont (void *cls,
541 handle->proc (handle->proc_cls, 580 handle->proc (handle->proc_cls,
542 GNUNET_REST_create_response (NULL), 581 GNUNET_REST_create_response (NULL),
543 MHD_HTTP_CONFLICT); 582 MHD_HTTP_CONFLICT);
544 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); 583 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
545 return; 584 return;
546 } 585 }
547
548 GNUNET_assert (NULL != handle->name);
549 handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle, 586 handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
550 &handle->zone_pkey, 587 handle->zone_pkey,
551 handle->name, 588 handle->label_name,
552 handle->rd_count, 589 GNUNET_REST_NAMESTORE_RD_COUNT,
553 handle->rd, 590 handle->rd,
554 &create_finished, 591 &create_finished,
555 handle); 592 handle);
556} 593}
557 594
558 595/**
559static void 596 * Handle namestore POST request
560del_finished (void *cls, 597 *
561 int32_t success, 598 * @param con_handle the connection handle
562 const char *emsg) 599 * @param url the url
600 * @param cls the RequestHandle
601 */
602void
603namestore_add (struct GNUNET_REST_RequestHandle *con_handle,
604 const char* url,
605 void *cls)
563{ 606{
564 struct RequestHandle *handle = cls; 607 struct RequestHandle *handle = cls;
608 struct GNUNET_GNSRECORD_Data *gns_record;
609 json_t *data_js;
610 json_t *name_json;
611 json_error_t err;
565 612
566 handle->add_qe = NULL; 613 struct EgoEntry *ego_entry = NULL;
567 if (GNUNET_NO == success) 614 struct GNUNET_HashCode key;
615 char *pubkey = NULL;
616 char *name = NULL;
617
618 char term_data[handle->rest_handle->data_size + 1];
619 struct GNUNET_JSON_Specification gnsspec[] = {
620 GNUNET_JSON_spec_gnsrecord_data(&gns_record),
621 GNUNET_JSON_spec_end ()
622 };
623
624 if (strlen (GNUNET_REST_API_NS_NAMESTORE) != strlen (handle->url))
568 { 625 {
569 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 626 handle->emsg = GNUNET_strdup("Wrong URL");
570 _("Deleting record failed, record does not exist%s%s\n"), 627 GNUNET_SCHEDULER_add_now (&do_error, handle);
571 (NULL != emsg) ? ": " : "",
572 (NULL != emsg) ? emsg : "");
573 GNUNET_SCHEDULER_add_now (&do_error, handle); //do_not_found TODO
574 return; 628 return;
575 } 629 }
576 if (GNUNET_SYSERR == success) 630 if (0 >= handle->rest_handle->data_size)
577 { 631 {
578 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 632 handle->emsg = GNUNET_strdup("No data");
579 _("Deleting record failed%s%s\n"),
580 (NULL != emsg) ? ": " : "",
581 (NULL != emsg) ? emsg : "");
582 GNUNET_SCHEDULER_add_now (&do_error, handle); 633 GNUNET_SCHEDULER_add_now (&do_error, handle);
583 return; 634 return;
584 } 635 }
585 handle->proc (handle->proc_cls, 636 term_data[handle->rest_handle->data_size] = '\0';
586 GNUNET_REST_create_response (NULL), 637 GNUNET_memcpy(term_data, handle->rest_handle->data,
587 MHD_HTTP_NO_CONTENT); 638 handle->rest_handle->data_size);
588 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); 639 data_js = json_loads (term_data, JSON_DECODE_ANY, &err);
589} 640 if (GNUNET_OK != GNUNET_JSON_parse (data_js, gnsspec, NULL, NULL))
590
591
592static void
593del_cont (void *cls,
594 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
595 const char *label,
596 unsigned int rd_count,
597 const struct GNUNET_GNSRECORD_Data *rd)
598{
599 struct RequestHandle *handle = cls;
600
601 handle->add_qe = NULL;
602 if (0 == rd_count)
603 { 641 {
604 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 642 handle->emsg = GNUNET_strdup("Invalid data");
605 _("There are no records under label `%s' that could be deleted.\n"), 643 GNUNET_SCHEDULER_add_now (&do_error, handle);
606 label); 644 GNUNET_JSON_parse_free(gnsspec);
607 do_error (handle); 645 json_decref (data_js);
608 return; 646 return;
609 } 647 }
648 handle->rd = gns_record;
610 649
611 handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle, 650 name_json = json_object_get(data_js, "label");
612 &handle->zone_pkey, 651 if (!json_is_string(name_json))
613 handle->name,
614 0, NULL,
615 &del_finished,
616 handle);
617}
618
619
620static void
621namestore_delete_cont (struct GNUNET_REST_RequestHandle *con,
622 const char *url,
623 void *cls)
624{
625 struct RequestHandle *handle = cls;
626
627 if (NULL == handle->name)
628 { 652 {
653 handle->emsg = GNUNET_strdup("Missing name");
629 GNUNET_SCHEDULER_add_now (&do_error, handle); 654 GNUNET_SCHEDULER_add_now (&do_error, handle);
655 json_decref (data_js);
630 return; 656 return;
631 } 657 }
632 658 handle->label_name = GNUNET_strdup(json_string_value(name_json));
633 handle->add_qe = GNUNET_NAMESTORE_records_lookup (handle->ns_handle, 659 if(NULL == handle->label_name)
634 &handle->zone_pkey,
635 handle->name,
636 &do_error,
637 handle,
638 &del_cont,
639 handle);
640}
641
642
643static int
644json_to_gnsrecord (const json_t *records_json,
645 struct GNUNET_GNSRECORD_Data **rd,
646 unsigned int *rd_count)
647{
648 struct GNUNET_TIME_Relative etime_rel;
649 struct GNUNET_TIME_Absolute etime_abs;
650 char *value;
651 void *rdata;
652 size_t rdata_size;
653 const char *typestring;
654 const char *expirationstring;
655 json_t *type_json;
656 json_t *value_json;
657 json_t *record_json;
658 json_t *exp_json;
659
660 *rd_count = json_array_size (records_json);
661 *rd = GNUNET_new_array (*rd_count,
662 struct GNUNET_GNSRECORD_Data);
663 for (unsigned int i = 0; i < *rd_count; i++)
664 { 660 {
665 memset (&(*rd)[i], 661 handle->emsg = GNUNET_strdup("Missing name");
666 0,
667 sizeof (struct GNUNET_GNSRECORD_Data));
668 record_json = json_array_get (records_json,
669 i);
670 type_json = json_object_get (record_json,
671 GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE);
672 if (! json_is_string (type_json))
673 {
674 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
675 "Type property is no string\n");
676 return GNUNET_SYSERR;
677 }
678 typestring = json_string_value (type_json);
679 (*rd)[i].record_type = GNUNET_GNSRECORD_typename_to_number (typestring);
680 if (UINT32_MAX == (*rd)[i].record_type)
681 {
682 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Unsupported type `%s'\n"),
683 json_string_value (type_json));
684 return GNUNET_SYSERR;
685 }
686 value_json = json_object_get (record_json,
687 GNUNET_REST_JSONAPI_NAMESTORE_VALUE);
688 if (! json_is_string (value_json))
689 {
690 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
691 "Value property is no string\n");
692 return GNUNET_SYSERR;
693 }
694 value = GNUNET_strdup (json_string_value (value_json));
695 if (GNUNET_OK !=
696 GNUNET_GNSRECORD_string_to_value ((*rd)[i].record_type,
697 value,
698 &rdata,
699 &rdata_size))
700 {
701 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
702 _("Value `%s' invalid for record type `%s'\n"),
703 value,
704 typestring);
705 return GNUNET_SYSERR;
706 }
707 (*rd)[i].data = rdata;
708 (*rd)[i].data_size = rdata_size;
709 /**TODO
710 * if (1 == handle->is_shadow)
711 rde->flags |= GNUNET_GNSRECORD_RF_SHADOW_RECORD;
712 if (1 != handle->is_public)
713 rde->flags |= GNUNET_GNSRECORD_RF_PRIVATE;
714 */
715 exp_json = json_object_get (record_json,
716 GNUNET_REST_JSONAPI_NAMESTORE_EXPIRATION);
717 if (! json_is_string (exp_json))
718 {
719 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
720 "Expiration property is no string\n");
721 return GNUNET_SYSERR;
722 }
723 expirationstring = json_string_value (exp_json);
724 if (0 == strcmp (expirationstring, "never"))
725 {
726 (*rd)[i].expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
727 }
728 else if (GNUNET_OK ==
729 GNUNET_STRINGS_fancy_time_to_relative (expirationstring,
730 &etime_rel))
731 {
732 (*rd)[i].expiration_time = etime_rel.rel_value_us;
733 (*rd)[i].flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
734 }
735 else if (GNUNET_OK ==
736 GNUNET_STRINGS_fancy_time_to_absolute (expirationstring,
737 &etime_abs))
738 {
739 (*rd)[i].expiration_time = etime_abs.abs_value_us;
740 }
741 else
742 {
743 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
744 _("Value `%s' invalid for record type `%s'\n"),
745 value,
746 typestring);
747 return GNUNET_SYSERR;
748 }
749 }
750 return GNUNET_OK;
751}
752
753
754static void
755namestore_create_cont (struct GNUNET_REST_RequestHandle *con,
756 const char *url,
757 void *cls)
758{
759 struct RequestHandle *handle = cls;
760 struct MHD_Response *resp;
761 struct GNUNET_JSONAPI_Document *json_obj;
762 struct GNUNET_JSONAPI_Resource *json_res;
763 json_t *records_json;
764 json_t *data_js;
765 json_error_t err;
766 char term_data[handle->rest_handle->data_size+1];
767 struct GNUNET_JSON_Specification docspec[] = {
768 GNUNET_JSON_spec_jsonapi_document (&json_obj),
769 GNUNET_JSON_spec_end()
770 };
771
772 if (strlen (GNUNET_REST_API_NS_NAMESTORE) != strlen (handle->url))
773 {
774 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
775 "Cannot create under %s\n", handle->url);
776 GNUNET_SCHEDULER_add_now (&do_error, handle); 662 GNUNET_SCHEDULER_add_now (&do_error, handle);
663 json_decref (data_js);
777 return; 664 return;
778 } 665 }
779 if (0 >= handle->rest_handle->data_size) 666 if (0 >= strlen(handle->label_name))
780 { 667 {
668 handle->emsg = GNUNET_strdup("Missing name");
781 GNUNET_SCHEDULER_add_now (&do_error, handle); 669 GNUNET_SCHEDULER_add_now (&do_error, handle);
670 json_decref (data_js);
782 return; 671 return;
783 } 672 }
784 term_data[handle->rest_handle->data_size] = '\0';
785 GNUNET_memcpy (term_data,
786 handle->rest_handle->data,
787 handle->rest_handle->data_size);
788 data_js = json_loads (term_data,
789 JSON_DECODE_ANY,
790 &err);
791 GNUNET_assert (GNUNET_OK ==
792 GNUNET_JSON_parse (data_js, docspec,
793 NULL, NULL));
794 json_decref (data_js); 673 json_decref (data_js);
795 if (NULL == json_obj) 674
675 //change zone if pubkey or name specified
676 GNUNET_CRYPTO_hash (GNUNET_REST_API_PARAM_PUBKEY,
677 strlen (GNUNET_REST_API_PARAM_PUBKEY),
678 &key);
679 if ( GNUNET_YES
680 == GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map,
681 &key))
796 { 682 {
797 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 683 pubkey = GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map,
798 "Unable to parse JSONAPI Object from %s\n", 684 &key);
799 term_data);
800 GNUNET_SCHEDULER_add_now (&do_error, handle);
801 return;
802 } 685 }
803 if (1 != GNUNET_JSONAPI_document_resource_count (json_obj)) 686 GNUNET_CRYPTO_hash (GNUNET_REST_API_PARAM_NAME,
687 strlen (GNUNET_REST_API_PARAM_NAME),
688 &key);
689 if ( GNUNET_YES
690 == GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map,
691 &key))
804 { 692 {
805 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 693 name = GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map,
806 "Cannot create more than 1 resource! (Got %d)\n", 694 &key);
807 GNUNET_JSONAPI_document_resource_count (json_obj));
808 GNUNET_JSONAPI_document_delete (json_obj);
809 GNUNET_SCHEDULER_add_now (&do_error, handle);
810 return;
811 } 695 }
812 json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0); 696
813 if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res, 697 ego_entry = get_egoentry(handle,pubkey,name);
814 GNUNET_REST_JSONAPI_NAMESTORE_RECORD)) 698 if (NULL == ego_entry)
815 { 699 {
816 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 700 if (NULL != pubkey || NULL != name)
817 "Unsupported JSON data type\n"); 701 {
818 GNUNET_JSONAPI_document_delete (json_obj); 702 handle->emsg = GNUNET_strdup("Invalid identity");
819 resp = GNUNET_REST_create_response (NULL); 703 handle->response_code = MHD_HTTP_NOT_FOUND;
820 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT); 704 GNUNET_SCHEDULER_add_now (&do_error, handle);
821 cleanup_handle (handle); 705 return;
822 return; 706 }
823 } 707 }
824 handle->name = GNUNET_strdup (GNUNET_JSONAPI_resource_get_id (json_res)); 708 if ( NULL != ego_entry )
825 records_json = GNUNET_JSONAPI_resource_read_attr (json_res,
826 GNUNET_REST_JSONAPI_NAMESTORE_RECORD);
827 if (NULL == records_json)
828 { 709 {
829 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 710 handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key(ego_entry->ego);
830 "No records given\n");
831 GNUNET_JSONAPI_document_delete (json_obj);
832 GNUNET_SCHEDULER_add_now (&do_error, handle);
833 return;
834 } 711 }
835 if (GNUNET_SYSERR == json_to_gnsrecord (records_json, &handle->rd, &handle->rd_count)) 712 if (NULL == handle->zone_pkey)
836 { 713 {
837 GNUNET_JSONAPI_document_delete (json_obj); 714 handle->emsg = GNUNET_strdup("No default identity for namestore");
838 GNUNET_SCHEDULER_add_now (&do_error, handle); 715 GNUNET_SCHEDULER_add_now (&do_error, handle);
839 return; 716 return;
840 } 717 }
841 GNUNET_JSONAPI_document_delete (json_obj);
842
843 handle->add_qe = GNUNET_NAMESTORE_records_lookup (handle->ns_handle, 718 handle->add_qe = GNUNET_NAMESTORE_records_lookup (handle->ns_handle,
844 &handle->zone_pkey, 719 handle->zone_pkey,
845 handle->name, 720 handle->label_name,
846 &do_error, 721 &do_error,
847 handle, 722 handle,
848 &create_new_record_cont, 723 &create_new_record_cont,
849 handle); 724 handle);
850} 725}
851 726
852 727
853static void 728static void
854namestore_zkey_response (void *cls, 729del_cont (void *cls,
855 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone, 730 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
856 const char *label, 731 const char *label,
857 unsigned int rd_count, 732 unsigned int rd_count,
858 const struct GNUNET_GNSRECORD_Data *rd) 733 const struct GNUNET_GNSRECORD_Data *rd)
859{ 734{
860 struct RequestHandle *handle = cls; 735 struct RequestHandle *handle = cls;
861 struct MHD_Response *resp;
862 struct GNUNET_JSONAPI_Document *json_obj;
863 struct GNUNET_JSONAPI_Resource *json_res;
864 json_t *name_json;
865 char* result;
866 736
867 handle->reverse_qe = NULL; 737 handle->add_qe = NULL;
868 json_obj = GNUNET_JSONAPI_document_new (); 738 if (0 == rd_count)
869 if (NULL != label)
870 {
871 name_json = json_string (label);
872 json_res = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_NAMESTORE_REVINFO,
873 handle->zkey_str);
874 GNUNET_JSONAPI_resource_add_attr (json_res,
875 GNUNET_REST_JSONAPI_NAMESTORE_NAME,
876 name_json);
877 GNUNET_JSONAPI_document_resource_add (json_obj, json_res);
878 json_decref (name_json);
879 }
880 //Handle response
881 if (GNUNET_SYSERR == GNUNET_JSONAPI_document_serialize (json_obj, &result))
882 { 739 {
883 GNUNET_JSONAPI_document_delete (json_obj); 740 handle->emsg = GNUNET_strdup("Record not found");
884 GNUNET_SCHEDULER_add_now (&do_error, handle); 741 GNUNET_SCHEDULER_add_now (&do_error, handle);
885 return; 742 return;
886 } 743 }
887 resp = GNUNET_REST_create_response (result);
888 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
889 GNUNET_JSONAPI_document_delete (json_obj);
890 GNUNET_free (result);
891 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
892}
893 744
745 handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
746 handle->zone_pkey,
747 handle->label_name,
748 0, NULL,
749 &del_finished,
750 handle);
751}
894 752
895static void 753/**
896namestore_zkey_cont (struct GNUNET_REST_RequestHandle *con, 754 * Handle namestore DELETE request
897 const char *url, 755 *
898 void *cls) 756 * @param con_handle the connection handle
757 * @param url the url
758 * @param cls the RequestHandle
759 */
760void
761namestore_delete (struct GNUNET_REST_RequestHandle *con_handle,
762 const char* url,
763 void *cls)
899{ 764{
900 struct RequestHandle *handle = cls; 765 struct RequestHandle *handle = cls;
901 struct GNUNET_HashCode key; 766 struct GNUNET_HashCode key;
902 struct GNUNET_CRYPTO_EcdsaPublicKey pubkey; 767 struct EgoEntry *ego_entry = NULL;
903 768 char *pubkey = NULL;
904 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_NAMESTORE_ZKEY, 769 char *name = NULL;
905 strlen (GNUNET_REST_JSONAPI_NAMESTORE_ZKEY), 770
906 &key); 771 //change zone if pubkey or name specified
907 if ( GNUNET_NO == 772 GNUNET_CRYPTO_hash (GNUNET_REST_API_PARAM_PUBKEY,
908 GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map, 773 strlen (GNUNET_REST_API_PARAM_PUBKEY),
909 &key) ) 774 &key);
775 if ( GNUNET_YES
776 == GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map,
777 &key))
910 { 778 {
911 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 779 pubkey = GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map,
912 "No zkey given %s\n", handle->url); 780 &key);
781 }
782 GNUNET_CRYPTO_hash (GNUNET_REST_API_PARAM_NAME,
783 strlen (GNUNET_REST_API_PARAM_NAME),
784 &key);
785 if ( GNUNET_YES
786 == GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map,
787 &key))
788 {
789 name = GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map,
790 &key);
791 }
792
793 ego_entry = get_egoentry(handle,pubkey,name);
794 if (NULL == ego_entry)
795 {
796 if (NULL != pubkey || NULL != name)
797 {
798 handle->emsg = GNUNET_strdup("Invalid identity");
799 handle->response_code = MHD_HTTP_NOT_FOUND;
800 GNUNET_SCHEDULER_add_now (&do_error, handle);
801 return;
802 }
803 }
804 if ( NULL != ego_entry )
805 {
806 handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key(ego_entry->ego);
807 }
808
809 GNUNET_CRYPTO_hash ("label", strlen ("label"), &key);
810 if ( GNUNET_NO
811 == GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map,
812 &key))
813 {
814 handle->emsg = GNUNET_strdup("Missing name");
913 GNUNET_SCHEDULER_add_now (&do_error, handle); 815 GNUNET_SCHEDULER_add_now (&do_error, handle);
914 return; 816 return;
915 } 817 }
916 handle->zkey_str = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map, 818 handle->label_name = GNUNET_strdup(
917 &key); 819 GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map, &key));
918 if ((NULL == handle->zkey_str) || 820
919 (GNUNET_OK != 821 if (NULL == handle->zone_pkey)
920 GNUNET_CRYPTO_ecdsa_public_key_from_string (handle->zkey_str,
921 strlen (handle->zkey_str),
922 &pubkey)))
923 { 822 {
924 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 823 handle->emsg = GNUNET_strdup("No default identity for namestore");
925 "Zkey invalid %s\n", handle->zkey_str);
926 GNUNET_SCHEDULER_add_now (&do_error, handle); 824 GNUNET_SCHEDULER_add_now (&do_error, handle);
927 return; 825 return;
928 } 826 }
929 handle->reverse_qe = GNUNET_NAMESTORE_zone_to_name (handle->ns_handle,
930 &handle->zone_pkey,
931 &pubkey,
932 &do_error,
933 handle,
934 &namestore_zkey_response,
935 handle);
936}
937
938 827
939static void 828 handle->add_qe = GNUNET_NAMESTORE_records_lookup (handle->ns_handle,
940namestore_info_cont (struct GNUNET_REST_RequestHandle *con, 829 handle->zone_pkey,
941 const char *url, 830 handle->label_name,
942 void *cls) 831 &do_error,
943{ 832 handle,
944 struct RequestHandle *handle = cls; 833 &del_cont,
834 handle);
945 835
946 handle->list_it = GNUNET_NAMESTORE_zone_iteration_start (handle->ns_handle,
947 &handle->zone_pkey,
948 &do_error,
949 handle,
950 &namestore_list_response,
951 handle,
952 &namestore_list_finished,
953 handle);
954} 836}
955 837
956 838
957static char*
958get_name_from_url (const char* url)
959{
960 if (strlen (url) <= strlen (GNUNET_REST_API_NS_NAMESTORE))
961 return NULL;
962 return (char*)url + strlen (GNUNET_REST_API_NS_NAMESTORE) + 1;
963}
964 839
965/** 840/**
966 * Respond to OPTIONS request 841 * Respond to OPTIONS request
@@ -977,101 +852,72 @@ options_cont (struct GNUNET_REST_RequestHandle *con_handle,
977 struct MHD_Response *resp; 852 struct MHD_Response *resp;
978 struct RequestHandle *handle = cls; 853 struct RequestHandle *handle = cls;
979 854
980 //For now, independent of path return all options 855 //independent of path return all options
981 resp = GNUNET_REST_create_response (NULL); 856 resp = GNUNET_REST_create_response (NULL);
982 MHD_add_response_header (resp, 857 MHD_add_response_header (resp,
983 "Access-Control-Allow-Methods", 858 "Access-Control-Allow-Methods",
984 allow_methods); 859 allow_methods);
985 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); 860 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
986 cleanup_handle (handle); 861 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
862 return;
987} 863}
988 864
989 865
990/** 866/**
991 * Callback invoked from identity service with ego information. 867 * Handle rest request
992 * An @a ego of NULL means the ego was not found.
993 * 868 *
994 * @param cls closure with the configuration 869 * @param handle the request handle
995 * @param ego an ego known to identity service, or NULL
996 */ 870 */
997static void 871static void
998identity_cb (void *cls, 872init_cont (struct RequestHandle *handle)
999 const struct GNUNET_IDENTITY_Ego *ego)
1000{ 873{
1001 struct RequestHandle *handle = cls;
1002 struct MHD_Response *resp;
1003 struct GNUNET_REST_RequestHandlerError err; 874 struct GNUNET_REST_RequestHandlerError err;
1004 static const struct GNUNET_REST_RequestHandler handlers[] = { 875 static const struct GNUNET_REST_RequestHandler handlers[] = {
1005 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_NAMESTORE_ZKEY, &namestore_zkey_cont}, //reverse 876 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_NAMESTORE, &namestore_get},
1006 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_NAMESTORE, &namestore_info_cont}, //list 877 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_NAMESTORE, &namestore_add},
1007 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_NAMESTORE, &namestore_create_cont}, //create 878 {MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_NAMESTORE, &namestore_delete},
1008 // {MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_NAMESTORE, &namestore_edit_cont}, //update. TODO this shoul be PATCH
1009 {MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_NAMESTORE, &namestore_delete_cont}, //delete
1010 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_NAMESTORE, &options_cont}, 879 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_NAMESTORE, &options_cont},
1011 GNUNET_REST_HANDLER_END 880 GNUNET_REST_HANDLER_END
1012 }; 881 };
1013 882
1014 handle->ego_lookup = NULL; 883 if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle,
1015 if (NULL == ego) 884 handlers,
1016 { 885 &err,
1017 if (NULL != handle->ego_name) 886 handle))
1018 {
1019 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1020 _("Ego `%s' not known to identity service\n"),
1021 handle->ego_name);
1022 }
1023 resp = GNUNET_REST_create_response (NULL);
1024 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
1025 cleanup_handle (handle);
1026 return;
1027 }
1028 handle->zone_pkey = *GNUNET_IDENTITY_ego_get_private_key (ego);
1029 handle->ns_handle = GNUNET_NAMESTORE_connect (cfg);
1030 if (NULL == handle->ns_handle)
1031 {
1032 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1033 _("Failed to connect to namestore\n"));
1034 GNUNET_SCHEDULER_add_now (&do_error, handle);
1035 return;
1036 }
1037
1038 if (GNUNET_OK !=
1039 GNUNET_JSONAPI_handle_request (handle->rest_handle,
1040 handlers,
1041 &err,
1042 handle))
1043 { 887 {
1044 handle->response_code = err.error_code; 888 handle->response_code = err.error_code;
1045 GNUNET_SCHEDULER_add_now (&do_error, 889 GNUNET_SCHEDULER_add_now (&do_error, handle);
1046 (void *) handle);
1047 } 890 }
1048} 891}
1049 892
1050 893/**
894 * @param cls closure
895 * @param ego ego handle
896 * @param ctx context for application to store data for this ego
897 * (during the lifetime of this process, initially NULL)
898 * @param identifier identifier assigned by the user for this ego,
899 * NULL if the user just deleted the ego and it
900 * must thus no longer be used
901 */
1051static void 902static void
1052default_ego_cb (void *cls, 903default_ego_cb (void *cls,
1053 struct GNUNET_IDENTITY_Ego *ego, 904 struct GNUNET_IDENTITY_Ego *ego,
1054 void **ctx, 905 void **ctx,
1055 const char *name) 906 const char *identifier)
1056{ 907{
1057 struct RequestHandle *handle = cls; 908 struct RequestHandle *handle = cls;
1058 struct MHD_Response *resp; 909 handle->op = NULL;
1059 handle->get_default = NULL; 910
1060 if (NULL == ego) 911 if (ego != NULL)
1061 {
1062 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1063 _("No default ego configured in identity service\n"));
1064 resp = GNUNET_REST_create_response (NULL);
1065 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
1066 cleanup_handle (handle);
1067 return;
1068 }
1069 else
1070 { 912 {
1071 identity_cb (cls, ego); 913 handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key (ego);
1072 } 914 }
1073} 915}
1074 916
917
918/**
919 * Connect to identity callback
920 */
1075static void 921static void
1076id_connect_cb (void *cls, 922id_connect_cb (void *cls,
1077 struct GNUNET_IDENTITY_Ego *ego, 923 struct GNUNET_IDENTITY_Ego *ego,
@@ -1079,12 +925,33 @@ id_connect_cb (void *cls,
1079 const char *name) 925 const char *name)
1080{ 926{
1081 struct RequestHandle *handle = cls; 927 struct RequestHandle *handle = cls;
1082 if (NULL == ego) 928 struct EgoEntry *ego_entry;
929 struct GNUNET_CRYPTO_EcdsaPublicKey pk;
930
931 if ((NULL == ego) && (NULL == handle->zone_pkey))
932 {
933 handle->op = GNUNET_IDENTITY_get (handle->identity_handle,
934 GNUNET_REST_SUBSYSTEM_NAMESTORE,
935 &default_ego_cb,
936 handle);
937 }
938 if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
939 {
940 handle->state = ID_REST_STATE_POST_INIT;
941 init_cont (handle);
942 return;
943 }
944 if (ID_REST_STATE_INIT == handle->state)
1083 { 945 {
1084 handle->get_default = GNUNET_IDENTITY_get (handle->identity_handle, 946 ego_entry = GNUNET_new(struct EgoEntry);
1085 "namestore", 947 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
1086 &default_ego_cb, handle); 948 ego_entry->keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
949 ego_entry->ego = ego;
950 GNUNET_asprintf (&ego_entry->identifier, "%s", name);
951 GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head, handle->ego_tail,
952 ego_entry);
1087 } 953 }
954
1088} 955}
1089 956
1090 957
@@ -1097,81 +964,38 @@ id_connect_cb (void *cls,
1097 * @param data_size length of the body 964 * @param data_size length of the body
1098 * @param proc callback function for the result 965 * @param proc callback function for the result
1099 * @param proc_cls closure for callback function 966 * @param proc_cls closure for callback function
1100 * @return #GNUNET_OK if request accepted 967 * @return GNUNET_OK if request accepted
1101 */ 968 */
1102static void 969static void
1103rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle, 970rest_process_request(struct GNUNET_REST_RequestHandle *rest_handle,
1104 GNUNET_REST_ResultProcessor proc, 971 GNUNET_REST_ResultProcessor proc,
1105 void *proc_cls) 972 void *proc_cls)
1106{ 973{
1107 struct RequestHandle *handle = GNUNET_new (struct RequestHandle); 974 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1108 struct MHD_Response *resp; 975
1109 struct GNUNET_HashCode key; 976 handle->response_code = 0;
1110 char *ego;
1111 char *name;
1112 char *type;
1113
1114 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL; 977 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1115 handle->proc_cls = proc_cls; 978 handle->proc_cls = proc_cls;
1116 handle->proc = proc; 979 handle->proc = proc;
1117 handle->rest_handle = rest_handle; 980 handle->rest_handle = rest_handle;
981 handle->zone_pkey = NULL;
982
1118 handle->url = GNUNET_strdup (rest_handle->url); 983 handle->url = GNUNET_strdup (rest_handle->url);
1119 if (handle->url[strlen (handle->url)-1] == '/') 984 if (handle->url[strlen (handle->url)-1] == '/')
1120 handle->url[strlen (handle->url)-1] = '\0'; 985 handle->url[strlen (handle->url)-1] = '\0';
1121 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 986 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n");
1122 "Connecting...\n");
1123 handle->cfg = cfg;
1124 ego = NULL;
1125 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_NAMESTORE_EGO,
1126 strlen (GNUNET_REST_JSONAPI_NAMESTORE_EGO),
1127 &key);
1128 if ( GNUNET_YES ==
1129 GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1130 &key) )
1131 {
1132 ego = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
1133 &key);
1134 }
1135 987
1136 handle->type = GNUNET_GNSRECORD_TYPE_ANY; 988 handle->identity_handle = GNUNET_IDENTITY_connect (cfg, &id_connect_cb, handle);
1137 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE, 989 handle->ns_handle = GNUNET_NAMESTORE_connect (cfg);
1138 strlen (GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE), 990 handle->timeout_task =
1139 &key); 991 GNUNET_SCHEDULER_add_delayed (handle->timeout,
1140 if ( GNUNET_YES == 992 &do_error,
1141 GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map, 993 handle);
1142 &key) ) 994
1143 { 995 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected\n");
1144 type = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
1145 &key);
1146 if (NULL != type)
1147 handle->type = GNUNET_GNSRECORD_typename_to_number (type);
1148 }
1149 name = get_name_from_url (handle->url);
1150 if (NULL != ego)
1151 handle->ego_name = GNUNET_strdup (ego);
1152 if (NULL != name)
1153 handle->name = GNUNET_strdup (name);
1154 if (NULL == handle->ego_name)
1155 {
1156 handle->identity_handle = GNUNET_IDENTITY_connect (handle->cfg, &id_connect_cb, handle);
1157 if (NULL == handle->identity_handle)
1158 {
1159 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Cannot connect to identity service\n"));
1160 resp = GNUNET_REST_create_response (NULL);
1161 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
1162 cleanup_handle (handle);
1163 }
1164 return;
1165 }
1166 handle->ego_lookup = GNUNET_IDENTITY_ego_lookup (cfg,
1167 handle->ego_name,
1168 &identity_cb,
1169 handle);
1170 handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout,
1171 &do_timeout,
1172 handle);
1173} 996}
1174 997
998
1175/** 999/**
1176 * Entry point for the plugin. 1000 * Entry point for the plugin.
1177 * 1001 *
@@ -1182,9 +1006,9 @@ void *
1182libgnunet_plugin_rest_namestore_init (void *cls) 1006libgnunet_plugin_rest_namestore_init (void *cls)
1183{ 1007{
1184 static struct Plugin plugin; 1008 static struct Plugin plugin;
1185 cfg = cls;
1186 struct GNUNET_REST_Plugin *api; 1009 struct GNUNET_REST_Plugin *api;
1187 1010
1011 cfg = cls;
1188 if (NULL != plugin.cfg) 1012 if (NULL != plugin.cfg)
1189 return NULL; /* can only initialize once! */ 1013 return NULL; /* can only initialize once! */
1190 memset (&plugin, 0, sizeof (struct Plugin)); 1014 memset (&plugin, 0, sizeof (struct Plugin));
@@ -1192,7 +1016,7 @@ libgnunet_plugin_rest_namestore_init (void *cls)
1192 api = GNUNET_new (struct GNUNET_REST_Plugin); 1016 api = GNUNET_new (struct GNUNET_REST_Plugin);
1193 api->cls = &plugin; 1017 api->cls = &plugin;
1194 api->name = GNUNET_REST_API_NS_NAMESTORE; 1018 api->name = GNUNET_REST_API_NS_NAMESTORE;
1195 api->process_request = &rest_identity_process_request; 1019 api->process_request = &rest_process_request;
1196 GNUNET_asprintf (&allow_methods, 1020 GNUNET_asprintf (&allow_methods,
1197 "%s, %s, %s, %s, %s", 1021 "%s, %s, %s, %s, %s",
1198 MHD_HTTP_METHOD_GET, 1022 MHD_HTTP_METHOD_GET,
@@ -1200,7 +1024,8 @@ libgnunet_plugin_rest_namestore_init (void *cls)
1200 MHD_HTTP_METHOD_PUT, 1024 MHD_HTTP_METHOD_PUT,
1201 MHD_HTTP_METHOD_DELETE, 1025 MHD_HTTP_METHOD_DELETE,
1202 MHD_HTTP_METHOD_OPTIONS); 1026 MHD_HTTP_METHOD_OPTIONS);
1203 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1027
1028 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1204 _("Namestore REST API initialized\n")); 1029 _("Namestore REST API initialized\n"));
1205 return api; 1030 return api;
1206} 1031}
@@ -1217,13 +1042,14 @@ libgnunet_plugin_rest_namestore_done (void *cls)
1217{ 1042{
1218 struct GNUNET_REST_Plugin *api = cls; 1043 struct GNUNET_REST_Plugin *api = cls;
1219 struct Plugin *plugin = api->cls; 1044 struct Plugin *plugin = api->cls;
1220
1221 plugin->cfg = NULL; 1045 plugin->cfg = NULL;
1222 GNUNET_free (api); 1046
1223 GNUNET_free_non_null (allow_methods); 1047 GNUNET_free_non_null (allow_methods);
1048 GNUNET_free (api);
1224 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1049 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1225 "Namestore REST plugin is finished\n"); 1050 "Namestore REST plugin is finished\n");
1226 return NULL; 1051 return NULL;
1227} 1052}
1228 1053
1229/* end of plugin_rest_namestore.c */ 1054/* end of plugin_rest_namestore.c */
1055
diff --git a/src/namestore/test_plugin_rest_namestore.sh b/src/namestore/test_plugin_rest_namestore.sh
new file mode 100755
index 000000000..de02dfafc
--- /dev/null
+++ b/src/namestore/test_plugin_rest_namestore.sh
@@ -0,0 +1,208 @@
1#!/usr/bin/bash
2
3#First, start gnunet-arm and the rest-service.
4#Exit 0 means success, exit 1 means failed test
5
6namestore_link="http://localhost:7776/namestore"
7wrong_link="http://localhost:7776/namestoreandmore"
8
9
10curl_get () {
11 #$1 is link
12 #$2 is grep
13 cache="$(curl -v "$1" 2>&1 | grep "$2")"
14 #echo $cache
15 if [ "" == "$cache" ]
16 then
17 exit 1
18 fi
19}
20
21curl_post () {
22 #$1 is link
23 #$2 is data
24 #$3 is grep
25 cache="$(curl -v -X "POST" "$1" --data "$2" 2>&1 | grep "$3")"
26 #echo $cache
27 if [ "" == "$cache" ]
28 then
29 exit 1
30 fi
31}
32
33curl_delete () {
34 #$1 is link
35 #$2 is grep
36 cache="$(curl -v -X "DELETE" "$1" 2>&1 | grep "$2")"
37 #echo $cache
38 if [ "" == "$cache" ]
39 then
40 exit 1
41 fi
42}
43
44# curl_put () {
45# #$1 is link
46# #$2 is data
47# #$3 is grep
48# cache="$(curl -v -X "PUT" "$1" --data "$2" 2>&1 | grep "$3")"
49# #echo $cache
50# if [ "" == "$cache" ]
51# then
52# exit 1
53# fi
54# }
55
56#Test subsystem default identity
57
58#Test GET
59gnunet-identity -D "test_plugin_rest_namestore"
60gnunet-identity -C "test_plugin_rest_namestore"
61test="$(gnunet-namestore -D -z "test_plugin_rest_namestore")"
62name="test_plugin_rest_namestore"
63public="$(gnunet-identity -d | grep "test_plugin_rest_namestore" | awk 'NR==1{print $3}')"
64if [ "" == "$test" ]
65then
66 #if no entries for test_plugin_rest_namestore
67 curl_get "${namestore_link}?name=$name" "error"
68 curl_get "${namestore_link}?name=" "error"
69 curl_get "${namestore_link}?name=$public" "error"
70
71 curl_get "${namestore_link}?pubkey=$public" "error"
72 curl_get "${namestore_link}?pubkey=$name" "error"
73 curl_get "${namestore_link}?pubkey=" "error"
74else
75 #if entries exists (that should not be possible)
76 curl_get "${namestore_link}" "HTTP/1.1 200 OK"
77 curl_get "${namestore_link}?name=$name" "HTTP/1.1 200 OK"
78 curl_get "${namestore_link}?name=" "error"
79 curl_get "${namestore_link}?name=$public" "error"
80
81 curl_get "${namestore_link}?pubkey=$public" "HTTP/1.1 200 OK"
82 curl_get "${namestore_link}?pubkey=$name" "error"
83 curl_get "${namestore_link}?pubkey=" "error"
84fi
85gnunet-namestore -z $name -p -a -n "test_entry" -e "1d" -V "HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG" -t "PKEY"
86curl_get "${namestore_link}" "HTTP/1.1 200 OK"
87curl_get "${namestore_link}?name=$name" "HTTP/1.1 200 OK"
88curl_get "${namestore_link}?name=" "error"
89curl_get "${namestore_link}?name=$public" "error"
90curl_get "${namestore_link}?pubkey=$public" "HTTP/1.1 200 OK"
91curl_get "${namestore_link}?pubkey=$name" "error"
92curl_get "${namestore_link}?pubkey=" "error"
93gnunet-namestore -z $name -d -n "test_entry"
94
95#Test POST with NAME
96curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":0,"label":"test_entry"}' "HTTP/1.1 204 No Content"
97gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
98#value
99curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRGxxx", "type":"PKEY", "expiration_time":"1d","flag":0,"label":"test_entry"}' "error"
100gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
101curl_post "${namestore_link}?name=$name" '{"value":"", "type":"PKEY", "expiration_time":"1d","flag":0,"label":"test_entry"}' "error"
102gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
103curl_post "${namestore_link}?name=$name" '{"value_missing":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRGxxx", "type":"PKEY", "expiration_time":"1d","flag":0,"label":"test_entry"}' "error"
104gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
105#time
106curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"0d","flag":0,"label":"test_entry"}' "HTTP/1.1 204"
107gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
108curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"10000d","flag":0,"label":"test_entry"}' "HTTP/1.1 204"
109gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
110curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"now","flag":0,"label":"test_entry"}' "error"
111gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
112curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"","flag":0,"label":"test_entry"}' "error"
113gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
114curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time_missing":"1d","flag":0,"label":"test_entry"}' "error"
115gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
116#flag
117curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":0,"label":"test_entry"}' "HTTP/1.1 204 No Content"
118gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
119curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":2,"label":"test_entry"}' "HTTP/1.1 204 No Content"
120gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
121curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":8,"label":"test_entry"}' "HTTP/1.1 204 No Content"
122gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
123curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":16,"label":"test_entry"}' "HTTP/1.1 204 No Content"
124gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
125curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":-1,"label":"test_entry"}' "error"
126gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
127curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":"Test","label":"test_entry"}' "error"
128gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
129curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":,"label":"test_entry"}' "error"
130gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
131curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag_missing":0,"label":"test_entry"}' "error"
132gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
133#label
134curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":0,"label":"test_entry"}' "HTTP/1.1 204 No Content"
135curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":0,"label":"test_entry"}' "HTTP/1.1 409"
136gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
137curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":0,"label":""}' "error"
138gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
139curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":0,"label_missing":"test_entry"}' "error"
140gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
141
142#Test POST with PUBKEY
143curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":0,"label":"test_entry"}' "HTTP/1.1 204 No Content"
144gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
145#value
146curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRGxxx", "type":"PKEY", "expiration_time":"1d","flag":0,"label":"test_entry"}' "error"
147gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
148curl_post "${namestore_link}?pubkey=$public" '{"value":"", "type":"PKEY", "expiration_time":"1d","flag":0,"label":"test_entry"}' "error"
149gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
150curl_post "${namestore_link}?pubkey=$public" '{"value_missing":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRGxxx", "type":"PKEY", "expiration_time":"1d","flag":0,"label":"test_entry"}' "error"
151gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
152#time
153curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"0d","flag":0,"label":"test_entry"}' "HTTP/1.1 204"
154gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
155curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"10000d","flag":0,"label":"test_entry"}' "HTTP/1.1 204"
156gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
157curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"now","flag":0,"label":"test_entry"}' "error"
158gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
159curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"","flag":0,"label":"test_entry"}' "error"
160gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
161curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time_missing":"1d","flag":0,"label":"test_entry"}' "error"
162gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
163#flag
164curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":0,"label":"test_entry"}' "HTTP/1.1 204 No Content"
165gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
166curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":2,"label":"test_entry"}' "HTTP/1.1 204 No Content"
167gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
168curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":8,"label":"test_entry"}' "HTTP/1.1 204 No Content"
169gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
170curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":16,"label":"test_entry"}' "HTTP/1.1 204 No Content"
171gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
172curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":-1,"label":"test_entry"}' "error"
173gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
174curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":"Test","label":"test_entry"}' "error"
175gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
176curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":,"label":"test_entry"}' "error"
177gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
178curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag_missing":0,"label":"test_entry"}' "error"
179gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
180#label
181curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":0,"label":"test_entry"}' "HTTP/1.1 204 No Content"
182curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":0,"label":"test_entry"}' "HTTP/1.1 409"
183gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
184curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":0,"label":""}' "error"
185gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
186curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":0,"label_missing":"test_entry"}' "error"
187gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
188
189#wrong zone
190curl_post "${namestore_link}?name=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":0,"label":"test_entry"}' "error"
191gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
192curl_post "${namestore_link}?pubkey=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":0,"label":"test_entry"}' "error"
193gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
194
195#Test DELETE
196gnunet-namestore -z $name -p -a -n "test_entry" -e "1d" -V "HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG" -t "PKEY"
197curl_delete "${namestore_link}?label=test_entry&name=$name" "HTTP/1.1 204"
198gnunet-namestore -z $name -p -a -n "test_entry" -e "1d" -V "HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG" -t "PKEY"
199curl_delete "${namestore_link}?label=test_entry&pubkey=$public" "HTTP/1.1 204"
200gnunet-namestore -z $name -p -a -n "test_entry" -e "1d" -V "HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG" -t "PKEY"
201curl_delete "${namestore_link}?label=test_entry&pubkey=$name" "HTTP/1.1 404"
202
203
204#Test default identity
205#not possible without defining
206
207exit 0;
208
diff --git a/src/peerinfo/Makefile.am b/src/peerinfo/Makefile.am
index eeb5ee54e..5e96250b1 100644
--- a/src/peerinfo/Makefile.am
+++ b/src/peerinfo/Makefile.am
@@ -5,6 +5,8 @@ pkgcfgdir= $(pkgdatadir)/config.d/
5 5
6libexecdir= $(pkglibdir)/libexec/ 6libexecdir= $(pkglibdir)/libexec/
7 7
8plugindir = $(libdir)/gnunet
9
8pkgcfg_DATA = \ 10pkgcfg_DATA = \
9 peerinfo.conf 11 peerinfo.conf
10 12
@@ -25,6 +27,8 @@ libgnunetpeerinfo_la_SOURCES = \
25libgnunetpeerinfo_la_LIBADD = \ 27libgnunetpeerinfo_la_LIBADD = \
26 $(top_builddir)/src/hello/libgnunethello.la \ 28 $(top_builddir)/src/hello/libgnunethello.la \
27 $(top_builddir)/src/util/libgnunetutil.la \ 29 $(top_builddir)/src/util/libgnunetutil.la \
30 $(top_builddir)/src/json/libgnunetjson.la \
31 $(top_builddir)/src/transport/libgnunettransport.la \
28 $(XLIB) \ 32 $(XLIB) \
29 $(LTLIBINTL) 33 $(LTLIBINTL)
30libgnunetpeerinfo_la_LDFLAGS = \ 34libgnunetpeerinfo_la_LDFLAGS = \
@@ -35,12 +39,30 @@ libgnunetpeerinfo_la_LDFLAGS = \
35libexec_PROGRAMS = \ 39libexec_PROGRAMS = \
36 gnunet-service-peerinfo 40 gnunet-service-peerinfo
37 41
42if HAVE_MHD
43if HAVE_JSON
44plugin_LTLIBRARIES = \
45 libgnunet_plugin_rest_peerinfo.la
46endif
47endif
48
38gnunet_service_peerinfo_SOURCES = \ 49gnunet_service_peerinfo_SOURCES = \
39 gnunet-service-peerinfo.c 50 gnunet-service-peerinfo.c
40gnunet_service_peerinfo_LDADD = \ 51gnunet_service_peerinfo_LDADD = \
41 $(top_builddir)/src/hello/libgnunethello.la \ 52 $(top_builddir)/src/hello/libgnunethello.la \
42 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 53 $(top_builddir)/src/statistics/libgnunetstatistics.la \
43 $(top_builddir)/src/util/libgnunetutil.la 54 $(top_builddir)/src/util/libgnunetutil.la
55
56
57libgnunet_plugin_rest_peerinfo_la_SOURCES = \
58 plugin_rest_peerinfo.c
59libgnunet_plugin_rest_peerinfo_la_LIBADD = \
60 libgnunetpeerinfo.la \
61 $(top_builddir)/src/rest/libgnunetrest.la \
62 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \
63 $(LTLIBINTL) -ljansson -lmicrohttpd
64libgnunet_plugin_rest_peerinfo_la_LDFLAGS = \
65 $(GN_PLUGIN_LDFLAGS)
44 66
45if HAVE_BENCHMARKS 67if HAVE_BENCHMARKS
46 PEERINFO_BENCHMARKS = \ 68 PEERINFO_BENCHMARKS = \
diff --git a/src/peerinfo/plugin_rest_peerinfo.c b/src/peerinfo/plugin_rest_peerinfo.c
new file mode 100644
index 000000000..97c473e36
--- /dev/null
+++ b/src/peerinfo/plugin_rest_peerinfo.c
@@ -0,0 +1,801 @@
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/**
19 * @author Martin Schanzenbach
20 * @author Philippe Buschmann
21 * @file peerinfo/plugin_rest_peerinfo.c
22 * @brief GNUnet Peerinfo REST plugin
23 */
24
25#include "platform.h"
26#include "gnunet_rest_plugin.h"
27#include "gnunet_peerinfo_service.h"
28#include "gnunet_transport_service.h"
29#include "gnunet_rest_lib.h"
30#include "gnunet_json_lib.h"
31#include "microhttpd.h"
32#include <jansson.h>
33
34#define GNUNET_REST_API_NS_PEERINFO "/peerinfo"
35
36#define GNUNET_REST_API_PEERINFO_PEER "peer"
37#define GNUNET_REST_API_PEERINFO_FRIEND "friend"
38#define GNUNET_REST_API_PEERINFO_ARRAY "array"
39
40#define GNUNET_REST_ERROR_UNKNOWN "Unkown Error"
41
42/**
43 * How long until we time out during address lookup?
44 */
45#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
46/**
47 * The configuration handle
48 */
49const struct GNUNET_CONFIGURATION_Handle *cfg;
50
51/**
52 * HTTP methods allows for this plugin
53 */
54static char* allow_methods;
55
56/**
57 * @brief struct returned by the initialization function of the plugin
58 */
59struct Plugin
60{
61 const struct GNUNET_CONFIGURATION_Handle *cfg;
62};
63
64
65/**
66 * Record we keep for each printable address.
67 */
68struct AddressRecord
69{
70 /**
71 * Current address-to-string context (if active, otherwise NULL).
72 */
73 struct GNUNET_TRANSPORT_AddressToStringContext *atsc;
74
75 /**
76 * Address expiration time
77 */
78 struct GNUNET_TIME_Absolute expiration;
79
80 /**
81 * Printable address.
82 */
83 char *result;
84
85 /**
86 * Print context this address record belongs to.
87 */
88 struct PrintContext *pc;
89};
90
91
92/**
93 * Structure we use to collect printable address information.
94 */
95struct PrintContext
96{
97
98 /**
99 * Kept in DLL.
100 */
101 struct PrintContext *next;
102
103 /**
104 * Kept in DLL.
105 */
106 struct PrintContext *prev;
107
108 /**
109 * Identity of the peer.
110 */
111 struct GNUNET_PeerIdentity peer;
112
113 /**
114 * List of printable addresses.
115 */
116 struct AddressRecord *address_list;
117
118 /**
119 * Number of completed addresses in @e address_list.
120 */
121 unsigned int num_addresses;
122
123 /**
124 * Number of addresses allocated in @e address_list.
125 */
126 unsigned int address_list_size;
127
128 /**
129 * Current offset in @e address_list (counted down).
130 */
131 unsigned int off;
132
133 /**
134 * Hello was friend only, #GNUNET_YES or #GNUNET_NO
135 */
136 int friend_only;
137
138 /**
139 * RequestHandle
140 */
141 struct RequestHandle *handle;
142
143};
144
145/**
146 * Head of list of print contexts.
147 */
148static struct PrintContext *pc_head;
149
150/**
151 * Tail of list of print contexts.
152 */
153static struct PrintContext *pc_tail;
154
155struct RequestHandle
156{
157 /**
158 * JSON temporary array
159 */
160 json_t *temp_array;
161
162 /**
163 * Expiration time string
164 */
165 char *expiration_str;
166
167 /**
168 * Address string
169 */
170 const char *address;
171
172 /**
173 * Iteration peer public key
174 */
175 char *pubkey;
176
177 /**
178 * JSON response
179 */
180 json_t *response;
181
182 /**
183 * Handle to PEERINFO it
184 */
185 struct GNUNET_PEERINFO_IteratorContext *list_it;
186
187 /**
188 * Handle to PEERINFO
189 */
190 struct GNUNET_PEERINFO_Handle *peerinfo_handle;
191
192 /**
193 * Rest connection
194 */
195 struct GNUNET_REST_RequestHandle *rest_handle;
196
197 /**
198 * Desired timeout for the lookup (default is no timeout).
199 */
200 struct GNUNET_TIME_Relative timeout;
201
202 /**
203 * ID of a task associated with the resolution process.
204 */
205 struct GNUNET_SCHEDULER_Task *timeout_task;
206
207 /**
208 * The plugin result processor
209 */
210 GNUNET_REST_ResultProcessor proc;
211
212 /**
213 * The closure of the result processor
214 */
215 void *proc_cls;
216
217 /**
218 * The url
219 */
220 char *url;
221
222 /**
223 * Error response message
224 */
225 char *emsg;
226
227 /**
228 * Reponse code
229 */
230 int response_code;
231
232};
233
234
235/**
236 * Cleanup lookup handle
237 * @param handle Handle to clean up
238 */
239static void
240cleanup_handle (void *cls)
241{
242 struct RequestHandle *handle = cls;
243
244 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
245 "Cleaning up\n");
246 if (NULL != handle->timeout_task)
247 {
248 GNUNET_SCHEDULER_cancel (handle->timeout_task);
249 handle->timeout_task = NULL;
250 }
251 if (NULL != handle->url)
252 GNUNET_free (handle->url);
253 if (NULL != handle->emsg)
254 GNUNET_free (handle->emsg);
255 if (NULL != handle->address)
256 GNUNET_free ((char*)handle->address);
257 if (NULL != handle->expiration_str)
258 GNUNET_free (handle->expiration_str);
259 if (NULL != handle->pubkey)
260 GNUNET_free (handle->pubkey);
261
262 if (NULL != handle->temp_array)
263 {
264 json_decref(handle->temp_array);
265 handle->temp_array = NULL;
266 }
267 if (NULL != handle->response)
268 {
269 json_decref(handle->response);
270 handle->response = NULL;
271 }
272
273 if (NULL != handle->list_it)
274 {
275 GNUNET_PEERINFO_iterate_cancel(handle->list_it);
276 handle->list_it = NULL;
277 }
278 if (NULL != handle->peerinfo_handle)
279 {
280 GNUNET_PEERINFO_disconnect(handle->peerinfo_handle);
281 handle->peerinfo_handle = NULL;
282 }
283
284 GNUNET_free (handle);
285}
286
287
288/**
289 * Task run on errors. Reports an error and cleans up everything.
290 *
291 * @param cls the `struct RequestHandle`
292 */
293static void
294do_error (void *cls)
295{
296 struct RequestHandle *handle = cls;
297 struct MHD_Response *resp;
298 json_t *json_error = json_object();
299 char *response;
300
301 if (NULL == handle->emsg)
302 handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_UNKNOWN);
303
304 json_object_set_new(json_error,"error", json_string(handle->emsg));
305
306 if (0 == handle->response_code)
307 handle->response_code = MHD_HTTP_OK;
308 response = json_dumps (json_error, 0);
309 resp = GNUNET_REST_create_response (response);
310 handle->proc (handle->proc_cls, resp, handle->response_code);
311 json_decref(json_error);
312 GNUNET_free(response);
313 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
314}
315
316
317/**
318 * Function that assembles our response.
319 */
320static void
321peerinfo_list_finished (void *cls)
322{
323 struct RequestHandle *handle = cls;
324 char *result_str;
325 struct MHD_Response *resp;
326
327 if (NULL == handle->response)
328 {
329 handle->emsg = GNUNET_strdup ("No peers found");
330 GNUNET_SCHEDULER_add_now (&do_error, handle);
331 return;
332 }
333
334 result_str = json_dumps (handle->response, 0);
335 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
336 resp = GNUNET_REST_create_response (result_str);
337 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
338 GNUNET_free_non_null (result_str);
339 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
340}
341
342
343/**
344 * Iterator callback to go over all addresses and count them.
345 *
346 * @param cls `struct PrintContext *` with `off` to increment
347 * @param address the address
348 * @param expiration expiration time
349 * @return #GNUNET_OK to keep the address and continue
350 */
351static int
352count_address (void *cls,
353 const struct GNUNET_HELLO_Address *address,
354 struct GNUNET_TIME_Absolute expiration)
355{
356 struct PrintContext *pc = cls;
357
358 if (0 == GNUNET_TIME_absolute_get_remaining (expiration).rel_value_us)
359 {
360 return GNUNET_OK; /* ignore expired address */
361 }
362
363 pc->off++;
364 return GNUNET_OK;
365}
366
367
368/**
369 * Print the collected address information to the console and free @a pc.
370 *
371 * @param pc printing context
372 */
373static void
374dump_pc (struct PrintContext *pc)
375{
376 struct RequestHandle *handle;
377 unsigned int i;
378 json_t *response_entry;
379 json_t *temp_array;
380 json_t *object;
381 json_t *address;
382 json_t *expires;
383 json_t *friend_and_peer_json;
384 char *friend_and_peer;
385
386 temp_array = json_array();
387 response_entry = json_object();
388
389// printf (_("%sPeer `%s'\n"),
390// (GNUNET_YES == pc->friend_only) ? "F2F: " : "",
391// GNUNET_i2s_full (&pc->peer));
392 for (i = 0; i < pc->num_addresses; i++)
393 {
394 if (NULL != pc->address_list[i].result)
395 {
396 object = json_object ();
397 address = json_string(pc->address_list[i].result);
398 expires = json_string(
399 GNUNET_STRINGS_absolute_time_to_string (pc->address_list[i].expiration));
400 json_object_set (object, "address", address);
401 json_object_set (object, "expires", expires);
402
403 json_decref(address);
404 json_decref(expires);
405
406 json_array_append(temp_array, object);
407 json_decref(object);
408 GNUNET_free (pc->address_list[i].result);
409 }
410 }
411
412 if (0 < json_array_size(temp_array))
413 {
414 GNUNET_asprintf(&friend_and_peer,
415 "%s%s",
416 (GNUNET_YES == pc->friend_only) ? "F2F:" : "",
417 GNUNET_i2s_full (&pc->peer));
418 friend_and_peer_json = json_string(friend_and_peer);
419 json_object_set(response_entry,
420 GNUNET_REST_API_PEERINFO_PEER,
421 friend_and_peer_json);
422 json_object_set(response_entry,
423 GNUNET_REST_API_PEERINFO_ARRAY,
424 temp_array);
425 json_array_append(pc->handle->response, response_entry);
426 json_decref(friend_and_peer_json);
427 GNUNET_free(friend_and_peer);
428 }
429
430 json_decref (temp_array);
431 json_decref(response_entry);
432
433 GNUNET_free_non_null (pc->address_list);
434 GNUNET_CONTAINER_DLL_remove (pc_head,
435 pc_tail,
436 pc);
437 handle = pc->handle;
438 GNUNET_free (pc);
439
440 if ( (NULL == pc_head) &&
441 (NULL == handle->list_it) )
442 {
443 GNUNET_SCHEDULER_add_now (&peerinfo_list_finished, handle);
444 }
445
446}
447
448
449/**
450 * Function to call with a human-readable format of an address
451 *
452 * @param cls closure
453 * @param address NULL on error, otherwise 0-terminated printable UTF-8 string
454 * @param res result of the address to string conversion:
455 * if #GNUNET_OK: address was valid (conversion to
456 * string might still have failed)
457 * if #GNUNET_SYSERR: address is invalid
458 */
459static void
460process_resolved_address (void *cls,
461 const char *address,
462 int res)
463{
464 struct AddressRecord *ar = cls;
465 struct PrintContext *pc = ar->pc;
466
467 if (NULL != address)
468 {
469 if (0 != strlen (address))
470 {
471 if (NULL != ar->result)
472 GNUNET_free (ar->result);
473 ar->result = GNUNET_strdup (address);
474 }
475 return;
476 }
477 ar->atsc = NULL;
478 if (GNUNET_SYSERR == res)
479 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
480 _("Failure: Cannot convert address to string for peer `%s'\n"),
481 GNUNET_i2s (&ar->pc->peer));
482 pc->num_addresses++;
483 if (pc->num_addresses == pc->address_list_size)
484 dump_pc (ar->pc);
485}
486
487
488/**
489 * Iterator callback to go over all addresses.
490 *
491 * @param cls closure
492 * @param address the address
493 * @param expiration expiration time
494 * @return #GNUNET_OK to keep the address and continue
495 */
496static int
497print_address (void *cls,
498 const struct GNUNET_HELLO_Address *address,
499 struct GNUNET_TIME_Absolute expiration)
500{
501 struct PrintContext *pc = cls;
502 struct AddressRecord *ar;
503
504 if (0 == GNUNET_TIME_absolute_get_remaining (expiration).rel_value_us)
505 {
506 return GNUNET_OK; /* ignore expired address */
507 }
508
509 GNUNET_assert (0 < pc->off);
510 ar = &pc->address_list[--pc->off];
511 ar->pc = pc;
512 ar->expiration = expiration;
513 GNUNET_asprintf (&ar->result,
514 "%s:%u:%u",
515 address->transport_name,
516 address->address_length,
517 address->local_info);
518 ar->atsc = GNUNET_TRANSPORT_address_to_string (cfg,
519 address,
520 GNUNET_NO,
521 TIMEOUT,
522 &process_resolved_address,
523 ar);
524 return GNUNET_OK;
525}
526
527
528/**
529 * Callback that processes each of the known HELLOs for the
530 * iteration response construction.
531 *
532 * @param cls closure, NULL
533 * @param peer id of the peer, NULL for last call
534 * @param hello hello message for the peer (can be NULL)
535 * @param err_msg message
536 */
537void
538peerinfo_list_iteration(void *cls,
539 const struct GNUNET_PeerIdentity *peer,
540 const struct GNUNET_HELLO_Message *hello,
541 const char *err_msg)
542{
543 struct RequestHandle *handle = cls;
544 struct PrintContext *pc;
545 int friend_only;
546
547 if (NULL == handle->response)
548 {
549 handle->response = json_array();
550 }
551
552 if (NULL == peer)
553 {
554 handle->list_it = NULL;
555 handle->emsg = GNUNET_strdup ("Error in communication with peerinfo");
556 if (NULL != err_msg)
557 {
558 GNUNET_free(handle->emsg);
559 handle->emsg = GNUNET_strdup (err_msg);
560 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
561 }
562 if (NULL == pc_head)
563 GNUNET_SCHEDULER_add_now (&do_error, handle);
564 return;
565 }
566 if (NULL == hello)
567 return;
568
569 friend_only = GNUNET_NO;
570 if (NULL != hello)
571 friend_only = GNUNET_HELLO_is_friend_only (hello);
572
573 pc = GNUNET_new(struct PrintContext);
574 GNUNET_CONTAINER_DLL_insert (pc_head,
575 pc_tail,
576 pc);
577 pc->peer = *peer;
578 pc->friend_only = friend_only;
579 pc->handle = handle;
580 GNUNET_HELLO_iterate_addresses (hello,
581 GNUNET_NO,
582 &count_address,
583 pc);
584 if (0 == pc->off)
585 {
586 dump_pc (pc);
587 return;
588 }
589 pc->address_list_size = pc->off;
590 pc->address_list = GNUNET_malloc(
591 sizeof(struct AddressRecord) * pc->off);
592 GNUNET_HELLO_iterate_addresses (hello,
593 GNUNET_NO,
594 &print_address,
595 pc);
596}
597
598/**
599 * Handle peerinfo GET request
600 *
601 * @param con_handle the connection handle
602 * @param url the url
603 * @param cls the RequestHandle
604 */
605void
606peerinfo_get (struct GNUNET_REST_RequestHandle *con_handle,
607 const char* url,
608 void *cls)
609{
610 struct RequestHandle *handle = cls;
611 struct GNUNET_HashCode key;
612 const struct GNUNET_PeerIdentity *specific_peer;
613 GNUNET_PEER_Id peer_id;
614 int include_friend_only;
615 char* include_friend_only_str;
616
617 include_friend_only = GNUNET_NO;
618 GNUNET_CRYPTO_hash (GNUNET_REST_API_PEERINFO_FRIEND,
619 strlen (GNUNET_REST_API_PEERINFO_FRIEND),
620 &key);
621 if ( GNUNET_YES
622 == GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map,
623 &key))
624 {
625 include_friend_only_str = GNUNET_CONTAINER_multihashmap_get (
626 con_handle->url_param_map, &key);
627 if (0 == strcmp(include_friend_only_str, "yes"))
628 {
629 include_friend_only = GNUNET_YES;
630 }
631 }
632
633 specific_peer = NULL;
634 GNUNET_CRYPTO_hash (GNUNET_REST_API_PEERINFO_PEER,
635 strlen (GNUNET_REST_API_PEERINFO_PEER),
636 &key);
637 if ( GNUNET_YES
638 == GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map,
639 &key))
640 {
641 peer_id = *(unsigned int*)GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map, &key);
642 specific_peer = GNUNET_PEER_resolve2(peer_id);
643 }
644
645 handle->list_it = GNUNET_PEERINFO_iterate(handle->peerinfo_handle,
646 include_friend_only,
647 specific_peer,
648 &peerinfo_list_iteration,
649 handle);
650}
651
652
653
654/**
655 * Respond to OPTIONS request
656 *
657 * @param con_handle the connection handle
658 * @param url the url
659 * @param cls the RequestHandle
660 */
661static void
662options_cont (struct GNUNET_REST_RequestHandle *con_handle,
663 const char* url,
664 void *cls)
665{
666 struct MHD_Response *resp;
667 struct RequestHandle *handle = cls;
668
669 //independent of path return all options
670 resp = GNUNET_REST_create_response (NULL);
671 MHD_add_response_header (resp,
672 "Access-Control-Allow-Methods",
673 allow_methods);
674 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
675 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
676 return;
677}
678
679
680/**
681 * Handle rest request
682 *
683 * @param handle the request handle
684 */
685static void
686init_cont (struct RequestHandle *handle)
687{
688 struct GNUNET_REST_RequestHandlerError err;
689 static const struct GNUNET_REST_RequestHandler handlers[] = {
690 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_PEERINFO, &peerinfo_get},
691 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_PEERINFO, &options_cont},
692 GNUNET_REST_HANDLER_END
693 };
694
695 if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle,
696 handlers,
697 &err,
698 handle))
699 {
700 handle->response_code = err.error_code;
701 GNUNET_SCHEDULER_add_now (&do_error, handle);
702 }
703}
704
705
706/**
707 * Function processing the REST call
708 *
709 * @param method HTTP method
710 * @param url URL of the HTTP request
711 * @param data body of the HTTP request (optional)
712 * @param data_size length of the body
713 * @param proc callback function for the result
714 * @param proc_cls closure for callback function
715 * @return GNUNET_OK if request accepted
716 */
717static void
718rest_process_request(struct GNUNET_REST_RequestHandle *rest_handle,
719 GNUNET_REST_ResultProcessor proc,
720 void *proc_cls)
721{
722 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
723
724 handle->response_code = 0;
725 handle->timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60);
726 handle->proc_cls = proc_cls;
727 handle->proc = proc;
728 handle->rest_handle = rest_handle;
729
730 handle->url = GNUNET_strdup (rest_handle->url);
731 if (handle->url[strlen (handle->url)-1] == '/')
732 handle->url[strlen (handle->url)-1] = '\0';
733 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n");
734 handle->peerinfo_handle = GNUNET_PEERINFO_connect(cfg);
735 init_cont(handle);
736 handle->timeout_task =
737 GNUNET_SCHEDULER_add_delayed (handle->timeout,
738 &do_error,
739 handle);
740
741 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected\n");
742}
743
744
745/**
746 * Entry point for the plugin.
747 *
748 * @param cls Config info
749 * @return NULL on error, otherwise the plugin context
750 */
751void *
752libgnunet_plugin_rest_peerinfo_init (void *cls)
753{
754 static struct Plugin plugin;
755 struct GNUNET_REST_Plugin *api;
756
757 cfg = cls;
758 if (NULL != plugin.cfg)
759 return NULL; /* can only initialize once! */
760 memset (&plugin, 0, sizeof (struct Plugin));
761 plugin.cfg = cfg;
762 api = GNUNET_new (struct GNUNET_REST_Plugin);
763 api->cls = &plugin;
764 api->name = GNUNET_REST_API_NS_PEERINFO;
765 api->process_request = &rest_process_request;
766 GNUNET_asprintf (&allow_methods,
767 "%s, %s, %s, %s, %s",
768 MHD_HTTP_METHOD_GET,
769 MHD_HTTP_METHOD_POST,
770 MHD_HTTP_METHOD_PUT,
771 MHD_HTTP_METHOD_DELETE,
772 MHD_HTTP_METHOD_OPTIONS);
773
774 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
775 _("Peerinfo REST API initialized\n"));
776 return api;
777}
778
779
780/**
781 * Exit point from the plugin.
782 *
783 * @param cls the plugin context (as returned by "init")
784 * @return always NULL
785 */
786void *
787libgnunet_plugin_rest_peerinfo_done (void *cls)
788{
789 struct GNUNET_REST_Plugin *api = cls;
790 struct Plugin *plugin = api->cls;
791 plugin->cfg = NULL;
792
793 GNUNET_free_non_null (allow_methods);
794 GNUNET_free (api);
795 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
796 "Peerinfo REST plugin is finished\n");
797 return NULL;
798}
799
800/* end of plugin_rest_peerinfo.c */
801