diff options
author | Matus Fabian <matfabia@cisco.com> | 2024-06-27 13:20:10 +0200 |
---|---|---|
committer | Florin Coras <florin.coras@gmail.com> | 2024-07-23 20:37:16 +0000 |
commit | d086a3650eea95056e738e2cc5dc18ce6edc278b (patch) | |
tree | 4dcb6d843b01143ab76428c268b6e382c6694545 /src | |
parent | 8ca6ce6fe1e65c8b57b9c0910dfd1243db0e49b9 (diff) |
http: state machine fix
When client sends second request without waiting for response of the
first request http_ts_rx_callback should drop request (pipelining is
not supported) instead of invoking return to state machine which can
lead to erroneous state, e.g. reading random data from server app
fifo.
Added simple http static server url handler for testing to simulate
long running request processing, for now hardcoded delay 5 seconds.
Type: fix
Change-Id: Ied9f7e2e4ee64c982f045c0f7f99a2dc5d7a2108
Signed-off-by: Matus Fabian <matfabia@cisco.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/plugins/hs_apps/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/plugins/hs_apps/test_builtins.c | 171 | ||||
-rw-r--r-- | src/plugins/http/http.c | 18 |
3 files changed, 187 insertions, 3 deletions
diff --git a/src/plugins/hs_apps/CMakeLists.txt b/src/plugins/hs_apps/CMakeLists.txt index 179c9c7a4c4..3553a25837e 100644 --- a/src/plugins/hs_apps/CMakeLists.txt +++ b/src/plugins/hs_apps/CMakeLists.txt @@ -23,6 +23,7 @@ add_vpp_plugin(hs_apps http_client_cli.c http_tps.c proxy.c + test_builtins.c ) ############################################################################## diff --git a/src/plugins/hs_apps/test_builtins.c b/src/plugins/hs_apps/test_builtins.c new file mode 100644 index 00000000000..cd6b00d0251 --- /dev/null +++ b/src/plugins/hs_apps/test_builtins.c @@ -0,0 +1,171 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright(c) 2024 Cisco Systems, Inc. + */ + +#include <http_static/http_static.h> +#include <vppinfra/tw_timer_2t_1w_2048sl.h> + +typedef struct +{ + u32 stop_timer_handle; + hss_session_handle_t sh; +} tw_timer_elt_t; + +typedef struct tb_main_ +{ + tw_timer_elt_t *delayed_resps; + tw_timer_wheel_2t_1w_2048sl_t tw; + hss_session_send_fn send_data; +} tb_main_t; + +static tb_main_t tb_main; + +static uword +test_builtins_timer_process (vlib_main_t *vm, vlib_node_runtime_t *rt, + vlib_frame_t *f) +{ + tb_main_t *tbm = &tb_main; + f64 now, timeout = 1.0; + uword *event_data = 0; + uword __clib_unused event_type; + + while (1) + { + vlib_process_wait_for_event_or_clock (vm, timeout); + now = vlib_time_now (vm); + event_type = vlib_process_get_events (vm, (uword **) &event_data); + + /* expire timers */ + tw_timer_expire_timers_2t_1w_2048sl (&tbm->tw, now); + + vec_reset_length (event_data); + } + return 0; +} + +VLIB_REGISTER_NODE (test_builtins_timer_process_node) = { + .function = test_builtins_timer_process, + .type = VLIB_NODE_TYPE_PROCESS, + .name = "test-builtins-timer-process", + .state = VLIB_NODE_STATE_DISABLED, +}; + +static void +send_data_to_hss (hss_session_handle_t sh, u8 *data) +{ + tb_main_t *tbm = &tb_main; + hss_url_handler_args_t args = {}; + + args.sh = sh; + args.data = data; + args.data_len = vec_len (data); + args.ct = HTTP_CONTENT_TEXT_PLAIN; + args.sc = HTTP_STATUS_OK; + args.free_vec_data = 1; + + tbm->send_data (&args); +} + +static hss_url_handler_rc_t +handle_get_test1 (hss_url_handler_args_t *args) +{ + u8 *data; + + clib_warning ("get request on test1"); + data = format (0, "hello"); + send_data_to_hss (args->sh, data); + + return HSS_URL_HANDLER_ASYNC; +} + +static hss_url_handler_rc_t +handle_get_test2 (hss_url_handler_args_t *args) +{ + u8 *data; + + clib_warning ("get request on test2"); + data = format (0, "some data"); + send_data_to_hss (args->sh, data); + + return HSS_URL_HANDLER_ASYNC; +} + +static void +delayed_resp_cb (u32 *expired_timers) +{ + tb_main_t *tbm = &tb_main; + int i; + u32 pool_index; + tw_timer_elt_t *e; + u8 *data; + + for (i = 0; i < vec_len (expired_timers); i++) + { + pool_index = expired_timers[i] & 0x7FFFFFFF; + e = pool_elt_at_index (tbm->delayed_resps, pool_index); + clib_warning ("sending delayed data"); + data = format (0, "delayed data"); + send_data_to_hss (e->sh, data); + pool_put (tbm->delayed_resps, e); + } +} + +static hss_url_handler_rc_t +handle_get_test_delayed (hss_url_handler_args_t *args) +{ + tb_main_t *tbm = &tb_main; + tw_timer_elt_t *e; + + clib_warning ("get request on test_delayed"); + pool_get (tbm->delayed_resps, e); + e->sh = args->sh; + e->stop_timer_handle = + tw_timer_start_2t_1w_2048sl (&tbm->tw, e - tbm->delayed_resps, 0, 5); + + return HSS_URL_HANDLER_ASYNC; +} + +static void +test_builtins_init (vlib_main_t *vm) +{ + tb_main_t *tbm = &tb_main; + hss_register_url_fn fp; + vlib_node_t *n; + + fp = vlib_get_plugin_symbol ("http_static_plugin.so", + "hss_register_url_handler"); + + if (fp == 0) + { + clib_warning ("http_static_plugin.so not loaded..."); + return; + } + + (*fp) (handle_get_test1, "test1", HTTP_REQ_GET); + (*fp) (handle_get_test2, "test2", HTTP_REQ_GET); + (*fp) (handle_get_test_delayed, "test_delayed", HTTP_REQ_GET); + + tbm->send_data = + vlib_get_plugin_symbol ("http_static_plugin.so", "hss_session_send_data"); + + tw_timer_wheel_init_2t_1w_2048sl (&tbm->tw, delayed_resp_cb, 1.0, ~0); + + vlib_node_set_state (vm, test_builtins_timer_process_node.index, + VLIB_NODE_STATE_POLLING); + n = vlib_get_node (vm, test_builtins_timer_process_node.index); + vlib_start_process (vm, n->runtime_index); +} + +static clib_error_t * +test_builtins_enable_command_fn (vlib_main_t *vm, unformat_input_t *input, + vlib_cli_command_t *cmd) +{ + test_builtins_init (vm); + return 0; +} + +VLIB_CLI_COMMAND (test_builtins_enable_command, static) = { + .path = "test-url-handler enable", + .short_help = "test-url-handler enable", + .function = test_builtins_enable_command_fn, +}; diff --git a/src/plugins/http/http.c b/src/plugins/http/http.c index db101539ac4..416ba8fe817 100644 --- a/src/plugins/http/http.c +++ b/src/plugins/http/http.c @@ -82,11 +82,19 @@ http_state_is_tx_valid (http_conn_t *hc) { http_state_t state = hc->http_state; return (state == HTTP_STATE_APP_IO_MORE_DATA || - state == HTTP_STATE_CLIENT_IO_MORE_DATA || state == HTTP_STATE_WAIT_APP_REPLY || state == HTTP_STATE_WAIT_APP_METHOD); } +static inline int +http_state_is_rx_valid (http_conn_t *hc) +{ + http_state_t state = hc->http_state; + return (state == HTTP_STATE_WAIT_SERVER_REPLY || + state == HTTP_STATE_CLIENT_IO_MORE_DATA || + state == HTTP_STATE_WAIT_CLIENT_METHOD); +} + static inline http_worker_t * http_worker_get (u32 thread_index) { @@ -1060,7 +1068,6 @@ http_state_wait_app_reply (http_conn_t *hc, transport_send_params_t *sp) return HTTP_SM_CONTINUE; error: - clib_warning ("unexpected msg type from app %u", msg.type); http_send_error (hc, sc); http_state_change (hc, HTTP_STATE_WAIT_CLIENT_METHOD); session_transport_closing_notify (&hc->connection); @@ -1294,12 +1301,16 @@ http_ts_rx_callback (session_t *ts) return -1; } - if (hc->state == HTTP_CONN_STATE_CLOSED) + if (!http_state_is_rx_valid (hc)) { + if (hc->state != HTTP_CONN_STATE_CLOSED) + clib_warning ("app data req state '%U' session state %u", + format_http_state, hc->http_state, hc->state); svm_fifo_dequeue_drop_all (ts->tx_fifo); return 0; } + HTTP_DBG (1, "run state machine"); http_req_run_state_machine (hc, 0); if (hc->state == HTTP_CONN_STATE_TRANSPORT_CLOSED) @@ -1605,6 +1616,7 @@ http_app_tx_callback (void *session, transport_send_params_t *sp) max_burst_sz = sp->max_burst_size * TRANSPORT_PACER_MIN_MSS; sp->max_burst_size = max_burst_sz; + HTTP_DBG (1, "run state machine"); http_req_run_state_machine (hc, sp); if (hc->state == HTTP_CONN_STATE_APP_CLOSED) |