diff options
author | Matus Fabian <matfabia@cisco.com> | 2024-10-17 13:41:51 +0200 |
---|---|---|
committer | Florin Coras <florin.coras@gmail.com> | 2024-10-25 23:33:15 +0000 |
commit | 841672258a55defb28b1ca6a35b6ad9830c132cf (patch) | |
tree | d9a0fa5366f5c53c8040b03e0904ee2569562b40 | |
parent | dced40dcaca0186d11eccbf5c75e21446db931b9 (diff) |
http: pass timeout using extended config
App can now pass http connection timeout using extended configuration,
ext cfg type TRANSPORT_ENDPT_EXT_CFG_HTTP, value (in seconds) set in ext
cfg member opaque.
It is optional, default value is 60 seconds.
Type: improvement
Change-Id: Ibeff4bbd3153421be350ff564ec3c8e52e5b9639
Signed-off-by: Matus Fabian <matfabia@cisco.com>
-rw-r--r-- | extras/hs-test/http_test.go | 36 | ||||
-rw-r--r-- | extras/hs-test/infra/utils.go | 2 | ||||
-rw-r--r-- | src/plugins/hs_apps/http_client_cli.c | 6 | ||||
-rw-r--r-- | src/plugins/http/http.c | 22 | ||||
-rw-r--r-- | src/plugins/http/http.h | 1 | ||||
-rw-r--r-- | src/plugins/http/http_timer.h | 11 | ||||
-rw-r--r-- | src/plugins/http_static/http_static.h | 2 | ||||
-rw-r--r-- | src/plugins/http_static/static_server.c | 17 | ||||
-rw-r--r-- | src/plugins/unittest/session_test.c | 48 | ||||
-rw-r--r-- | src/vnet/session/application_interface.h | 4 | ||||
-rw-r--r-- | src/vnet/session/transport_types.h | 1 |
11 files changed, 132 insertions, 18 deletions
diff --git a/extras/hs-test/http_test.go b/extras/hs-test/http_test.go index 982cab77d80..0b345d140ff 100644 --- a/extras/hs-test/http_test.go +++ b/extras/hs-test/http_test.go @@ -32,7 +32,7 @@ func init() { HttpInvalidContentLengthTest, HttpInvalidTargetSyntaxTest, HttpStaticPathTraversalTest, HttpUriDecodeTest, HttpHeadersTest, HttpStaticFileHandlerTest, HttpStaticFileHandlerDefaultMaxAgeTest, HttpClientTest, HttpClientErrRespTest, HttpClientPostFormTest, HttpClientPostFileTest, HttpClientPostFilePtrTest, AuthorityFormTargetTest, HttpRequestLineTest, - HttpStaticFileHandlerWrkTest, HttpStaticUrlHandlerWrkTest) + HttpStaticFileHandlerWrkTest, HttpStaticUrlHandlerWrkTest, HttpConnTimeoutTest) RegisterNoTopoSoloTests(HttpStaticPromTest, HttpGetTpsTest, HttpGetTpsInterruptModeTest, PromConcurrentConnectionsTest, PromMemLeakTest, HttpClientPostMemLeakTest, HttpInvalidClientRequestMemLeakTest, HttpPostTpsTest, HttpPostTpsInterruptModeTest, PromConsecutiveConnectionsTest) @@ -804,10 +804,10 @@ func HttpCliBadRequestTest(s *NoTopoSuite) { func HttpStaticBuildInUrlGetVersionTest(s *NoTopoSuite) { vpp := s.GetContainerByName("vpp").VppInstance serverAddress := s.VppAddr() - s.Log(vpp.Vppctl("http static server uri tcp://" + serverAddress + "/80 url-handlers debug")) + s.Log(vpp.Vppctl("http static server uri tls://" + serverAddress + "/80 url-handlers debug")) client := NewHttpClient(defaultHttpTimeout) - req, err := http.NewRequest("GET", "http://"+serverAddress+":80/version.json", nil) + req, err := http.NewRequest("GET", "https://"+serverAddress+":80/version.json", nil) s.AssertNil(err, fmt.Sprint(err)) resp, err := client.Do(req) s.AssertNil(err, fmt.Sprint(err)) @@ -1205,3 +1205,33 @@ func HeaderServerTest(s *NoTopoSuite) { s.AssertHttpHeaderWithValue(resp, "Server", "http_cli_server") s.AssertHttpHeaderWithValue(resp, "Content-Type", "text/html") } + +func HttpConnTimeoutTest(s *NoTopoSuite) { + vpp := s.GetContainerByName("vpp").VppInstance + serverAddress := s.VppAddr() + s.Log(vpp.Vppctl("http static server uri tcp://" + serverAddress + "/80 url-handlers debug keepalive-timeout 2")) + + req := "GET /version.json HTTP/1.1\r\nHost:" + serverAddress + ":80\r\nUser-Agent:test\r\n\r\n" + conn, err := net.DialTimeout("tcp", serverAddress+":80", time.Second*30) + s.AssertNil(err, fmt.Sprint(err)) + defer conn.Close() + err = conn.SetDeadline(time.Now().Add(time.Second * 30)) + s.AssertNil(err, fmt.Sprint(err)) + _, err = conn.Write([]byte(req)) + s.AssertNil(err, fmt.Sprint(err)) + reply := make([]byte, 1024) + _, err = conn.Read(reply) + s.AssertNil(err, fmt.Sprint(err)) + s.AssertContains(string(reply), "HTTP/1.1 200 OK") + s.Log(vpp.Vppctl("show session verbose 2")) + + s.Log("waiting for close on the server side") + time.Sleep(time.Second * 5) + s.Log(vpp.Vppctl("show session verbose 2")) + + _, err = conn.Write([]byte(req)) + s.AssertNil(err, fmt.Sprint(err)) + reply = make([]byte, 1024) + _, err = conn.Read(reply) + s.AssertMatchError(err, io.EOF, "connection not closed by server") +} diff --git a/extras/hs-test/infra/utils.go b/extras/hs-test/infra/utils.go index c5e5cc7cdc5..30abb6ac715 100644 --- a/extras/hs-test/infra/utils.go +++ b/extras/hs-test/infra/utils.go @@ -1,6 +1,7 @@ package hst import ( + "crypto/tls" "errors" "fmt" "io" @@ -90,6 +91,7 @@ func NewHttpClient(timeout time.Duration) *http.Client { transport := http.DefaultTransport transport.(*http.Transport).Proxy = nil transport.(*http.Transport).DisableKeepAlives = true + transport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true} client := &http.Client{ Transport: transport, Timeout: timeout, diff --git a/src/plugins/hs_apps/http_client_cli.c b/src/plugins/hs_apps/http_client_cli.c index 4b8ef173bd9..18523de4555 100644 --- a/src/plugins/hs_apps/http_client_cli.c +++ b/src/plugins/hs_apps/http_client_cli.c @@ -380,6 +380,7 @@ hcc_connect () hcc_main_t *hcm = &hcc_main; hcc_worker_t *wrk; hcc_session_t *hs; + transport_endpt_ext_cfg_t *ext_cfg; vec_validate (a, 0); clib_memset (a, 0, sizeof (a[0])); @@ -387,6 +388,11 @@ hcc_connect () clib_memcpy (&a->sep_ext, &hcm->connect_sep, sizeof (hcm->connect_sep)); a->app_index = hcm->app_index; + /* set http (response) timeout to 10 seconds */ + ext_cfg = session_endpoint_add_ext_cfg ( + &a->sep_ext, TRANSPORT_ENDPT_EXT_CFG_HTTP, sizeof (ext_cfg->opaque)); + ext_cfg->opaque = 10; + /* allocate http session on main thread */ wrk = hcc_worker_get (0); hs = hcc_session_alloc (wrk); diff --git a/src/plugins/http/http.c b/src/plugins/http/http.c index 6afb80d11c4..8c145da7b20 100644 --- a/src/plugins/http/http.c +++ b/src/plugins/http/http.c @@ -158,6 +158,7 @@ http_ho_conn_alloc (void) hc->h_hc_index = hc - hm->ho_conn_pool; hc->h_pa_session_handle = SESSION_INVALID_HANDLE; hc->h_tc_session_handle = SESSION_INVALID_HANDLE; + hc->timeout = HTTP_CONN_TIMEOUT; return hc->h_hc_index; } @@ -169,6 +170,7 @@ http_listener_alloc (void) pool_get_zero (hm->listener_pool, lhc); lhc->c_c_index = lhc - hm->listener_pool; + lhc->timeout = HTTP_CONN_TIMEOUT; return lhc->c_c_index; } @@ -1821,6 +1823,7 @@ http_transport_connect (transport_endpoint_cfg_t *tep) int error; u32 hc_index; session_t *ho; + transport_endpt_ext_cfg_t *ext_cfg; app_worker_t *app_wrk = app_worker_get (sep->app_wrk_index); clib_memset (cargs, 0, sizeof (*cargs)); @@ -1837,6 +1840,13 @@ http_transport_connect (transport_endpoint_cfg_t *tep) hc->state = HTTP_CONN_STATE_CONNECTING; cargs->api_context = hc_index; + ext_cfg = session_endpoint_get_ext_cfg (sep, TRANSPORT_ENDPT_EXT_CFG_HTTP); + if (ext_cfg) + { + HTTP_DBG (1, "app set timeout %u", ext_cfg->opaque); + hc->timeout = ext_cfg->opaque; + } + hc->is_server = 0; if (vec_len (app->name)) @@ -1894,7 +1904,10 @@ http_start_listen (u32 app_listener_index, transport_endpoint_cfg_t *tep) ext_cfg = session_endpoint_get_ext_cfg (sep, TRANSPORT_ENDPT_EXT_CFG_CRYPTO); if (ext_cfg) - tp = TRANSPORT_PROTO_TLS; + { + HTTP_DBG (1, "app set tls"); + tp = TRANSPORT_PROTO_TLS; + } args->sep_ext.transport_proto = tp; if (vnet_listen (args)) @@ -1903,6 +1916,13 @@ http_start_listen (u32 app_listener_index, transport_endpoint_cfg_t *tep) lhc_index = http_listener_alloc (); lhc = http_listener_get (lhc_index); + ext_cfg = session_endpoint_get_ext_cfg (sep, TRANSPORT_ENDPT_EXT_CFG_HTTP); + if (ext_cfg) + { + HTTP_DBG (1, "app set timeout %u", ext_cfg->opaque); + lhc->timeout = ext_cfg->opaque; + } + /* Grab transport connection listener and link to http listener */ lhc->h_tc_session_handle = args->handle; al = app_listener_get_w_handle (lhc->h_tc_session_handle); diff --git a/src/plugins/http/http.h b/src/plugins/http/http.h index abaa8f81447..b984c9564d6 100644 --- a/src/plugins/http/http.h +++ b/src/plugins/http/http.h @@ -388,6 +388,7 @@ typedef struct http_tc_ http_conn_state_t state; u32 timer_handle; + u32 timeout; u8 pending_timer; u8 *app_name; u8 *host; diff --git a/src/plugins/http/http_timer.h b/src/plugins/http/http_timer.h index 06baa1f8557..43d20d004d8 100644 --- a/src/plugins/http/http_timer.h +++ b/src/plugins/http/http_timer.h @@ -43,15 +43,13 @@ http_conn_timer_start (http_conn_t *hc) { http_tw_ctx_t *twc = &http_tw_ctx; u32 hs_handle; - u64 timeout; ASSERT (hc->timer_handle == HTTP_TIMER_HANDLE_INVALID); - timeout = HTTP_CONN_TIMEOUT; hs_handle = hc->c_thread_index << 24 | hc->c_c_index; clib_spinlock_lock (&twc->tw_lock); hc->timer_handle = - tw_timer_start_2t_1w_2048sl (&twc->tw, hs_handle, 0, timeout); + tw_timer_start_2t_1w_2048sl (&twc->tw, hs_handle, 0, hc->timeout); clib_spinlock_unlock (&twc->tw_lock); } @@ -74,19 +72,16 @@ static inline void http_conn_timer_update (http_conn_t *hc) { http_tw_ctx_t *twc = &http_tw_ctx; - u64 timeout; u32 hs_handle; - timeout = HTTP_CONN_TIMEOUT; - clib_spinlock_lock (&twc->tw_lock); if (hc->timer_handle != HTTP_TIMER_HANDLE_INVALID) - tw_timer_update_2t_1w_2048sl (&twc->tw, hc->timer_handle, timeout); + tw_timer_update_2t_1w_2048sl (&twc->tw, hc->timer_handle, hc->timeout); else { hs_handle = hc->c_thread_index << 24 | hc->c_c_index; hc->timer_handle = - tw_timer_start_2t_1w_2048sl (&twc->tw, hs_handle, 0, timeout); + tw_timer_start_2t_1w_2048sl (&twc->tw, hs_handle, 0, hc->timeout); } clib_spinlock_unlock (&twc->tw_lock); } diff --git a/src/plugins/http_static/http_static.h b/src/plugins/http_static/http_static.h index bee79090d2b..fac24db4ec9 100644 --- a/src/plugins/http_static/http_static.h +++ b/src/plugins/http_static/http_static.h @@ -162,6 +162,8 @@ typedef struct u32 max_age; /** Formatted max_age: "max-age=xyz" */ u8 *max_age_formatted; + /** Timeout during which client connection will stay open */ + u32 keepalive_timeout; /** hash table of file extensions to mime types string indices */ uword *mime_type_indices_by_file_extensions; diff --git a/src/plugins/http_static/static_server.c b/src/plugins/http_static/static_server.c index 0b02cc8e682..8133bbf2382 100644 --- a/src/plugins/http_static/static_server.c +++ b/src/plugins/http_static/static_server.c @@ -804,6 +804,7 @@ hss_listen (void) vnet_listen_args_t _a, *a = &_a; char *uri = "tcp://0.0.0.0/80"; u8 need_crypto; + transport_endpt_ext_cfg_t *ext_cfg; int rv; clib_memset (a, 0, sizeof (*a)); @@ -820,9 +821,13 @@ hss_listen (void) sep.transport_proto = TRANSPORT_PROTO_HTTP; clib_memcpy (&a->sep_ext, &sep, sizeof (sep)); + ext_cfg = session_endpoint_add_ext_cfg ( + &a->sep_ext, TRANSPORT_ENDPT_EXT_CFG_HTTP, sizeof (ext_cfg->opaque)); + ext_cfg->opaque = hsm->keepalive_timeout; + if (need_crypto) { - transport_endpt_ext_cfg_t *ext_cfg = session_endpoint_add_ext_cfg ( + ext_cfg = session_endpoint_add_ext_cfg ( &a->sep_ext, TRANSPORT_ENDPT_EXT_CFG_CRYPTO, sizeof (transport_endpt_crypto_cfg_t)); ext_cfg->crypto.ckpair_index = hsm->ckpair_index; @@ -898,6 +903,7 @@ hss_create_command_fn (vlib_main_t *vm, unformat_input_t *input, hsm->fifo_size = 0; hsm->cache_size = 10 << 20; hsm->max_age = HSS_DEFAULT_MAX_AGE; + hsm->keepalive_timeout = 60; /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) @@ -922,6 +928,9 @@ hss_create_command_fn (vlib_main_t *vm, unformat_input_t *input, ; else if (unformat (line_input, "debug %d", &hsm->debug_level)) ; + else if (unformat (line_input, "keepalive-timeout %d", + &hsm->keepalive_timeout)) + ; else if (unformat (line_input, "debug")) hsm->debug_level = 1; else if (unformat (line_input, "ptr-thresh %U", unformat_memory_size, @@ -985,14 +994,16 @@ done: * http static server www-root /tmp/www uri tcp://0.0.0.0/80 cache-size 2m * @cliend * @cliexcmd{http static server www-root <path> [prealloc-fios <nn>] - * [private-segment-size <nnMG>] [fifo-size <nbytes>] [uri <uri>]} + * [private-segment-size <nnMG>] [fifo-size <nbytes>] [uri <uri>] + * [keepalive-timeout <nn>]} ?*/ VLIB_CLI_COMMAND (hss_create_command, static) = { .path = "http static server", .short_help = "http static server www-root <path> [prealloc-fifos <nn>]\n" "[private-segment-size <nnMG>] [fifo-size <nbytes>] [max-age <nseconds>]\n" - "[uri <uri>] [ptr-thresh <nn>] [url-handlers] [debug [nn]]\n", + "[uri <uri>] [ptr-thresh <nn>] [url-handlers] [debug [nn]]\n" + "[keepalive-timeout <nn>]\n", .function = hss_create_command_fn, }; diff --git a/src/plugins/unittest/session_test.c b/src/plugins/unittest/session_test.c index f01e661157c..4e9b2fb38a1 100644 --- a/src/plugins/unittest/session_test.c +++ b/src/plugins/unittest/session_test.c @@ -2389,6 +2389,50 @@ session_test_sdl (vlib_main_t *vm, unformat_input_t *input) return 0; } +static int +session_test_ext_cfg (vlib_main_t *vm, unformat_input_t *input) +{ + session_endpoint_cfg_t sep = SESSION_ENDPOINT_CFG_NULL; + transport_endpt_ext_cfg_t *ext_cfg; + + ext_cfg = session_endpoint_add_ext_cfg (&sep, TRANSPORT_ENDPT_EXT_CFG_HTTP, + sizeof (ext_cfg->opaque)); + ext_cfg->opaque = 60; + + ext_cfg = + session_endpoint_add_ext_cfg (&sep, TRANSPORT_ENDPT_EXT_CFG_CRYPTO, + sizeof (transport_endpt_crypto_cfg_t)); + ext_cfg->crypto.ckpair_index = 1; + + ext_cfg = session_endpoint_add_ext_cfg (&sep, TRANSPORT_ENDPT_EXT_CFG_NONE, + sizeof (ext_cfg->opaque)); + ext_cfg->opaque = 345; + + ext_cfg = session_endpoint_get_ext_cfg (&sep, TRANSPORT_ENDPT_EXT_CFG_HTTP); + SESSION_TEST ((ext_cfg != 0), + "TRANSPORT_ENDPT_EXT_CFG_HTTP should be present"); + SESSION_TEST ((ext_cfg->opaque == 60), + "TRANSPORT_ENDPT_EXT_CFG_HTTP opaque value should be 60: %u", + ext_cfg->opaque); + ext_cfg = + session_endpoint_get_ext_cfg (&sep, TRANSPORT_ENDPT_EXT_CFG_CRYPTO); + SESSION_TEST ((ext_cfg != 0), + "TRANSPORT_ENDPT_EXT_CFG_CRYPTO should be present"); + SESSION_TEST ( + (ext_cfg->crypto.ckpair_index == 1), + "TRANSPORT_ENDPT_EXT_CFG_HTTP ckpair_index value should be 1: %u", + ext_cfg->crypto.ckpair_index); + ext_cfg = session_endpoint_get_ext_cfg (&sep, TRANSPORT_ENDPT_EXT_CFG_NONE); + SESSION_TEST ((ext_cfg != 0), + "TRANSPORT_ENDPT_EXT_CFG_NONE should be present"); + SESSION_TEST ((ext_cfg->opaque == 345), + "TRANSPORT_ENDPT_EXT_CFG_HTTP opaque value should be 345: %u", + ext_cfg->opaque); + session_endpoint_free_ext_cfgs (&sep); + + return 0; +} + static clib_error_t * session_test (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd_arg) @@ -2419,6 +2463,8 @@ session_test (vlib_main_t * vm, res = session_test_enable_disable (vm, input); else if (unformat (input, "sdl")) res = session_test_sdl (vm, input); + else if (unformat (input, "ext-cfg")) + res = session_test_ext_cfg (vm, input); else if (unformat (input, "all")) { if ((res = session_test_basic (vm, input))) @@ -2439,6 +2485,8 @@ session_test (vlib_main_t * vm, goto done; if ((res = session_test_sdl (vm, input))) goto done; + if ((res = session_test_ext_cfg (vm, input))) + goto done; if ((res = session_test_enable_disable (vm, input))) goto done; } diff --git a/src/vnet/session/application_interface.h b/src/vnet/session/application_interface.h index 0ad4d973bd9..d5656ff8341 100644 --- a/src/vnet/session/application_interface.h +++ b/src/vnet/session/application_interface.h @@ -953,9 +953,7 @@ session_endpoint_get_ext_cfg (session_endpoint_cfg_t *sep_ext, { if (ext_cfg->type == type) return ext_cfg; - ext_cfg = - (transport_endpt_ext_cfg_t *) (sep_ext->ext_cfgs.data + ext_cfg->len + - TRANSPORT_ENDPT_EXT_CFG_HEADER_SIZE); + ext_cfg = (transport_endpt_ext_cfg_t *) (ext_cfg->data + ext_cfg->len); } return 0; } diff --git a/src/vnet/session/transport_types.h b/src/vnet/session/transport_types.h index 8ea66142de7..f3b84998743 100644 --- a/src/vnet/session/transport_types.h +++ b/src/vnet/session/transport_types.h @@ -284,6 +284,7 @@ typedef enum transport_endpt_ext_cfg_type_ { TRANSPORT_ENDPT_EXT_CFG_NONE, TRANSPORT_ENDPT_EXT_CFG_CRYPTO, + TRANSPORT_ENDPT_EXT_CFG_HTTP, } transport_endpt_ext_cfg_type_t; typedef struct transport_endpt_crypto_cfg_ |