twister

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

commit c815c8cededea0ae8cf31f6d7405f8cb6e024bda
parent 0f30e5ab837a144164b6af7d3006b5cc5ea6b9ed
Author: Marcello Stanisci <stanisci.m@gmail.com>
Date:   Fri, 16 Mar 2018 01:15:10 +0100

fix headers preparation for malformed uploads.

Diffstat:
Msrc/include/taler_twister_testing_lib.h | 14++++++++++++++
Msrc/twister/taler-twister-service.c | 60++++++++++++++++++++++++++++++++++++++++++++++--------------
Msrc/twister/testing_api_cmd_exec_client.c | 122++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
3 files changed, 181 insertions(+), 15 deletions(-)

diff --git a/src/include/taler_twister_testing_lib.h b/src/include/taler_twister_testing_lib.h @@ -94,4 +94,18 @@ TALER_TESTING_cmd_modify_object (const char *label, struct TALER_TESTING_Command TALER_TESTING_cmd_malform_response (const char *label, const char *config_filename); + +/** + * This command makes the next request randomly malformed + * (by truncating it). + * + * @param label command label + * @param config_filename configuration filename. + * + * @return the command + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_malform_request (const char *label, + const char *config_filename); + #endif diff --git a/src/twister/taler-twister-service.c b/src/twister/taler-twister-service.c @@ -51,6 +51,11 @@ #define LOG_CURL_EASY(level,fun,rc) \ GNUNET_log(level, _("%s failed at %s:%d: `%s'\n"), fun, __FILE__, __LINE__, curl_easy_strerror (rc)) +/** + * Constant value to make sure the + * final } from JSONs gets dropped, when truncating. + */ +#define TRUNC_SIZE 4 /* ******** Datastructures for HTTP handling ********** */ @@ -269,6 +274,11 @@ static unsigned int malform = GNUNET_NO; */ static char modify_value[TWISTER_VALUE_LENGTH]; +/** + * Size of the malformed body to be uploaded to the + * proxied service. + */ +static size_t malformed_size; /** * Will point to the path if it has to be deleted @@ -288,11 +298,13 @@ run_mhd_now (void); /** - * We're getting an HTTP response header from cURL. Convert it to the - * MHD response headers. Mostly copies the headers, but makes special - * adjustments based on control requests. + * We're getting an HTTP response header from cURL. + * Convert it to the MHD response headers. Mostly copies + * the headers, but makes special adjustments based on + * control requests. * - * @param buffer curl buffer with a single line of header data; not 0-terminated! + * @param buffer curl buffer with a single + * line of header data; not 0-terminated! * @param size curl blocksize * @param nmemb curl blocknumber * @param cls our `struct HttpRequest *` @@ -472,6 +484,7 @@ create_mhd_response_from_hr (struct HttpRequest *hr) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating MHD response with code %u\n", (unsigned int) resp_code); + hr->response_code = resp_code; hr->json = json_loadb (hr->io_buf, hr->io_len, @@ -575,6 +588,7 @@ curl_upload_cb (void *buf, GNUNET_memcpy (buf, hr->io_buf, to_copy); + /* shift remaining data back to the beginning of the buffer. */ memmove (hr->io_buf, &hr->io_buf[to_copy], hr->io_len - to_copy); @@ -648,7 +662,8 @@ curl_download_prepare () if (-1 == to) rtime = GNUNET_TIME_UNIT_FOREVER_REL; else - rtime = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, to); + rtime = GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MILLISECONDS, to); if (-1 != max) { grs = GNUNET_NETWORK_fdset_create (); @@ -784,9 +799,9 @@ curl_task_download (void *cls) /** - * Read HTTP request header field from the request. Copies the fields - * over to the 'headers' that will be given to curl. However, - * substitutions may be applied. + * Read HTTP request header field from the request. + * Copies the fields over to the 'headers' that will be + * given to curl. However, substitutions may be applied. * * @param cls our `struct HttpRequest` * @param kind value kind @@ -802,6 +817,7 @@ con_val_iter (void *cls, { struct HttpRequest *hr = cls; char *hdr; + char *new_value = NULL; (void) kind; #if 0 @@ -809,6 +825,19 @@ con_val_iter (void *cls, (NULL != hr->leho) ) value = hr->leho; #endif + + if (GNUNET_YES == malform_upload) + { + if (0 == strcmp ("Content-Length", key)) + { + GNUNET_asprintf (&new_value, + "%lu", + malformed_size); + value = new_value; + malform_upload = GNUNET_NO; + } + } + GNUNET_asprintf (&hdr, "%s: %s", key, @@ -819,6 +848,7 @@ con_val_iter (void *cls, hr->headers = curl_slist_append (hr->headers, hdr); GNUNET_free (hdr); + GNUNET_free_non_null (new_value); return MHD_YES; } @@ -1114,14 +1144,15 @@ create_response (void *cls, return MHD_YES; } - /* Malform request body. */ + /* Malform request body. Note, this flag will be + * cleared only after having set the right malformed + * body lenght in the request headers. */ if (GNUNET_YES == malform_upload) { TALER_LOG_DEBUG ("Will (badly) truncate the request.\n"); - hr->io_len = GNUNET_CRYPTO_random_u32 - (GNUNET_CRYPTO_QUALITY_WEAK, hr->io_len - 1); - malform_upload = GNUNET_NO; + malformed_size = hr->io_len - TRUNC_SIZE; + hr->io_len = malformed_size; } /* Upload finished, generate curl request */ @@ -1299,6 +1330,8 @@ create_response (void *cls, CURLOPT_HTTPHEADER, hr->headers); curl_download_prepare (); + + /* means (?) upload is over. */ if (0 == hr->io_len) hr->state = REQUEST_STATE_DOWNLOAD_STARTED; return MHD_YES; @@ -1345,8 +1378,7 @@ create_response (void *cls, TALER_LOG_DEBUG ("Will (badly) truncate the response.\n"); - fake_len = GNUNET_CRYPTO_random_u32 - (GNUNET_CRYPTO_QUALITY_WEAK, hr->io_len - 1); + fake_len = hr->io_len - TRUNC_SIZE; body_len = fake_len; malform = GNUNET_NO; } diff --git a/src/twister/testing_api_cmd_exec_client.c b/src/twister/testing_api_cmd_exec_client.c @@ -69,6 +69,18 @@ struct DeleteObjectState const char *config_filename; }; +struct MalformRequestState +{ + /** + * Process handle for the twister CLI client. + */ + struct GNUNET_OS_Process *proc; + + /** + * Config file name to pass to the CLI client. + */ + const char *config_filename; +}; struct MalformResponseState { @@ -81,7 +93,6 @@ struct MalformResponseState * Config file name to pass to the CLI client. */ const char *config_filename; - }; struct HackResponseCodeState @@ -422,6 +433,88 @@ TALER_TESTING_cmd_delete_object (const char *label, * TODO. */ static void +malform_request_cleanup + (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct MalformRequestState *mrs = cls; + + if (NULL != mrs->proc) + { + GNUNET_break (0 == GNUNET_OS_process_kill (mrs->proc, + SIGKILL)); + GNUNET_OS_process_wait (mrs->proc); + GNUNET_OS_process_destroy (mrs->proc); + mrs->proc = NULL; + } + GNUNET_free (mrs); +} + + +/** + * Extract information from a command that is useful for other + * commands. + * + * @param cls closure + * @param ret[out] result (could be anything) + * @param trait name of the trait + * @param selector more detailed information about which object + * to return in case there were multiple generated + * by the command + * @return #GNUNET_OK on success + */ +static int +malform_request_traits (void *cls, + void **ret, + const char *trait, + unsigned int index) +{ + + struct MalformRequestState *mrs = cls; + struct TALER_TESTING_Trait traits[] = { + TALER_TESTING_make_trait_process (0, &mrs->proc), + TALER_TESTING_trait_end () + }; + + return TALER_TESTING_get_trait (traits, + ret, + trait, + index); +} + + +/** + * FIXME: document. + */ +static void +malform_request_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct MalformRequestState *mrs = cls; + + mrs->proc = GNUNET_OS_start_process (GNUNET_NO, + GNUNET_OS_INHERIT_STD_ALL, + NULL, NULL, NULL, + "taler-twister", + "taler-twister", + "-c", mrs->config_filename, + "--malformupload", + NULL); + if (NULL == mrs->proc) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + TALER_TESTING_wait_for_sigchld (is); +} + + +/** + * TODO. + */ +static void malform_response_cleanup (void *cls, const struct TALER_TESTING_Command *cmd) @@ -499,6 +592,33 @@ malform_response_run (void *cls, TALER_TESTING_wait_for_sigchld (is); } +/** + * This command makes the next request randomly malformed + * (by truncating it). + * + * @param label command label + * @param config_filename configuration filename. + * + * @return the command + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_malform_request (const char *label, + const char *config_filename) +{ + struct MalformRequestState *mrs; + struct TALER_TESTING_Command cmd; + + mrs = GNUNET_new (struct MalformRequestState); + mrs->config_filename = config_filename; + + cmd.label = label; + cmd.run = &malform_request_run; + cmd.cleanup = &malform_request_cleanup; + cmd.traits = &malform_request_traits; + cmd.cls = mrs; + + return cmd; +} /** * This command makes the next response randomly malformed