twister

HTTP fault injector for testing
Log | Files | Refs | README | LICENSE

commit 0fd827bdc833aec5a50a0575b51a79543a2bacb2
parent c4368a157fe9d2e12a4949464ddade5c8ae3cf4f
Author: Marcello Stanisci <stanisci.m@gmail.com>
Date:   Tue,  6 Mar 2018 16:12:34 +0100

parse proxied response.

Diffstat:
Msrc/include/taler_twister_service.h | 18++++++++++++++++++
Msrc/twister/taler-twister-service.c | 78++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
Msrc/twister/taler-twister.c | 27++++++++++++++++++++++++++-
Msrc/twister/twister.h | 59+++++++++++++++++++++++++++++++++++++++++++++--------------
Msrc/twister/twister_api.c | 39+++++++++++++++++++++++++++++++++++++++
5 files changed, 202 insertions(+), 19 deletions(-)

diff --git a/src/include/taler_twister_service.h b/src/include/taler_twister_service.h @@ -93,6 +93,24 @@ TALER_TWISTER_change_response_code /** + * Delete the object pointed to by @a path. + * + * @param h twister instance to control + * @param path object-like notation to point the object to be + deleted. E.g., the path "f1.f2.0" will delete the object + {"f1": {"f2": [{"to be": "deleted"}]}}. + * @param cb function to call once twister is ready + * @param cb_cls closure for @a cb + * @return operation handle (to possibly abort) + */ +struct TALER_TWISTER_Operation * +TALER_TWISTER_delete_path + (struct TALER_TWISTER_Handle *h, + const char *path, + GNUNET_SCHEDULER_TaskCallback cb, + void *cb_cls); + +/** * Abort operation. Twister behavior may then include the * changes requested by the operation, or not! Must be called * before the operations callback was invoked. diff --git a/src/twister/taler-twister-service.c b/src/twister/taler-twister-service.c @@ -35,6 +35,9 @@ #endif #include <gnunet/gnunet_util_lib.h> #include "twister.h" +#include <jansson.h> +#include <microhttpd.h> +#include <taler/taler_util.h> /** @@ -184,6 +187,14 @@ struct HttpRequest /* *********************** Globals **************************** */ +/** + * Generic error message to return as a response in case the + * twister is not able to parse the response it got from the + * proxied service. FIXME: define Taler-compatible error codes + * and messages.. + */ +static char *error_msg = "{\"error\": \ + \"Failed to parse proxied response\"}"; /** * The cURL download task (curl multi API). @@ -229,7 +240,14 @@ static char *target_server_base_url; */ static unsigned int hack_response_code; +/** + * Will point to a JSON object to delete + */ +static char delete_path[TWISTER_PATH_LENGTH]; +/** + * Will point to the path if it has to be deleted + */ /* ************************* Global helpers ********************* */ @@ -430,10 +448,14 @@ create_mhd_response_from_hr (struct HttpRequest *hr) "Creating MHD response with code %u\n", (unsigned int) resp_code); hr->response_code = resp_code; - hr->response = MHD_create_response_from_buffer (hr->io_len, - hr->io_buf, - MHD_RESPMEM_MUST_COPY); - for (header = hr->header_head; NULL != header; header = header->next) + hr->response = MHD_create_response_from_buffer + (hr->io_len, + hr->io_buf, + MHD_RESPMEM_MUST_COPY); + + for (header = hr->header_head; + NULL != header; + header = header->next) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding MHD response header %s->%s\n", @@ -1060,6 +1082,31 @@ create_response (void *cls, hr->response_code = hack_response_code; hack_response_code = 0; /* reset for next request */ } + + if ('\0' != delete_path[0]) + { + json_t *parsed_response; + json_error_t error; + + MHD_destroy_response (hr->response); + + if (NULL == MHD_lookup_connection_value (con, + MHD_HEADER_KIND, + "application/json")) + /* No JSON header, but will try to parse it anyway. */ + TALER_LOG_WARNING ("Response is not a JSON (?)\n"); + + if (NULL == (parsed_response = json_loadb + (hr->io_buf, hr->io_len, JSON_DECODE_ANY, &error))) + { + TALER_LOG_ERROR ("Could not parse response\n"); + hr->response = MHD_create_response_from_buffer + (strlen (error_msg), + error_msg, + MHD_RESPMEM_PERSISTENT); + } + } + return MHD_queue_response (con, hr->response_code, hr->response); @@ -1350,6 +1397,8 @@ run (void *cls, (void) cls; (void) service; cfg = c; + delete_path[0] = '\0'; + if (0 != curl_global_init (CURL_GLOBAL_WIN32)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, @@ -1470,6 +1519,22 @@ send_acknowledgement (struct GNUNET_SERVICE_Client *c) GNUNET_SERVICE_client_continue (c); } +/** + * Control handler for deleting JSON objects + * + * @param cls message queue for sending replies + * @param src received message + */ +static void +handle_delete_path (void *cls, + const struct TWISTER_DeletePath *src) +{ + struct GNUNET_SERVICE_Client *c = cls; + + strcpy (delete_path, src->path); + send_acknowledgement (c); +} + /** * Control handler for changing the response code @@ -1502,6 +1567,11 @@ GNUNET_SERVICE_MAIN TWISTER_MESSAGE_TYPE_SET_RESPONSE_CODE, struct TWISTER_SetResponseCode, NULL), + + GNUNET_MQ_hd_fixed_size (delete_path, + TWISTER_MESSAGE_TYPE_DELETE_PATH, + struct TWISTER_DeletePath, + NULL), GNUNET_MQ_handler_end ()); diff --git a/src/twister/taler-twister.c b/src/twister/taler-twister.c @@ -45,6 +45,14 @@ static int status; static unsigned int hack_response_code; /** + * Path to a object to be deleted. The format is "object-like": + * path "field0.field1.2.field3" will delete the following object: + * + * {"field1": {"field2": [0, 1, {"field3": "TO DELETE!"}]}}. + */ +static char *delete_path; + +/** * This option is used to check whether the twister can accept * connections over the unix domain socket interface. Used when * launching it to see if everything (?) is okay. @@ -133,6 +141,14 @@ run (void *cls, /* TODO: add other operations here */ + if ( (NULL != delete_path) && + (NULL != TALER_TWISTER_delete_path + (tth, + delete_path, + &handle_acknowledgement, + NULL)) ) + num_ops++; + if (0 == num_ops) { fprintf (stderr, "No valid hacks specified!\n"); @@ -152,16 +168,25 @@ main (int argc, char *const *argv) { struct GNUNET_GETOPT_CommandLineOption options[] = { + + GNUNET_GETOPT_option_string + ('d', + "deleteobject", + "PATH", + gettext_noop ("Delete object pointed by PATH\n"), + &delete_path), + GNUNET_GETOPT_option_flag ('a', "checkalive", gettext_noop ("Check if twister accepts IPC connections\n"), &check_alive), + GNUNET_GETOPT_option_uint ('r', "responsecode", "STATUS", - gettext_noop ("set the next response code to STATUS"), + gettext_noop ("Set the next response code to STATUS"), &hack_response_code), GNUNET_GETOPT_OPTION_END }; diff --git a/src/twister/twister.h b/src/twister/twister.h @@ -2,20 +2,20 @@ This file is part of GNUnet. Copyright (C) 2018 Taler Systems SA - Twister is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, or (at your - option) any later version. - - Twister 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 - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Twister; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. + Twister is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version + 3, or (at your option) any later version. + + Twister 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 General Public License for more details. + + You should have received a copy of the GNU General Public + License along with Twister; see the file COPYING. If not, + write to the Free Software Foundation, Inc., 51 Franklin + Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** @@ -29,11 +29,42 @@ #include <gnunet/gnunet_common.h> +/** + * Max length for a JSON path. + */ +#define TWISTER_PATH_LENGTH 100 #define TWISTER_MESSAGE_TYPE_ACKNOWLEDGEMENT 1 #define TWISTER_MESSAGE_TYPE_SET_RESPONSE_CODE 2 +#define TWISTER_MESSAGE_TYPE_DELETE_PATH 3 + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Network size estimate sent from the service + * to clients. Contains the current size estimate + * (or 0 if none has been calculated) and the + * standard deviation of known estimates. + * + */ +struct TWISTER_DeletePath +{ + /** + * Type: #TWISTER_MESSAGE_TYPE_DELETE_PATH + */ + struct GNUNET_MessageHeader header; + + /** + * The new response code, in big endian. + */ + char path[TWISTER_PATH_LENGTH]; + +}; +GNUNET_NETWORK_STRUCT_END + GNUNET_NETWORK_STRUCT_BEGIN diff --git a/src/twister/twister_api.c b/src/twister/twister_api.c @@ -204,6 +204,45 @@ TALER_TWISTER_cancel (struct TALER_TWISTER_Operation *op) /** + * Delete the object pointed to by @a path. + * + * @param h twister instance to control + * @param path object-like notation to point the object to be + deleted. E.g., the path "f1.f2.0" will delete the object + {"f1": {"f2": [{"to be": "deleted"}]}}. + * @param cb function to call once twister is ready + * @param cb_cls closure for @a cb + * @return operation handle (to possibly abort) + */ +struct TALER_TWISTER_Operation * +TALER_TWISTER_delete_path + (struct TALER_TWISTER_Handle *h, + const char *path, + GNUNET_SCHEDULER_TaskCallback cb, + void *cb_cls) +{ + struct TALER_TWISTER_Operation *op; + struct GNUNET_MQ_Envelope *env; + struct TWISTER_DeletePath *src; //FIXME 'src' right name? + + op = GNUNET_new (struct TALER_TWISTER_Operation); + op->h = h; + op->cb = cb; + op->cb_cls = cb_cls; + GNUNET_CONTAINER_DLL_insert_tail (h->op_head, + h->op_tail, + op); + /* Prepare *env*elope. */ + env = GNUNET_MQ_msg + (src, TWISTER_MESSAGE_TYPE_DELETE_PATH); + /* Put data into the envelope. */ + strcpy (src->path, path); + /* Send message. */ + GNUNET_MQ_send (h->mq, env); + return op; +} + +/** * Change the next response code to @a new_rc. * * @param h twister instance to control