/*
This file is part of GNUnet.
Copyright (C) 2012-2018 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 .
SPDX-License-Identifier: AGPL3.0-or-later
*/
/**
* @author Martin Schanzenbach
* @file gns/plugin_rest_config.c
* @brief REST plugin for configuration
*
*/
#include "platform.h"
#include "gnunet_rest_plugin.h"
#include
#include
#include
#define GNUNET_REST_API_NS_CONFIG "/config"
/**
* @brief struct returned by the initialization function of the plugin
*/
struct Plugin
{
const struct GNUNET_CONFIGURATION_Handle *cfg;
};
const struct GNUNET_CONFIGURATION_Handle *cfg;
struct RequestHandle
{
/**
* DLL
*/
struct RequestHandle *next;
/**
* DLL
*/
struct RequestHandle *prev;
/**
* Handle to rest request
*/
struct GNUNET_REST_RequestHandle *rest_handle;
/**
* The plugin result processor
*/
GNUNET_REST_ResultProcessor proc;
/**
* The closure of the result processor
*/
void *proc_cls;
/**
* HTTP response code
*/
int response_code;
/**
* The URL
*/
char *url;
};
/**
* DLL
*/
static struct RequestHandle *requests_head;
/**
* DLL
*/
static struct RequestHandle *requests_tail;
/**
* Cleanup request handle.
*
* @param handle Handle to clean up
*/
static void
cleanup_handle (struct RequestHandle *handle)
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
if (NULL != handle->url)
GNUNET_free (handle->url);
GNUNET_CONTAINER_DLL_remove (requests_head,
requests_tail,
handle);
GNUNET_free (handle);
}
/**
* Task run on shutdown. Cleans up everything.
*
* @param cls unused
* @param tc scheduler context
*/
static void
do_error (void *cls)
{
struct RequestHandle *handle = cls;
struct MHD_Response *resp;
resp = GNUNET_REST_create_response (NULL);
handle->proc (handle->proc_cls, resp, handle->response_code);
cleanup_handle (handle);
}
static void
add_sections (void *cls,
const char *section,
const char *option,
const char *value)
{
json_t *sections_obj = cls;
json_t *sec_obj;
sec_obj = json_object_get (sections_obj, section);
if (NULL != sec_obj)
{
json_object_set_new (sec_obj, option, json_string (value));
return;
}
sec_obj = json_object ();
json_object_set_new (sec_obj, option, json_string (value));
json_object_set_new (sections_obj, section, sec_obj);
}
static void
add_section_contents (void *cls,
const char *section,
const char *option,
const char *value)
{
json_t *section_obj = cls;
json_object_set_new (section_obj, option, json_string (value));
}
/**
* Handle rest request
*
* @param handle the lookup handle
*/
static void
get_cont (struct GNUNET_REST_RequestHandle *con_handle,
const char *url,
void *cls)
{
struct MHD_Response *resp;
struct RequestHandle *handle = cls;
const char *section;
char *response;
json_t *result;
if (strlen (GNUNET_REST_API_NS_CONFIG) > strlen (handle->url))
{
handle->response_code = MHD_HTTP_BAD_REQUEST;
GNUNET_SCHEDULER_add_now (&do_error, handle);
return;
}
if (strlen (GNUNET_REST_API_NS_CONFIG) == strlen (handle->url))
{
result = json_object ();
GNUNET_CONFIGURATION_iterate (cfg, &add_sections, result);
}
else
{
result = json_object ();
section = &handle->url[strlen (GNUNET_REST_API_NS_CONFIG) + 1];
GNUNET_CONFIGURATION_iterate_section_values (cfg,
section,
&add_section_contents,
result);
}
response = json_dumps (result, 0);
resp = GNUNET_REST_create_response (response);
MHD_add_response_header (resp, "Content-Type", "application/json");
handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
cleanup_handle (handle);
GNUNET_free (response);
json_decref (result);
}
struct GNUNET_CONFIGURATION_Handle *
set_value (struct GNUNET_CONFIGURATION_Handle *config,
const char *section,
const char *option,
json_t *value)
{
if (json_is_string (value))
GNUNET_CONFIGURATION_set_value_string (config, section, option,
json_string_value (value));
else if (json_is_number (value))
GNUNET_CONFIGURATION_set_value_number (config, section, option,
json_integer_value (value));
else if (json_is_null (value))
GNUNET_CONFIGURATION_set_value_string (config, section, option, NULL);
else if (json_is_true (value))
GNUNET_CONFIGURATION_set_value_string (config, section, option, "yes");
else if (json_is_false (value))
GNUNET_CONFIGURATION_set_value_string (config, section, option, "no");
else
return NULL;
return config; // for error handling (0 -> success, 1 -> error)
}
/**
* Handle REST POST request
*
* @param handle the lookup handle
*/
static void
set_cont (struct GNUNET_REST_RequestHandle *con_handle,
const char *url,
void *cls)
{
struct RequestHandle *handle = cls;
char term_data[handle->rest_handle->data_size + 1];
struct GNUNET_CONFIGURATION_Handle *out = GNUNET_CONFIGURATION_dup (cfg);
json_error_t err;
json_t *data_json;
const char *section;
const char *option;
json_t *sec_obj;
json_t *value;
char *cfg_fn;
// invalid url
if (strlen (GNUNET_REST_API_NS_CONFIG) > strlen (handle->url))
{
handle->response_code = MHD_HTTP_BAD_REQUEST;
GNUNET_SCHEDULER_add_now (&do_error, handle);
return;
}
// extract data from handle
term_data[handle->rest_handle->data_size] = '\0';
GNUNET_memcpy (term_data,
handle->rest_handle->data,
handle->rest_handle->data_size);
data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
if (NULL == data_json)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unable to parse JSON Object from %s\n",
term_data);
GNUNET_SCHEDULER_add_now (&do_error, handle);
return;
}
// POST /config => { : {