/*
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
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
#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 <jansson.h>
-#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
*/
struct GNUNET_GNS_LookupRequest *lookup_request;
+ /**
+ * Handle to rest request
+ */
+ struct GNUNET_REST_RequestHandle *rest_handle;
+
/**
* Lookup an ego with the identity service.
*/
/**
* 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
/**
* 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;
*/
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,
* @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;
(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);
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; i<rd_count; i++)
{
if ( (rd[i].record_type != handle->type) &&
(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);
}
}
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;
}
}
{
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
{
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);
* @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;
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(struct RestConnectionDataHandle *conndata_handle,
- 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 (conndata_handle->url, handle))
+ 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 < conndata_handle->data_size)
- {
- if (GNUNET_OK != parse_json (conndata_handle->data, conndata_handle->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);
&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);
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,
(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));
}
}
+/**
+ * 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 callback function
+ * @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)
+{
+ 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;
+
+ 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
+ };
+
+ 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.
*
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"));