diff options
author | Schanzenbach, Martin <martin.schanzenbach@aisec.fraunhofer.de> | 2018-08-09 23:57:14 +0200 |
---|---|---|
committer | Schanzenbach, Martin <martin.schanzenbach@aisec.fraunhofer.de> | 2018-08-09 23:57:14 +0200 |
commit | 08c410658159c0975ad87d7b7582259cd2ac6ee4 (patch) | |
tree | f567c9020be2505f1c16a7249020e3e965ba7194 /src | |
parent | 389f4939845a0cb00e5ce0d8ea3ab7fc0541fd1c (diff) | |
parent | 1ad7b69834fffc95e05354983009e435030c0861 (diff) |
Merge branch 'gsoc2018/rest_api'
Diffstat (limited to 'src')
-rw-r--r-- | src/gns/plugin_rest_gns.c | 674 | ||||
-rwxr-xr-x | src/gns/test_plugin_rest_gns.sh | 50 | ||||
-rw-r--r-- | src/gnsrecord/gnsrecord.c | 3 | ||||
-rw-r--r-- | src/identity/Makefile.am | 2 | ||||
-rw-r--r-- | src/identity/plugin_rest_identity.c | 1057 | ||||
-rwxr-xr-x | src/identity/test_plugin_rest_identity.sh | 159 | ||||
-rw-r--r-- | src/include/gnunet_json_lib.h | 23 | ||||
-rw-r--r-- | src/json/Makefile.am | 4 | ||||
-rw-r--r-- | src/json/json_generator.c | 35 | ||||
-rw-r--r-- | src/json/json_gnsrecord.c | 177 | ||||
-rw-r--r-- | src/namestore/Makefile.am | 4 | ||||
-rw-r--r-- | src/namestore/plugin_rest_namestore.c | 1276 | ||||
-rwxr-xr-x | src/namestore/test_plugin_rest_namestore.sh | 208 | ||||
-rw-r--r-- | src/peerinfo/Makefile.am | 22 | ||||
-rw-r--r-- | src/peerinfo/plugin_rest_peerinfo.c | 801 |
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 */ + |