twister

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

commit 2363dcc3d93b758b807ef9b2f4cd8cb87899f786
parent 97e27f606af034099036e62de95dd0173a820716
Author: Marcello Stanisci <stanisci.m@gmail.com>
Date:   Wed, 15 May 2019 19:00:46 +0200

Importing inflating function from GNUnet..

..and not recompressing data before proxying.

Diffstat:
Msrc/twister/taler-twister-service.c | 242+++++++++++++++++++++++++++++++++++++++++--------------------------------------
1 file changed, 127 insertions(+), 115 deletions(-)

diff --git a/src/twister/taler-twister-service.c b/src/twister/taler-twister-service.c @@ -233,17 +233,6 @@ struct HttpRequest * Did we pause CURL processing? */ int curl_paused; - - /** - * if GNUNET_YES, then request and response will carry - * a compressed body. - */ - int deflate; - - /** - * Zlib internal state. - */ - z_stream zstate; }; @@ -437,15 +426,6 @@ curl_check_hdr (void *buffer, hdr_type, hdr_val); - if ((0 == strcasecmp (hdr_type, - MHD_HTTP_HEADER_CONTENT_ENCODING)) - && (NULL != strstr (hdr_val, - "deflate"))) - { - TALER_LOG_INFO ("Compressed response\n"); - hr->deflate = GNUNET_YES; - } - /* Skip "Host:" header as it will be wrong, given that we are man-in-the-middling the connection */ if (0 == strcasecmp (hdr_type, @@ -890,8 +870,7 @@ static int con_val_iter (void *cls, enum MHD_ValueKind kind, const char *key, - const char *value, - size_t value_size) + const char *value) { struct HttpRequest *hr = cls; char *hdr; @@ -902,10 +881,7 @@ con_val_iter (void *cls, if ((0 == strcmp (MHD_HTTP_HEADER_ACCEPT_ENCODING, key))) { - TALER_LOG_INFO ("Compressed request\n"); - curl_easy_setopt (hr->curl, - CURLOPT_ENCODING, - value); + TALER_LOG_INFO ("Do not re-compressed request\n"); return MHD_YES; } @@ -964,6 +940,7 @@ walk_response_object (const char *path, char *last_token; char *path_dup; + GNUNET_assert (NULL != json); GNUNET_asprintf (&path_dup, ".%s", /* Make sure path starts with dot. */ path); @@ -1116,7 +1093,7 @@ modify_object (struct MHD_Connection *con, * Flip a random character to the string pointed to by @a path. * * @param con FIXME deprecated. - * @param json the object whose filed will be flipped. + * @param json the object whose field will be flipped. * @param flip_path the path to the string-field to flip. */ static void @@ -1250,52 +1227,98 @@ delete_object (struct MHD_Connection *con, return; } - /** - * Try to compress a response body. - * Updates @a buf and @a buf_size. + * Decompress data. * - * @param[in,out] buf pointer to body to compress - * @param[in,out] buf_size pointer to initial size of @a buf - * @return #MHD_YES if @a buf was compressed + * @param request contains input data to inflate + * @return result code indicating the status of the operation */ static int -body_compress (void **buf, - size_t *buf_size) +inflate_data (struct HttpRequest *request) { - Bytef *cbuf; - uLongf cbuf_size; + z_stream z; + char *tmp; + size_t tmp_size; int ret; - cbuf_size = compressBound (*buf_size); - cbuf = malloc (cbuf_size); - if (NULL == cbuf) + memset (&z, 0, sizeof (z)); + z.next_in = (Bytef *) request->io_buf; + z.avail_in = request->io_len; + tmp_size = GNUNET_MIN (REQUEST_BUFFER_MAX, request->io_len * 4); + tmp = GNUNET_malloc (tmp_size); + z.next_out = (Bytef *) tmp; + z.avail_out = tmp_size; + ret = inflateInit (&z); + switch (ret) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Could not allocate the compression buffer\n"); - return MHD_NO; + case Z_MEM_ERROR: + GNUNET_break (0); + return GNUNET_JSON_PR_OUT_OF_MEMORY; + case Z_STREAM_ERROR: + GNUNET_break_op (0); + return GNUNET_JSON_PR_JSON_INVALID; + case Z_OK: + break; } - - ret = compress (cbuf, - &cbuf_size, - (const Bytef *) *buf, - *buf_size); - - if (Z_OK != ret) + while (1) { - /* compression failed */ - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Compression failed\n"); - free (cbuf); - return MHD_NO; - } - free (*buf); - *buf = (void *) cbuf; - *buf_size = (size_t) cbuf_size; - return MHD_YES; + ret = inflate (&z, 0); + switch (ret) + { + case Z_MEM_ERROR: + GNUNET_break (0); + GNUNET_break (Z_OK == inflateEnd (&z)); + GNUNET_free (tmp); + return GNUNET_JSON_PR_OUT_OF_MEMORY; + case Z_DATA_ERROR: + GNUNET_break (0); + GNUNET_break (Z_OK == inflateEnd (&z)); + GNUNET_free (tmp); + return GNUNET_JSON_PR_JSON_INVALID; + case Z_NEED_DICT: + GNUNET_break (0); + GNUNET_break (Z_OK == inflateEnd (&z)); + GNUNET_free (tmp); + return GNUNET_JSON_PR_JSON_INVALID; + case Z_OK: + if ((0 < z.avail_out) && (0 == z.avail_in)) + { + /* truncated input stream */ + GNUNET_break (0); + GNUNET_break (Z_OK == inflateEnd (&z)); + GNUNET_free (tmp); + return GNUNET_JSON_PR_JSON_INVALID; + } + if (0 < z.avail_out) + continue; /* just call it again */ + /* output buffer full, can we grow it? */ + if (tmp_size == REQUEST_BUFFER_MAX) + { + /* already at max */ + GNUNET_break (0); + GNUNET_break (Z_OK == inflateEnd (&z)); + GNUNET_free (tmp); + return GNUNET_JSON_PR_OUT_OF_MEMORY; + } + if (tmp_size * 2 < tmp_size) + tmp_size = REQUEST_BUFFER_MAX; + else + tmp_size = GNUNET_MIN (REQUEST_BUFFER_MAX, tmp_size * 2); + tmp = GNUNET_realloc (tmp, tmp_size); + z.next_out = (Bytef *) &tmp[z.total_out]; + continue; + case Z_STREAM_END: + /* decompression successful, make 'tmp' the new 'data' */ + GNUNET_free (request->io_buf); + request->io_buf = tmp; + request->io_size = tmp_size; + request->io_len = z.total_out; + GNUNET_break (Z_OK == inflateEnd (&z)); + return GNUNET_JSON_PR_SUCCESS; /* at least for now */ + } + } /* while (1) */ } - /** * Main MHD callback for handling requests. * @@ -1381,12 +1404,7 @@ create_response (void *cls, hr->io_len += *upload_data_size; *upload_data_size = 0; - if (GNUNET_YES == hr->curl_paused) - { - hr->curl_paused = GNUNET_NO; - curl_easy_pause (hr->curl, - CURLPAUSE_CONT); - } + return MHD_YES; } @@ -1396,6 +1414,32 @@ create_response (void *cls, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Finished processing UPLOAD\n"); hr->state = REQUEST_STATE_UPLOAD_DONE; + if (0 != hr->io_len) + { + #if 1 + const char *ce; + ce = MHD_lookup_connection_value + (con, + MHD_HEADER_KIND, + MHD_HTTP_HEADER_CONTENT_ENCODING); + if ((NULL != ce) && (0 == strcmp ("deflate", ce))) + GNUNET_assert (Z_OK == inflate_data (hr)); + #endif + + json_error_t error; + hr->json = json_loadb (hr->io_buf, + hr->io_len, + JSON_DECODE_ANY, + &error); + if (NULL == hr->json) + { + TALER_LOG_ERROR ("Could not parse JSON from client: %s (%s)\n", + error.text, + error.source); + /* Quick and dirty. */ + return MHD_NO; + } + } } /* generate curl request to the proxied service. */ @@ -1419,27 +1463,9 @@ create_response (void *cls, "Will try to flip: %s\n", flip_path_ul); - GNUNET_assert (0 == strcmp (MHD_HTTP_METHOD_POST, - meth)); - GNUNET_break - (GNUNET_JSON_PR_SUCCESS != GNUNET_JSON_post_parser - (REQUEST_BUFFER_MAX, - con, - con_cls, - hr->io_buf, - &hr->io_len, - &hr->json)); - flip_object (con, hr->json, flip_path_ul); - /* Existing io_len is enough to accomodate this encoding. */ - json_dumpb (hr->json, - hr->io_buf, - hr->io_len, - JSON_COMPACT); - - json_decref (hr->json); } if ('\0' != modify_path_ul[0]) @@ -1448,29 +1474,18 @@ create_response (void *cls, "Will try to modify: %s\n", flip_path_ul); - GNUNET_assert (0 == strcmp (MHD_HTTP_METHOD_POST, - meth)); - GNUNET_break - (GNUNET_JSON_PR_SUCCESS != GNUNET_JSON_post_parser - (REQUEST_BUFFER_MAX, - con, - con_cls, - hr->io_buf, - &hr->io_len, - &hr->json)); - modify_object (con, hr->json, modify_path_ul); - - /* Existing io_len is enough to accomodate this encoding. */ - json_dumpb (hr->json, - hr->io_buf, - hr->io_len, - JSON_COMPACT); - json_decref (hr->json); } + /* Existing io_len is enough to accomodate this encoding. */ + json_dumpb (hr->json, + hr->io_buf, + hr->io_len, + JSON_COMPACT); + json_decref (hr->json); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Generating curl request\n"); hr->curl = curl_easy_init (); @@ -1481,10 +1496,12 @@ create_response (void *cls, MHD_HTTP_INTERNAL_SERVER_ERROR, curl_failure_response); } - if (0 != hr->io_len) - curl_easy_setopt (hr->curl, - CURLOPT_POSTFIELDSIZE, - hr->io_len); + + /* No need to check whether we're POSTing or PUTting. + * If not needed, this value will just be ignored.*/ + curl_easy_setopt (hr->curl, + CURLOPT_POSTFIELDSIZE, + hr->io_len); curl_easy_setopt (hr->curl, CURLOPT_HEADERFUNCTION, &curl_check_hdr); @@ -1527,6 +1544,9 @@ create_response (void *cls, if (0 == strcasecmp (meth, MHD_HTTP_METHOD_PUT)) { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Crafting a CURL PUT request\n"); + curl_easy_setopt (hr->curl, CURLOPT_UPLOAD, 1L); @@ -1759,14 +1779,6 @@ create_response (void *cls, malform = GNUNET_NO; } - /** - * COMPRESSION STARTS HERE. - */ - if (GNUNET_YES == hr->deflate) - GNUNET_assert - (MHD_YES == body_compress ((void **) &hr->io_buf, - &hr->io_len)); - hr->response = MHD_create_response_from_buffer (hr->io_len, hr->io_buf,