aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdrian Villin <avillin@cisco.com>2025-02-27 15:04:56 +0100
committerFlorin Coras <florin.coras@gmail.com>2025-03-03 19:20:46 +0000
commite1d40bf585ef23e24145bee1cd89ae0ab8bc303d (patch)
tree7a9bbcf1773f4fc5cdb4f3d992f4842ea202df75
parent9c948e4d2a71269acffa634b3c6b2741d558cee0 (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.go25
-rw-r--r--src/plugins/hs_apps/http_client.c24
-rw-r--r--src/vnet/session/application_interface.c91
-rw-r--r--src/vnet/session/application_interface.h1
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);