session: uri parsing improvements 17/42417/5
authorAdrian Villin <avillin@cisco.com>
Thu, 27 Feb 2025 14:04:56 +0000 (15:04 +0100)
committerFlorin Coras <florin.coras@gmail.com>
Mon, 3 Mar 2025 19:20:46 +0000 (19:20 +0000)
- 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>
extras/hs-test/http_test.go
src/plugins/hs_apps/http_client.c
src/vnet/session/application_interface.c
src/vnet/session/application_interface.h

index 99c0a05..91d0823 100644 (file)
@@ -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"
        }
index e475931..4701253 100644 (file)
@@ -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>] "
index a62f914..e2f9a68 100644 (file)
  *
  */
 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;
@@ -51,6 +51,54 @@ unformat_vnet_uri (unformat_input_t * input, va_list * args)
       sep->is_ip4 = 1;
       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)
 {
index 21ed979..33b6118 100644 (file)
@@ -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);