diff options
author | 2025-02-27 15:04:56 +0100 | |
---|---|---|
committer | 2025-03-03 19:20:46 +0000 | |
commit | e1d40bf585ef23e24145bee1cd89ae0ab8bc303d (patch) | |
tree | 7a9bbcf1773f4fc5cdb4f3d992f4842ea202df75 | |
parent | 9c948e4d2a71269acffa634b3c6b2741d558cee0 (diff) |
session: uri parsing improvements
- It is now possible to use "proto://ip4:port/target" or
"proto://[ip6]:port/target" format.
- Updated http_client and related tests to use the new format
Type: improvement
Change-Id: Ic6afd8c66eddca2ab1d7afc034e193441c34f8ee
Signed-off-by: Adrian Villin <avillin@cisco.com>
-rw-r--r-- | extras/hs-test/http_test.go | 25 | ||||
-rw-r--r-- | src/plugins/hs_apps/http_client.c | 24 | ||||
-rw-r--r-- | src/vnet/session/application_interface.c | 91 | ||||
-rw-r--r-- | src/vnet/session/application_interface.h | 1 |
4 files changed, 115 insertions, 26 deletions
diff --git a/extras/hs-test/http_test.go b/extras/hs-test/http_test.go index 99c0a05b849..91d0823d9c3 100644 --- a/extras/hs-test/http_test.go +++ b/extras/hs-test/http_test.go @@ -318,9 +318,9 @@ func HttpClientPostFormTest(s *NoTopoSuite) { server.Start() defer server.Close() - uri := "http://" + serverAddress + "/80" + uri := "http://" + serverAddress + "/test" vpp := s.Containers.Vpp.VppInstance - o := vpp.Vppctl("http client post verbose header Hello:World uri " + uri + " target /test data " + body) + o := vpp.Vppctl("http client post verbose header Hello:World uri " + uri + " data " + body) s.Log(o) s.AssertContains(o, "200 OK") @@ -346,7 +346,6 @@ func HttpClientGetNoResponseBodyTest(s *NoTopoSuite) { func httpClientGet(s *NoTopoSuite, response string, size int) { serverAddress := s.HostAddr() vpp := s.Containers.Vpp.VppInstance - server := ghttp.NewUnstartedServer() l, err := net.Listen("tcp", serverAddress+":80") s.AssertNil(err, fmt.Sprint(err)) @@ -354,7 +353,7 @@ func httpClientGet(s *NoTopoSuite, response string, size int) { server.AppendHandlers( ghttp.CombineHandlers( s.LogHttpReq(false), - ghttp.VerifyRequest("GET", "/test"), + ghttp.VerifyRequest("GET", "/"), ghttp.VerifyHeaderKV("Hello", "World"), ghttp.VerifyHeaderKV("Test-H2", "Test-K2"), ghttp.RespondWith(http.StatusOK, string(response), http.Header{"Content-Length": {strconv.Itoa(size)}}), @@ -362,8 +361,8 @@ func httpClientGet(s *NoTopoSuite, response string, size int) { server.Start() defer server.Close() - uri := "http://" + serverAddress + "/80" - cmd := "http client use-ptr verbose header Hello:World header Test-H2:Test-K2 save-to response.txt uri " + uri + " target /test" + uri := "http://" + serverAddress + cmd := "http client use-ptr verbose header Hello:World header Test-H2:Test-K2 save-to response.txt uri " + uri o := vpp.Vppctl(cmd) outputLen := len(o) @@ -420,8 +419,8 @@ func httpClientRepeat(s *NoTopoSuite, requestMethod string, clientArgs string) { requestMethod += " file /tmp/test_file.txt" } - uri := "http://" + serverAddress + "/" + s.GetPortFromPpid() - cmd := fmt.Sprintf("http client %s %s duration %d header Hello:World uri %s target /index.html", + uri := "http://" + serverAddress + ":" + s.GetPortFromPpid() + "/index" + cmd := fmt.Sprintf("http client %s %s duration %d header Hello:World uri %s", requestMethod, clientArgs, durationInSec, uri) s.Log("Duration %ds", durationInSec) @@ -442,7 +441,7 @@ func httpClientRepeat(s *NoTopoSuite, requestMethod string, clientArgs string) { s.AssertGreaterThan(replyCountInt, 15000) replyCount = "" - cmd = fmt.Sprintf("http client %s %s repeat %d header Hello:World uri %s target /index.html", + cmd = fmt.Sprintf("http client %s %s repeat %d header Hello:World uri %s", requestMethod, clientArgs, repeatAmount, uri) s.AssertNil(err, fmt.Sprint(err)) @@ -480,8 +479,8 @@ func HttpClientGetTimeout(s *NoTopoSuite) { )) server.Start() defer server.Close() - uri := "http://" + serverAddress + "/" + s.GetPortFromPpid() - cmd := "http client verbose timeout 1 uri " + uri + " target /timeout" + uri := "http://" + serverAddress + ":" + s.GetPortFromPpid() + "/timeout" + cmd := "http client verbose timeout 1 uri " + uri o := vpp.Vppctl(cmd) s.Log(o) @@ -510,8 +509,8 @@ func httpClientPostFile(s *NoTopoSuite, usePtr bool, fileSize int) { server.Start() defer server.Close() - uri := "http://" + serverAddress + "/80" - cmd := "http client post verbose uri " + uri + " target /test file " + fileName + uri := "http://" + serverAddress + "/test" + cmd := "http client post verbose uri " + uri + " file " + fileName if usePtr { cmd += " use-ptr" } diff --git a/src/plugins/hs_apps/http_client.c b/src/plugins/hs_apps/http_client.c index e4759317cbe..4701253bf59 100644 --- a/src/plugins/hs_apps/http_client.c +++ b/src/plugins/hs_apps/http_client.c @@ -693,9 +693,9 @@ hc_get_event (vlib_main_t *vm) { wrk = hc_worker_get (hcm->worker_index); hc_session = hc_session_get (wrk->session_index, wrk->thread_index); - vlib_cli_output (vm, "< %v< %v", hc_session->response_status, - hc_session->resp_headers); - vlib_cli_output (vm, "\n%v\n", hc_session->http_response); + vlib_cli_output (vm, "< %v\n< %v\n%v", hc_session->response_status, + hc_session->resp_headers, + hc_session->http_response); } break; case HC_REPEAT_DONE: @@ -851,8 +851,6 @@ hc_command_fn (vlib_main_t *vm, unformat_input_t *input, ; else if (unformat (line_input, "data %v", &hcm->data)) hcm->is_file = 0; - else if (unformat (line_input, "target %s", &hcm->target)) - ; else if (unformat (line_input, "file %s", &path)) hcm->is_file = 1; else if (unformat (line_input, "use-ptr")) @@ -919,11 +917,7 @@ hc_command_fn (vlib_main_t *vm, unformat_input_t *input, err = clib_error_return (0, "URI not defined"); goto done; } - if (!hcm->target) - { - err = clib_error_return (0, "target not defined"); - goto done; - } + if (!hcm->data && hcm->req_method == HTTP_REQ_POST) { if (path) @@ -939,6 +933,7 @@ hc_command_fn (vlib_main_t *vm, unformat_input_t *input, goto done; } } + if (hcm->duration && hcm->repeat_count) { err = clib_error_return ( @@ -953,6 +948,13 @@ hc_command_fn (vlib_main_t *vm, unformat_input_t *input, goto done; } + if ((rv = parse_target ((char **) &hcm->uri, (char **) &hcm->target))) + { + err = clib_error_return (0, "target parse error: %U", + format_session_error, rv); + goto done; + } + if ((rv = parse_uri ((char *) hcm->uri, &hcm->connect_sep))) { err = @@ -1000,7 +1002,7 @@ done: VLIB_CLI_COMMAND (hc_command, static) = { .path = "http client", .short_help = - "[post] uri http://<ip-addr> target <origin-form> " + "[post] uri http://<ip-addr>/<origin-form> " "[data <form-urlencoded> | file <file-path>] [use-ptr] " "[save-to <filename>] [header <Key:Value>] [verbose] " "[timeout <seconds> (default = 10)] [repeat <count> | duration <seconds>] " diff --git a/src/vnet/session/application_interface.c b/src/vnet/session/application_interface.c index a62f914d43a..e2f9a6883fe 100644 --- a/src/vnet/session/application_interface.c +++ b/src/vnet/session/application_interface.c @@ -38,12 +38,12 @@ * */ uword -unformat_vnet_uri (unformat_input_t * input, va_list * args) +unformat_vnet_uri (unformat_input_t *input, va_list *args) { session_endpoint_cfg_t *sep = va_arg (*args, session_endpoint_cfg_t *); u32 transport_proto = 0, port; - if (unformat (input, "%U://%U/%d", unformat_transport_proto, + if (unformat (input, "%U://%U:%d", unformat_transport_proto, &transport_proto, unformat_ip4_address, &sep->ip.ip4, &port)) { sep->transport_proto = transport_proto; @@ -52,6 +52,54 @@ unformat_vnet_uri (unformat_input_t * input, va_list * args) return 1; } else if (unformat (input, "%U://%U/%d", unformat_transport_proto, + &transport_proto, unformat_ip4_address, &sep->ip.ip4, + &port)) + { + sep->transport_proto = transport_proto; + sep->port = clib_host_to_net_u16 (port); + sep->is_ip4 = 1; + return 1; + } + else if (unformat (input, "%U://%U", unformat_transport_proto, + &transport_proto, unformat_ip4_address, &sep->ip.ip4)) + { + sep->transport_proto = transport_proto; + if (sep->transport_proto == TRANSPORT_PROTO_HTTP) + port = 80; + else if (sep->transport_proto == TRANSPORT_PROTO_TLS) + port = 443; + else + return 0; + + sep->port = clib_host_to_net_u16 (port); + sep->is_ip4 = 1; + return 1; + } + else if (unformat (input, "%U://[%U]:%d", unformat_transport_proto, + &transport_proto, unformat_ip6_address, &sep->ip.ip6, + &port)) + { + sep->transport_proto = transport_proto; + sep->port = clib_host_to_net_u16 (port); + sep->is_ip4 = 0; + return 1; + } + else if (unformat (input, "%U://[%U]", unformat_transport_proto, + &transport_proto, unformat_ip6_address, &sep->ip.ip6)) + { + sep->transport_proto = transport_proto; + if (sep->transport_proto == TRANSPORT_PROTO_HTTP) + port = 80; + else if (sep->transport_proto == TRANSPORT_PROTO_TLS) + port = 443; + else + return 0; + + sep->port = clib_host_to_net_u16 (port); + sep->is_ip4 = 0; + return 1; + } + else if (unformat (input, "%U://%U/%d", unformat_transport_proto, &transport_proto, unformat_ip6_address, &sep->ip.ip6, &port)) { @@ -106,6 +154,45 @@ parse_uri (char *uri, session_endpoint_cfg_t *sep) return 0; } +/* Use before 'parse_uri()'. Removes target from URI and copies it to 'char + * **target'. char **target is resized automatically. + */ +session_error_t +parse_target (char **uri, char **target) +{ + u8 counter = 0; + + for (u32 i = 0; i < (u32) strlen (*uri); i++) + { + if ((*uri)[i] == '/') + counter++; + + if (counter == 3) + { + /* resize and make space for NULL terminator */ + if (vec_len (*target) < strlen (*uri) - i + 2) + vec_resize (*target, strlen (*uri) - i + 2); + + strncpy (*target, *uri + i, strlen (*uri) - i); + (*uri)[i + 1] = '\0'; + break; + } + } + + if (!*target) + { + vec_resize (*target, 2); + **target = '/'; + } + + vec_terminate_c_string (*target); + + if (!*target) + return SESSION_E_INVALID; + + return 0; +} + session_error_t vnet_bind_uri (vnet_listen_args_t *a) { diff --git a/src/vnet/session/application_interface.h b/src/vnet/session/application_interface.h index 21ed97998f2..33b61187fe3 100644 --- a/src/vnet/session/application_interface.h +++ b/src/vnet/session/application_interface.h @@ -281,6 +281,7 @@ typedef enum session_fd_flag_ } session_fd_flag_t; session_error_t parse_uri (char *uri, session_endpoint_cfg_t *sep); +session_error_t parse_target (char **uri, char **target); session_error_t vnet_bind_uri (vnet_listen_args_t *); session_error_t vnet_unbind_uri (vnet_unlisten_args_t *a); session_error_t vnet_connect_uri (vnet_connect_args_t *a); |