summaryrefslogtreecommitdiff
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)
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 @@
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Affero General Public License for more details.
-
+
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
- * @author Martin Schanzenbach
+ * @author Philippe Buschmann
* @file gns/plugin_rest_gns.c
- * @brief GNUnet GNS REST plugin
- *
+ * @brief GNUnet Gns REST plugin
*/
#include "platform.h"
#include "gnunet_rest_plugin.h"
-#include <gnunet_dnsparser_lib.h>
-#include <gnunet_identity_service.h>
-#include <gnunet_gnsrecord_lib.h>
-#include <gnunet_namestore_service.h>
-#include <gnunet_gns_service.h>
-#include <gnunet_rest_lib.h>
-#include <gnunet_jsonapi_lib.h>
-#include <gnunet_jsonapi_util.h>
+#include "gnunet_rest_lib.h"
+#include "gnunet_json_lib.h"
+#include "gnunet_gnsrecord_lib.h"
+#include "gnunet_gns_service.h"
+#include "microhttpd.h"
#include <jansson.h>
#define GNUNET_REST_API_NS_GNS "/gns"
-#define GNUNET_REST_JSONAPI_GNS_RECORD_TYPE "record_type"
-
-#define GNUNET_REST_JSONAPI_GNS_TYPEINFO "gns_name"
-#define GNUNET_REST_JSONAPI_GNS_RECORD "records"
+#define GNUNET_REST_GNS_PARAM_NAME "name"
-#define GNUNET_REST_JSONAPI_GNS_EGO "ego"
+#define GNUNET_REST_GNS_PARAM_RECORD_TYPE "record_type"
+#define GNUNET_REST_GNS_ERROR_UNKNOWN "Unknown Error"
-#define GNUNET_REST_JSONAPI_GNS_PKEY "pkey"
+/**
+ * The configuration handle
+ */
+const struct GNUNET_CONFIGURATION_Handle *cfg;
-#define GNUNET_REST_JSONAPI_GNS_OPTIONS "options"
+/**
+ * HTTP methods allows for this plugin
+ */
+static char* allow_methods;
/**
* @brief struct returned by the initialization function of the plugin
@@ -56,54 +56,44 @@ struct Plugin
const struct GNUNET_CONFIGURATION_Handle *cfg;
};
-const struct GNUNET_CONFIGURATION_Handle *cfg;
-struct LookupHandle
+struct RequestHandle
{
- /**
- * Handle to GNS service.
- */
- struct GNUNET_GNS_Handle *gns;
/**
- * Desired timeout for the lookup (default is no timeout).
+ * Connection to GNS
*/
- struct GNUNET_TIME_Relative timeout;
+ struct GNUNET_GNS_Handle *gns;
/**
- * Handle to lookup request
+ * Active GNS lookup
*/
- struct GNUNET_GNS_LookupRequest *lookup_request;
+ struct GNUNET_GNS_LookupWithTldRequest *gns_lookup;
/**
- * Handle to rest request
+ * Name to look up
*/
- struct GNUNET_REST_RequestHandle *rest_handle;
+ char *name;
/**
- * Lookup an ego with the identity service.
+ * Record type to look up
*/
- struct GNUNET_IDENTITY_EgoLookup *el;
+ int record_type;
/**
- * Handle for identity service.
+ * Rest connection
*/
- struct GNUNET_IDENTITY_Handle *identity;
-
+ struct GNUNET_REST_RequestHandle *rest_handle;
+
/**
- * Active operation on identity service.
+ * Desired timeout for the lookup (default is no timeout).
*/
- struct GNUNET_IDENTITY_Operation *id_op;
+ struct GNUNET_TIME_Relative timeout;
/**
* ID of a task associated with the resolution process.
*/
- struct GNUNET_SCHEDULER_Task * timeout_task;
-
- /**
- * The root of the received JSON or NULL
- */
- json_t *json_root;
+ struct GNUNET_SCHEDULER_Task *timeout_task;
/**
* The plugin result processor
@@ -116,49 +106,17 @@ struct LookupHandle
void *proc_cls;
/**
- * The name to look up
- */
- char *name;
-
- /**
- * The ego to use
- * In string representation from JSON
- */
- const char *ego_str;
-
- /**
- * The Pkey to use
- * In string representation from JSON
- */
- const char *pkey_str;
-
- /**
- * The record type
+ * The url
*/
- int type;
+ char *url;
/**
- * The public key of to use for lookup
+ * Error response message
*/
- struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
+ char *emsg;
/**
- * The public key to use for lookup
- */
- struct GNUNET_CRYPTO_EcdsaPublicKey pkeym;
-
- /**
- * The resolver options
- */
- enum GNUNET_GNS_LocalOptions options;
-
- /**
- * the shorten key
- */
- struct GNUNET_CRYPTO_EcdsaPrivateKey shorten_key;
-
- /**
- * HTTP response code
+ * Reponse code
*/
int response_code;
@@ -166,39 +124,20 @@ struct LookupHandle
/**
- * Cleanup lookup handle.
- *
+ * Cleanup lookup handle
* @param handle Handle to clean up
*/
static void
-cleanup_handle (struct LookupHandle *handle)
+cleanup_handle (void *cls)
{
+ struct RequestHandle *handle = cls;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Cleaning up\n");
- if (NULL != handle->json_root)
- json_decref (handle->json_root);
- if (NULL != handle->name)
- GNUNET_free (handle->name);
- if (NULL != handle->el)
- {
- GNUNET_IDENTITY_ego_lookup_cancel (handle->el);
- handle->el = NULL;
- }
- if (NULL != handle->id_op)
- {
- GNUNET_IDENTITY_cancel (handle->id_op);
- handle->id_op = NULL;
- }
- if (NULL != handle->lookup_request)
- {
- GNUNET_GNS_lookup_cancel (handle->lookup_request);
- handle->lookup_request = NULL;
- }
- if (NULL != handle->identity)
+ if (NULL != handle->gns_lookup)
{
- GNUNET_IDENTITY_disconnect (handle->identity);
- handle->identity = NULL;
+ GNUNET_GNS_lookup_with_tld_cancel (handle->gns_lookup);
+ handle->gns_lookup = NULL;
}
if (NULL != handle->gns)
{
@@ -209,387 +148,181 @@ cleanup_handle (struct LookupHandle *handle)
if (NULL != handle->timeout_task)
{
GNUNET_SCHEDULER_cancel (handle->timeout_task);
+ handle->timeout_task = NULL;
}
+ if (NULL != handle->url)
+ GNUNET_free (handle->url);
+ if (NULL != handle->name)
+ GNUNET_free (handle->name);
+ if (NULL != handle->emsg)
+ GNUNET_free (handle->emsg);
+
GNUNET_free (handle);
}
/**
- * Task run on shutdown. Cleans up everything.
+ * Task run on errors. Reports an error and cleans up everything.
*
- * @param cls unused
- * @param tc scheduler context
+ * @param cls the `struct RequestHandle`
*/
static void
do_error (void *cls)
{
- struct LookupHandle *handle = cls;
+ struct RequestHandle *handle = cls;
struct MHD_Response *resp;
+ json_t *json_error = json_object();
+ char *response;
- resp = GNUNET_REST_create_response (NULL);
- handle->proc (handle->proc_cls, resp, handle->response_code);
- cleanup_handle (handle);
-}
-
+ if (NULL == handle->emsg)
+ handle->emsg = GNUNET_strdup(GNUNET_REST_GNS_ERROR_UNKNOWN);
-/**
- * Create json representation of a GNSRECORD
- *
- * @param rd the GNSRECORD_Data
- */
-static json_t *
-gnsrecord_to_json (const struct GNUNET_GNSRECORD_Data *rd)
-{
- const char *typename;
- char *string_val;
- const char *exp_str;
- json_t *record_obj;
-
- typename = GNUNET_GNSRECORD_number_to_typename (rd->record_type);
- string_val = GNUNET_GNSRECORD_value_to_string (rd->record_type,
- rd->data,
- rd->data_size);
+ json_object_set_new(json_error,"error", json_string(handle->emsg));
- if (NULL == string_val)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Record of type %d malformed, skipping\n",
- (int) rd->record_type);
- return NULL;
- }
- record_obj = json_object ();
- json_object_set_new (record_obj, "type", json_string (typename));
- json_object_set_new (record_obj, "value", json_string (string_val));
- GNUNET_free (string_val);
-
- if (GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION & rd->flags)
- {
- struct GNUNET_TIME_Relative time_rel;
- time_rel.rel_value_us = rd->expiration_time;
- exp_str = GNUNET_STRINGS_relative_time_to_string (time_rel, 1);
- }
- else
- {
- struct GNUNET_TIME_Absolute time_abs;
- time_abs.abs_value_us = rd->expiration_time;
- exp_str = GNUNET_STRINGS_absolute_time_to_string (time_abs);
- }
- json_object_set_new (record_obj, "expiration_time", json_string (exp_str));
-
- json_object_set_new (record_obj, "expired",
- json_boolean (GNUNET_YES == GNUNET_GNSRECORD_is_expired (rd)));
- return record_obj;
-}
-
-
-static void
-do_cleanup (void *cls)
-{
- struct LookupHandle *handle = cls;
- cleanup_handle (handle);
+ if (0 == handle->response_code)
+ handle->response_code = MHD_HTTP_OK;
+ response = json_dumps (json_error, 0);
+ resp = GNUNET_REST_create_response (response);
+ handle->proc (handle->proc_cls, resp, handle->response_code);
+ json_decref(json_error);
+ GNUNET_free(response);
+ GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
}
/**
- * Function called with the result of a GNS lookup.
+ * Iterator called on obtained result for a GNS lookup.
*
- * @param cls the 'const char *' name that was resolved
- * @param rd_count number of records returned
- * @param rd array of @a rd_count records with the results
+ * @param cls closure with the object
+ * @param was_gns #GNUNET_NO if name was not a GNS name
+ * @param rd_count number of records in @a rd
+ * @param rd the records in reply
*/
static void
-process_lookup_result (void *cls, uint32_t rd_count,
- const struct GNUNET_GNSRECORD_Data *rd)
+handle_gns_response (void *cls,
+ int was_gns,
+ uint32_t rd_count,
+ const struct GNUNET_GNSRECORD_Data *rd)
{
- struct LookupHandle *handle = cls;
+ struct RequestHandle *handle = cls;
struct MHD_Response *resp;
- struct GNUNET_JSONAPI_Document *json_document;
- struct GNUNET_JSONAPI_Resource *json_resource;
- uint32_t i;
- char *result;
json_t *result_array;
json_t *record_obj;
+ char *result;
+
+ handle->gns_lookup = NULL;
+
+ if (GNUNET_NO == was_gns)
+ {
+ handle->emsg = GNUNET_strdup("Name not found in GNS");
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ return;
+ }
result_array = json_array();
- json_document = GNUNET_JSONAPI_document_new ();
- json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_GNS_TYPEINFO, handle->name);
- handle->lookup_request = NULL;
- for (i=0; i<rd_count; i++)
+ for (uint32_t i=0;i<rd_count;i++)
{
- if ( (rd[i].record_type != handle->type) &&
- (GNUNET_GNSRECORD_TYPE_ANY != handle->type) )
+ if ((rd[i].record_type != handle->record_type) &&
+ (GNUNET_GNSRECORD_TYPE_ANY != handle->record_type) )
+ {
continue;
- record_obj = gnsrecord_to_json (&(rd[i]));
+ }
+
+ record_obj = GNUNET_JSON_from_gns_record(NULL,&rd[i]);
json_array_append (result_array, record_obj);
json_decref (record_obj);
}
- GNUNET_JSONAPI_resource_add_attr (json_resource,
- GNUNET_REST_JSONAPI_GNS_RECORD,
- result_array);
- GNUNET_JSONAPI_document_resource_add (json_document, json_resource);
- GNUNET_JSONAPI_document_serialize (json_document, &result);
+
+ result = json_dumps(result_array, 0);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result);
- json_decref (result_array);
- GNUNET_JSONAPI_document_delete (json_document);
resp = GNUNET_REST_create_response (result);
handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
GNUNET_free (result);
- GNUNET_SCHEDULER_add_now (&do_cleanup, handle);
+ json_decref (result_array);
+ GNUNET_SCHEDULER_add_now(&cleanup_handle, handle);
}
/**
- * Perform the actual resolution, starting with the zone
- * identified by the given public key and the shorten zone.
+ * Handle gns GET request
*
- * @param pkey public key to use for the zone, can be NULL
+ * @param con_handle the connection handle
+ * @param url the url
+ * @param cls the RequestHandle
*/
-static void
-lookup_with_public_key (struct LookupHandle *handle)
+void
+get_gns_cont (struct GNUNET_REST_RequestHandle *con_handle,
+ const char* url,
+ void *cls)
{
- if (UINT32_MAX == handle->type)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _("Invalid typename specified, assuming `ANY'\n"));
- handle->type = GNUNET_GNSRECORD_TYPE_ANY;
- }
- if (NULL != handle->name)
- {
- handle->lookup_request = GNUNET_GNS_lookup (handle->gns,
- handle->name,
- &handle->pkey,
- handle->type,
- handle->options,
- &process_lookup_result,
- handle);
- }
- else
+ struct RequestHandle *handle = cls;
+ struct GNUNET_HashCode key;
+ char *record_type;
+ char *name;
+
+ GNUNET_CRYPTO_hash (GNUNET_REST_GNS_PARAM_NAME,
+ strlen (GNUNET_REST_GNS_PARAM_NAME),
+ &key);
+ if ( GNUNET_NO
+ == GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map,
+ &key))
{
+ handle->emsg = GNUNET_strdup("Parameter name is missing");
GNUNET_SCHEDULER_add_now (&do_error, handle);
return;
}
-}
-
-
-/**
- * Method called to with the ego we are to use for the lookup,
- * when the ego is determined by a name.
- *
- * @param cls closure (NULL, unused)
- * @param ego ego handle, NULL if not found
- */
-static void
-identity_zone_cb (void *cls,
- const struct GNUNET_IDENTITY_Ego *ego)
-{
- struct LookupHandle *handle = cls;
-
- handle->el = NULL;
- if (NULL == ego)
+ name = GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map,&key);
+ if(0 >= strlen (name))
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _("Ego for not found, cannot perform lookup.\n"));
+ handle->emsg = GNUNET_strdup("Length of parameter name is zero");
GNUNET_SCHEDULER_add_now (&do_error, handle);
return;
}
- else
- {
- GNUNET_IDENTITY_ego_get_public_key (ego, &handle->pkey);
- lookup_with_public_key (handle);
- }
- json_decref(handle->json_root);
-}
-
+ handle->name = GNUNET_strdup(name);
-/**
- * Method called to with the ego we are to use for the lookup,
- * when the ego is the one for the default master zone.
- *
- * @param cls closure (NULL, unused)
- * @param ego ego handle, NULL if not found
- * @param ctx context for application to store data for this ego
- * (during the lifetime of this process, initially NULL)
- * @param name name assigned by the user for this ego,
- * NULL if the user just deleted the ego and it
- * must thus no longer be used
- */
-static void
-identity_master_cb (void *cls,
- struct GNUNET_IDENTITY_Ego *ego,
- void **ctx,
- const char *name)
-{
- const char *dot;
- struct LookupHandle *handle = cls;
-
- handle->id_op = NULL;
- if (NULL == ego)
+ handle->record_type = UINT32_MAX;
+ GNUNET_CRYPTO_hash (GNUNET_REST_GNS_PARAM_RECORD_TYPE,
+ strlen (GNUNET_REST_GNS_PARAM_RECORD_TYPE),
+ &key);
+ if ( GNUNET_YES
+ == GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map,
+ &key))
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _("Ego for `gns-master' not found, cannot perform lookup. Did you run gnunet-gns-import.sh?\n"));
- GNUNET_SCHEDULER_add_now (&do_error, handle);
- return;
+ record_type = GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map, &key);
+ handle->record_type = GNUNET_GNSRECORD_typename_to_number(record_type);
}
- GNUNET_IDENTITY_ego_get_public_key (ego,
- &handle->pkey);
- /* main name is our own master zone, do no look for that in the DHT */
- handle->options = GNUNET_GNS_LO_LOCAL_MASTER;
- /* if the name is of the form 'label.gnu', never go to the DHT */
- dot = NULL;
- if (NULL != handle->name)
- dot = strchr (handle->name, '.');
- if ( (NULL != dot) &&
- (0 == strcasecmp (dot, ".gnu")) )
- handle->options = GNUNET_GNS_LO_NO_DHT;
- lookup_with_public_key (handle);
-}
-
-/**
- * Parse REST uri for name and record type
- *
- * @param url Url to parse
- * @param handle lookup handle to populate
- * @return GNUNET_SYSERR on error
- */
-static int
-parse_url (const char *url, struct LookupHandle *handle)
-{
- char *name;
- char tmp_url[strlen(url)+1];
- char *tok;
-
- strcpy (tmp_url, url);
- tok = strtok ((char*)tmp_url, "/");
- if (NULL == tok)
- return GNUNET_SYSERR;
- name = strtok (NULL, "/");
- if (NULL == name)
- return GNUNET_SYSERR;
- GNUNET_asprintf (&handle->name,
- "%s",
- name);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Got name: %s\n", handle->name);
- return GNUNET_OK;
-}
-
-static void
-get_gns_cont (struct GNUNET_REST_RequestHandle *conndata_handle,
- const char* url,
- void *cls)
-{
- struct LookupHandle *handle = cls;
- struct GNUNET_HashCode key;
- //parse name and type from url
- if (GNUNET_OK != parse_url (url, handle))
+ if(UINT32_MAX == handle->record_type)
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error parsing url...\n");
- GNUNET_SCHEDULER_add_now (&do_error, handle);
- return;
+ handle->record_type = GNUNET_GNSRECORD_TYPE_ANY;
}
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Connecting...\n");
+
handle->gns = GNUNET_GNS_connect (cfg);
- handle->identity = GNUNET_IDENTITY_connect (cfg, NULL, NULL);
- handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout,
- &do_error, handle);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Connected\n");
if (NULL == handle->gns)
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Connecting to GNS failed\n");
+ handle->emsg = GNUNET_strdup ("GNS not available");
GNUNET_SCHEDULER_add_now (&do_error, handle);
return;
}
- GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_GNS_OPTIONS,
- strlen (GNUNET_REST_JSONAPI_GNS_OPTIONS),
- &key);
- handle->options = GNUNET_GNS_LO_DEFAULT;
- if ( GNUNET_YES ==
- GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map,
- &key) )
- {
- handle->options = GNUNET_GNS_LO_DEFAULT;//TODO(char*) GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map,
- //&key);
- }
- GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_GNS_RECORD_TYPE,
- strlen (GNUNET_REST_JSONAPI_GNS_RECORD_TYPE),
- &key);
- if ( GNUNET_YES ==
- GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map,
- &key) )
- {
- handle->type = GNUNET_GNSRECORD_typename_to_number
- (GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map,
- &key));
- }
- else
- handle->type = GNUNET_GNSRECORD_TYPE_ANY;
- GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_GNS_PKEY,
- strlen (GNUNET_REST_JSONAPI_GNS_PKEY),
- &key);
- if ( GNUNET_YES ==
- GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map,
- &key) )
- {
- handle->pkey_str = GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map,
- &key);
- GNUNET_assert (NULL != handle->pkey_str);
- if (GNUNET_OK !=
- GNUNET_CRYPTO_ecdsa_public_key_from_string (handle->pkey_str,
- strlen(handle->pkey_str),
- &(handle->pkey)))
- {
- GNUNET_SCHEDULER_add_now (&do_error, handle);
- return;
- }
- lookup_with_public_key (handle);
- return;
- }
- GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_GNS_EGO,
- strlen (GNUNET_REST_JSONAPI_GNS_EGO),
- &key);
- if ( GNUNET_YES ==
- GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map,
- &key) )
- {
- handle->ego_str = GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map,
- &key);
- handle->el = GNUNET_IDENTITY_ego_lookup (cfg,
- handle->ego_str,
- &identity_zone_cb,
- handle);
- return;
- }
- if ( (NULL != handle->name) &&
- (strlen (handle->name) > 4) &&
- (0 == strcmp (".zkey",
- &handle->name[strlen (handle->name) - 4])) )
- {
- GNUNET_CRYPTO_ecdsa_key_get_public
- (GNUNET_CRYPTO_ecdsa_key_get_anonymous (),
- &(handle->pkey));
- lookup_with_public_key (handle);
- }
- else
- {
- GNUNET_break (NULL == handle->id_op);
- handle->id_op = GNUNET_IDENTITY_get (handle->identity,
- "gns-master",
- &identity_master_cb,
- handle);
- GNUNET_assert (NULL != handle->id_op);
- }
+ handle->gns_lookup = GNUNET_GNS_lookup_with_tld (handle->gns,
+ handle->name,
+ handle->record_type,
+ GNUNET_NO,
+ &handle_gns_response,
+ handle);
+ return;
}
+
+
/**
- * Handle rest request
+ * Respond to OPTIONS request
*
- * @param handle the lookup handle
+ * @param con_handle the connection handle
+ * @param url the url
+ * @param cls the RequestHandle
*/
static void
options_cont (struct GNUNET_REST_RequestHandle *con_handle,
@@ -597,53 +330,38 @@ options_cont (struct GNUNET_REST_RequestHandle *con_handle,
void *cls)
{
struct MHD_Response *resp;
- struct LookupHandle *handle = cls;
+ struct RequestHandle *handle = cls;
- //For GNS, independent of path return all options
+ //independent of path return all options
resp = GNUNET_REST_create_response (NULL);
MHD_add_response_header (resp,
"Access-Control-Allow-Methods",
- MHD_HTTP_METHOD_GET);
- handle->proc (handle->proc_cls,
- resp,
- MHD_HTTP_OK);
- cleanup_handle (handle);
+ allow_methods);
+ handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
+ GNUNET_SCHEDULER_add_now(&cleanup_handle, handle);
+ return;
}
/**
- * Function processing the REST call
+ * Handle rest request
*
- * @param method HTTP method
- * @param url URL of the HTTP request
- * @param data body of the HTTP request (optional)
- * @param data_size length of the body
- * @param proc callback function for the result
- * @param proc_cls closure for @a proc
- * @return #GNUNET_OK if request accepted
+ * @param handle the request handle
*/
static void
-rest_gns_process_request (struct GNUNET_REST_RequestHandle *conndata_handle,
- GNUNET_REST_ResultProcessor proc,
- void *proc_cls)
+init_cont (struct RequestHandle *handle)
{
+ struct GNUNET_REST_RequestHandlerError err;
static const struct GNUNET_REST_RequestHandler handlers[] = {
{MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_GNS, &get_gns_cont},
{MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_GNS, &options_cont},
GNUNET_REST_HANDLER_END
};
- struct LookupHandle *handle = GNUNET_new (struct LookupHandle);
- struct GNUNET_REST_RequestHandlerError err;
-
- handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
- handle->proc_cls = proc_cls;
- handle->proc = proc;
- handle->rest_handle = conndata_handle;
- if (GNUNET_NO == GNUNET_JSONAPI_handle_request (conndata_handle,
- handlers,
- &err,
- handle))
+ if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle,
+ handlers,
+ &err,
+ handle))
{
handle->response_code = err.error_code;
GNUNET_SCHEDULER_add_now (&do_error, handle);
@@ -652,18 +370,58 @@ rest_gns_process_request (struct GNUNET_REST_RequestHandle *conndata_handle,
/**
+ * Function processing the REST call
+ *
+ * @param method HTTP method
+ * @param url URL of the HTTP request
+ * @param data body of the HTTP request (optional)
+ * @param data_size length of the body
+ * @param proc callback function for the result
+ * @param proc_cls closure for callback function
+ * @return GNUNET_OK if request accepted
+ */
+static void
+rest_process_request(struct GNUNET_REST_RequestHandle *rest_handle,
+ GNUNET_REST_ResultProcessor proc,
+ void *proc_cls)
+{
+ struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
+
+ handle->response_code = 0;
+ handle->timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60);
+ handle->proc_cls = proc_cls;
+ handle->proc = proc;
+ handle->rest_handle = rest_handle;
+
+ handle->url = GNUNET_strdup (rest_handle->url);
+ if (handle->url[strlen (handle->url)-1] == '/')
+ handle->url[strlen (handle->url)-1] = '\0';
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n");
+
+ init_cont(handle);
+
+ handle->timeout_task =
+ GNUNET_SCHEDULER_add_delayed (handle->timeout,
+ &do_error,
+ handle);
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected\n");
+}
+
+
+/**
* Entry point for the plugin.
*
- * @param cls the "struct GNUNET_NAMESTORE_PluginEnvironment*"
+ * @param cls Config info
* @return NULL on error, otherwise the plugin context
*/
void *
libgnunet_plugin_rest_gns_init (void *cls)
{
static struct Plugin plugin;
- cfg = cls;
struct GNUNET_REST_Plugin *api;
+ cfg = cls;
if (NULL != plugin.cfg)
return NULL; /* can only initialize once! */
memset (&plugin, 0, sizeof (struct Plugin));
@@ -671,9 +429,17 @@ libgnunet_plugin_rest_gns_init (void *cls)
api = GNUNET_new (struct GNUNET_REST_Plugin);
api->cls = &plugin;
api->name = GNUNET_REST_API_NS_GNS;
- api->process_request = &rest_gns_process_request;
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- _("GNS REST API initialized\n"));
+ api->process_request = &rest_process_request;
+ GNUNET_asprintf (&allow_methods,
+ "%s, %s, %s, %s, %s",
+ MHD_HTTP_METHOD_GET,
+ MHD_HTTP_METHOD_POST,
+ MHD_HTTP_METHOD_PUT,
+ MHD_HTTP_METHOD_DELETE,
+ MHD_HTTP_METHOD_OPTIONS);
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ _("Gns REST API initialized\n"));
return api;
}
@@ -689,12 +455,14 @@ libgnunet_plugin_rest_gns_done (void *cls)
{
struct GNUNET_REST_Plugin *api = cls;
struct Plugin *plugin = api->cls;
-
plugin->cfg = NULL;
+
+ GNUNET_free_non_null (allow_methods);
GNUNET_free (api);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "GNS REST plugin is finished\n");
+ "Gns REST plugin is finished\n");
return NULL;
}
/* end of plugin_rest_gns.c */
+
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 @@
+#!/usr/bin/bash
+
+#First, start gnunet-arm and the rest-service.
+#Exit 0 means success, exit 1 means failed test
+
+gns_link="http://localhost:7776/gns"
+wrong_link="http://localhost:7776/gnsandmore"
+
+curl_get () {
+ #$1 is link
+ #$2 is grep
+ cache="$(curl -v "$1" 2>&1 | grep "$2")"
+ #echo $cache
+ if [ "" == "$cache" ]
+ then
+ exit 1
+ fi
+}
+
+gnunet-identity -D "test_plugin_rest_gns" > /dev/null 2>&1
+
+curl_get "$gns_link?name=www.test_plugin_rest_gns" "error"
+
+gnunet-identity -C "test_plugin_rest_gns"
+
+curl_get "$gns_link?name=www.test_plugin_rest_gns" "\[\]"
+
+gnunet-namestore -z "test_plugin_rest_gns" -p -a -n www -e 1d -V 1.1.1.1 -t A
+
+curl_get "$gns_link?name=www.test_plugin_rest_gns" "1.1.1.1"
+
+gnunet-namestore -z "test_plugin_rest_gns" -p -a -n www -e 1d -V 1::1 -t AAAA
+
+curl_get "$gns_link?name=www.test_plugin_rest_gns" "1::1.*1.1.1.1"
+
+gnunet-namestore -z "test_plugin_rest_gns" -p -a -n www -e 1d -V 1.1.1.2 -t A
+
+curl_get "$gns_link?name=www.test_plugin_rest_gns" "1.1.1.2.*1::1.*1.1.1.1"
+curl_get "$gns_link?name=www.test_plugin_rest_gns&record_type=A" "1.1.1.2.*1.1.1.1"
+curl_get "$gns_link?name=www.test_plugin_rest_gns&record_type=AAAA" "1::1"
+curl_get "$gns_link?name=www.test_plugin_rest_gns&record_type=WRONG_TYPE" "1.1.1.2.*1::1.*1.1.1.1"
+
+gnunet-namestore -z "test_plugin_rest_gns" -p -a -n www1 -e 1d -V 1.1.1.1 -t A
+curl_get "$gns_link?name=www1.test_plugin_rest_gns" "1.1.1.1"
+
+gnunet-identity -D "test_plugin_rest_gns"
+
+curl_get "$gns_link?name=www1.test_plugin_rest_gns" "error"
+
+exit 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 @@
#include "gnunet_constants.h"
#include "gnunet_gnsrecord_lib.h"
#include "gnunet_gnsrecord_plugin.h"
+#include "gnunet_json_lib.h"
#include "gnunet_tun_lib.h"
+#include <jansson.h>
#define LOG(kind,...) GNUNET_log_from (kind, "gnsrecord",__VA_ARGS__)
@@ -245,5 +247,4 @@ GNUNET_GNSRECORD_number_to_typename (uint32_t type)
return NULL;
}
-
/* 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 = \
libgnunet_plugin_rest_identity_la_LIBADD = \
libgnunetidentity.la \
$(top_builddir)/src/rest/libgnunetrest.la \
- $(top_builddir)/src/jsonapi/libgnunetjsonapi.la \
- $(top_builddir)/src/jsonapi/libgnunetjsonapiutils.la \
$(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \
$(LTLIBINTL) -ljansson -lmicrohttpd
libgnunet_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 @@
/*
- This file is part of GNUnet.
- Copyright (C) 2012-2015 GNUnet e.V.
+ This file is part of GNUnet.
+ Copyright (C) 2012-2015 GNUnet e.V.
GNUnet is free software: you can redistribute it and/or modify it
under the terms of the GNU Affero General Public License as published
@@ -11,74 +11,51 @@
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Affero General Public License for more details.
-
+
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
+ */
/**
* @author Martin Schanzenbach
+ * @author Philippe Buschmann
* @file identity/plugin_rest_identity.c
- * @brief GNUnet Namestore REST plugin
- *
+ * @brief GNUnet Identity REST plugin
*/
#include "platform.h"
#include "gnunet_rest_plugin.h"
#include "gnunet_identity_service.h"
#include "gnunet_rest_lib.h"
-#include "gnunet_jsonapi_lib.h"
-#include "gnunet_jsonapi_util.h"
#include "microhttpd.h"
#include <jansson.h>
-#include "gnunet_signatures.h"
-/**
- * REST root namespace
- */
#define GNUNET_REST_API_NS_IDENTITY "/identity"
/**
- * State while collecting all egos
- */
-#define ID_REST_STATE_INIT 0
-
-/**
- * Done collecting egos
- */
-#define ID_REST_STATE_POST_INIT 1
-
-/**
- * Resource type
- */
-#define GNUNET_REST_JSONAPI_IDENTITY_EGO "ego"
-
-/**
- * Name attribute
- */
-#define GNUNET_REST_JSONAPI_IDENTITY_NAME "name"
-
-/**
- * Attribute to rename "name" TODO we changed id to the pubkey
- * so this can be unified with "name"
- */
-#define GNUNET_REST_JSONAPI_IDENTITY_NEWNAME "newname"
-
-/**
- * URL parameter to change the subsytem for ego
+ * Parameter names
*/
-#define GNUNET_REST_JSONAPI_IDENTITY_SUBSYSTEM "subsystem"
-
+#define GNUNET_REST_PARAM_PUBKEY "pubkey"
+#define GNUNET_REST_PARAM_SUBSYSTEM "subsystem"
+#define GNUNET_REST_PARAM_NAME "name"
+#define GNUNET_REST_PARAM_NEWNAME "newname"
/**
* Error messages
*/
+#define GNUNET_REST_IDENTITY_ERROR_UNKNOWN "Unknown Error"
#define GNUNET_REST_ERROR_RESOURCE_INVALID "Resource location invalid"
#define GNUNET_REST_ERROR_NO_DATA "No data"
+#define GNUNET_REST_ERROR_DATA_INVALID "Data invalid"
/**
- * GNUid token lifetime
+ * State while collecting all egos
*/
-#define GNUNET_GNUID_TOKEN_EXPIRATION_MICROSECONDS 300000000
+#define ID_REST_STATE_INIT 0
+
+/**
+ * Done collecting egos
+ */
+#define ID_REST_STATE_POST_INIT 1
/**
* The configuration handle
@@ -129,28 +106,37 @@ struct EgoEntry
struct GNUNET_IDENTITY_Ego *ego;
};
-
struct RequestHandle
{
/**
- * Ego list
+ * The data from the REST request
*/
- struct EgoEntry *ego_head;
+ const char* data;
/**
- * Ego list
+ * The name to look up
*/
- struct EgoEntry *ego_tail;
+ char *name;
/**
- * Handle to the rest connection
+ * the length of the REST data
*/
- struct GNUNET_REST_RequestHandle *conndata_handle;
+ size_t data_size;
/**
- * response code
+ * Requested Subsystem
*/
- int response_code;
+ char *subsystem;
+
+ /**
+ * Ego list
+ */
+ struct EgoEntry *ego_head;
+
+ /**
+ * Ego list
+ */
+ struct EgoEntry *ego_tail;
/**
* The processing state
@@ -158,7 +144,7 @@ struct RequestHandle
int state;
/**
- * Handle to GNS service.
+ * Handle to Identity service.
*/
struct GNUNET_IDENTITY_Handle *identity_handle;
@@ -168,6 +154,11 @@ struct RequestHandle
struct GNUNET_IDENTITY_Operation *op;
/**
+ * Rest connection
+ */
+ struct GNUNET_REST_RequestHandle *rest_handle;
+
+ /**
* Desired timeout for the lookup (default is no timeout).
*/
struct GNUNET_TIME_Relative timeout;
@@ -175,7 +166,7 @@ struct RequestHandle
/**
* ID of a task associated with the resolution process.
*/
- struct GNUNET_SCHEDULER_Task * timeout_task;
+ struct GNUNET_SCHEDULER_Task *timeout_task;
/**
* The plugin result processor
@@ -188,81 +179,63 @@ struct RequestHandle
void *proc_cls;
/**
- * The name to look up
- */
- char *name;
-
- /**
- * The subsystem set from REST
- */
- char *subsys;
-
- /**
* The url
*/
char *url;
/**
- * The data from the REST request
- */
- const char* data;
-
- /**
- * the length of the REST data
- */
- size_t data_size;
-
- /**
- * HTTP method
+ * Error response message
*/
- const char* method;
+ char *emsg;
/**
- * Error response message
+ * Reponse code
*/
- char *emsg;
+ int response_code;
};
-
/**
* Cleanup lookup handle
* @param handle Handle to clean up
*/
static void
-cleanup_handle (struct RequestHandle *handle)
+cleanup_handle (void *cls)
{
+ struct RequestHandle *handle = cls;
struct EgoEntry *ego_entry;
struct EgoEntry *ego_tmp;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Cleaning up\n");
- if (NULL != handle->name)
- GNUNET_free (handle->name);
+
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
if (NULL != handle->timeout_task)
{
GNUNET_SCHEDULER_cancel (handle->timeout_task);
handle->timeout_task = NULL;
}
- if (NULL != handle->identity_handle)
- GNUNET_IDENTITY_disconnect (handle->identity_handle);
- if (NULL != handle->subsys)
- GNUNET_free (handle->subsys);
+
+ if (NULL != handle->subsystem)
+ GNUNET_free(handle->subsystem);
if (NULL != handle->url)
- GNUNET_free (handle->url);
+ GNUNET_free(handle->url);
if (NULL != handle->emsg)
- GNUNET_free (handle->emsg);
+ GNUNET_free(handle->emsg);
+ if (NULL != handle->name)
+ GNUNET_free (handle->name);
+ if (NULL != handle->identity_handle)
+ GNUNET_IDENTITY_disconnect (handle->identity_handle);
+
for (ego_entry = handle->ego_head;
- NULL != ego_entry;)
+ NULL != ego_entry;)
{
ego_tmp = ego_entry;
ego_entry = ego_entry->next;
- GNUNET_free (ego_tmp->identifier);
- GNUNET_free (ego_tmp->keystring);
- GNUNET_free (ego_tmp);
+ GNUNET_free(ego_tmp->identifier);
+ GNUNET_free(ego_tmp->keystring);
+ GNUNET_free(ego_tmp);
}
- GNUNET_free (handle);
-}
+ GNUNET_free(handle);
+}
/**
* Task run on errors. Reports an error and cleans up everything.
@@ -274,23 +247,67 @@ do_error (void *cls)
{
struct RequestHandle *handle = cls;
struct MHD_Response *resp;
- char *json_error;
-
- GNUNET_asprintf (&json_error,
- "{Error while processing request: %s}",
- &handle->emsg);
-
- resp = GNUNET_REST_create_response (json_error);
- handle->proc (handle->proc_cls,
- resp,
- handle->response_code);
- cleanup_handle (handle);
- GNUNET_free (json_error);
+ json_t *json_error = json_object();
+ char *response;
+
+ if (NULL == handle->emsg)
+ handle->emsg = GNUNET_strdup(GNUNET_REST_IDENTITY_ERROR_UNKNOWN);
+
+ json_object_set_new(json_error,"error", json_string(handle->emsg));
+
+ if (0 == handle->response_code)
+ handle->response_code = MHD_HTTP_OK;
+ response = json_dumps (json_error, 0);
+ resp = GNUNET_REST_create_response (response);
+ handle->proc (handle->proc_cls, resp, handle->response_code);
+ json_decref(json_error);
+ GNUNET_free(response);
+ GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
}
+
/**
- * Callback for IDENTITY_get()
+ * Get EgoEntry from list with either a public key or a name
+ * If public key and name are not NULL, it returns the public key result first
+ *
+ * @param handle the RequestHandle
+ * @param pubkey the public key of an identity (only one can be NULL)
+ * @param name the name of an identity (only one can be NULL)
+ * @return EgoEntry or NULL if not found
+ */
+struct EgoEntry*
+get_egoentry(struct RequestHandle *handle, char* pubkey, char *name)
+{
+ struct EgoEntry *ego_entry;
+ if (NULL != pubkey)
+ {
+ for (ego_entry = handle->ego_head;
+ NULL != ego_entry;
+ ego_entry = ego_entry->next)
+ {
+ if (0 != strcasecmp (pubkey, ego_entry->keystring))
+ continue;
+ return ego_entry;
+ }
+ }
+ if (NULL != name)
+ {
+ for (ego_entry = handle->ego_head;
+ NULL != ego_entry;
+ ego_entry = ego_entry->next)
+ {
+ if (0 != strcasecmp (name, ego_entry->identifier))
+ continue;
+ return ego_entry;
+ }
+ }
+ return NULL;
+}
+
+
+/**
+ * Callback for GET Request with subsystem
*
* @param cls the RequestHandle
* @param ego the Ego found
@@ -298,153 +315,177 @@ do_error (void *cls)
* @param name the id of the ego
*/
static void
-get_ego_for_subsys (void *cls,
- struct GNUNET_IDENTITY_Ego *ego,
- void **ctx,
- const char *name)
+ego_get_for_subsystem (void *cls, struct GNUNET_IDENTITY_Ego *ego, void **ctx,
+ const char *name)
{
struct RequestHandle *handle = cls;
- struct GNUNET_JSONAPI_Document *json_document;
- struct GNUNET_JSONAPI_Resource *json_resource;
- struct EgoEntry *ego_entry;
struct MHD_Response *resp;
- json_t *name_json;
+ struct GNUNET_CRYPTO_EcdsaPublicKey public_key;
+ json_t *json_root;
char *result_str;
+ char *public_key_string;
- json_document = GNUNET_JSONAPI_document_new ();
-
- for (ego_entry = handle->ego_head;
- NULL != ego_entry;
- ego_entry = ego_entry->next)
+ if(NULL == ego)
{
- if ( (NULL != name) && (0 != strcmp (name, ego_entry->identifier)) )
- continue;
- if (NULL == name)
- continue;
- json_resource = GNUNET_JSONAPI_resource_new
- (GNUNET_REST_JSONAPI_IDENTITY_EGO, ego_entry->keystring);
- name_json = json_string (ego_entry->identifier);
- GNUNET_JSONAPI_resource_add_attr (json_resource,
- GNUNET_REST_JSONAPI_IDENTITY_NAME,
- name_json);
- json_decref (name_json);
- GNUNET_JSONAPI_document_resource_add (json_document, json_resource);
- break;
- }
- if (0 == GNUNET_JSONAPI_document_resource_count (json_document))
- {
- GNUNET_JSONAPI_document_delete (json_document);
- handle->emsg = GNUNET_strdup("No identity matches results!");
+ handle->emsg = GNUNET_strdup("No identity found for subsystem");
GNUNET_SCHEDULER_add_now (&do_error, handle);
return;
}
- GNUNET_JSONAPI_document_serialize (json_document, &result_str);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
+
+ GNUNET_IDENTITY_ego_get_public_key(ego,&public_key);
+ public_key_string = GNUNET_CRYPTO_ecdsa_public_key_to_string(&public_key);
+
+ // create json with subsystem identity
+ json_root = json_object ();
+ json_object_set_new (json_root, GNUNET_REST_PARAM_PUBKEY, json_string(public_key_string));
+ json_object_set_new (json_root, GNUNET_REST_PARAM_NAME, json_string(name));
+
+ result_str = json_dumps (json_root, 0);
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
resp = GNUNET_REST_create_response (result_str);
- GNUNET_JSONAPI_document_delete (json_document);
+
+ json_decref (json_root);
handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
- GNUNET_free (result_str);
- cleanup_handle (handle);
+ GNUNET_free(result_str);
+ GNUNET_free(public_key_string);
+ GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
}
/**
- * Create a response with requested ego(s)
+ * Handle identity GET request
*
- * @param con the Rest handle
- * @param url the requested url
- * @param cls the request handle
+ * @param con_handle the connection handle
+ * @param url the url
+ * @param cls the RequestHandle
*/
-static void
-ego_info_response (struct GNUNET_REST_RequestHandle *con,
- const char *url,
- void *cls)
+void
+ego_get (struct GNUNET_REST_RequestHandle *con_handle, const char* url,
+ void *cls)
{
- const char *egoname;
- char *result_str;
- char *subsys_val;
- char *keystring;
struct RequestHandle *handle = cls;
struct EgoEntry *ego_entry;
struct GNUNET_HashCode key;
struct MHD_Response *resp;
- struct GNUNET_JSONAPI_Document *json_document;
- struct GNUNET_JSONAPI_Resource *json_resource;
- json_t *name_str;
+ char *keystring;
+ char *egoname;
+ json_t *json_root;
+ json_t *json_ego;
+ char *result_str;
- if (GNUNET_NO == GNUNET_REST_namespace_match (handle->url, GNUNET_REST_API_NS_IDENTITY))
+ //requested default identity of subsystem
+ GNUNET_CRYPTO_hash (GNUNET_REST_PARAM_SUBSYSTEM,
+ strlen (GNUNET_REST_PARAM_SUBSYSTEM), &key);
+ if ( GNUNET_YES
+ == GNUNET_CONTAINER_multihashmap_contains (
+ handle->rest_handle->url_param_map, &key))
{
- resp = GNUNET_REST_create_response (NULL);
- handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
- cleanup_handle (handle);
+ handle->subsystem = GNUNET_strdup(
+ GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
+ &key));
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Looking for %s's ego\n",
+ handle->subsystem);
+
+ handle->op = GNUNET_IDENTITY_get (handle->identity_handle,
+ handle->subsystem,
+ &ego_get_for_subsystem,
+ handle);
+ if (NULL == handle->op)
+ {
+ handle->emsg = GNUNET_strdup("No identity found for subsystem");
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ return;
+ }
return;
}
egoname = NULL;
keystring = NULL;
- if (strlen (GNUNET_REST_API_NS_IDENTITY) < strlen (handle->url))
+
+ //one identity requested with key
+ GNUNET_CRYPTO_hash (GNUNET_REST_PARAM_PUBKEY,
+ strlen (GNUNET_REST_PARAM_PUBKEY),
+ &key);
+ if ( GNUNET_YES
+ == GNUNET_CONTAINER_multihashmap_contains (
+ handle->rest_handle->url_param_map, &key))
{
- keystring = &handle->url[strlen (GNUNET_REST_API_NS_IDENTITY)+1];
- //Return all egos
- for (ego_entry = handle->ego_head;
- NULL != ego_entry;
- ego_entry = ego_entry->next)
+ keystring = GNUNET_CONTAINER_multihashmap_get (
+ handle->rest_handle->url_param_map, &key);
+
+ ego_entry = get_egoentry(handle, keystring, NULL);
+ if (NULL == ego_entry)
{
- if ( (NULL != keystring) && (0 != strcmp (keystring, ego_entry->keystring)) )
- continue;
- egoname = ego_entry->identifier;
+ handle->emsg = GNUNET_strdup("No identity found for public key");
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ return;
}
+ egoname = ego_entry->identifier;
}
- if ( NULL == egoname ) {
- GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_IDENTITY_SUBSYSTEM,
- strlen (GNUNET_REST_JSONAPI_IDENTITY_SUBSYSTEM),
- &key);
- if ( GNUNET_YES ==
- GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
- &key) )
+ //one identity requested with name
+ if (NULL == egoname)
+ {
+ GNUNET_CRYPTO_hash (GNUNET_REST_PARAM_NAME,
+ strlen (GNUNET_REST_PARAM_NAME),
+ &key);
+ if ( GNUNET_YES
+ == GNUNET_CONTAINER_multihashmap_contains (
+ handle->rest_handle->url_param_map, &key))
{
- subsys_val = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
- &key);
- if (NULL != subsys_val)
+ egoname = GNUNET_CONTAINER_multihashmap_get (
+ handle->rest_handle->url_param_map, &key);
+ if (0 >= strlen(egoname))
{
- GNUNET_asprintf (&handle->subsys, "%s", subsys_val);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Looking for %s's ego\n", subsys_val);
- handle->op = GNUNET_IDENTITY_get (handle->identity_handle,
- handle->subsys,
- &get_ego_for_subsys,
- handle);
+ handle->emsg = GNUNET_strdup("No identity found for name");
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
return;
}
+ //LOWERCASE ego names?
+ GNUNET_STRINGS_utf8_tolower(egoname, egoname);
}
}
- json_document = GNUNET_JSONAPI_document_new ();
-
- //Return all egos
+ json_root = json_array ();
+ //Return ego/egos
for (ego_entry = handle->ego_head;
- NULL != ego_entry;
- ego_entry = ego_entry->next)
+ NULL != ego_entry; ego_entry = ego_entry->next)
{
- if ( (NULL != egoname) && (0 != strcmp (egoname, ego_entry->identifier)) )
- continue;
- json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_EGO,
- ego_entry->keystring);
- name_str = json_string (ego_entry->identifier);
- GNUNET_JSONAPI_resource_add_attr (
- json_resource,
- GNUNET_REST_JSONAPI_IDENTITY_NAME,
- name_str);
- json_decref (name_str);
- GNUNET_JSONAPI_document_resource_add (json_document, json_resource);
+ //if only one ego requested
+ if ((NULL != egoname)){
+ if(0 != strcmp (egoname, ego_entry->identifier)){
+ continue;
+ }
+ }
+
+ json_ego = json_object ();
+ json_object_set_new (json_ego,
+ GNUNET_REST_PARAM_PUBKEY,
+ json_string (ego_entry->keystring));
+ json_object_set_new (json_ego,
+ GNUNET_REST_PARAM_NAME,
+ json_string (ego_entry->identifier));
+ json_array_append (json_root, json_ego);
+ json_decref (json_ego);
+ }
+
+ if ((size_t) 0 == json_array_size (json_root))
+ {
+ json_decref (json_root);
+ handle->emsg = GNUNET_strdup("No identities found!");
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ return;
}
- GNUNET_JSONAPI_document_serialize (json_document, &result_str);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
+
+ result_str = json_dumps (json_root, 0);
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
resp = GNUNET_REST_create_response (result_str);
- GNUNET_JSONAPI_document_delete (json_document);
+
+ json_decref (json_root);
handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
- GNUNET_free (result_str);
- cleanup_handle (handle);
+ GNUNET_free(result_str);
+ GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
}
+
/**
* Processing finished
*
@@ -460,311 +501,363 @@ do_finished (void *cls, const char *emsg)
handle->op = NULL;
if (NULL != emsg)
{
- handle->emsg = GNUNET_strdup (emsg);
+ handle->emsg = GNUNET_strdup(emsg);
GNUNET_SCHEDULER_add_now (&do_error, handle);
return;
}
resp = GNUNET_REST_create_response (NULL);
- handle->proc (handle->proc_cls, resp, MHD_HTTP_NO_CONTENT);
- cleanup_handle (handle);
+ handle->proc (handle->proc_cls, resp, handle->response_code);
+ GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
}
+
/**
- * Create a new ego
+ * Handle identity PUT request
*
- * @param con rest handle
- * @param url url
- * @param cls request handle
+ * @param con_handle the connection handle
+ * @param url the url
+ * @param cls the RequestHandle
*/
-static void
-ego_create_cont (struct GNUNET_REST_RequestHandle *con,
- const char *url,
- void *cls)
+void
+ego_edit (struct GNUNET_REST_RequestHandle *con_handle,
+ const char* url,
+ void *cls)
{
struct RequestHandle *handle = cls;
struct EgoEntry *ego_entry;
+ struct EgoEntry *ego_entry_tmp;
struct MHD_Response *resp;
- struct GNUNET_JSONAPI_Document *json_obj;
- struct GNUNET_JSONAPI_Resource *json_res;
- json_t *egoname_json;
+ int json_state;
json_t *data_js;
json_error_t err;
- const char* egoname;
- char term_data[handle->data_size+1];
- struct GNUNET_JSON_Specification docspec[] = {
- GNUNET_JSON_spec_jsonapi_document (&json_obj),
- GNUNET_JSON_spec_end()
- };
- if (strlen (GNUNET_REST_API_NS_IDENTITY) != strlen (handle->url))
- {
- handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_RESOURCE_INVALID);
- GNUNET_SCHEDULER_add_now (&do_error, handle);
- return;
- }
+ char *pubkey;
+ char *name;
+ char *newsubsys;
+ char *newname;
+ char term_data[handle->data_size + 1];
+
+ //if no data
if (0 >= handle->data_size)
{
- handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_NO_DATA);
+ handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA);
GNUNET_SCHEDULER_add_now (&do_error, handle);
return;
}
+ //if not json
term_data[handle->data_size] = '\0';
- GNUNET_memcpy (term_data, handle->data, handle->data_size);
- data_js = json_loads (term_data,
- JSON_DECODE_ANY,
- &err);
- GNUNET_assert (NULL != data_js);
- GNUNET_assert (GNUNET_OK ==
- GNUNET_JSON_parse (data_js, docspec,
- NULL, NULL));
+ GNUNET_memcpy(term_data, handle->data, handle->data_size);
+ data_js = json_loads (term_data,JSON_DECODE_ANY,&err);
- json_decref (data_js);
-
- if (NULL == json_obj)
+ if (NULL == data_js)
{
+ handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA);
GNUNET_SCHEDULER_add_now (&do_error, handle);
return;
}
- if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
- {
- GNUNET_JSONAPI_document_delete (json_obj);
- handle->emsg = GNUNET_strdup ("Provided resource count invalid");
- GNUNET_SCHEDULER_add_now (&do_error, handle);
- return;
- }
- json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
- if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res, GNUNET_REST_JSONAPI_IDENTITY_EGO))
- {
- GNUNET_JSONAPI_document_delete (json_obj);
- resp = GNUNET_REST_create_response (NULL);
- handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
- cleanup_handle (handle);
- return;
- }
- egoname_json = GNUNET_JSONAPI_resource_read_attr (json_res, GNUNET_REST_JSONAPI_IDENTITY_NAME);
- if (!json_is_string (egoname_json))
+
+ ego_entry = NULL;
+ pubkey = NULL;
+ name = NULL;
+ newname = NULL;
+ //NEW NAME
+ json_state = 0;
+ json_state = json_unpack(data_js,
+ "{s:s,s?:s,s?:s}",
+ GNUNET_REST_PARAM_NEWNAME,
+ &newname,
+ GNUNET_REST_PARAM_PUBKEY,
+ &pubkey,
+ GNUNET_REST_PARAM_NAME,
+ &name);
+ //Change name with pubkey or name identifier
+ if (0 == json_state)
{
- GNUNET_JSONAPI_document_delete (json_obj);
- handle->emsg = GNUNET_strdup ("No name provided");
- GNUNET_SCHEDULER_add_now (&do_error, handle);
+ if (NULL == newname)
+ {
+ handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID);
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ json_decref (data_js);
+ return;
+ }
+
+ if (0 >= strlen(newname))
+ {
+ handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID);
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ json_decref (data_js);
+ return;
+ }
+ //lower case name
+ GNUNET_STRINGS_utf8_tolower(newname,newname);
+
+ ego_entry = get_egoentry(handle,pubkey,name);
+
+ if (NULL == ego_entry)
+ {
+ resp = GNUNET_REST_create_response (NULL);
+ handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
+ GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
+ json_decref (data_js);
+ return;
+ }
+
+ for (ego_entry_tmp = handle->ego_head;
+ NULL != ego_entry_tmp; ego_entry_tmp = ego_entry_tmp->next)
+ {
+ if (0 == strcasecmp (newname, ego_entry_tmp->identifier))
+ {
+ //Ego with same name not allowed
+ resp = GNUNET_REST_create_response (NULL);
+ handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
+ GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
+ json_decref (data_js);
+ return;
+ }
+ }
+ handle->response_code = MHD_HTTP_NO_CONTENT;
+ handle->op = GNUNET_IDENTITY_rename (handle->identity_handle,
+ ego_entry->identifier, newname,
+ &do_finished, handle);
+ json_decref (data_js);
return;
}
- egoname = json_string_value (egoname_json);
- for (ego_entry = handle->ego_head;
- NULL != ego_entry;
- ego_entry = ego_entry->next)
+
+ newsubsys = NULL;
+ //SUBSYSTEM
+ json_state = 0;
+ json_state = json_unpack(data_js,
+ "{s:s,s?:s,s?:s}",
+ GNUNET_REST_PARAM_SUBSYSTEM,
+ &newsubsys,
+ GNUNET_REST_PARAM_PUBKEY,
+ &pubkey,
+ GNUNET_REST_PARAM_NAME,
+ &name);
+ //Change subsystem with pubkey or name identifier
+ if (0 == json_state)
{
- if (0 == strcasecmp (egoname, ego_entry->identifier))
+ if (NULL == newsubsys || (NULL == pubkey && NULL == name))
{
- GNUNET_JSONAPI_document_delete (json_obj);
- resp = GNUNET_REST_create_response (NULL);
- handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
- cleanup_handle (handle);
+ handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID);
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ json_decref (data_js);
+ return;
+ }
+
+ if (0 >= strlen(newsubsys))
+ {
+ handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID);
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ json_decref (data_js);
return;
}
+
+ ego_entry = get_egoentry(handle, pubkey, name);
+
+ if (NULL == ego_entry)
+ {
+ handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID);
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ json_decref (data_js);
+ return;
+ }
+
+ handle->response_code = MHD_HTTP_NO_CONTENT;
+ handle->op = GNUNET_IDENTITY_set (handle->identity_handle,
+ newsubsys,
+ ego_entry->ego,
+ &do_finished,
+ handle);
+ json_decref (data_js);
+ return;
}
- GNUNET_asprintf (&handle->name, "%s", egoname);
- GNUNET_JSONAPI_document_delete (json_obj);
- handle->op = GNUNET_IDENTITY_create (handle->identity_handle,
- handle->name,
- &do_finished,
- handle);
-}
+ handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID);
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ json_decref (data_js);
+ return;
+}
/**
- * Handle ego edit request
+ * Handle identity POST request
*
- * @param con rest connection handle
- * @param url the url that is requested
+ * @param con_handle the connection handle
+ * @param url the url
* @param cls the RequestHandle
*/
-static void
-ego_edit_cont (struct GNUNET_REST_RequestHandle *con,
- const char *url,
- void *cls)
+void
+ego_create (struct GNUNET_REST_RequestHandle *con_handle, const char* url,
+ void *cls)
{
- struct GNUNET_JSONAPI_Document *json_obj;
- struct GNUNET_JSONAPI_Resource *json_res;
struct RequestHandle *handle = cls;
struct EgoEntry *ego_entry;
- struct EgoEntry *ego_entry_tmp;
struct MHD_Response *resp;
- json_t *subsys_json;
- json_t *name_json;
json_t *data_js;
json_error_t err;
- const char *keystring;
- const char *subsys;
- const char *newname;
- char term_data[handle->data_size+1];
- int ego_exists = GNUNET_NO;
- struct GNUNET_JSON_Specification docspec[] = {
- GNUNET_JSON_spec_jsonapi_document (&json_obj),
- GNUNET_JSON_spec_end()
- };
+ char* egoname;
+ int json_unpack_state;
+ char term_data[handle->data_size + 1];
- if (strlen (GNUNET_REST_API_NS_IDENTITY) > strlen (handle->url))
+ if (strlen (GNUNET_REST_API_NS_IDENTITY) != strlen (handle->url))
{
- handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_RESOURCE_INVALID);
+ handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_RESOURCE_INVALID);
GNUNET_SCHEDULER_add_now (&do_error, handle);
return;
}
- keystring = &handle->url[strlen(GNUNET_REST_API_NS_IDENTITY)+1];
-
- for (ego_entry = handle->ego_head;
- NULL != ego_entry;
- ego_entry = ego_entry->next)
- {
- if (0 != strcasecmp (keystring, ego_entry->keystring))
- continue;
- ego_exists = GNUNET_YES;
- break;
- }
-
- if (GNUNET_NO == ego_exists)
- {
- resp = GNUNET_REST_create_response (NULL);
- handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
- cleanup_handle (handle);
- return;
- }
-
if (0 >= handle->data_size)
{
- handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_NO_DATA);
+ handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA);
GNUNET_SCHEDULER_add_now (&do_error, handle);
return;
}
-
term_data[handle->data_size] = '\0';
- GNUNET_memcpy (term_data, handle->data, handle->data_size);
+ GNUNET_memcpy(term_data, handle->data, handle->data_size);
data_js = json_loads (term_data,
- JSON_DECODE_ANY,
- &err);
- GNUNET_assert (NULL != data_js);
- GNUNET_assert (GNUNET_OK ==
- GNUNET_JSON_parse (data_js, docspec,
- NULL, NULL));
-
- json_decref (data_js);
-
- if (NULL == json_obj)
+ JSON_DECODE_ANY,
+ &err);
+ if (NULL == data_js)
{
- handle->emsg = GNUNET_strdup ("Data invalid");
+ handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_NO_DATA);
GNUNET_SCHEDULER_add_now (&do_error, handle);
+ json_decref (data_js);
return;
}
-
- if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
+ json_unpack_state = 0;
+ json_unpack_state = json_unpack(data_js,
+ "{s:s!}",
+ GNUNET_REST_PARAM_NAME,
+ &egoname);
+ if (0 != json_unpack_state)
{
- GNUNET_JSONAPI_document_delete (json_obj);
- handle->emsg = GNUNET_strdup ("Resource amount invalid");
+ handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_DATA_INVALID);
GNUNET_SCHEDULER_add_now (&do_error, handle);
+ json_decref (data_js);
return;
}
- json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
- if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res, GNUNET_REST_JSONAPI_IDENTITY_EGO))
+ if (NULL == egoname)
{
- GNUNET_JSONAPI_document_delete (json_obj);
- handle->emsg = GNUNET_strdup ("Resource type invalid");
+ handle->emsg = GNUNET_strdup("No name provided");
GNUNET_SCHEDULER_add_now (&do_error, handle);
+ json_decref (data_js);
return;
}
-
- //This is a rename
- name_json = GNUNET_JSONAPI_resource_read_attr (json_res,
- GNUNET_REST_JSONAPI_IDENTITY_NEWNAME);
- if ((NULL != name_json) && json_is_string (name_json))
+ if (0 >= strlen (egoname))
{
- newname = json_string_value (name_json);
- for (ego_entry_tmp = handle->ego_head;
- NULL != ego_entry_tmp;
- ego_entry_tmp = ego_entry_tmp->next)
- {
- if (0 == strcasecmp (newname, ego_entry_tmp->identifier) &&
- 0 != strcasecmp (keystring, ego_entry_tmp->keystring))
- {
- //Ego with same name not allowed
- GNUNET_JSONAPI_document_delete (json_obj);
- resp = GNUNET_REST_create_response (NULL);
- handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
- cleanup_handle (handle);
- return;
- }
- }
- handle->op = GNUNET_IDENTITY_rename (handle->identity_handle,
- ego_entry->identifier,
- newname,
- &do_finished,
- handle);
- GNUNET_JSONAPI_document_delete (json_obj);
+ json_decref (data_js);
+ handle->emsg = GNUNET_strdup("No name provided");
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
return;
}
-
- //Set subsystem
- subsys_json = GNUNET_JSONAPI_resource_read_attr (json_res, GNUNET_REST_JSONAPI_IDENTITY_SUBSYSTEM);
- if ( (NULL != subsys_json) && json_is_string (subsys_json))
+ GNUNET_STRINGS_utf8_tolower(egoname, egoname);
+ for (ego_entry = handle->ego_head;
+ NULL != ego_entry; ego_entry = ego_entry->next)
{
- subsys = json_string_value (subsys_json);
- GNUNET_asprintf (&handle->subsys, "%s", subsys);
- GNUNET_JSONAPI_document_delete (json_obj);
- handle->op = GNUNET_IDENTITY_set (handle->identity_handle,
- handle->subsys,
- ego_entry->ego,
- &do_finished,
- handle);
- return;
+ if (0 == strcasecmp (egoname, ego_entry->identifier))
+ {
+ resp = GNUNET_REST_create_response (NULL);
+ handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
+ GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
+ json_decref (data_js);
+ return;
+ }
}
- GNUNET_JSONAPI_document_delete (json_obj);
- handle->emsg = GNUNET_strdup ("Subsystem not provided");
- GNUNET_SCHEDULER_add_now (&do_error, handle);
+ handle->name = GNUNET_strdup(egoname);
+ json_decref (data_js);
+ handle->response_code = MHD_HTTP_CREATED;
+ handle->op = GNUNET_IDENTITY_create (handle->identity_handle, handle->name,
+ &do_finished, handle);
}
+/**
+ * Handle identity DELETE request
+ *
+ * @param con_handle the connection handle
+ * @param url the url
+ * @param cls the RequestHandle
+ */
void
-ego_delete_cont (struct GNUNET_REST_RequestHandle *con_handle,
- const char* url,
- void *cls)
+ego_delete (struct GNUNET_REST_RequestHandle *con_handle, const char* url,
+ void *cls)
{
- const char *keystring;
+ struct RequestHandle *handle = cls;
struct EgoEntry *ego_entry;
+ struct GNUNET_HashCode key;
struct MHD_Response *resp;
- struct RequestHandle *handle = cls;
+ const char *keystring;
+ char *egoname;
int ego_exists = GNUNET_NO;
- if (strlen (GNUNET_REST_API_NS_IDENTITY) >= strlen (handle->url))
+ keystring = NULL;
+ egoname = NULL;
+
+ //delete with pubkey
+ GNUNET_CRYPTO_hash (GNUNET_REST_PARAM_PUBKEY,
+ strlen (GNUNET_REST_PARAM_PUBKEY), &key);
+ if ( GNUNET_YES
+ == GNUNET_CONTAINER_multihashmap_contains (
+ handle->rest_handle->url_param_map, &key))
{
- handle->emsg = GNUNET_strdup (GNUNET_REST_ERROR_RESOURCE_INVALID);
- GNUNET_SCHEDULER_add_now (&do_error, handle);
- return;
+ keystring = GNUNET_CONTAINER_multihashmap_get (
+ handle->rest_handle->url_param_map,&key);
}
- keystring = &handle->url[strlen(GNUNET_REST_API_NS_IDENTITY)+1];
- for (ego_entry = handle->ego_head;
- NULL != ego_entry;
- ego_entry = ego_entry->next)
+ GNUNET_CRYPTO_hash (GNUNET_REST_PARAM_NAME,
+ strlen (GNUNET_REST_PARAM_NAME), &key);
+ if ( GNUNET_YES
+ == GNUNET_CONTAINER_multihashmap_contains (
+ handle->rest_handle->url_param_map, &key))
{
- if (0 != strcasecmp (keystring, ego_entry->keystring))
- continue;
- ego_exists = GNUNET_YES;
- break;
+ egoname = GNUNET_CONTAINER_multihashmap_get (
+ handle->rest_handle->url_param_map, &key);
+ //LOWERCASE ego names?
+ //GNUNET_STRINGS_utf8_tolower(egoname, egoname);
}
+
+ if (NULL != keystring)
+ {
+ for (ego_entry = handle->ego_head;
+ NULL != ego_entry; ego_entry = ego_entry->next)
+ {
+ if (0 != strcasecmp (keystring, ego_entry->keystring))
+ continue;
+ ego_exists = GNUNET_YES;
+ break;
+ }
+ }
+ else if (NULL != egoname)
+ {
+ for (ego_entry = handle->ego_head;
+ NULL != ego_entry; ego_entry = ego_entry->next)
+ {
+ if (0 != strcmp (egoname, ego_entry->identifier))
+ continue;
+ ego_exists = GNUNET_YES;
+ break;
+ }
+ }
+ else
+ {
+ handle->emsg = GNUNET_strdup("Missing parameter pubkey or name");
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ return;
+ }
+
if (GNUNET_NO == ego_exists)
{
resp = GNUNET_REST_create_response (NULL);
handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
- cleanup_handle (handle);
+ GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
return;
}
+ handle->response_code = MHD_HTTP_NO_CONTENT;
handle->op = GNUNET_IDENTITY_delete (handle->identity_handle,
- ego_entry->identifier,
- &do_finished,
- handle);
+ ego_entry->identifier, &do_finished,
+ handle);
}
-
/**
* Respond to OPTIONS request
*
@@ -773,20 +866,17 @@ ego_delete_cont (struct GNUNET_REST_RequestHandle *con_handle,
* @param cls the RequestHandle
*/
static void
-options_cont (struct GNUNET_REST_RequestHandle *con_handle,
- const char* url,
- void *cls)
+options_cont (struct GNUNET_REST_RequestHandle *con_handle, const char* url,
+ void *cls)
{
struct MHD_Response *resp;
struct RequestHandle *handle = cls;
//For now, independent of path return all options
resp = GNUNET_REST_create_response (NULL);
- MHD_add_response_header (resp,
- "Access-Control-Allow-Methods",
- allow_methods);
+ MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods);
handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
- cleanup_handle (handle);
+ GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
return;
}
@@ -800,18 +890,17 @@ init_cont (struct RequestHandle *handle)
{
struct GNUNET_REST_RequestHandlerError err;
static const struct GNUNET_REST_RequestHandler handlers[] = {
- {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY, &ego_info_response},
- {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY, &ego_create_cont},
- {MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_IDENTITY, &ego_edit_cont},
- {MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_IDENTITY, &ego_delete_cont},
- {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY, &options_cont},
- GNUNET_REST_HANDLER_END
+ { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY, &ego_get },
+ { MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_IDENTITY, &ego_edit },
+ { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY, &ego_create },
+ { MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_IDENTITY, &ego_delete },
+ { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY, &options_cont },
+ GNUNET_REST_HANDLER_END
};
- if (GNUNET_NO == GNUNET_JSONAPI_handle_request (handle->conndata_handle,
- handlers,
- &err,
- handle))
+ if (GNUNET_NO
+ == GNUNET_REST_handle_request (handle->rest_handle, handlers, &err,
+ handle))
{
handle->response_code = err.error_code;
GNUNET_SCHEDULER_add_now (&do_error, handle);
@@ -852,10 +941,8 @@ init_cont (struct RequestHandle *handle)
* must thus no longer be used
*/
static void
-list_ego (void *cls,
- struct GNUNET_IDENTITY_Ego *ego,
- void **ctx,
- const char *identifier)
+init_egos (void *cls, struct GNUNET_IDENTITY_Ego *ego, void **ctx,
+ const char *identifier)
{
struct RequestHandle *handle = cls;
struct EgoEntry *ego_entry;
@@ -867,16 +954,16 @@ list_ego (void *cls,
init_cont (handle);
return;
}
- if (ID_REST_STATE_INIT == handle->state) {
- ego_entry = GNUNET_new (struct EgoEntry);
+ if (ID_REST_STATE_INIT == handle->state)
+ {
+ ego_entry = GNUNET_new(struct EgoEntry);
GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
- ego_entry->keystring =
- GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
+ ego_entry->keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
ego_entry->ego = ego;
GNUNET_asprintf (&ego_entry->identifier, "%s", identifier);
- GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry);
+ GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head, handle->ego_tail,
+ ego_entry);
}
-
}
/**
@@ -891,39 +978,30 @@ list_ego (void *cls,
* @return GNUNET_OK if request accepted
*/
static void
-rest_identity_process_request(struct GNUNET_REST_RequestHandle *conndata_handle,
- GNUNET_REST_ResultProcessor proc,
- void *proc_cls)
+rest_process_request (struct GNUNET_REST_RequestHandle *rest_handle,
+ GNUNET_REST_ResultProcessor proc, void *proc_cls)
{
- struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
-
-
+ struct RequestHandle *handle = GNUNET_new(struct RequestHandle);
+ handle->response_code = 0;
handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
-
handle->proc_cls = proc_cls;
handle->proc = proc;
- handle->state = ID_REST_STATE_INIT;
- handle->conndata_handle = conndata_handle;
- handle->data = conndata_handle->data;
- handle->data_size = conndata_handle->data_size;
- handle->method = conndata_handle->method;
- GNUNET_asprintf (&handle->url, "%s", conndata_handle->url);
- if (handle->url[strlen (handle->url)-1] == '/')
- handle->url[strlen (handle->url)-1] = '\0';
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Connecting...\n");
- handle->identity_handle = GNUNET_IDENTITY_connect (cfg,
- &list_ego,
- handle);
- handle->timeout_task =
- GNUNET_SCHEDULER_add_delayed (handle->timeout,
- &do_error,
- handle);
-
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Connected\n");
+ handle->rest_handle = rest_handle;
+ handle->data = rest_handle->data;
+ handle->data_size = rest_handle->data_size;
+
+ handle->url = GNUNET_strdup(rest_handle->url);
+ if (handle->url[strlen (handle->url) - 1] == '/')
+ handle->url[strlen (handle->url) - 1] = '\0';
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n");
+
+ handle->identity_handle = GNUNET_IDENTITY_connect (cfg, &init_egos, handle);
+
+ handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout,
+ &do_error, handle);
+
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Connected\n");
}
/**
@@ -940,27 +1018,24 @@ libgnunet_plugin_rest_identity_init (void *cls)
cfg = cls;
if (NULL != plugin.cfg)
- return NULL; /* can only initialize once! */
- memset (&plugin, 0, sizeof (struct Plugin));
+ return NULL; /* can only initialize once! */
+ memset (&plugin, 0, sizeof(struct Plugin));
plugin.cfg = cfg;
- api = GNUNET_new (struct GNUNET_REST_Plugin);
+ api = GNUNET_new(struct GNUNET_REST_Plugin);
api->cls = &plugin;
api->name = GNUNET_REST_API_NS_IDENTITY;
- api->process_request = &rest_identity_process_request;
- GNUNET_asprintf (&allow_methods,
- "%s, %s, %s, %s, %s",
- MHD_HTTP_METHOD_GET,
- MHD_HTTP_METHOD_POST,
- MHD_HTTP_METHOD_PUT,
- MHD_HTTP_METHOD_DELETE,
- MHD_HTTP_METHOD_OPTIONS);
-
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- _("Identity REST API initialized\n"));
+ api->process_request = &rest_process_request;
+ GNUNET_asprintf (&allow_methods, "%s, %s, %s, %s, %s",
+ MHD_HTTP_METHOD_GET,
+ MHD_HTTP_METHOD_POST,
+ MHD_HTTP_METHOD_PUT,
+ MHD_HTTP_METHOD_DELETE,
+ MHD_HTTP_METHOD_OPTIONS);
+
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, _("Identity REST API initialized\n"));
return api;
}
-
/**
* Exit point from the plugin.
*
@@ -972,13 +1047,13 @@ libgnunet_plugin_rest_identity_done (void *cls)
{
struct GNUNET_REST_Plugin *api = cls;
struct Plugin *plugin = api->cls;
-
plugin->cfg = NULL;
- GNUNET_free_non_null (allow_methods);
- GNUNET_free (api);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Identity REST plugin is finished\n");
+
+ GNUNET_free_non_null(allow_methods);
+ GNUNET_free(api);
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Identity REST plugin is finished\n");
return NULL;
}
-/* end of plugin_rest_gns.c */
+/* end of plugin_rest_identity.c */
+
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 @@
+#!/usr/bin/bash
+
+#First, start gnunet-arm and the rest-service.
+#Exit 0 means success, exit 1 means failed test
+
+identity_link="http://localhost:7776/identity"
+wrong_link="http://localhost:7776/identityandmore"
+
+
+curl_get () {
+ #$1 is link
+ #$2 is grep
+ cache="$(curl -v "$1" 2>&1 | grep "$2")"
+ #echo $cache
+ if [ "" == "$cache" ]
+ then
+ exit 1
+ fi
+}
+
+curl_post () {
+ #$1 is link
+ #$2 is data
+ #$3 is grep
+ cache="$(curl -v -X "POST" "$1" --data "$2" 2>&1 | grep "$3")"
+ #echo $cache
+ if [ "" == "$cache" ]
+ then
+ exit 1
+ fi
+}
+
+curl_delete () {
+ #$1 is link
+ #$2 is grep
+ cache="$(curl -v -X "DELETE" "$1" 2>&1 | grep "$2")"
+ #echo $cache
+ if [ "" == "$cache" ]
+ then
+ exit 1
+ fi
+}
+
+curl_put () {
+ #$1 is link
+ #$2 is data
+ #$3 is grep
+ cache="$(curl -v -X "PUT" "$1" --data "$2" 2>&1 | grep "$3")"
+ #echo $cache
+ if [ "" == "$cache" ]
+ then
+ exit 1
+ fi
+}
+
+#Test GET
+test="$(gnunet-identity -d)"
+#if no identity exists
+if [ "" == "$test" ]
+then
+ curl_get "$identity_link" "error"
+ gnunet-identity -C "test_plugin_rest_identity"
+ name="$(gnunet-identity -d | awk 'NR==1{print $1}')"
+ public="$(gnunet-identity -d | awk 'NR==1{print $3}')"
+
+ curl_get "${identity_link}?name=$name" "$public"
+ curl_get "${identity_link}?name=" "error"
+ curl_get "${identity_link}?name=$public" "error"
+
+ curl_get "${identity_link}?pubkey=$public" "$name"
+ curl_get "${identity_link}?pubkey=$name" "error"
+ curl_get "${identity_link}?pubkey=" "error"
+
+ gnunet-identity -D "test_plugin_rest_identity"
+else
+ name="$(gnunet-identity -d | awk 'NR==1{print $1}')"
+ public="$(gnunet-identity -d | awk 'NR==1{print $3}')"
+
+ curl_get "${identity_link}?name=$name" "$public"
+ curl_get "${identity_link}?name=" "error"
+ curl_get "${identity_link}?name=$public" "error"
+
+ curl_get "${identity_link}?pubkey=$public" "$name"
+ curl_get "${identity_link}?pubkey=$name" "error"
+ curl_get "${identity_link}?pubkey=" "error"
+fi
+
+#Test POST
+gnunet-identity -D "test_plugin_rest_identity" > /dev/null 2>&1
+gnunet-identity -D "test_plugin_rest_identity1" > /dev/null 2>&1
+
+curl_post "${identity_link}" '{"name":"test_plugin_rest_identity"}' "HTTP/1.1 201 Created"
+curl_post "${identity_link}" '{"name":"test_plugin_rest_identity"}' "HTTP/1.1 409"
+curl_post "${identity_link}" '{"name":"Test_plugin_rest_identity"}' "HTTP/1.1 409"
+curl_post "${identity_link}" '{}' "error"
+curl_post "${identity_link}" '' "error"
+curl_post "${identity_link}" '{"name":""}' "error"
+curl_post "${identity_link}" '{"name":123}' "error"
+curl_post "${identity_link}" '{"name":[]}' "error"
+curl_post "${identity_link}" '{"name1":"test_plugin_rest_identity"}' "error"
+curl_post "${identity_link}" '{"other":""}' "error"
+curl_post "${identity_link}" '{"name":"test_plugin_rest_identity1", "other":"test_plugin_rest_identity2"}' "error"
+
+#Test PUT
+name="$(gnunet-identity -d | grep "test_plugin_rest_identity" | awk 'NR==1{print $1}')"
+public="$(gnunet-identity -d | grep "test_plugin_rest_identity" | awk 'NR==1{print $3}')"
+
+curl_put "${identity_link}" '{"newname":"test_plugin_rest_identity1","pubkey":"'$public'"}' "HTTP/1.1 204"
+curl_put "${identity_link}" '{"newname":"test_plugin_rest_identity1","pubkey":"'$public'"}' "HTTP/1.1 409"
+curl_put "${identity_link}" '{"newname":"test_plugin_rest_identity1","pubkey":"'$public'xx"}' "HTTP/1.1 404"
+curl_put "${identity_link}" '{"newname":"test_plugin_rest_identity1","pubkey":""}' "HTTP/1.1 404"
+curl_put "${identity_link}" '{"newname":"test_plugin_rest_identity1","pubke":""}' "HTTP/1.1 404"
+curl_put "${identity_link}" '{"newname":"test_plugin_rest_identity1","pubke":"","other":"sdfdsf"}' "HTTP/1.1 404"
+curl_put "${identity_link}" '{"newname":"test_plugin_rest_identity1","pubke":"","name":"sdfdsf"}' "HTTP/1.1 404"
+curl_put "${identity_link}" '{"newname":"test_plugin_rest_identity","pubke":"","name":"test_plugin_rest_identity1"}' "HTTP/1.1 204"
+curl_put "${identity_link}" '{"newnam":"test_plugin_rest_identity","pubkey":"'$public'"}' "error"
+curl_put "${identity_link}" '{"newname":"test_plugin_rest_identity1","name":"test_plugin_rest_identity"}' "HTTP/1.1 204"
+curl_put "${identity_link}" '{"newname":"TEST_plugin_rest_identity1","name":"test_plugin_rest_identity1"}' "HTTP/1.1 409"
+curl_put "${identity_link}" '{"newname":"test_plugin_rest_identity1","name":"test_plugin_rest_identity1"}' "HTTP/1.1 409"
+curl_put "${identity_link}" '{"newname":"test_plugin_rest_identity","name":"test_plugin_rest_identityxxx"}' "HTTP/1.1 404"
+curl_put "${identity_link}" '{"newname":"test_plugin_rest_identity","name":"test_plugin_rest_identity1"}' "HTTP/1.1 204"
+curl_put "${identity_link}" '{"newnam":"test_plugin_rest_identityfail","name":"test_plugin_rest_identity"}' "error"
+
+
+#Test subsystem
+curl_put "${identity_link}" '{"subsystem":"namestore","name":"test_plugin_rest_identity"}' "HTTP/1.1 204"
+curl_put "${identity_link}" '{"subsystem":"namestore","name":"test_plugin_rest_identity"}' "HTTP/1.1 204"
+curl_get "${identity_link}?subsystem=namestore" "test_plugin_rest_identity"
+curl_post "${identity_link}" '{"name":"test_plugin_rest_identity1"}' "HTTP/1.1 201 Created"
+public="$(gnunet-identity -d | grep "test_plugin_rest_identity" | awk 'NR==1{print $3}')"
+curl_put "${identity_link}" '{"subsystem":"namestore","pubkey":"'"$public"'"}' "HTTP/1.1 204"
+curl_get "${identity_link}?subsystem=namestore" "test_plugin_rest_identity1"
+curl_get "${identity_link}?subsystem=test_plugin_rest_identity_no_subsystem" "error"
+curl_put "${identity_link}" '{"subsystem":"test_plugin_rest_identity_no_subsystem","name":"test_plugin_rest_identity1"}' "HTTP/1.1 204"
+curl_get "${identity_link}?subsystem=test_plugin_rest_identity_no_subsystem" "test_plugin_rest_identity1"
+
+curl_put "${identity_link}" '{"subsyste":"test_plugin_rest_identity_no_subsystem","name":"test_plugin_rest_identity1"}' "error"
+curl_put "${identity_link}" '{"subsystem":"test_plugin_rest_identity_no_subsystem","name":"Test_plugin_rest_identity1"}' "HTTP/1.1 204"
+
+#Test DELETE
+curl_delete "${identity_link}?name=test_plugin_rest_identity" "HTTP/1.1 204"
+curl_get "${identity_link}?name=test_plugin_rest_identity" "error"
+curl_delete "${identity_link}?name=TEST_plugin_rest_identity1" "HTTP/1.1 404"
+curl_delete "${identity_link}?name=test_plugin_rest_identity1" "HTTP/1.1 204"
+curl_get "${identity_link}?name=test_plugin_rest_identity1" "error"
+curl_delete "${identity_link}?name=test_plugin_rest_identity_not_found" "HTTP/1.1 404"
+curl_post "${identity_link}" '{"name":"test_plugin_rest_identity1"}' "HTTP/1.1 201 Created"
+public="$(gnunet-identity -d | grep "test_plugin_rest_identity1" | awk 'NR==1{print $3}')"
+curl_delete "${identity_link}?pubkey=$public" "HTTP/1.1 204"
+curl_delete "${identity_link}?pubke=$public" "error"
+curl_delete "${identity_link}?pubkey=$public&other=232" "HTTP/1.1 404"
+
+#Test wrong_link
+curl_get "$wrong_link" "HTTP/1.1 404"
+curl_post "$wrong_link" '{"name":"test_plugin_rest_identity"}' "HTTP/1.1 404"
+curl_put "$wrong_link" '{"newname":"test_plugin_rest_identity1","name":"test_plugin_rest_identity"}' "HTTP/1.1 404"
+curl_delete "$wrong_link?name=test_plugin_rest_identity1" "HTTP/1.1 404"
+
+exit 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 @@
#define GNUNET_JSON_LIB_H
#include "gnunet_util_lib.h"
+#include "gnunet_gnsrecord_lib.h"
#include <jansson.h>
@@ -318,6 +319,17 @@ GNUNET_JSON_spec_rsa_signature (const char *name,
struct GNUNET_CRYPTO_RsaSignature **sig);
+
+/**
+ * JSON Specification for GNS Records.
+ *
+ * @param gnsrecord_object struct of GNUNET_GNSRECORD_Data to fill
+ * @return JSON Specification
+ */
+struct GNUNET_JSON_Specification
+GNUNET_JSON_spec_gnsrecord_data (struct GNUNET_GNSRECORD_Data **gnsrecord_object);
+
+
/* ****************** Generic generator interface ******************* */
@@ -393,6 +405,16 @@ GNUNET_JSON_from_rsa_public_key (const struct GNUNET_CRYPTO_RsaPublicKey *pk);
json_t *
GNUNET_JSON_from_rsa_signature (const struct GNUNET_CRYPTO_RsaSignature *sig);
+/**
+ * Convert Gns record to JSON.
+ *
+ * @param rname name of record
+ * @param rd record data
+ * @return corresponding JSON encoding
+ */
+json_t *
+GNUNET_JSON_from_gns_record (const char* rname,
+ const struct GNUNET_GNSRECORD_Data *rd);
/* ******************* Helpers for MHD upload handling ******************* */
@@ -479,7 +501,6 @@ GNUNET_JSON_getopt (char shortName,
const char *description,
json_t **json);
-
#endif
/* 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 = \
json.c \
json_mhd.c \
json_generator.c \
- json_helper.c
+ json_helper.c \
+ json_gnsrecord.c
libgnunetjson_la_LIBADD = \
$(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
-ljansson \
$(XLIB)
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)
return ret;
}
+/**
+ * Convert Gns record to JSON.
+ *
+ * @param rname name of record
+ * @param rd record data
+ * @return corresponding JSON encoding
+ */
+json_t *
+GNUNET_JSON_from_gns_record (const char* rname,
+ const struct GNUNET_GNSRECORD_Data *rd)
+{
+ struct GNUNET_TIME_Absolute expiration_time;
+ const char *expiration_time_str;
+ const char *record_type_str;
+ char *value_str;
+ json_t *ret;
+ int flags;
+
+ value_str = GNUNET_GNSRECORD_value_to_string(rd->record_type,rd->data,rd->data_size);
+ expiration_time = GNUNET_GNSRECORD_record_get_expiration_time(1, rd);
+ expiration_time_str = GNUNET_STRINGS_absolute_time_to_string(expiration_time);
+ flags = (int)rd->flags; //maybe necessary
+ record_type_str = GNUNET_GNSRECORD_number_to_typename(rd->record_type);
+
+ // ? for possible NULL values
+ ret = json_pack("{s:s?,s:s?,s:s?,s:i,s:s?}",
+ "value", value_str,
+ "type", record_type_str,
+ "expiration_time", expiration_time_str,
+ "flag", flags,
+ "label", rname);
+ GNUNET_free_non_null(value_str);
+ return ret;
+}
+
/* 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 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2009-2013 GNUnet e.V.
+
+ GNUnet is free software: you can redistribute it and/or modify it
+ under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License,
+ or (at your option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file json/json_gnsrecord.c
+ * @brief JSON handling of GNS record data
+ * @author Philippe Buschmann
+ */
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_json_lib.h"
+
+#define GNUNET_JSON_GNSRECORD_VALUE "value"
+#define GNUNET_JSON_GNSRECORD_TYPE "type"
+#define GNUNET_JSON_GNSRECORD_EXPIRATION_TIME "expiration_time"
+#define GNUNET_JSON_GNSRECORD_FLAG "flag"
+#define GNUNET_JSON_GNSRECORD_LABEL "label"
+#define GNUNET_JSON_GNSRECORD_NEVER "never"
+
+
+/**
+ * Parse given JSON object to gns record
+ *
+ * @param cls closure, NULL
+ * @param root the json object representing data
+ * @param spec where to write the data
+ * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
+ */
+static int
+parse_gnsrecordobject (void *cls,
+ json_t *root,
+ struct GNUNET_JSON_Specification *spec)
+{
+ struct GNUNET_GNSRECORD_Data *gnsrecord_object;
+ struct GNUNET_TIME_Absolute abs_expiration_time;
+ int unpack_state=0;
+ const char *value;
+ const char *expiration_time;
+ const char *record_type;
+ const char *label;
+ int flag;
+ void *rdata = NULL;
+ size_t rdata_size;
+
+ GNUNET_assert(NULL != root);
+ if(!json_is_object(root))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Error json is not array nor object!\n");
+ return GNUNET_SYSERR;
+ }
+ //interpret single gns record
+ unpack_state = json_unpack(root,
+ "{s:s, s:s, s:s, s?:i, s:s!}",
+ GNUNET_JSON_GNSRECORD_VALUE, &value,
+ GNUNET_JSON_GNSRECORD_TYPE, &record_type,
+ GNUNET_JSON_GNSRECORD_EXPIRATION_TIME, &expiration_time,
+ GNUNET_JSON_GNSRECORD_FLAG, &flag,
+ GNUNET_JSON_GNSRECORD_LABEL, &label);
+ if (0 != unpack_state)
+ {
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
+ "Error json object has a wrong format!\n");
+ return GNUNET_SYSERR;
+ }
+ gnsrecord_object = GNUNET_new (struct GNUNET_GNSRECORD_Data);
+ gnsrecord_object->record_type = GNUNET_GNSRECORD_typename_to_number(record_type);
+ if (UINT32_MAX == gnsrecord_object->record_type)
+ {
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,"Unsupported type\n");
+ GNUNET_free(gnsrecord_object);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK
+ != GNUNET_GNSRECORD_string_to_value (gnsrecord_object->record_type,
+ value,
+ &rdata,
+ &rdata_size))
+ {
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,"Value invalid for record type\n");
+ GNUNET_free(gnsrecord_object);
+ return GNUNET_SYSERR;
+ }
+
+ gnsrecord_object->data = rdata;
+ gnsrecord_object->data_size = rdata_size;
+
+ if (0 == strcmp (expiration_time, GNUNET_JSON_GNSRECORD_NEVER))
+ {
+ gnsrecord_object->expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
+ }
+ else if (GNUNET_OK
+ == GNUNET_STRINGS_fancy_time_to_absolute (expiration_time,
+ &abs_expiration_time))
+ {
+ gnsrecord_object->expiration_time = abs_expiration_time.abs_value_us;
+ }
+ else
+ {
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Expiration time invalid\n");
+ GNUNET_free_non_null(rdata);
+ GNUNET_free(gnsrecord_object);
+ return GNUNET_SYSERR;
+ }
+ // check if flag is a valid enum value
+ if ((GNUNET_GNSRECORD_RF_NONE != flag)
+ && (GNUNET_GNSRECORD_RF_PRIVATE != flag)
+ && (GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION != flag)
+ && (GNUNET_GNSRECORD_RF_SHADOW_RECORD) != flag)
+ {
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Flag invalid\n");
+ GNUNET_free_non_null(rdata);
+ GNUNET_free(gnsrecord_object);
+ return GNUNET_SYSERR;
+ }
+ gnsrecord_object->flags = (enum GNUNET_GNSRECORD_Flags)flag;
+ *(struct GNUNET_GNSRECORD_Data **) spec->ptr = gnsrecord_object;
+ return GNUNET_OK;
+}
+
+/**
+ * Cleanup data left from parsing RSA public key.
+ *
+ * @param cls closure, NULL
+ * @param[out] spec where to free the data
+ */
+static void
+clean_gnsrecordobject (void *cls, struct GNUNET_JSON_Specification *spec)
+{
+ struct GNUNET_GNSRECORD_Data **gnsrecord_object;
+ gnsrecord_object = (struct GNUNET_GNSRECORD_Data **) spec->ptr;
+ if (NULL != *gnsrecord_object)
+ {
+ if (NULL != (*gnsrecord_object)->data)
+ GNUNET_free((char*)(*gnsrecord_object)->data);
+
+ GNUNET_free(*gnsrecord_object);
+ *gnsrecord_object = NULL;
+ }
+}
+
+/**
+ * JSON Specification for GNS Records.
+ *
+ * @param gnsrecord_object struct of GNUNET_GNSRECORD_Data to fill
+ * @return JSON Specification
+ */
+struct GNUNET_JSON_Specification
+GNUNET_JSON_spec_gnsrecord_data (struct GNUNET_GNSRECORD_Data **gnsrecord_object)
+{
+ struct GNUNET_JSON_Specification ret = {
+ .parser = &parse_gnsrecordobject,
+ .cleaner = &clean_gnsrecordobject,
+ .cls = NULL,
+ .field = NULL,
+ .ptr = gnsrecord_object,
+ .ptr_size = 0,
+ .size_ptr = NULL
+ };
+ *gnsrecord_object = NULL;
+ return ret;
+}
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 = \
libgnunetnamestore.la \
$(top_builddir)/src/rest/libgnunetrest.la \
$(top_builddir)/src/identity/libgnunetidentity.la \
- $(top_builddir)/src/jsonapi/libgnunetjsonapi.la \
- $(top_builddir)/src/jsonapi/libgnunetjsonapiutils.la \
+ $(top_builddir)/src/json/libgnunetjson.la \
+ $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
$(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \
$(LTLIBINTL) -ljansson -lmicrohttpd
libgnunet_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 @@
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Affero General Public License for more details.
-
+
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @author Martin Schanzenbach
+ * @author Philippe Buschmann
* @file namestore/plugin_rest_namestore.c
* @brief GNUnet Namestore REST plugin
- *
*/
#include "platform.h"
@@ -28,38 +28,45 @@
#include "gnunet_namestore_service.h"
#include "gnunet_identity_service.h"
#include "gnunet_rest_lib.h"
-#include "gnunet_jsonapi_lib.h"
-#include "gnunet_jsonapi_util.h"
+#include "gnunet_json_lib.h"
#include "microhttpd.h"
#include <jansson.h>
-#define GNUNET_REST_API_NS_NAMESTORE "/names"
-
-#define GNUNET_REST_API_NS_NAMESTORE_ZKEY "/names/zkey"
-
-#define GNUNET_REST_JSONAPI_NAMESTORE_TYPEINFO "record"
-
-#define GNUNET_REST_JSONAPI_NAMESTORE_NAME "name"
-
-#define GNUNET_REST_JSONAPI_NAMESTORE_REVINFO "revinfo"
-#define GNUNET_REST_JSONAPI_NAMESTORE_RECORD GNUNET_REST_JSONAPI_NAMESTORE_TYPEINFO
+#define GNUNET_REST_API_NS_NAMESTORE "/namestore"
+#define GNUNET_REST_SUBSYSTEM_NAMESTORE "namestore"
-#define GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE "record_type"
-
-#define GNUNET_REST_JSONAPI_NAMESTORE_VALUE "value"
-
-#define GNUNET_REST_JSONAPI_NAMESTORE_PUBLIC "public"
+/**
+ * Parameter names
+ */
+#define GNUNET_REST_API_PARAM_PUBKEY "pubkey"
+#define GNUNET_REST_API_PARAM_NAME "name"
-#define GNUNET_REST_JSONAPI_NAMESTORE_SHADOW "shadow"
+/**
+ * Error messages
+ */
+#define GNUNET_REST_NAMESTORE_ERROR_UNKNOWN "Unknown Error"
-#define GNUNET_REST_JSONAPI_NAMESTORE_PKEY "pkey"
+#define GNUNET_REST_NAMESTORE_RD_COUNT 1
-#define GNUNET_REST_JSONAPI_NAMESTORE_ZKEY "zkey"
+/**
+ * State while collecting all egos
+ */
+#define ID_REST_STATE_INIT 0
-#define GNUNET_REST_JSONAPI_NAMESTORE_EXPIRATION "expiration"
+/**
+ * Done collecting egos
+ */
+#define ID_REST_STATE_POST_INIT 1
+/**
+ * The configuration handle
+ */
+const struct GNUNET_CONFIGURATION_Handle *cfg;
-#define GNUNET_REST_JSONAPI_NAMESTORE_EGO "ego"
+/**
+ * HTTP methods allows for this plugin
+ */
+static char* allow_methods;
/**
* @brief struct returned by the initialization function of the plugin
@@ -69,135 +76,110 @@ struct Plugin
const struct GNUNET_CONFIGURATION_Handle *cfg;
};
-
/**
- * HTTP methods allows for this plugin
+ * The default namestore ego
*/
-static char* allow_methods;
-
-const struct GNUNET_CONFIGURATION_Handle *cfg;
-
-struct RecordEntry
+struct EgoEntry
{
/**
* DLL
*/
- struct RecordEntry *next;
+ struct EgoEntry *next;
/**
* DLL
*/
- struct RecordEntry *prev;
-
-};
-
-struct RequestHandle
-{
- /**
- * Ego list
- */
- struct RecordEntry *record_head;
-
- /**
- * Ego list
- */
- struct record_entry *record_tail;
+ struct EgoEntry *prev;
/**
- * JSON response object
+ * Ego Identifier
*/
- struct GNUNET_JSONAPI_Document *resp_object;
+ char *identifier;
/**
- * Rest connection
+ * Public key string
*/
- struct GNUNET_REST_RequestHandle *rest_handle;
+ char *keystring;
/**
- * Handle to GNS service.
- */
- struct GNUNET_IDENTITY_Handle *identity_handle;
-
- /**
- * Handle to NAMESTORE
+ * The Ego
*/
- struct GNUNET_NAMESTORE_Handle *ns_handle;
+ struct GNUNET_IDENTITY_Ego *ego;
+};
- /**
- * Handle to NAMESTORE it
- */
- struct GNUNET_NAMESTORE_ZoneIterator *list_it;
+struct RequestHandle
+{
/**
- * Private key for the zone
+ * Records to store
*/
- struct GNUNET_CRYPTO_EcdsaPrivateKey zone_pkey;
+ char *label_name;
/**
- * Handle to identity lookup
+ * Records to store
*/
- struct GNUNET_IDENTITY_EgoLookup *ego_lookup;
+ struct GNUNET_GNSRECORD_Data *rd;
/**
- * Default Ego operation
+ * NAMESTORE Operation
*/
- struct GNUNET_IDENTITY_Operation *get_default;
+ struct GNUNET_NAMESTORE_QueueEntry *add_qe;
/**
- * Name of the ego
+ * Response object
*/
- char *ego_name;
+ json_t *resp_object;
/**
- * Record is public
+ * The processing state
*/
- int is_public;
+ int state;
/**
- * Shadow record
+ * Handle to NAMESTORE
*/
- int is_shadow;
+ struct GNUNET_NAMESTORE_Handle *ns_handle;
/**
- * Name of the record to modify
+ * Handle to NAMESTORE it
*/
- char *name;
+ struct GNUNET_NAMESTORE_ZoneIterator *list_it;
/**
- * Value of the record
+ * Private key for the zone
*/
- char *value;
+ const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_pkey;
/**
- * Zkey string
+ * IDENTITY Operation
*/
- const char* zkey_str;
+ struct EgoEntry *ego_entry;
/**
- * record type
+ * Ego list
*/
- uint32_t type;
+ struct EgoEntry *ego_head;
/**
- * Records to store
+ * Ego list
*/
- struct GNUNET_GNSRECORD_Data *rd;
+ struct EgoEntry *ego_tail;
/**
- * record count
+ * IDENTITY Operation
*/
- unsigned int rd_count;
+ struct GNUNET_IDENTITY_Operation *op;
/**
- * NAMESTORE Operation
+ * Handle to Identity service.
*/
- struct GNUNET_NAMESTORE_QueueEntry *add_qe;
+ struct GNUNET_IDENTITY_Handle *identity_handle;
/**
- * NAMESTORE Operation
+ * Rest connection
*/
- struct GNUNET_NAMESTORE_QueueEntry *reverse_qe;
-
+ struct GNUNET_REST_RequestHandle *rest_handle;
+
/**
* Desired timeout for the lookup (default is no timeout).
*/
@@ -206,7 +188,7 @@ struct RequestHandle
/**
* ID of a task associated with the resolution process.
*/
- struct GNUNET_SCHEDULER_Task * timeout_task;
+ struct GNUNET_SCHEDULER_Task *timeout_task;
/**
* The plugin result processor
@@ -224,164 +206,201 @@ struct RequestHandle
char *url;
/**
- * Cfg
+ * Error response message
*/
- const struct GNUNET_CONFIGURATION_Handle *cfg;
+ char *emsg;
/**
- * HTTP response code
+ * Reponse code
*/
int response_code;
};
-
/**
* Cleanup lookup handle
- *
* @param handle Handle to clean up
*/
static void
-cleanup_handle (struct RequestHandle *handle)
+cleanup_handle (void *cls)
{
- struct RecordEntry *record_entry;
- struct RecordEntry *record_tmp;
+ struct RequestHandle *handle = cls;
+ struct EgoEntry *ego_entry;
+ struct EgoEntry *ego_tmp;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Cleaning up\n");
- if (NULL != handle->resp_object)
- GNUNET_JSONAPI_document_delete (handle->resp_object);
- if (NULL != handle->name)
- GNUNET_free (handle->name);
if (NULL != handle->timeout_task)
+ {
GNUNET_SCHEDULER_cancel (handle->timeout_task);
- if (NULL != handle->ego_lookup)
- GNUNET_IDENTITY_ego_lookup_cancel (handle->ego_lookup);
- if (NULL != handle->get_default)
- GNUNET_IDENTITY_cancel (handle->get_default);
+ handle->timeout_task = NULL;
+ }
+ if (NULL != handle->label_name)
+ GNUNET_free(handle->label_name);
+ if (NULL != handle->url)
+ GNUNET_free(handle->url);
+ if (NULL != handle->emsg)
+ GNUNET_free(handle->emsg);
+ if (NULL != handle->rd)
+ {
+ if (NULL != handle->rd->data)
+ GNUNET_free((void*)handle->rd->data);
+ GNUNET_free(handle->rd);
+ }
+ if (NULL != handle->timeout_task)
+ GNUNET_SCHEDULER_cancel(handle->timeout_task);
if (NULL != handle->list_it)
- GNUNET_NAMESTORE_zone_iteration_stop (handle->list_it);
+ GNUNET_NAMESTORE_zone_iteration_stop(handle->list_it);
if (NULL != handle->add_qe)
- GNUNET_NAMESTORE_cancel (handle->add_qe);
+ GNUNET_NAMESTORE_cancel(handle->add_qe);
if (NULL != handle->identity_handle)
- GNUNET_IDENTITY_disconnect (handle->identity_handle);
+ GNUNET_IDENTITY_disconnect(handle->identity_handle);
if (NULL != handle->ns_handle)
- GNUNET_NAMESTORE_disconnect (handle->ns_handle);
- if (NULL != handle->url)
- GNUNET_free (handle->url);
- if (NULL != handle->value)
- GNUNET_free (handle->value);
- if (NULL != handle->rd)
{
- for (unsigned int i = 0; i < handle->rd_count; i++)
- {
- if (NULL != handle->rd[i].data)
- GNUNET_free ((void*)handle->rd[i].data);
- }
- GNUNET_free (handle->rd);
+ GNUNET_NAMESTORE_disconnect(handle->ns_handle);
}
- if (NULL != handle->ego_name)
- GNUNET_free (handle->ego_name);
- for (record_entry = handle->record_head;
- NULL != record_entry;)
+
+ for (ego_entry = handle->ego_head;
+ NULL != ego_entry;)
{
- record_tmp = record_entry;
- record_entry = record_entry->next;
- GNUNET_free (record_tmp);
+ ego_tmp = ego_entry;
+ ego_entry = ego_entry->next;
+ GNUNET_free(ego_tmp->identifier);
+ GNUNET_free(ego_tmp->keystring);
+ GNUNET_free(ego_tmp);
}
+
+ if(NULL != handle->resp_object)
+ {
+ json_decref(handle->resp_object);
+ }
+
GNUNET_free (handle);
}
/**
- * Create json representation of a GNSRECORD
+ * Task run on errors. Reports an error and cleans up everything.
*
- * @param rd the GNSRECORD_Data
+ * @param cls the `struct RequestHandle`
*/
-static json_t *
-gnsrecord_to_json (const struct GNUNET_GNSRECORD_Data *rd)
+static void
+do_error (void *cls)
{
- const char *typename;
- char *string_val;
- const char *exp_str;
- json_t *record_obj;
+ struct RequestHandle *handle = cls;
+ struct MHD_Response *resp;
+ json_t *json_error = json_object();
+ char *response;
- typename = GNUNET_GNSRECORD_number_to_typename (rd->record_type);
- string_val = GNUNET_GNSRECORD_value_to_string (rd->record_type,
- rd->data,
- rd->data_size);
+ if (NULL == handle->emsg)
+ handle->emsg = GNUNET_strdup(GNUNET_REST_NAMESTORE_ERROR_UNKNOWN);
- if (NULL == string_val)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Record of type %d malformed, skipping\n",
- (int) rd->record_type);
- return NULL;
- }
- record_obj = json_object();
- json_object_set_new (record_obj,
- GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE,
- json_string (typename));
- json_object_set_new (record_obj,
- GNUNET_REST_JSONAPI_NAMESTORE_VALUE,
- json_string (string_val));
- GNUNET_free (string_val);
-
- if (GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION & rd->flags)
+ json_object_set_new(json_error,"error", json_string(handle->emsg));
+
+ if (0 == handle->response_code)
+ handle->response_code = MHD_HTTP_OK;
+ response = json_dumps (json_error, 0);
+ resp = GNUNET_REST_create_response (response);
+ handle->proc (handle->proc_cls, resp, handle->response_code);
+ json_decref(json_error);
+ GNUNET_free(response);
+ GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
+}
+
+
+/**
+ * Get EgoEntry from list with either a public key or a name
+ * If public key and name are not NULL, it returns the public key result first
+ *
+ * @param handle the RequestHandle
+ * @param pubkey the public key of an identity (only one can be NULL)
+ * @param name the name of an identity (only one can be NULL)
+ * @return EgoEntry or NULL if not found
+ */
+struct EgoEntry*
+get_egoentry(struct RequestHandle *handle, char* pubkey, char *name)
+{
+ struct EgoEntry *ego_entry;
+ if (NULL != pubkey)
{
- struct GNUNET_TIME_Relative time_rel;
- time_rel.rel_value_us = rd->expiration_time;
- exp_str = GNUNET_STRINGS_relative_time_to_string (time_rel, 1);
+ for (ego_entry = handle->ego_head;
+ NULL != ego_entry;
+ ego_entry = ego_entry->next)
+ {
+ if (0 != strcasecmp (pubkey, ego_entry->keystring))
+ continue;
+ return ego_entry;
+ }
}
- else
+ if (NULL != name)
{
- struct GNUNET_TIME_Absolute time_abs;
- time_abs.abs_value_us = rd->expiration_time;
- exp_str = GNUNET_STRINGS_absolute_time_to_string (time_abs);
+ for (ego_entry = handle->ego_head;
+ NULL != ego_entry;
+ ego_entry = ego_entry->next)
+ {
+ if (0 != strcasecmp (name, ego_entry->identifier))
+ continue;
+ return ego_entry;
+ }
}
- json_object_set_new (record_obj, GNUNET_REST_JSONAPI_NAMESTORE_EXPIRATION, json_string (exp_str));
-
- json_object_set_new (record_obj, "expired",
- json_boolean (GNUNET_YES == GNUNET_GNSRECORD_is_expired (rd)));
- return record_obj;
+ return NULL;
}
/**
- * Task run on error. Generates error response and cleans up.
- *
- * @param cls the request to generate an error response for
+ * Does internal server error when iteration failed.
*/
static void
-do_error (void *cls)
+namestore_iteration_error (void *cls)
{
struct RequestHandle *handle = cls;
struct MHD_Response *resp = GNUNET_REST_create_response (NULL);
-
- handle->proc (handle->proc_cls, resp, handle->response_code);
- cleanup_handle (handle);
+ handle->proc (handle->proc_cls, resp, MHD_HTTP_INTERNAL_SERVER_ERROR);
+ GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
}
-/**
- * Task run on timeout.
- *
- * @param cls the request to time out
- */
static void
-do_timeout (void *cls)
+create_finished (void *cls, int32_t success, const char *emsg)
{
struct RequestHandle *handle = cls;
+ struct MHD_Response *resp;
- handle->timeout_task = NULL;
- do_error (handle);
+ handle->add_qe = NULL;
+ if (GNUNET_YES != success)
+ {
+ handle->emsg = GNUNET_strdup("Error storing records");
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ return;
+ }
+ resp = GNUNET_REST_create_response (NULL);
+ handle->proc (handle->proc_cls, resp, MHD_HTTP_NO_CONTENT);
+ GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
}
static void
-cleanup_handle_delayed (void *cls)
+del_finished (void *cls, int32_t success, const char *emsg)
{
- cleanup_handle (cls);
+ struct RequestHandle *handle = cls;
+
+ handle->add_qe = NULL;
+ if (GNUNET_NO == success)
+ {
+ handle->emsg = GNUNET_strdup("Deleting record failed. Record does not exist");
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ return;
+ }
+ if (GNUNET_SYSERR == success)
+ {
+ handle->emsg = GNUNET_strdup("Deleting record failed");
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ return;
+ }
+ handle->proc (handle->proc_cls,
+ GNUNET_REST_create_response (NULL),
+ MHD_HTTP_NO_CONTENT);
+ GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
}
@@ -395,31 +414,24 @@ static void
namestore_list_finished (void *cls)
{
struct RequestHandle *handle = cls;
- char *result;
+ char *result_str;
struct MHD_Response *resp;
handle->list_it = NULL;
- if (NULL == handle->resp_object)
- handle->resp_object = GNUNET_JSONAPI_document_new ();
- if (GNUNET_SYSERR ==
- GNUNET_JSONAPI_document_serialize (handle->resp_object,
- &result))
+ if (NULL == handle->resp_object)
{
- handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
- GNUNET_SCHEDULER_add_now (&do_error,
- handle);
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
return;
}
- resp = GNUNET_REST_create_response (result);
- handle->proc (handle->proc_cls,
- resp,
- MHD_HTTP_OK);
- GNUNET_free_non_null (result);
- GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed,
- handle);
-}
+ result_str = json_dumps (handle->resp_object, 0);
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
+ resp = GNUNET_REST_create_response (result_str);
+ handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
+ GNUNET_free_non_null (result_str);
+ GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
+}
/**
@@ -428,84 +440,111 @@ namestore_list_finished (void *cls)
* @param handle the RequestHandle
*/
static void
-namestore_list_response (void *cls,
+namestore_list_iteration (void *cls,
const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
const char *rname,
unsigned int rd_len,
const struct GNUNET_GNSRECORD_Data *rd)
{
struct RequestHandle *handle = cls;
- struct GNUNET_JSONAPI_Resource *json_resource;
- json_t *result_array;
json_t *record_obj;
if (NULL == handle->resp_object)
- handle->resp_object = GNUNET_JSONAPI_document_new ();
+ handle->resp_object = json_array();
- if ( (NULL != handle->name) &&
- (0 != strcmp (handle->name,
+ /*if ( (NULL != handle->ego_entry->identifier) &&
+ (0 != strcmp (handle->ego_entry->identifier,
rname)) )
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%s does not match %s\n",
- rname,
- handle->name);
- GNUNET_NAMESTORE_zone_iterator_next (handle->list_it,
- 1);
+ "%s does not match %s\n", rname,
+ handle->ego_entry->identifier);
+ GNUNET_NAMESTORE_zone_iterator_next (handle->list_it, 1);
return;
- }
+ }*/
- result_array = json_array ();
- for (unsigned int i=0; i<rd_len; i++)
+ for (unsigned int i = 0; i < rd_len; i++)
{
if ( (GNUNET_GNSRECORD_TYPE_NICK == rd[i].record_type) &&
(0 != strcmp (rname, GNUNET_GNS_EMPTY_LABEL_AT)) )
continue;
- if ( (rd[i].record_type != handle->type) &&
- (GNUNET_GNSRECORD_TYPE_ANY != handle->type) )
+ record_obj = GNUNET_JSON_from_gns_record(rname,rd);
+
+ if(NULL == record_obj)
continue;
- record_obj = gnsrecord_to_json (&rd[i]);
- json_array_append (result_array,
- record_obj);
- json_decref (record_obj);
- }
- if (0 < json_array_size(result_array))
- {
- json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_NAMESTORE_TYPEINFO,
- rname);
- GNUNET_JSONAPI_resource_add_attr (json_resource,
- GNUNET_REST_JSONAPI_NAMESTORE_RECORD,
- result_array);
- GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
+ json_array_append (handle->resp_object, record_obj);
+ json_decref (record_obj);
}
- json_decref (result_array);
- GNUNET_NAMESTORE_zone_iterator_next (handle->list_it,
- 1);
+ GNUNET_NAMESTORE_zone_iterator_next (handle->list_it, 1);
}
-static void
-create_finished (void *cls, int32_t success, const char *emsg)
+/**
+ * Handle namestore GET request
+ *
+ * @param con_handle the connection handle
+ * @param url the url
+ * @param cls the RequestHandle
+ */
+void
+namestore_get (struct GNUNET_REST_RequestHandle *con_handle,
+ const char* url,
+ void *cls)
{
struct RequestHandle *handle = cls;
- struct MHD_Response *resp;
+ struct EgoEntry *ego_entry = NULL;
+ struct GNUNET_HashCode key;
+ char *pubkey = NULL;
+ char *name = NULL;
+
+ //change zone if pubkey or name specified
+ GNUNET_CRYPTO_hash (GNUNET_REST_API_PARAM_PUBKEY,
+ strlen (GNUNET_REST_API_PARAM_PUBKEY),
+ &key);
+ if ( GNUNET_YES
+ == GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map,
+ &key))
+ {
+ pubkey = GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map,
+ &key);
+ }
+ GNUNET_CRYPTO_hash (GNUNET_REST_API_PARAM_NAME,
+ strlen (GNUNET_REST_API_PARAM_NAME),
+ &key);
+ if ( GNUNET_YES
+ == GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map,
+ &key))
+ {
+ name = GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map,
+ &key);
+ }
- handle->add_qe = NULL;
- if (GNUNET_YES != success)
+ ego_entry = get_egoentry(handle,pubkey,name);
+ if (NULL == ego_entry)
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Error storing records%s%s\n",
- (NULL == emsg) ? "" : ": ",
- (NULL == emsg) ? "" : emsg);
- GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
- return;
+ if (NULL != pubkey || NULL != name)
+ {
+ handle->emsg = GNUNET_strdup("Invalid identity");
+ handle->response_code = MHD_HTTP_NOT_FOUND;
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ return;
+ }
}
- resp = GNUNET_REST_create_response (NULL);
- handle->proc (handle->proc_cls, resp, MHD_HTTP_NO_CONTENT);
- GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
+ if ( NULL != ego_entry )
+ {
+ handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key(ego_entry->ego);
+ }
+ handle->list_it = GNUNET_NAMESTORE_zone_iteration_start (handle->ns_handle,
+ handle->zone_pkey,
+ &namestore_iteration_error,
+ handle,
+ &namestore_list_iteration,
+ handle,
+ &namestore_list_finished,
+ handle);
}
@@ -529,10 +568,10 @@ create_new_record_cont (void *cls,
struct RequestHandle *handle = cls;
handle->add_qe = NULL;
- if (0 != strcmp (rec_name, handle->name))
+ if (0 != strcmp (rec_name, handle->label_name))
{
GNUNET_break (0);
- do_error (handle);
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
return;
}
@@ -541,426 +580,262 @@ create_new_record_cont (void *cls,
handle->proc (handle->proc_cls,
GNUNET_REST_create_response (NULL),
MHD_HTTP_CONFLICT);
- GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
+ GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
return;
}
-
- GNUNET_assert (NULL != handle->name);
handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
- &handle->zone_pkey,
- handle->name,
- handle->rd_count,
+ handle->zone_pkey,
+ handle->label_name,
+ GNUNET_REST_NAMESTORE_RD_COUNT,
handle->rd,
&create_finished,
handle);
}
-
-static void
-del_finished (void *cls,
- int32_t success,
- const char *emsg)
+/**
+ * Handle namestore POST request
+ *
+ * @param con_handle the connection handle
+ * @param url the url
+ * @param cls the RequestHandle
+ */
+void
+namestore_add (struct GNUNET_REST_RequestHandle *con_handle,
+ const char* url,
+ void *cls)
{
struct RequestHandle *handle = cls;
+ struct GNUNET_GNSRECORD_Data *gns_record;
+ json_t *data_js;
+ json_t *name_json;
+ json_error_t err;
- handle->add_qe = NULL;
- if (GNUNET_NO == success)
+ struct EgoEntry *ego_entry = NULL;
+ struct GNUNET_HashCode key;
+ char *pubkey = NULL;
+ char *name = NULL;
+
+ char term_data[handle->rest_handle->data_size + 1];
+ struct GNUNET_JSON_Specification gnsspec[] = {
+ GNUNET_JSON_spec_gnsrecord_data(&gns_record),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (strlen (GNUNET_REST_API_NS_NAMESTORE) != strlen (handle->url))
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _("Deleting record failed, record does not exist%s%s\n"),
- (NULL != emsg) ? ": " : "",
- (NULL != emsg) ? emsg : "");
- GNUNET_SCHEDULER_add_now (&do_error, handle); //do_not_found TODO
+ handle->emsg = GNUNET_strdup("Wrong URL");
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
return;
}
- if (GNUNET_SYSERR == success)
+ if (0 >= handle->rest_handle->data_size)
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _("Deleting record failed%s%s\n"),
- (NULL != emsg) ? ": " : "",
- (NULL != emsg) ? emsg : "");
+ handle->emsg = GNUNET_strdup("No data");
GNUNET_SCHEDULER_add_now (&do_error, handle);
return;
}
- handle->proc (handle->proc_cls,
- GNUNET_REST_create_response (NULL),
- MHD_HTTP_NO_CONTENT);
- GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
-}
-
-
-static void
-del_cont (void *cls,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
- const char *label,
- unsigned int rd_count,
- const struct GNUNET_GNSRECORD_Data *rd)
-{
- struct RequestHandle *handle = cls;
-
- handle->add_qe = NULL;
- if (0 == rd_count)
+ term_data[handle->rest_handle->data_size] = '\0';
+ GNUNET_memcpy(term_data, handle->rest_handle->data,
+ handle->rest_handle->data_size);
+ data_js = json_loads (term_data, JSON_DECODE_ANY, &err);
+ if (GNUNET_OK != GNUNET_JSON_parse (data_js, gnsspec, NULL, NULL))
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _("There are no records under label `%s' that could be deleted.\n"),
- label);
- do_error (handle);
+ handle->emsg = GNUNET_strdup("Invalid data");
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ GNUNET_JSON_parse_free(gnsspec);
+ json_decref (data_js);
return;
}
+ handle->rd = gns_record;
- handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
- &handle->zone_pkey,
- handle->name,
- 0, NULL,
- &del_finished,
- handle);
-}
-
-
-static void
-namestore_delete_cont (struct GNUNET_REST_RequestHandle *con,
- const char *url,
- void *cls)
-{
- struct RequestHandle *handle = cls;
-
- if (NULL == handle->name)
+ name_json = json_object_get(data_js, "label");
+ if (!json_is_string(name_json))
{
+ handle->emsg = GNUNET_strdup("Missing name");
GNUNET_SCHEDULER_add_now (&do_error, handle);
+ json_decref (data_js);
return;
}
-
- handle->add_qe = GNUNET_NAMESTORE_records_lookup (handle->ns_handle,
- &handle->zone_pkey,
- handle->name,
- &do_error,
- handle,
- &del_cont,
- handle);
-}
-
-
-static int
-json_to_gnsrecord (const json_t *records_json,
- struct GNUNET_GNSRECORD_Data **rd,
- unsigned int *rd_count)
-{
- struct GNUNET_TIME_Relative etime_rel;
- struct GNUNET_TIME_Absolute etime_abs;
- char *value;
- void *rdata;
- size_t rdata_size;
- const char *typestring;
- const char *expirationstring;
- json_t *type_json;
- json_t *value_json;
- json_t *record_json;
- json_t *exp_json;
-
- *rd_count = json_array_size (records_json);
- *rd = GNUNET_new_array (*rd_count,
- struct GNUNET_GNSRECORD_Data);
- for (unsigned int i = 0; i < *rd_count; i++)
+ handle->label_name = GNUNET_strdup(json_string_value(name_json));
+ if(NULL == handle->label_name)
{
- memset (&(*rd)[i],
- 0,
- sizeof (struct GNUNET_GNSRECORD_Data));
- record_json = json_array_get (records_json,
- i);
- type_json = json_object_get (record_json,
- GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE);
- if (! json_is_string (type_json))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Type property is no string\n");
- return GNUNET_SYSERR;
- }
- typestring = json_string_value (type_json);
- (*rd)[i].record_type = GNUNET_GNSRECORD_typename_to_number (typestring);
- if (UINT32_MAX == (*rd)[i].record_type)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Unsupported type `%s'\n"),
- json_string_value (type_json));
- return GNUNET_SYSERR;
- }
- value_json = json_object_get (record_json,
- GNUNET_REST_JSONAPI_NAMESTORE_VALUE);
- if (! json_is_string (value_json))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Value property is no string\n");
- return GNUNET_SYSERR;
- }
- value = GNUNET_strdup (json_string_value (value_json));
- if (GNUNET_OK !=
- GNUNET_GNSRECORD_string_to_value ((*rd)[i].record_type,
- value,
- &rdata,
- &rdata_size))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _("Value `%s' invalid for record type `%s'\n"),
- value,
- typestring);
- return GNUNET_SYSERR;
- }
- (*rd)[i].data = rdata;
- (*rd)[i].data_size = rdata_size;
- /**TODO
- * if (1 == handle->is_shadow)
- rde->flags |= GNUNET_GNSRECORD_RF_SHADOW_RECORD;
- if (1 != handle->is_public)
- rde->flags |= GNUNET_GNSRECORD_RF_PRIVATE;
- */
- exp_json = json_object_get (record_json,
- GNUNET_REST_JSONAPI_NAMESTORE_EXPIRATION);
- if (! json_is_string (exp_json))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Expiration property is no string\n");
- return GNUNET_SYSERR;
- }
- expirationstring = json_string_value (exp_json);
- if (0 == strcmp (expirationstring, "never"))
- {
- (*rd)[i].expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
- }
- else if (GNUNET_OK ==
- GNUNET_STRINGS_fancy_time_to_relative (expirationstring,
- &etime_rel))
- {
- (*rd)[i].expiration_time = etime_rel.rel_value_us;
- (*rd)[i].flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
- }
- else if (GNUNET_OK ==
- GNUNET_STRINGS_fancy_time_to_absolute (expirationstring,
- &etime_abs))
- {
- (*rd)[i].expiration_time = etime_abs.abs_value_us;
- }
- else
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _("Value `%s' invalid for record type `%s'\n"),
- value,
- typestring);
- return GNUNET_SYSERR;
- }
- }
- return GNUNET_OK;
-}
-
-
-static void
-namestore_create_cont (struct GNUNET_REST_RequestHandle *con,
- const char *url,
- void *cls)
-{
- struct RequestHandle *handle = cls;
- struct MHD_Response *resp;
- struct GNUNET_JSONAPI_Document *json_obj;
- struct GNUNET_JSONAPI_Resource *json_res;
- json_t *records_json;
- json_t *data_js;
- json_error_t err;
- char term_data[handle->rest_handle->data_size+1];
- struct GNUNET_JSON_Specification docspec[] = {
- GNUNET_JSON_spec_jsonapi_document (&json_obj),
- GNUNET_JSON_spec_end()
- };
-
- if (strlen (GNUNET_REST_API_NS_NAMESTORE) != strlen (handle->url))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Cannot create under %s\n", handle->url);
+ handle->emsg = GNUNET_strdup("Missing name");
GNUNET_SCHEDULER_add_now (&do_error, handle);
+ json_decref (data_js);
return;
}
- if (0 >= handle->rest_handle->data_size)
+ if (0 >= strlen(handle->label_name))
{
+ handle->emsg = GNUNET_strdup("Missing name");
GNUNET_SCHEDULER_add_now (&do_error, handle);
+ json_decref (data_js);
return;
}
- term_data[handle->rest_handle->data_size] = '\0';
- GNUNET_memcpy (term_data,
- handle->rest_handle->data,
- handle->rest_handle->data_size);
- data_js = json_loads (term_data,
- JSON_DECODE_ANY,
- &err);
- GNUNET_assert (GNUNET_OK ==
- GNUNET_JSON_parse (data_js, docspec,
- NULL, NULL));
json_decref (data_js);
- if (NULL == json_obj)
+
+ //change zone if pubkey or name specified
+ GNUNET_CRYPTO_hash (GNUNET_REST_API_PARAM_PUBKEY,
+ strlen (GNUNET_REST_API_PARAM_PUBKEY),
+ &key);
+ if ( GNUNET_YES
+ == GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map,
+ &key))
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unable to parse JSONAPI Object from %s\n",
- term_data);
- GNUNET_SCHEDULER_add_now (&do_error, handle);
- return;
+ pubkey = GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map,
+ &key);
}
- if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
+ GNUNET_CRYPTO_hash (GNUNET_REST_API_PARAM_NAME,
+ strlen (GNUNET_REST_API_PARAM_NAME),
+ &key);
+ if ( GNUNET_YES
+ == GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map,
+ &key))
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Cannot create more than 1 resource! (Got %d)\n",
- GNUNET_JSONAPI_document_resource_count (json_obj));
- GNUNET_JSONAPI_document_delete (json_obj);
- GNUNET_SCHEDULER_add_now (&do_error, handle);
- return;
+ name = GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map,
+ &key);
}
- json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
- if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res,
- GNUNET_REST_JSONAPI_NAMESTORE_RECORD))
+
+ ego_entry = get_egoentry(handle,pubkey,name);
+ if (NULL == ego_entry)
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unsupported JSON data type\n");
- GNUNET_JSONAPI_document_delete (json_obj);
- resp = GNUNET_REST_create_response (NULL);
- handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
- cleanup_handle (handle);
- return;
+ if (NULL != pubkey || NULL != name)
+ {
+ handle->emsg = GNUNET_strdup("Invalid identity");
+ handle->response_code = MHD_HTTP_NOT_FOUND;
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ return;
+ }
}
- handle->name = GNUNET_strdup (GNUNET_JSONAPI_resource_get_id (json_res));
- records_json = GNUNET_JSONAPI_resource_read_attr (json_res,
- GNUNET_REST_JSONAPI_NAMESTORE_RECORD);
- if (NULL == records_json)
+ if ( NULL != ego_entry )
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "No records given\n");
- GNUNET_JSONAPI_document_delete (json_obj);
- GNUNET_SCHEDULER_add_now (&do_error, handle);
- return;
+ handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key(ego_entry->ego);
}
- if (GNUNET_SYSERR == json_to_gnsrecord (records_json, &handle->rd, &handle->rd_count))
+ if (NULL == handle->zone_pkey)
{
- GNUNET_JSONAPI_document_delete (json_obj);
+ handle->emsg = GNUNET_strdup("No default identity for namestore");
GNUNET_SCHEDULER_add_now (&do_error, handle);
return;
}
- GNUNET_JSONAPI_document_delete (json_obj);
-
handle->add_qe = GNUNET_NAMESTORE_records_lookup (handle->ns_handle,
- &handle->zone_pkey,
- handle->name,
- &do_error,
- handle,
- &create_new_record_cont,
- handle);
+ handle->zone_pkey,
+ handle->label_name,
+ &do_error,
+ handle,
+ &create_new_record_cont,
+ handle);
}
static void
-namestore_zkey_response (void *cls,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
- const char *label,
- unsigned int rd_count,
- const struct GNUNET_GNSRECORD_Data *rd)
+del_cont (void *cls,
+ const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
+ const char *label,
+ unsigned int rd_count,
+ const struct GNUNET_GNSRECORD_Data *rd)
{
struct RequestHandle *handle = cls;
- struct MHD_Response *resp;
- struct GNUNET_JSONAPI_Document *json_obj;
- struct GNUNET_JSONAPI_Resource *json_res;
- json_t *name_json;
- char* result;
- handle->reverse_qe = NULL;
- json_obj = GNUNET_JSONAPI_document_new ();
- if (NULL != label)
- {
- name_json = json_string (label);
- json_res = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_NAMESTORE_REVINFO,
- handle->zkey_str);
- GNUNET_JSONAPI_resource_add_attr (json_res,
- GNUNET_REST_JSONAPI_NAMESTORE_NAME,
- name_json);
- GNUNET_JSONAPI_document_resource_add (json_obj, json_res);
- json_decref (name_json);
- }
- //Handle response
- if (GNUNET_SYSERR == GNUNET_JSONAPI_document_serialize (json_obj, &result))
+ handle->add_qe = NULL;
+ if (0 == rd_count)
{
- GNUNET_JSONAPI_document_delete (json_obj);
+ handle->emsg = GNUNET_strdup("Record not found");
GNUNET_SCHEDULER_add_now (&do_error, handle);
return;
}
- resp = GNUNET_REST_create_response (result);
- handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
- GNUNET_JSONAPI_document_delete (json_obj);
- GNUNET_free (result);
- GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
-}
+ handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
+ handle->zone_pkey,
+ handle->label_name,
+ 0, NULL,
+ &del_finished,
+ handle);
+}
-static void
-namestore_zkey_cont (struct GNUNET_REST_RequestHandle *con,
- const char *url,
- void *cls)
+/**
+ * Handle namestore DELETE request
+ *
+ * @param con_handle the connection handle
+ * @param url the url
+ * @param cls the RequestHandle
+ */
+void
+namestore_delete (struct GNUNET_REST_RequestHandle *con_handle,
+ const char* url,
+ void *cls)
{
struct RequestHandle *handle = cls;
struct GNUNET_HashCode key;
- struct GNUNET_CRYPTO_EcdsaPublicKey pubkey;
-
- GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_NAMESTORE_ZKEY,
- strlen (GNUNET_REST_JSONAPI_NAMESTORE_ZKEY),
- &key);
- if ( GNUNET_NO ==
- GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
- &key) )
+ struct EgoEntry *ego_entry = NULL;
+ char *pubkey = NULL;
+ char *name = NULL;
+
+ //change zone if pubkey or name specified
+ GNUNET_CRYPTO_hash (GNUNET_REST_API_PARAM_PUBKEY,
+ strlen (GNUNET_REST_API_PARAM_PUBKEY),
+ &key);
+ if ( GNUNET_YES
+ == GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map,
+ &key))
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "No zkey given %s\n", handle->url);
+ pubkey = GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map,
+ &key);
+ }
+ GNUNET_CRYPTO_hash (GNUNET_REST_API_PARAM_NAME,
+ strlen (GNUNET_REST_API_PARAM_NAME),
+ &key);
+ if ( GNUNET_YES
+ == GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map,
+ &key))
+ {
+ name = GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map,
+ &key);
+ }
+
+ ego_entry = get_egoentry(handle,pubkey,name);
+ if (NULL == ego_entry)
+ {
+ if (NULL != pubkey || NULL != name)
+ {
+ handle->emsg = GNUNET_strdup("Invalid identity");
+ handle->response_code = MHD_HTTP_NOT_FOUND;
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ return;
+ }
+ }
+ if ( NULL != ego_entry )
+ {
+ handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key(ego_entry->ego);
+ }
+
+ GNUNET_CRYPTO_hash ("label", strlen ("label"), &key);
+ if ( GNUNET_NO
+ == GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map,
+ &key))
+ {
+ handle->emsg = GNUNET_strdup("Missing name");
GNUNET_SCHEDULER_add_now (&do_error, handle);
return;
}
- handle->zkey_str = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
- &key);
- if ((NULL == handle->zkey_str) ||
- (GNUNET_OK !=
- GNUNET_CRYPTO_ecdsa_public_key_from_string (handle->zkey_str,
- strlen (handle->zkey_str),
- &pubkey)))
+ handle->label_name = GNUNET_strdup(
+ GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map, &key));
+
+ if (NULL == handle->zone_pkey)
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Zkey invalid %s\n", handle->zkey_str);
+ handle->emsg = GNUNET_strdup("No default identity for namestore");
GNUNET_SCHEDULER_add_now (&do_error, handle);
return;
}
- handle->reverse_qe = GNUNET_NAMESTORE_zone_to_name (handle->ns_handle,
- &handle->zone_pkey,
- &pubkey,
- &do_error,
- handle,
- &namestore_zkey_response,
- handle);
-}
-
-static void
-namestore_info_cont (struct GNUNET_REST_RequestHandle *con,
- const char *url,
- void *cls)
-{
- struct RequestHandle *handle = cls;
+ handle->add_qe = GNUNET_NAMESTORE_records_lookup (handle->ns_handle,
+ handle->zone_pkey,
+ handle->label_name,
+ &do_error,
+ handle,
+ &del_cont,
+ handle);
- handle->list_it = GNUNET_NAMESTORE_zone_iteration_start (handle->ns_handle,
- &handle->zone_pkey,
- &do_error,
- handle,
- &namestore_list_response,
- handle,
- &namestore_list_finished,
- handle);
}
-static char*
-get_name_from_url (const char* url)
-{
- if (strlen (url) <= strlen (GNUNET_REST_API_NS_NAMESTORE))
- return NULL;
- return (char*)url + strlen (GNUNET_REST_API_NS_NAMESTORE) + 1;
-}
/**
* Respond to OPTIONS request
@@ -977,101 +852,72 @@ options_cont (struct GNUNET_REST_RequestHandle *con_handle,
struct MHD_Response *resp;
struct RequestHandle *handle = cls;
- //For now, independent of path return all options
+ //independent of path return all options
resp = GNUNET_REST_create_response (NULL);
MHD_add_response_header (resp,
"Access-Control-Allow-Methods",
allow_methods);
handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
- cleanup_handle (handle);
+ GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
+ return;
}
/**
- * Callback invoked from identity service with ego information.
- * An @a ego of NULL means the ego was not found.
+ * Handle rest request
*
- * @param cls closure with the configuration
- * @param ego an ego known to identity service, or NULL
+ * @param handle the request handle
*/
static void
-identity_cb (void *cls,
- const struct GNUNET_IDENTITY_Ego *ego)
+init_cont (struct RequestHandle *handle)
{
- struct RequestHandle *handle = cls;
- struct MHD_Response *resp;
struct GNUNET_REST_RequestHandlerError err;
static const struct GNUNET_REST_RequestHandler handlers[] = {
- {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_NAMESTORE_ZKEY, &namestore_zkey_cont}, //reverse
- {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_NAMESTORE, &namestore_info_cont}, //list
- {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_NAMESTORE, &namestore_create_cont}, //create
- // {MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_NAMESTORE, &namestore_edit_cont}, //update. TODO this shoul be PATCH
- {MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_NAMESTORE, &namestore_delete_cont}, //delete
+ {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_NAMESTORE, &namestore_get},
+ {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_NAMESTORE, &namestore_add},
+ {MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_NAMESTORE, &namestore_delete},
{MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_NAMESTORE, &options_cont},
GNUNET_REST_HANDLER_END
};
- handle->ego_lookup = NULL;
- if (NULL == ego)
- {
- if (NULL != handle->ego_name)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _("Ego `%s' not known to identity service\n"),
- handle->ego_name);
- }
- resp = GNUNET_REST_create_response (NULL);
- handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
- cleanup_handle (handle);
- return;
- }
- handle->zone_pkey = *GNUNET_IDENTITY_ego_get_private_key (ego);
- handle->ns_handle = GNUNET_NAMESTORE_connect (cfg);
- if (NULL == handle->ns_handle)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _("Failed to connect to namestore\n"));
- GNUNET_SCHEDULER_add_now (&do_error, handle);
- return;
- }
-
- if (GNUNET_OK !=
- GNUNET_JSONAPI_handle_request (handle->rest_handle,
- handlers,
- &err,
- handle))
+ if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle,
+ handlers,
+ &err,
+ handle))
{
handle->response_code = err.error_code;
- GNUNET_SCHEDULER_add_now (&do_error,
- (void *) handle);
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
}
}
-
+/**
+ * @param cls closure
+ * @param ego ego handle
+ * @param ctx context for application to store data for this ego
+ * (during the lifetime of this process, initially NULL)
+ * @param identifier identifier assigned by the user for this ego,
+ * NULL if the user just deleted the ego and it
+ * must thus no longer be used
+ */
static void
default_ego_cb (void *cls,
struct GNUNET_IDENTITY_Ego *ego,
void **ctx,
- const char *name)
+ const char *identifier)
{
struct RequestHandle *handle = cls;
- struct MHD_Response *resp;
- handle->get_default = NULL;
- if (NULL == ego)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _("No default ego configured in identity service\n"));
- resp = GNUNET_REST_create_response (NULL);
- handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
- cleanup_handle (handle);
- return;
- }
- else
+ handle->op = NULL;
+
+ if (ego != NULL)
{
- identity_cb (cls, ego);
+ handle->zone_pkey = GNUNET_IDENTITY_ego_get_private_key (ego);
}
}
+
+/**
+ * Connect to identity callback
+ */
static void
id_connect_cb (void *cls,
struct GNUNET_IDENTITY_Ego *ego,
@@ -1079,12 +925,33 @@ id_connect_cb (void *cls,
const char *name)
{
struct RequestHandle *handle = cls;
- if (NULL == ego)
+ struct EgoEntry *ego_entry;
+ struct GNUNET_CRYPTO_EcdsaPublicKey pk;
+
+ if ((NULL == ego) && (NULL == handle->zone_pkey))
+ {
+ handle->op = GNUNET_IDENTITY_get (handle->identity_handle,
+ GNUNET_REST_SUBSYSTEM_NAMESTORE,
+ &default_ego_cb,
+ handle);
+ }
+ if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
+ {
+ handle->state = ID_REST_STATE_POST_INIT;
+ init_cont (handle);
+ return;
+ }
+ if (ID_REST_STATE_INIT == handle->state)
{
- handle->get_default = GNUNET_IDENTITY_get (handle->identity_handle,
- "namestore",
- &default_ego_cb, handle);
+ ego_entry = GNUNET_new(struct EgoEntry);
+ GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
+ ego_entry->keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
+ ego_entry->ego = ego;
+ GNUNET_asprintf (&ego_entry->identifier, "%s", name);
+ GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head, handle->ego_tail,
+ ego_entry);
}
+
}
@@ -1097,81 +964,38 @@ id_connect_cb (void *cls,
* @param data_size length of the body
* @param proc callback function for the result
* @param proc_cls closure for callback function
- * @return #GNUNET_OK if request accepted
+ * @return GNUNET_OK if request accepted
*/
static void
-rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle,
+rest_process_request(struct GNUNET_REST_RequestHandle *rest_handle,
GNUNET_REST_ResultProcessor proc,
void *proc_cls)
{
struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
- struct MHD_Response *resp;
- struct GNUNET_HashCode key;
- char *ego;
- char *name;
- char *type;
-
+
+ handle->response_code = 0;
handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
handle->proc_cls = proc_cls;
handle->proc = proc;
handle->rest_handle = rest_handle;
+ handle->zone_pkey = NULL;
+
handle->url = GNUNET_strdup (rest_handle->url);
if (handle->url[strlen (handle->url)-1] == '/')
handle->url[strlen (handle->url)-1] = '\0';
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Connecting...\n");
- handle->cfg = cfg;
- ego = NULL;
- GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_NAMESTORE_EGO,
- strlen (GNUNET_REST_JSONAPI_NAMESTORE_EGO),
- &key);
- if ( GNUNET_YES ==
- GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
- &key) )
- {
- ego = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
- &key);
- }
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n");
- handle->type = GNUNET_GNSRECORD_TYPE_ANY;
- GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE,
- strlen (GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE),
- &key);
- if ( GNUNET_YES ==
- GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
- &key) )
- {
- type = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
- &key);
- if (NULL != type)
- handle->type = GNUNET_GNSRECORD_typename_to_number (type);
- }
- name = get_name_from_url (handle->url);
- if (NULL != ego)
- handle->ego_name = GNUNET_strdup (ego);
- if (NULL != name)
- handle->name = GNUNET_strdup (name);
- if (NULL == handle->ego_name)
- {
- handle->identity_handle = GNUNET_IDENTITY_connect (handle->cfg, &id_connect_cb, handle);
- if (NULL == handle->identity_handle)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Cannot connect to identity service\n"));
- resp = GNUNET_REST_create_response (NULL);
- handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
- cleanup_handle (handle);
- }
- return;
- }
- handle->ego_lookup = GNUNET_IDENTITY_ego_lookup (cfg,
- handle->ego_name,
- &identity_cb,
- handle);
- handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout,
- &do_timeout,
- handle);
+ handle->identity_handle = GNUNET_IDENTITY_connect (cfg, &id_connect_cb, handle);
+ handle->ns_handle = GNUNET_NAMESTORE_connect (cfg);
+ handle->timeout_task =
+ GNUNET_SCHEDULER_add_delayed (handle->timeout,
+ &do_error,
+ handle);
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected\n");
}
+
/**
* Entry point for the plugin.
*
@@ -1182,9 +1006,9 @@ void *
libgnunet_plugin_rest_namestore_init (void *cls)
{
static struct Plugin plugin;
- cfg = cls;
struct GNUNET_REST_Plugin *api;
+ cfg = cls;
if (NULL != plugin.cfg)
return NULL; /* can only initialize once! */
memset (&plugin, 0, sizeof (struct Plugin));
@@ -1192,7 +1016,7 @@ libgnunet_plugin_rest_namestore_init (void *cls)
api = GNUNET_new (struct GNUNET_REST_Plugin);
api->cls = &plugin;
api->name = GNUNET_REST_API_NS_NAMESTORE;
- api->process_request = &rest_identity_process_request;
+ api->process_request = &rest_process_request;
GNUNET_asprintf (&allow_methods,
"%s, %s, %s, %s, %s",
MHD_HTTP_METHOD_GET,
@@ -1200,7 +1024,8 @@ libgnunet_plugin_rest_namestore_init (void *cls)
MHD_HTTP_METHOD_PUT,
MHD_HTTP_METHOD_DELETE,
MHD_HTTP_METHOD_OPTIONS);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
_("Namestore REST API initialized\n"));
return api;
}
@@ -1217,13 +1042,14 @@ libgnunet_plugin_rest_namestore_done (void *cls)
{
struct GNUNET_REST_Plugin *api = cls;
struct Plugin *plugin = api->cls;
-
plugin->cfg = NULL;
- GNUNET_free (api);
+
GNUNET_free_non_null (allow_methods);
+ GNUNET_free (api);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Namestore REST plugin is finished\n");
return NULL;
}
/* end of plugin_rest_namestore.c */
+
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 @@
+#!/usr/bin/bash
+
+#First, start gnunet-arm and the rest-service.
+#Exit 0 means success, exit 1 means failed test
+
+namestore_link="http://localhost:7776/namestore"
+wrong_link="http://localhost:7776/namestoreandmore"
+
+
+curl_get () {
+ #$1 is link
+ #$2 is grep
+ cache="$(curl -v "$1" 2>&1 | grep "$2")"
+ #echo $cache
+ if [ "" == "$cache" ]
+ then
+ exit 1
+ fi
+}
+
+curl_post () {
+ #$1 is link
+ #$2 is data
+ #$3 is grep
+ cache="$(curl -v -X "POST" "$1" --data "$2" 2>&1 | grep "$3")"
+ #echo $cache
+ if [ "" == "$cache" ]
+ then
+ exit 1
+ fi
+}
+
+curl_delete () {
+ #$1 is link
+ #$2 is grep
+ cache="$(curl -v -X "DELETE" "$1" 2>&1 | grep "$2")"
+ #echo $cache
+ if [ "" == "$cache" ]
+ then
+ exit 1
+ fi
+}
+
+# curl_put () {
+# #$1 is link
+# #$2 is data
+# #$3 is grep
+# cache="$(curl -v -X "PUT" "$1" --data "$2" 2>&1 | grep "$3")"
+# #echo $cache
+# if [ "" == "$cache" ]
+# then
+# exit 1
+# fi
+# }
+
+#Test subsystem default identity
+
+#Test GET
+gnunet-identity -D "test_plugin_rest_namestore"
+gnunet-identity -C "test_plugin_rest_namestore"
+test="$(gnunet-namestore -D -z "test_plugin_rest_namestore")"
+name="test_plugin_rest_namestore"
+public="$(gnunet-identity -d | grep "test_plugin_rest_namestore" | awk 'NR==1{print $3}')"
+if [ "" == "$test" ]
+then
+ #if no entries for test_plugin_rest_namestore
+ curl_get "${namestore_link}?name=$name" "error"
+ curl_get "${namestore_link}?name=" "error"
+ curl_get "${namestore_link}?name=$public" "error"
+
+ curl_get "${namestore_link}?pubkey=$public" "error"
+ curl_get "${namestore_link}?pubkey=$name" "error"
+ curl_get "${namestore_link}?pubkey=" "error"
+else
+ #if entries exists (that should not be possible)
+ curl_get "${namestore_link}" "HTTP/1.1 200 OK"
+ curl_get "${namestore_link}?name=$name" "HTTP/1.1 200 OK"
+ curl_get "${namestore_link}?name=" "error"
+ curl_get "${namestore_link}?name=$public" "error"
+
+ curl_get "${namestore_link}?pubkey=$public" "HTTP/1.1 200 OK"
+ curl_get "${namestore_link}?pubkey=$name" "error"
+ curl_get "${namestore_link}?pubkey=" "error"
+fi
+gnunet-namestore -z $name -p -a -n "test_entry" -e "1d" -V "HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG" -t "PKEY"
+curl_get "${namestore_link}" "HTTP/1.1 200 OK"
+curl_get "${namestore_link}?name=$name" "HTTP/1.1 200 OK"
+curl_get "${namestore_link}?name=" "error"
+curl_get "${namestore_link}?name=$public" "error"
+curl_get "${namestore_link}?pubkey=$public" "HTTP/1.1 200 OK"
+curl_get "${namestore_link}?pubkey=$name" "error"
+curl_get "${namestore_link}?pubkey=" "error"
+gnunet-namestore -z $name -d -n "test_entry"
+
+#Test POST with NAME
+curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":0,"label":"test_entry"}' "HTTP/1.1 204 No Content"
+gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
+#value
+curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRGxxx", "type":"PKEY", "expiration_time":"1d","flag":0,"label":"test_entry"}' "error"
+gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
+curl_post "${namestore_link}?name=$name" '{"value":"", "type":"PKEY", "expiration_time":"1d","flag":0,"label":"test_entry"}' "error"
+gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
+curl_post "${namestore_link}?name=$name" '{"value_missing":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRGxxx", "type":"PKEY", "expiration_time":"1d","flag":0,"label":"test_entry"}' "error"
+gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
+#time
+curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"0d","flag":0,"label":"test_entry"}' "HTTP/1.1 204"
+gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
+curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"10000d","flag":0,"label":"test_entry"}' "HTTP/1.1 204"
+gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
+curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"now","flag":0,"label":"test_entry"}' "error"
+gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
+curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"","flag":0,"label":"test_entry"}' "error"
+gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
+curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time_missing":"1d","flag":0,"label":"test_entry"}' "error"
+gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
+#flag
+curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":0,"label":"test_entry"}' "HTTP/1.1 204 No Content"
+gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
+curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":2,"label":"test_entry"}' "HTTP/1.1 204 No Content"
+gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
+curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":8,"label":"test_entry"}' "HTTP/1.1 204 No Content"
+gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
+curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":16,"label":"test_entry"}' "HTTP/1.1 204 No Content"
+gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
+curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":-1,"label":"test_entry"}' "error"
+gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
+curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":"Test","label":"test_entry"}' "error"
+gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
+curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":,"label":"test_entry"}' "error"
+gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
+curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag_missing":0,"label":"test_entry"}' "error"
+gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
+#label
+curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":0,"label":"test_entry"}' "HTTP/1.1 204 No Content"
+curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":0,"label":"test_entry"}' "HTTP/1.1 409"
+gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
+curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":0,"label":""}' "error"
+gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
+curl_post "${namestore_link}?name=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":0,"label_missing":"test_entry"}' "error"
+gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
+
+#Test POST with PUBKEY
+curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":0,"label":"test_entry"}' "HTTP/1.1 204 No Content"
+gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
+#value
+curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRGxxx", "type":"PKEY", "expiration_time":"1d","flag":0,"label":"test_entry"}' "error"
+gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
+curl_post "${namestore_link}?pubkey=$public" '{"value":"", "type":"PKEY", "expiration_time":"1d","flag":0,"label":"test_entry"}' "error"
+gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
+curl_post "${namestore_link}?pubkey=$public" '{"value_missing":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRGxxx", "type":"PKEY", "expiration_time":"1d","flag":0,"label":"test_entry"}' "error"
+gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
+#time
+curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"0d","flag":0,"label":"test_entry"}' "HTTP/1.1 204"
+gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
+curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"10000d","flag":0,"label":"test_entry"}' "HTTP/1.1 204"
+gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
+curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"now","flag":0,"label":"test_entry"}' "error"
+gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
+curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"","flag":0,"label":"test_entry"}' "error"
+gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
+curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time_missing":"1d","flag":0,"label":"test_entry"}' "error"
+gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
+#flag
+curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":0,"label":"test_entry"}' "HTTP/1.1 204 No Content"
+gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
+curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":2,"label":"test_entry"}' "HTTP/1.1 204 No Content"
+gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
+curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":8,"label":"test_entry"}' "HTTP/1.1 204 No Content"
+gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
+curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":16,"label":"test_entry"}' "HTTP/1.1 204 No Content"
+gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
+curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":-1,"label":"test_entry"}' "error"
+gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
+curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":"Test","label":"test_entry"}' "error"
+gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
+curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":,"label":"test_entry"}' "error"
+gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
+curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag_missing":0,"label":"test_entry"}' "error"
+gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
+#label
+curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":0,"label":"test_entry"}' "HTTP/1.1 204 No Content"
+curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":0,"label":"test_entry"}' "HTTP/1.1 409"
+gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
+curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":0,"label":""}' "error"
+gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
+curl_post "${namestore_link}?pubkey=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":0,"label_missing":"test_entry"}' "error"
+gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
+
+#wrong zone
+curl_post "${namestore_link}?name=$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":0,"label":"test_entry"}' "error"
+gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
+curl_post "${namestore_link}?pubkey=$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "type":"PKEY", "expiration_time":"1d","flag":0,"label":"test_entry"}' "error"
+gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1
+
+#Test DELETE
+gnunet-namestore -z $name -p -a -n "test_entry" -e "1d" -V "HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG" -t "PKEY"
+curl_delete "${namestore_link}?label=test_entry&name=$name" "HTTP/1.1 204"
+gnunet-namestore -z $name -p -a -n "test_entry" -e "1d" -V "HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG" -t "PKEY"
+curl_delete "${namestore_link}?label=test_entry&pubkey=$public" "HTTP/1.1 204"
+gnunet-namestore -z $name -p -a -n "test_entry" -e "1d" -V "HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG" -t "PKEY"
+curl_delete "${namestore_link}?label=test_entry&pubkey=$name" "HTTP/1.1 404"
+
+
+#Test default identity
+#not possible without defining
+
+exit 0;
+
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/
libexecdir= $(pkglibdir)/libexec/
+plugindir = $(libdir)/gnunet
+
pkgcfg_DATA = \
peerinfo.conf
@@ -25,6 +27,8 @@ libgnunetpeerinfo_la_SOURCES = \
libgnunetpeerinfo_la_LIBADD = \
$(top_builddir)/src/hello/libgnunethello.la \
$(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/json/libgnunetjson.la \
+ $(top_builddir)/src/transport/libgnunettransport.la \
$(XLIB) \
$(LTLIBINTL)
libgnunetpeerinfo_la_LDFLAGS = \
@@ -35,12 +39,30 @@ libgnunetpeerinfo_la_LDFLAGS = \
libexec_PROGRAMS = \
gnunet-service-peerinfo
+if HAVE_MHD
+if HAVE_JSON
+plugin_LTLIBRARIES = \
+ libgnunet_plugin_rest_peerinfo.la
+endif
+endif
+
gnunet_service_peerinfo_SOURCES = \
gnunet-service-peerinfo.c
gnunet_service_peerinfo_LDADD = \
$(top_builddir)/src/hello/libgnunethello.la \
$(top_builddir)/src/statistics/libgnunetstatistics.la \
$(top_builddir)/src/util/libgnunetutil.la
+
+
+libgnunet_plugin_rest_peerinfo_la_SOURCES = \
+ plugin_rest_peerinfo.c
+libgnunet_plugin_rest_peerinfo_la_LIBADD = \
+ libgnunetpeerinfo.la \
+ $(top_builddir)/src/rest/libgnunetrest.la \
+ $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \
+ $(LTLIBINTL) -ljansson -lmicrohttpd
+libgnunet_plugin_rest_peerinfo_la_LDFLAGS = \
+ $(GN_PLUGIN_LDFLAGS)
if HAVE_BENCHMARKS
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 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2012-2015 GNUnet e.V.
+
+ GNUnet is free software: you can redistribute it and/or modify it
+ under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License,
+ or (at your option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/**
+ * @author Martin Schanzenbach
+ * @author Philippe Buschmann
+ * @file peerinfo/plugin_rest_peerinfo.c
+ * @brief GNUnet Peerinfo REST plugin
+ */
+
+#include "platform.h"
+#include "gnunet_rest_plugin.h"
+#include "gnunet_peerinfo_service.h"
+#include "gnunet_transport_service.h"
+#include "gnunet_rest_lib.h"
+#include "gnunet_json_lib.h"
+#include "microhttpd.h"
+#include <jansson.h>
+
+#define GNUNET_REST_API_NS_PEERINFO "/peerinfo"
+
+#define GNUNET_REST_API_PEERINFO_PEER "peer"
+#define GNUNET_REST_API_PEERINFO_FRIEND "friend"
+#define GNUNET_REST_API_PEERINFO_ARRAY "array"
+
+#define GNUNET_REST_ERROR_UNKNOWN "Unkown Error"
+
+/**
+ * How long until we time out during address lookup?
+ */
+#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
+/**
+ * The configuration handle
+ */
+const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+/**
+ * HTTP methods allows for this plugin
+ */
+static char* allow_methods;
+
+/**
+ * @brief struct returned by the initialization function of the plugin
+ */
+struct Plugin
+{
+ const struct GNUNET_CONFIGURATION_Handle *cfg;
+};
+
+
+/**
+ * Record we keep for each printable address.
+ */
+struct AddressRecord
+{
+ /**
+ * Current address-to-string context (if active, otherwise NULL).
+ */
+ struct GNUNET_TRANSPORT_AddressToStringContext *atsc;
+
+ /**
+ * Address expiration time
+ */
+ struct GNUNET_TIME_Absolute expiration;
+
+ /**
+ * Printable address.
+ */
+ char *result;
+
+ /**
+ * Print context this address record belongs to.
+ */
+ struct PrintContext *pc;
+};
+
+
+/**
+ * Structure we use to collect printable address information.
+ */
+struct PrintContext
+{
+
+ /**
+ * Kept in DLL.
+ */
+ struct PrintContext *next;
+
+ /**
+ * Kept in DLL.
+ */
+ struct PrintContext *prev;
+
+ /**
+ * Identity of the peer.
+ */
+ struct GNUNET_PeerIdentity peer;
+
+ /**
+ * List of printable addresses.
+ */
+ struct AddressRecord *address_list;
+
+ /**
+ * Number of completed addresses in @e address_list.
+ */
+ unsigned int num_addresses;
+
+ /**
+ * Number of addresses allocated in @e address_list.
+ */
+ unsigned int address_list_size;
+
+ /**
+ * Current offset in @e address_list (counted down).
+ */
+ unsigned int off;
+
+ /**
+ * Hello was friend only, #GNUNET_YES or #GNUNET_NO
+ */
+ int friend_only;
+
+ /**
+ * RequestHandle
+ */
+ struct RequestHandle *handle;
+
+};
+
+/**
+ * Head of list of print contexts.
+ */
+static struct PrintContext *pc_head;
+
+/**
+ * Tail of list of print contexts.
+ */
+static struct PrintContext *pc_tail;
+
+struct RequestHandle
+{
+ /**
+ * JSON temporary array
+ */
+ json_t *temp_array;
+
+ /**
+ * Expiration time string
+ */
+ char *expiration_str;
+
+ /**
+ * Address string
+ */
+ const char *address;
+
+ /**
+ * Iteration peer public key
+ */
+ char *pubkey;
+
+ /**
+ * JSON response
+ */
+ json_t *response;
+
+ /**
+ * Handle to PEERINFO it
+ */
+ struct GNUNET_PEERINFO_IteratorContext *list_it;
+
+ /**
+ * Handle to PEERINFO
+ */
+ struct GNUNET_PEERINFO_Handle *peerinfo_handle;
+
+ /**
+ * Rest connection
+ */
+ struct GNUNET_REST_RequestHandle *rest_handle;
+
+ /**
+ * Desired timeout for the lookup (default is no timeout).
+ */
+ struct GNUNET_TIME_Relative timeout;
+
+ /**
+ * ID of a task associated with the resolution process.
+ */
+ struct GNUNET_SCHEDULER_Task *timeout_task;
+
+ /**
+ * The plugin result processor
+ */
+ GNUNET_REST_ResultProcessor proc;
+
+ /**
+ * The closure of the result processor
+ */
+ void *proc_cls;
+
+ /**
+ * The url
+ */
+ char *url;
+
+ /**
+ * Error response message
+ */
+ char *emsg;
+
+ /**
+ * Reponse code
+ */
+ int response_code;
+
+};
+
+
+/**
+ * Cleanup lookup handle
+ * @param handle Handle to clean up
+ */
+static void
+cleanup_handle (void *cls)
+{
+ struct RequestHandle *handle = cls;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Cleaning up\n");
+ if (NULL != handle->timeout_task)
+ {
+ GNUNET_SCHEDULER_cancel (handle->timeout_task);
+ handle->timeout_task = NULL;
+ }
+ if (NULL != handle->url)
+ GNUNET_free (handle->url);
+ if (NULL != handle->emsg)
+ GNUNET_free (handle->emsg);
+ if (NULL != handle->address)
+ GNUNET_free ((char*)handle->address);
+ if (NULL != handle->expiration_str)
+ GNUNET_free (handle->expiration_str);
+ if (NULL != handle->pubkey)
+ GNUNET_free (handle->pubkey);
+
+ if (NULL != handle->temp_array)
+ {
+ json_decref(handle->temp_array);
+ handle->temp_array = NULL;
+ }
+ if (NULL != handle->response)
+ {
+ json_decref(handle->response);
+ handle->response = NULL;
+ }
+
+ if (NULL != handle->list_it)
+ {
+ GNUNET_PEERINFO_iterate_cancel(handle->list_it);
+ handle->list_it = NULL;
+ }
+ if (NULL != handle->peerinfo_handle)
+ {
+ GNUNET_PEERINFO_disconnect(handle->peerinfo_handle);
+ handle->peerinfo_handle = NULL;
+ }
+
+ GNUNET_free (handle);
+}
+
+
+/**
+ * Task run on errors. Reports an error and cleans up everything.
+ *
+ * @param cls the `struct RequestHandle`
+ */
+static void
+do_error (void *cls)
+{
+ struct RequestHandle *handle = cls;
+ struct MHD_Response *resp;
+ json_t *json_error = json_object();
+ char *response;
+
+ if (NULL == handle->emsg)
+ handle->emsg = GNUNET_strdup(GNUNET_REST_ERROR_UNKNOWN);
+
+ json_object_set_new(json_error,"error", json_string(handle->emsg));
+
+ if (0 == handle->response_code)
+ handle->response_code = MHD_HTTP_OK;
+ response = json_dumps (json_error, 0);
+ resp = GNUNET_REST_create_response (response);
+ handle->proc (handle->proc_cls, resp, handle->response_code);
+ json_decref(json_error);
+ GNUNET_free(response);
+ GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
+}
+
+
+/**
+ * Function that assembles our response.
+ */
+static void
+peerinfo_list_finished (void *cls)
+{
+ struct RequestHandle *handle = cls;
+ char *result_str;
+ struct MHD_Response *resp;
+
+ if (NULL == handle->response)
+ {
+ handle->emsg = GNUNET_strdup ("No peers found");
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ return;
+ }
+
+ result_str = json_dumps (handle->response, 0);
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
+ resp = GNUNET_REST_create_response (result_str);
+ handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
+ GNUNET_free_non_null (result_str);
+ GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
+}
+
+
+/**
+ * Iterator callback to go over all addresses and count them.
+ *
+ * @param cls `struct PrintContext *` with `off` to increment
+ * @param address the address
+ * @param expiration expiration time
+ * @return #GNUNET_OK to keep the address and continue
+ */
+static int
+count_address (void *cls,
+ const struct GNUNET_HELLO_Address *address,
+ struct GNUNET_TIME_Absolute expiration)
+{
+ struct PrintContext *pc = cls;
+
+ if (0 == GNUNET_TIME_absolute_get_remaining (expiration).rel_value_us)
+ {
+ return GNUNET_OK; /* ignore expired address */
+ }
+
+ pc->off++;
+ return GNUNET_OK;
+}
+
+
+/**
+ * Print the collected address information to the console and free @a pc.
+ *
+ * @param pc printing context
+ */
+static void
+dump_pc (struct PrintContext *pc)
+{
+ struct RequestHandle *handle;
+ unsigned int i;
+ json_t *response_entry;
+ json_t *temp_array;
+ json_t *object;
+ json_t *address;
+ json_t *expires;
+ json_t *friend_and_peer_json;
+ char *friend_and_peer;
+
+ temp_array = json_array();
+ response_entry = json_object();
+
+// printf (_("%sPeer `%s'\n"),
+// (GNUNET_YES == pc->friend_only) ? "F2F: " : "",
+// GNUNET_i2s_full (&pc->peer));
+ for (i = 0; i < pc->num_addresses; i++)
+ {
+ if (NULL != pc->address_list[i].result)
+ {
+ object = json_object ();
+ address = json_string(pc->address_list[i].result);
+ expires = json_string(
+ GNUNET_STRINGS_absolute_time_to_string (pc->address_list[i].expiration));
+ json_object_set (object, "address", address);
+ json_object_set (object, "expires", expires);
+
+ json_decref(address);
+ json_decref(expires);
+
+ json_array_append(temp_array, object);
+ json_decref(object);
+ GNUNET_free (pc->address_list[i].result);
+ }
+ }
+
+ if (0 < json_array_size(temp_array))
+ {
+ GNUNET_asprintf(&friend_and_peer,
+ "%s%s",
+ (GNUNET_YES == pc->friend_only) ? "F2F:" : "",
+ GNUNET_i2s_full (&pc->peer));
+ friend_and_peer_json = json_string(friend_and_peer);
+ json_object_set(response_entry,
+ GNUNET_REST_API_PEERINFO_PEER,
+ friend_and_peer_json);
+ json_object_set(response_entry,
+ GNUNET_REST_API_PEERINFO_ARRAY,
+ temp_array);
+ json_array_append(pc->handle->response, response_entry);
+ json_decref(friend_and_peer_json);
+ GNUNET_free(friend_and_peer);
+ }
+
+ json_decref (temp_array);
+ json_decref(response_entry);
+
+ GNUNET_free_non_null (pc->address_list);
+ GNUNET_CONTAINER_DLL_remove (pc_head,
+ pc_tail,
+ pc);
+ handle = pc->handle;
+ GNUNET_free (pc);
+
+ if ( (NULL == pc_head) &&
+ (NULL == handle->list_it) )
+ {
+ GNUNET_SCHEDULER_add_now (&peerinfo_list_finished, handle);
+ }
+
+}
+
+
+/**
+ * Function to call with a human-readable format of an address
+ *
+ * @param cls closure
+ * @param address NULL on error, otherwise 0-terminated printable UTF-8 string
+ * @param res result of the address to string conversion:
+ * if #GNUNET_OK: address was valid (conversion to
+ * string might still have failed)
+ * if #GNUNET_SYSERR: address is invalid
+ */
+static void
+process_resolved_address (void *cls,
+ const char *address,
+ int res)
+{
+ struct AddressRecord *ar = cls;
+ struct PrintContext *pc = ar->pc;
+
+ if (NULL != address)
+ {
+ if (0 != strlen (address))
+ {
+ if (NULL != ar->result)
+ GNUNET_free (ar->result);
+ ar->result = GNUNET_strdup (address);
+ }
+ return;
+ }
+ ar->atsc = NULL;
+ if (GNUNET_SYSERR == res)
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _("Failure: Cannot convert address to string for peer `%s'\n"),
+ GNUNET_i2s (&ar->pc->peer));
+ pc->num_addresses++;
+ if (pc->num_addresses == pc->address_list_size)
+ dump_pc (ar->pc);
+}
+
+
+/**
+ * Iterator callback to go over all addresses.
+ *
+ * @param cls closure
+ * @param address the address
+ * @param expiration expiration time
+ * @return #GNUNET_OK to keep the address and continue
+ */
+static int
+print_address (void *cls,
+ const struct GNUNET_HELLO_Address *address,
+ struct GNUNET_TIME_Absolute expiration)
+{
+ struct PrintContext *pc = cls;
+ struct AddressRecord *ar;
+
+ if (0 == GNUNET_TIME_absolute_get_remaining (expiration).rel_value_us)
+ {
+ return GNUNET_OK; /* ignore expired address */
+ }
+
+ GNUNET_assert (0 < pc->off);
+ ar = &pc->address_list[--pc->off];
+ ar->pc = pc;
+ ar->expiration = expiration;
+ GNUNET_asprintf (&ar->result,
+ "%s:%u:%u",
+ address->transport_name,
+ address->address_length,
+ address->local_info);
+ ar->atsc = GNUNET_TRANSPORT_address_to_string (cfg,
+ address,
+ GNUNET_NO,
+ TIMEOUT,
+ &process_resolved_address,
+ ar);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Callback that processes each of the known HELLOs for the
+ * iteration response construction.
+ *
+ * @param cls closure, NULL
+ * @param peer id of the peer, NULL for last call
+ * @param hello hello message for the peer (can be NULL)
+ * @param err_msg message
+ */
+void
+peerinfo_list_iteration(void *cls,
+ const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_HELLO_Message *hello,
+ const char *err_msg)
+{
+ struct RequestHandle *handle = cls;
+ struct PrintContext *pc;
+ int friend_only;
+
+ if (NULL == handle->response)
+ {
+ handle->response = json_array();
+ }
+
+ if (NULL == peer)
+ {
+ handle->list_it = NULL;
+ handle->emsg = GNUNET_strdup ("Error in communication with peerinfo");
+ if (NULL != err_msg)
+ {
+ GNUNET_free(handle->emsg);
+ handle->emsg = GNUNET_strdup (err_msg);
+ handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
+ }
+ if (NULL == pc_head)
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ return;
+ }
+ if (NULL == hello)
+ return;
+
+ friend_only = GNUNET_NO;
+ if (NULL != hello)
+ friend_only = GNUNET_HELLO_is_friend_only (hello);
+
+ pc = GNUNET_new(struct PrintContext);
+ GNUNET_CONTAINER_DLL_insert (pc_head,
+ pc_tail,
+ pc);
+ pc->peer = *peer;
+ pc->friend_only = friend_only;
+ pc->handle = handle;
+ GNUNET_HELLO_iterate_addresses (hello,
+ GNUNET_NO,
+ &count_address,
+ pc);
+ if (0 == pc->off)
+ {
+ dump_pc (pc);
+ return;
+ }
+ pc->address_list_size = pc->off;
+ pc->address_list = GNUNET_malloc(
+ sizeof(struct AddressRecord) * pc->off);
+ GNUNET_HELLO_iterate_addresses (hello,
+ GNUNET_NO,
+ &print_address,
+ pc);
+}
+
+/**
+ * Handle peerinfo GET request
+ *
+ * @param con_handle the connection handle
+ * @param url the url
+ * @param cls the RequestHandle
+ */
+void
+peerinfo_get (struct GNUNET_REST_RequestHandle *con_handle,
+ const char* url,
+ void *cls)
+{
+ struct RequestHandle *handle = cls;
+ struct GNUNET_HashCode key;
+ const struct GNUNET_PeerIdentity *specific_peer;
+ GNUNET_PEER_Id peer_id;
+ int include_friend_only;
+ char* include_friend_only_str;
+
+ include_friend_only = GNUNET_NO;
+ GNUNET_CRYPTO_hash (GNUNET_REST_API_PEERINFO_FRIEND,
+ strlen (GNUNET_REST_API_PEERINFO_FRIEND),
+ &key);
+ if ( GNUNET_YES
+ == GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map,
+ &key))
+ {
+ include_friend_only_str = GNUNET_CONTAINER_multihashmap_get (
+ con_handle->url_param_map, &key);
+ if (0 == strcmp(include_friend_only_str, "yes"))
+ {
+ include_friend_only = GNUNET_YES;
+ }
+ }
+
+ specific_peer = NULL;
+ GNUNET_CRYPTO_hash (GNUNET_REST_API_PEERINFO_PEER,
+ strlen (GNUNET_REST_API_PEERINFO_PEER),
+ &key);
+ if ( GNUNET_YES
+ == GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map,
+ &key))
+ {
+ peer_id = *(unsigned int*)GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map, &key);
+ specific_peer = GNUNET_PEER_resolve2(peer_id);
+ }
+
+ handle->list_it = GNUNET_PEERINFO_iterate(handle->peerinfo_handle,
+ include_friend_only,
+ specific_peer,
+ &peerinfo_list_iteration,
+ handle);
+}
+
+
+
+/**
+ * Respond to OPTIONS request
+ *
+ * @param con_handle the connection handle
+ * @param url the url
+ * @param cls the RequestHandle
+ */
+static void
+options_cont (struct GNUNET_REST_RequestHandle *con_handle,
+ const char* url,
+ void *cls)
+{
+ struct MHD_Response *resp;
+ struct RequestHandle *handle = cls;
+
+ //independent of path return all options
+ resp = GNUNET_REST_create_response (NULL);
+ MHD_add_response_header (resp,
+ "Access-Control-Allow-Methods",
+ allow_methods);
+ handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
+ GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
+ return;
+}
+
+
+/**
+ * Handle rest request
+ *
+ * @param handle the request handle
+ */
+static void
+init_cont (struct RequestHandle *handle)
+{
+ struct GNUNET_REST_RequestHandlerError err;
+ static const struct GNUNET_REST_RequestHandler handlers[] = {
+ {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_PEERINFO, &peerinfo_get},
+ {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_PEERINFO, &options_cont},
+ GNUNET_REST_HANDLER_END
+ };
+
+ if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle,
+ handlers,
+ &err,
+ handle))
+ {
+ handle->response_code = err.error_code;
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ }
+}
+
+
+/**
+ * Function processing the REST call
+ *
+ * @param method HTTP method
+ * @param url URL of the HTTP request
+ * @param data body of the HTTP request (optional)
+ * @param data_size length of the body
+ * @param proc callback function for the result
+ * @param proc_cls closure for callback function
+ * @return GNUNET_OK if request accepted
+ */
+static void
+rest_process_request(struct GNUNET_REST_RequestHandle *rest_handle,
+ GNUNET_REST_ResultProcessor proc,
+ void *proc_cls)
+{
+ struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
+
+ handle->response_code = 0;
+ handle->timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60);
+ handle->proc_cls = proc_cls;
+ handle->proc = proc;
+ handle->rest_handle = rest_handle;
+
+ handle->url = GNUNET_strdup (rest_handle->url);
+ if (handle->url[strlen (handle->url)-1] == '/')
+ handle->url[strlen (handle->url)-1] = '\0';
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n");
+ handle->peerinfo_handle = GNUNET_PEERINFO_connect(cfg);
+ init_cont(handle);
+ handle->timeout_task =
+ GNUNET_SCHEDULER_add_delayed (handle->timeout,
+ &do_error,
+ handle);
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected\n");
+}
+
+
+/**
+ * Entry point for the plugin.
+ *
+ * @param cls Config info
+ * @return NULL on error, otherwise the plugin context
+ */
+void *
+libgnunet_plugin_rest_peerinfo_init (void *cls)
+{
+ static struct Plugin plugin;
+ struct GNUNET_REST_Plugin *api;
+
+ cfg = cls;
+ if (NULL != plugin.cfg)
+ return NULL; /* can only initialize once! */
+ memset (&plugin, 0, sizeof (struct Plugin));
+ plugin.cfg = cfg;
+ api = GNUNET_new (struct GNUNET_REST_Plugin);
+ api->cls = &plugin;
+ api->name = GNUNET_REST_API_NS_PEERINFO;
+ api->process_request = &rest_process_request;
+ GNUNET_asprintf (&allow_methods,
+ "%s, %s, %s, %s, %s",
+ MHD_HTTP_METHOD_GET,
+ MHD_HTTP_METHOD_POST,
+ MHD_HTTP_METHOD_PUT,
+ MHD_HTTP_METHOD_DELETE,
+ MHD_HTTP_METHOD_OPTIONS);
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ _("Peerinfo REST API initialized\n"));
+ return api;
+}
+
+
+/**
+ * Exit point from the plugin.
+ *
+ * @param cls the plugin context (as returned by "init")
+ * @return always NULL
+ */
+void *
+libgnunet_plugin_rest_peerinfo_done (void *cls)
+{
+ struct GNUNET_REST_Plugin *api = cls;
+ struct Plugin *plugin = api->cls;
+ plugin->cfg = NULL;
+
+ GNUNET_free_non_null (allow_methods);
+ GNUNET_free (api);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Peerinfo REST plugin is finished\n");
+ return NULL;
+}
+
+/* end of plugin_rest_peerinfo.c */
+