X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Fgns%2Fplugin_rest_gns.c;h=1d215b6a495bf81adef75d4d82ec4953e3b0083e;hb=620bdac536dff4b17317d9d20b8a6840836d6490;hp=75b0ff28881e692296d542f0b34f0ca429087153;hpb=59f6e4b0c42486d16a370c3524b78d88ac7fbcbc;p=oweals%2Fgnunet.git diff --git a/src/gns/plugin_rest_gns.c b/src/gns/plugin_rest_gns.c index 75b0ff288..1d215b6a4 100644 --- a/src/gns/plugin_rest_gns.c +++ b/src/gns/plugin_rest_gns.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - Copyright (C) 2012-2015 Christian Grothoff (and other contributing authors) + 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 General Public License as published @@ -14,8 +14,8 @@ You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ /** * @author Martin Schanzenbach @@ -31,9 +31,24 @@ #include #include #include +#include +#include +#include #include -#define API_NAMESPACE "/gns" +#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_JSONAPI_GNS_EGO "ego" + +#define GNUNET_REST_JSONAPI_GNS_PKEY "pkey" + +#define GNUNET_REST_JSONAPI_GNS_OPTIONS "options" /** * @brief struct returned by the initialization function of the plugin @@ -62,6 +77,11 @@ struct LookupHandle */ struct GNUNET_GNS_LookupRequest *lookup_request; + /** + * Handle to rest request + */ + struct GNUNET_REST_RequestHandle *rest_handle; + /** * Lookup an ego with the identity service. */ @@ -80,7 +100,7 @@ struct LookupHandle /** * ID of a task associated with the resolution process. */ - struct GNUNET_SCHEDULER_Task * timeout_task; + struct GNUNET_SCHEDULER_Task * timeout_task; /** * The root of the received JSON or NULL @@ -110,12 +130,12 @@ struct LookupHandle /** * The Pkey to use - * In stirng representation from JSON + * In string representation from JSON */ const char *pkey_str; /** - * The record type to look up + * The record type */ int type; @@ -139,13 +159,20 @@ struct LookupHandle */ struct GNUNET_CRYPTO_EcdsaPrivateKey shorten_key; + /** + * HTTP response code + */ + int response_code; + }; + /** - * Cleanup lookup handle - * @praram handle Handle to clean up + * Cleanup lookup handle. + * + * @param handle Handle to clean up */ -void +static void cleanup_handle (struct LookupHandle *handle) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, @@ -196,20 +223,23 @@ cleanup_handle (struct LookupHandle *handle) * @param tc scheduler context */ static void -do_error (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) +do_error (void *cls) { struct LookupHandle *handle = cls; - handle->proc (handle->proc_cls, NULL, 0, GNUNET_SYSERR); + struct MHD_Response *resp; + + resp = GNUNET_REST_create_response (NULL); + handle->proc (handle->proc_cls, resp, handle->response_code); cleanup_handle (handle); } + /** * Create json representation of a GNSRECORD * * @param rd the GNSRECORD_Data */ -json_t * +static json_t * gnsrecord_to_json (const struct GNUNET_GNSRECORD_Data *rd) { const char *typename; @@ -229,7 +259,7 @@ gnsrecord_to_json (const struct GNUNET_GNSRECORD_Data *rd) (int) rd->record_type); return NULL; } - record_obj = json_object(); + 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); @@ -265,36 +295,37 @@ process_lookup_result (void *cls, uint32_t rd_count, const struct GNUNET_GNSRECORD_Data *rd) { struct LookupHandle *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_root; - json_t *result_name; json_t *result_array; json_t *record_obj; - result_root = json_object(); - result_name = json_string (handle->name); result_array = json_array(); - json_object_set (result_root, "name", result_name); - json_decref (result_name); + 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; itype) && (GNUNET_GNSRECORD_TYPE_ANY != handle->type) ) continue; - record_obj = gnsrecord_to_json (&(rd[i])); json_array_append (result_array, record_obj); json_decref (record_obj); } - json_object_set (result_root, "query_result", result_array); - json_decref (result_array); - result = json_dumps (result_root, JSON_COMPACT); + 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); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result); - json_decref (result_root); - handle->proc (handle->proc_cls, result, strlen (result), GNUNET_OK); + 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); cleanup_handle (handle); } @@ -305,10 +336,9 @@ process_lookup_result (void *cls, uint32_t rd_count, * identified by the given public key and the shorten zone. * * @param pkey public key to use for the zone, can be NULL - * @param shorten_key private key used for shortening, can be NULL */ static void -lookup_with_keys (struct LookupHandle *handle, const struct GNUNET_CRYPTO_EcdsaPrivateKey *shorten_key) +lookup_with_public_key (struct LookupHandle *handle) { if (UINT32_MAX == handle->type) { @@ -323,69 +353,16 @@ lookup_with_keys (struct LookupHandle *handle, const struct GNUNET_CRYPTO_EcdsaP &handle->pkey, handle->type, handle->options, - shorten_key, &process_lookup_result, handle); } else { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Please specify name to lookup!\n")); - handle->proc (handle->proc_cls, NULL, 0, GNUNET_SYSERR); - cleanup_handle (handle); + GNUNET_SCHEDULER_add_now (&do_error, handle); return; } } -/** - * Method called to with the ego we are to use for shortening - * during the lookup. - * - * @param cls closure contains the public key to use - * @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_shorten_cb (void *cls, - struct GNUNET_IDENTITY_Ego *ego, - void **ctx, - const char *name) -{ - struct LookupHandle *handle = cls; - - handle->id_op = NULL; - if (NULL == ego) - lookup_with_keys (handle, NULL); - else - lookup_with_keys (handle, - GNUNET_IDENTITY_ego_get_private_key (ego)); -} - -/** - * Perform the actual resolution, starting with the zone - * identified by the given public key. - * - * @param pkey public key to use for the zone - */ -static void -lookup_with_public_key (struct LookupHandle *handle) -{ - handle->pkeym = handle->pkey; - GNUNET_break (NULL == handle->id_op); - handle->id_op = GNUNET_IDENTITY_get (handle->identity, - "gns-short", - &identity_shorten_cb, - handle); - if (NULL == handle->id_op) - { - GNUNET_break (0); - lookup_with_keys (handle, NULL); - } -} /** * Method called to with the ego we are to use for the lookup, @@ -405,8 +382,7 @@ identity_zone_cb (void *cls, { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Ego for not found, cannot perform lookup.\n")); - handle->proc (handle->proc_cls, NULL, 0, GNUNET_SYSERR); - cleanup_handle (handle); + GNUNET_SCHEDULER_add_now (&do_error, handle); return; } else @@ -417,6 +393,7 @@ identity_zone_cb (void *cls, json_decref(handle->json_root); } + /** * Method called to with the ego we are to use for the lookup, * when the ego is the one for the default master zone. @@ -443,11 +420,11 @@ identity_master_cb (void *cls, { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Ego for `gns-master' not found, cannot perform lookup. Did you run gnunet-gns-import.sh?\n")); - handle->proc (handle->proc_cls, NULL, 0, GNUNET_SYSERR); - cleanup_handle (handle); + GNUNET_SCHEDULER_add_now (&do_error, handle); return; } - GNUNET_IDENTITY_ego_get_public_key (ego, &handle->pkey); + 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 */ @@ -467,11 +444,10 @@ identity_master_cb (void *cls, * @param handle lookup handle to populate * @return GNUNET_SYSERR on error */ -int +static int parse_url (const char *url, struct LookupHandle *handle) { char *name; - char *type; char tmp_url[strlen(url)+1]; char *tok; @@ -487,117 +463,25 @@ parse_url (const char *url, struct LookupHandle *handle) name); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got name: %s\n", handle->name); - type = strtok (NULL, "/"); - if (NULL == type) - { - handle->type = GNUNET_GNSRECORD_TYPE_ANY; - return GNUNET_OK; - } - handle->type = GNUNET_GNSRECORD_typename_to_number (type); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Got type: %s\n", type); return GNUNET_OK; } -/** - * Parse json from REST request - * - * @param data REST data - * @param data_size data size - * @param handle Handle to populate - * @return GNUNET_SYSERR on error - */ -int -parse_json (const char *data, size_t data_size, struct LookupHandle *handle) -{ - json_error_t error; - json_t *pkey_json; - json_t *ego_json; - json_t *options_json; - - char term_data[data_size+1]; - term_data[data_size] = '\0'; - - memcpy (term_data, data, data_size); - - handle->json_root = json_loads (term_data, 0, &error); - - if (NULL == handle->json_root) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, error.text); - return GNUNET_SYSERR; - } - if(!json_is_object(handle->json_root)) - { - return GNUNET_SYSERR; - } - - ego_json = json_object_get (handle->json_root, "ego"); - - if(json_is_string(ego_json)) - { - handle->ego_str = json_string_value (ego_json); - } - - pkey_json = json_object_get (handle->json_root, "pkey"); - if(json_is_string(pkey_json)) - { - handle->pkey_str = json_string_value (pkey_json); - } - - options_json = json_object_get (handle->json_root, "options"); - if(json_is_integer (options_json)) - { - handle->options = json_integer_value (options_json); - } - return GNUNET_OK; -} - - -/** - * 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 - */ -void -rest_gns_process_request(const char *method, - const char *url, - const char *data, - size_t data_size, - GNUNET_REST_ResultProcessor proc, - void *proc_cls) +static void +get_gns_cont (struct GNUNET_REST_RequestHandle *conndata_handle, + const char* url, + void *cls) { - struct LookupHandle *handle = GNUNET_new (struct LookupHandle); - handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL; + struct LookupHandle *handle = cls; + struct GNUNET_HashCode key; //parse name and type from url if (GNUNET_OK != parse_url (url, handle)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error parsing url...\n"); - proc (proc_cls, NULL, 0, GNUNET_SYSERR); - cleanup_handle (handle); + GNUNET_SCHEDULER_add_now (&do_error, handle); return; } - - handle->proc_cls = proc_cls; - handle->proc = proc; - if (0 < data_size) - { - if (GNUNET_OK != parse_json (data, data_size, handle)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error parsing json...\n"); - proc (proc_cls, NULL, 0, GNUNET_SYSERR); - cleanup_handle (handle); - return; - } - } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n"); handle->gns = GNUNET_GNS_connect (cfg); @@ -606,32 +490,68 @@ rest_gns_process_request(const char *method, &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"); - proc (proc_cls, NULL, 0, GNUNET_SYSERR); - cleanup_handle (handle); + 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; - if (NULL != handle->pkey_str) + 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))) { - proc (proc_cls, NULL, 0, GNUNET_SYSERR); - cleanup_handle (handle); + GNUNET_SCHEDULER_add_now (&do_error, handle); return; } lookup_with_public_key (handle); - + return; } - if (NULL != handle->ego_str) + 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, @@ -643,7 +563,6 @@ rest_gns_process_request(const char *method, (0 == strcmp (".zkey", &handle->name[strlen (handle->name) - 4])) ) { - /* no zone required, use 'anonymous' zone */ GNUNET_CRYPTO_ecdsa_key_get_public (GNUNET_CRYPTO_ecdsa_key_get_anonymous (), &(handle->pkey)); @@ -660,6 +579,71 @@ rest_gns_process_request(const char *method, } } +/** + * Handle rest request + * + * @param handle the lookup handle + */ +static void +options_cont (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + struct MHD_Response *resp; + struct LookupHandle *handle = cls; + + //For GNS, 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); +} + + +/** + * 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 @a proc + * @return #GNUNET_OK if request accepted + */ +static void +rest_gns_process_request (struct GNUNET_REST_RequestHandle *conndata_handle, + GNUNET_REST_ResultProcessor proc, + void *proc_cls) +{ + 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)) + { + handle->response_code = err.error_code; + GNUNET_SCHEDULER_add_now (&do_error, handle); + } +} + + /** * Entry point for the plugin. * @@ -679,7 +663,7 @@ libgnunet_plugin_rest_gns_init (void *cls) plugin.cfg = cfg; api = GNUNET_new (struct GNUNET_REST_Plugin); api->cls = &plugin; - api->name = API_NAMESPACE; + 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"));