http: target parsing improvement 37/42137/5
authorMatus Fabian <[email protected]>
Sun, 12 Jan 2025 21:18:56 +0000 (22:18 +0100)
committerMatus Fabian <[email protected]>
Tue, 21 Jan 2025 18:47:28 +0000 (13:47 -0500)
Make it http version neutral, since h2 and h3 use 3 pseudo-headers.
Added scheme, target_authority_offset and target_authority_len
to http_msg_data_t, target_form removed.
Http transport now validate if correct form of request target
is received, so now we are also able to receive requests with
absolute-form target in server apps like http_static.
As bonus, unformat is not longer used to parse IP addresses.

Type: improvement

Change-Id: I369f77e2639c43cc1244d91f883c526eb88af63e
Signed-off-by: Matus Fabian <[email protected]>
14 files changed:
extras/hs-test/http_test.go
extras/hs-test/infra/connect_udp_client.go
extras/hs-test/proxy_test.go
src/plugins/hs_apps/http_cli.c
src/plugins/hs_apps/http_client.c
src/plugins/hs_apps/http_client_cli.c
src/plugins/hs_apps/http_tps.c
src/plugins/hs_apps/proxy.c
src/plugins/hs_apps/vcl/vcl_test_protos.c
src/plugins/http/http.c
src/plugins/http/http.h
src/plugins/http/http_plugin.rst
src/plugins/http/test/http_test.c
src/plugins/http_static/static_server.c

index 4b67d27..4cbcdeb 100644 (file)
@@ -26,7 +26,7 @@ func init() {
        RegisterVethTests(HttpCliTest, HttpCliConnectErrorTest)
        RegisterSoloVethTests(HttpClientGetMemLeakTest)
        RegisterNoTopoTests(HeaderServerTest, HttpPersistentConnectionTest, HttpPipeliningTest,
-               HttpStaticMovedTest, HttpStaticNotFoundTest, HttpCliMethodNotAllowedTest,
+               HttpStaticMovedTest, HttpStaticNotFoundTest, HttpCliMethodNotAllowedTest, HttpAbsoluteFormUriTest,
                HttpCliBadRequestTest, HttpStaticBuildInUrlGetIfStatsTest, HttpStaticBuildInUrlPostIfStatsTest,
                HttpInvalidRequestLineTest, HttpMethodNotImplementedTest, HttpInvalidHeadersTest,
                HttpContentLengthTest, HttpStaticBuildInUrlGetIfListTest, HttpStaticBuildInUrlGetVersionTest,
@@ -36,7 +36,7 @@ func init() {
                HttpClientErrRespTest, HttpClientPostFormTest, HttpClientGet128kbResponseTest, HttpClientGetResponseBodyTest,
                HttpClientGetNoResponseBodyTest, HttpClientPostFileTest, HttpClientPostFilePtrTest, HttpUnitTest,
                HttpRequestLineTest, HttpClientGetTimeout, HttpStaticFileHandlerWrkTest, HttpStaticUrlHandlerWrkTest, HttpConnTimeoutTest,
-               HttpClientGetRepeat, HttpClientPostRepeat, HttpIgnoreH2UpgradeTest)
+               HttpClientGetRepeat, HttpClientPostRepeat, HttpIgnoreH2UpgradeTest, HttpInvalidAuthorityFormUriTest)
        RegisterNoTopoSoloTests(HttpStaticPromTest, HttpGetTpsTest, HttpGetTpsInterruptModeTest, PromConcurrentConnectionsTest,
                PromMemLeakTest, HttpClientPostMemLeakTest, HttpInvalidClientRequestMemLeakTest, HttpPostTpsTest, HttpPostTpsInterruptModeTest,
                PromConsecutiveConnectionsTest, HttpGetTpsTlsTest, HttpPostTpsTlsTest)
@@ -1204,6 +1204,18 @@ func HttpInvalidTargetSyntaxTest(s *NoTopoSuite) {
        s.AssertNil(err, fmt.Sprint(err))
        s.AssertContains(resp, "HTTP/1.1 400 Bad Request",
                "after '%' there must be two hex-digit characters in target query")
+
+       resp, err = TcpSendReceive(serverAddress+":80", "GET * HTTP/1.1\r\n\r\n")
+       s.AssertNil(err, fmt.Sprint(err))
+       s.AssertContains(resp, "HTTP/1.1 400 Bad Request", "asterisk-form is only used for a server-wide OPTIONS request")
+
+       resp, err = TcpSendReceive(serverAddress+":80", "GET www.example.com:80 HTTP/1.1\r\n\r\n")
+       s.AssertNil(err, fmt.Sprint(err))
+       s.AssertContains(resp, "HTTP/1.1 400 Bad Request", "authority-form is only used for CONNECT requests")
+
+       resp, err = TcpSendReceive(serverAddress+":80", "CONNECT https://www.example.com/tunnel HTTP/1.1\r\n\r\n")
+       s.AssertNil(err, fmt.Sprint(err))
+       s.AssertContains(resp, "HTTP/1.1 400 Bad Request", "CONNECT requests must use authority-form only")
 }
 
 func HttpInvalidContentLengthTest(s *NoTopoSuite) {
@@ -1294,6 +1306,58 @@ func HttpUriDecodeTest(s *NoTopoSuite) {
        s.AssertHttpHeaderWithValue(resp, "Content-Type", "text/html")
 }
 
+func HttpAbsoluteFormUriTest(s *NoTopoSuite) {
+       vpp := s.Containers.Vpp.VppInstance
+       serverAddress := s.VppAddr()
+       vpp.Vppctl("http cli server")
+
+       resp, err := TcpSendReceive(serverAddress+":80", "GET http://"+serverAddress+"/show/version HTTP/1.1\r\n\r\n")
+       s.AssertNil(err, fmt.Sprint(err))
+       s.AssertContains(resp, "HTTP/1.1 200 OK")
+
+       resp, err = TcpSendReceive(serverAddress+":80", "GET http://"+serverAddress+":80/show/version HTTP/1.1\r\n\r\n")
+       s.AssertNil(err, fmt.Sprint(err))
+       s.AssertContains(resp, "HTTP/1.1 200 OK")
+}
+
+func HttpInvalidAuthorityFormUriTest(s *NoTopoSuite) {
+       vpp := s.Containers.Vpp.VppInstance
+       serverAddress := s.VppAddr()
+       vpp.Vppctl("test proxy server fifo-size 512k server-uri http://%s/8080", serverAddress)
+
+       resp, err := TcpSendReceive(serverAddress+":8080", "CONNECT 1.2.3.4:80a HTTP/1.1\r\n\r\n")
+       s.AssertNil(err, fmt.Sprint(err))
+       s.AssertContains(resp, "HTTP/1.1 400 Bad Request")
+
+       resp, err = TcpSendReceive(serverAddress+":8080", "CONNECT 1.2.3.4:80000000 HTTP/1.1\r\n\r\n")
+       s.AssertNil(err, fmt.Sprint(err))
+       s.AssertContains(resp, "HTTP/1.1 400 Bad Request")
+
+       resp, err = TcpSendReceive(serverAddress+":8080", "CONNECT 1.2a3.4:80 HTTP/1.1\r\n\r\n")
+       s.AssertNil(err, fmt.Sprint(err))
+       s.AssertContains(resp, "HTTP/1.1 400 Bad Request")
+
+       resp, err = TcpSendReceive(serverAddress+":8080", "CONNECT 1.2.4:80 HTTP/1.1\r\n\r\n")
+       s.AssertNil(err, fmt.Sprint(err))
+       s.AssertContains(resp, "HTTP/1.1 400 Bad Request")
+
+       resp, err = TcpSendReceive(serverAddress+":8080", "CONNECT [dead:beef::1234:443 HTTP/1.1\r\n\r\n")
+       s.AssertNil(err, fmt.Sprint(err))
+       s.AssertContains(resp, "HTTP/1.1 400 Bad Request")
+
+       resp, err = TcpSendReceive(serverAddress+":8080", "CONNECT [zyx:beef::1234]:443 HTTP/1.1\r\n\r\n")
+       s.AssertNil(err, fmt.Sprint(err))
+       s.AssertContains(resp, "HTTP/1.1 400 Bad Request")
+
+       resp, err = TcpSendReceive(serverAddress+":8080", "CONNECT dead:beef::1234:443 HTTP/1.1\r\n\r\n")
+       s.AssertNil(err, fmt.Sprint(err))
+       s.AssertContains(resp, "HTTP/1.1 400 Bad Request")
+
+       resp, err = TcpSendReceive(serverAddress+":8080", "CONNECT example.org:443 HTTP/1.1\r\n\r\n")
+       s.AssertNil(err, fmt.Sprint(err))
+       s.AssertContains(resp, "HTTP/1.1 400 Bad Request", "name resolution not supported")
+}
+
 func HttpHeadersTest(s *NoTopoSuite) {
        vpp := s.Containers.Vpp.VppInstance
        serverAddress := s.VppAddr()
index 595f7e7..a30ad3a 100644 (file)
@@ -81,6 +81,7 @@ func (c *ConnectUdpClient) Dial(proxyAddress, targetUri string) error {
                return errors.New("request failed: " + resp.Status)
        }
        if resp.Header.Get("Connection") != "upgrade" || resp.Header.Get("Upgrade") != "connect-udp" || resp.Header.Get("Capsule-Protocol") != "?1" {
+               conn.Close()
                return errors.New("invalid response")
        }
 
index ec90d24..192451f 100644 (file)
@@ -26,7 +26,7 @@ func init() {
        RegisterVppProxySoloTests(VppProxyHttpGetTcpMTTest, VppProxyHttpPutTcpMTTest, VppProxyTcpIperfMTTest,
                VppProxyUdpIperfMTTest, VppConnectProxyStressTest, VppConnectProxyStressMTTest, VppConnectProxyConnectionFailedMTTest)
        RegisterVppUdpProxyTests(VppProxyUdpTest, VppConnectUdpProxyTest, VppConnectUdpInvalidCapsuleTest,
-               VppConnectUdpUnknownCapsuleTest, VppConnectUdpClientCloseTest)
+               VppConnectUdpUnknownCapsuleTest, VppConnectUdpClientCloseTest, VppConnectUdpInvalidTargetTest)
        RegisterVppUdpProxySoloTests(VppProxyUdpMigrationMTTest, VppConnectUdpStressMTTest, VppConnectUdpStressTest)
        RegisterEnvoyProxyTests(EnvoyProxyHttpGetTcpTest, EnvoyProxyHttpPutTcpTest)
        RegisterNginxProxyTests(NginxMirroringTest)
@@ -411,6 +411,29 @@ func VppConnectUdpProxyTest(s *VppUdpProxySuite) {
        s.AssertEqual(data, payload)
 }
 
+func VppConnectUdpInvalidTargetTest(s *VppUdpProxySuite) {
+       vppProxy := s.Containers.VppProxy.VppInstance
+       cmd := fmt.Sprintf("test proxy server fifo-size 512k server-uri http://%s/%d", s.VppProxyAddr(), s.ProxyPort())
+       s.Log(vppProxy.Vppctl(cmd))
+
+       proxyAddress := fmt.Sprintf("%s:%d", s.VppProxyAddr(), s.ProxyPort())
+
+       targetUri := fmt.Sprintf("http://%s:%d/.well-known/masque/udp/example.com/80/", s.VppProxyAddr(), s.ProxyPort())
+       c := s.NewConnectUdpClient(s.MaxTimeout, true)
+       err := c.Dial(proxyAddress, targetUri)
+       s.AssertNotNil(err, "name resolution not supported")
+
+       targetUri = fmt.Sprintf("http://%s:%d/.well-known/masque/udp/1.2.3.4/800000000/", s.VppProxyAddr(), s.ProxyPort())
+       c = s.NewConnectUdpClient(s.MaxTimeout, true)
+       err = c.Dial(proxyAddress, targetUri)
+       s.AssertNotNil(err, "invalid port number")
+
+       targetUri = fmt.Sprintf("http://%s:%d/masque/udp/1.2.3.4/80/", s.VppProxyAddr(), s.ProxyPort())
+       c = s.NewConnectUdpClient(s.MaxTimeout, true)
+       err = c.Dial(proxyAddress, targetUri)
+       s.AssertNotNil(err, "invalid prefix")
+}
+
 func VppConnectUdpInvalidCapsuleTest(s *VppUdpProxySuite) {
        remoteServerConn := s.StartEchoServer()
        defer remoteServerConn.Close()
index 3ca86d2..89eb49c 100644 (file)
@@ -387,8 +387,7 @@ hcs_ts_rx_callback (session_t *ts)
       goto done;
     }
 
-  if (msg.data.target_path_len == 0 ||
-      msg.data.target_form != HTTP_TARGET_ORIGIN_FORM)
+  if (msg.data.target_path_len == 0)
     {
       start_send_data (hs, HTTP_STATUS_BAD_REQUEST);
       goto done;
index bfecc9a..91ac6cf 100644 (file)
@@ -238,7 +238,6 @@ hc_session_connected_callback (u32 app_index, u32 hc_session_index,
 
   wrk->msg.type = HTTP_MSG_REQUEST;
   /* request target */
-  wrk->msg.data.target_form = HTTP_TARGET_ORIGIN_FORM;
   wrk->msg.data.target_path_len = vec_len (hcm->target);
   /* custom headers */
   wrk->msg.data.headers_len = vec_len (wrk->headers_buf);
index b9658ed..3c50e24 100644 (file)
@@ -166,7 +166,6 @@ hcc_ts_connected_callback (u32 app_index, u32 hc_index, session_t *as,
   msg.type = HTTP_MSG_REQUEST;
   msg.method_type = HTTP_REQ_GET;
   /* request target */
-  msg.data.target_form = HTTP_TARGET_ORIGIN_FORM;
   msg.data.target_path_offset = 0;
   msg.data.target_path_len = vec_len (hcm->http_query);
   /* custom headers */
index a40a31c..f4ef808 100644 (file)
@@ -401,8 +401,7 @@ hts_ts_rx_callback (session_t *ts)
          goto done;
        }
 
-      if (msg.data.target_path_len == 0 ||
-         msg.data.target_form != HTTP_TARGET_ORIGIN_FORM)
+      if (msg.data.target_path_len == 0)
        {
          hts_start_send_data (hs, HTTP_STATUS_BAD_REQUEST);
          goto done;
index f96940e..f3b1fdc 100644 (file)
@@ -507,12 +507,11 @@ proxy_http_connect (session_t *s, vnet_connect_args_t *a)
 {
   proxy_main_t *pm = &proxy_main;
   http_msg_t msg;
-  http_uri_t target_uri;
+  http_uri_authority_t target_uri;
   session_endpoint_cfg_t target_sep = SESSION_ENDPOINT_CFG_NULL;
   int rv;
   u8 *rx_buf = pm->rx_buf[s->thread_index];
   http_header_table_t req_headers = pm->req_headers[s->thread_index];
-  u32 target_offset, target_len;
 
   rv = svm_fifo_dequeue (s->rx_fifo, sizeof (msg), (u8 *) &msg);
   ASSERT (rv == sizeof (msg));
@@ -528,22 +527,27 @@ proxy_http_connect (session_t *s, vnet_connect_args_t *a)
     {
       /* TCP tunnel (RFC9110 section 9.3.6) */
       PROXY_DBG ("CONNECT");
-      if (msg.data.target_form != HTTP_TARGET_AUTHORITY_FORM)
+      /* get tunnel target */
+      if (!msg.data.target_authority_len)
        {
-         PROXY_DBG ("CONNECT target not authority form");
+         PROXY_DBG ("CONNECT target missing");
          goto bad_req;
        }
-
-      /* get tunnel target */
-      ASSERT (msg.data.target_path_len <= pm->rcv_buffer_size);
-      rv = svm_fifo_peek (s->rx_fifo, msg.data.target_path_offset,
-                         msg.data.target_path_len, rx_buf);
-      ASSERT (rv == msg.data.target_path_len);
-      rv = http_parse_authority_form_target (rx_buf, msg.data.target_path_len,
-                                            &target_uri);
+      ASSERT (msg.data.target_authority_len <= pm->rcv_buffer_size);
+      rv = svm_fifo_peek (s->rx_fifo, msg.data.target_authority_offset,
+                         msg.data.target_authority_len, rx_buf);
+      ASSERT (rv == msg.data.target_authority_len);
+      rv = http_parse_authority (rx_buf, msg.data.target_authority_len,
+                                &target_uri);
       if (rv)
        {
-         PROXY_DBG ("target parsing failed");
+         PROXY_DBG ("authority parsing failed");
+         goto bad_req;
+       }
+      /* TODO reg-name resolution */
+      if (target_uri.host_type == HTTP_URI_HOST_TYPE_REG_NAME)
+       {
+         PROXY_DBG ("reg-name resolution not supported");
          goto bad_req;
        }
       target_sep.transport_proto = TRANSPORT_PROTO_TCP;
@@ -553,50 +557,28 @@ proxy_http_connect (session_t *s, vnet_connect_args_t *a)
       /* UDP tunnel (RFC9298) */
       PROXY_DBG ("CONNECT-UDP");
       /* get tunnel target */
-      if (msg.data.target_form == HTTP_TARGET_ORIGIN_FORM)
-       {
-         if (msg.data.target_path_len < MASQUE_UDP_URI_MIN_LEN)
-           {
-             PROXY_DBG ("target too short");
-             goto bad_req;
-           }
-         rv = svm_fifo_peek (s->rx_fifo, msg.data.target_path_offset,
-                             msg.data.target_path_len, rx_buf);
-         ASSERT (rv == msg.data.target_path_len);
-         target_offset = 0;
-         target_len = msg.data.target_path_len;
-       }
-      else if (msg.data.target_form == HTTP_TARGET_ABSOLUTE_FORM)
+      if (msg.data.target_path_len < MASQUE_UDP_URI_MIN_LEN)
        {
-         http_url_t target_url;
-         ASSERT (msg.data.target_path_len <= pm->rcv_buffer_size);
-         rv = svm_fifo_peek (s->rx_fifo, msg.data.target_path_offset,
-                             msg.data.target_path_len, rx_buf);
-         ASSERT (rv == msg.data.target_path_len);
-         rv = http_parse_absolute_form (rx_buf, msg.data.target_path_len,
-                                        &target_url);
-         if (rv || target_url.path_len < MASQUE_UDP_URI_MIN_LEN)
-           {
-             PROXY_DBG ("target parsing failed");
-             goto bad_req;
-           }
-         target_offset = target_url.path_offset;
-         target_len = target_url.path_len;
+         PROXY_DBG ("invalid target");
+         goto bad_req;
        }
-      else
+      ASSERT (msg.data.target_path_len <= pm->rcv_buffer_size);
+      rv = svm_fifo_peek (s->rx_fifo, msg.data.target_path_offset,
+                         msg.data.target_path_len, rx_buf);
+      ASSERT (rv == msg.data.target_path_len);
+      if (http_validate_target_syntax (rx_buf, msg.data.target_path_len, 0, 0))
        {
-         PROXY_DBG ("invalid target form");
+         PROXY_DBG ("invalid target");
          goto bad_req;
        }
-      if (memcmp (rx_buf + target_offset, masque_udp_uri_prefix,
-                 MASQUE_UDP_URI_PREFIX_LEN))
+      if (memcmp (rx_buf, masque_udp_uri_prefix, MASQUE_UDP_URI_PREFIX_LEN))
        {
          PROXY_DBG ("uri prefix not match");
          goto bad_req;
        }
       rv = http_parse_masque_host_port (
-       rx_buf + target_offset + MASQUE_UDP_URI_PREFIX_LEN,
-       target_len - MASQUE_UDP_URI_PREFIX_LEN, &target_uri);
+       rx_buf + MASQUE_UDP_URI_PREFIX_LEN,
+       msg.data.target_path_len - MASQUE_UDP_URI_PREFIX_LEN, &target_uri);
       if (rv)
        {
          PROXY_DBG ("masque host/port parsing failed");
@@ -633,9 +615,10 @@ proxy_http_connect (session_t *s, vnet_connect_args_t *a)
       return;
     }
   PROXY_DBG ("proxy target %U:%u", format_ip46_address, &target_uri.ip,
-            target_uri.is_ip4, clib_net_to_host_u16 (target_uri.port));
+            target_uri.host_type == HTTP_URI_HOST_TYPE_IP4,
+            clib_net_to_host_u16 (target_uri.port));
   svm_fifo_dequeue_drop (s->rx_fifo, msg.data.len);
-  target_sep.is_ip4 = target_uri.is_ip4;
+  target_sep.is_ip4 = target_uri.host_type == HTTP_URI_HOST_TYPE_IP4;
   target_sep.ip = target_uri.ip;
   target_sep.port = target_uri.port;
   clib_memcpy (&a->sep_ext, &target_sep, sizeof (target_sep));
index 9c81c5f..da4b699 100644 (file)
@@ -1087,13 +1087,6 @@ vt_process_http_server_read_msg (vcl_test_session_t *ts, void *buf,
              return 0;
            }
 
-         if (msg.data.target_form != HTTP_TARGET_ORIGIN_FORM)
-           {
-             vt_http_send_reply_msg (ts, HTTP_STATUS_BAD_REQUEST);
-             vterr ("error! http target not in origin form", 0);
-             return 0;
-           }
-
          /* validate target path syntax */
          if (msg.data.target_path_len)
            {
@@ -1225,7 +1218,6 @@ vt_process_http_client_write_msg (vcl_test_session_t *ts, void *buf,
       msg.method_type = HTTP_REQ_POST;
 
       /* target */
-      msg.data.target_form = HTTP_TARGET_ORIGIN_FORM;
       target = (u8 *) "/vcl_test_http\0";
       msg.data.target_path_len = strlen ((char *) target);
 
index c33c85a..666f45c 100644 (file)
@@ -42,6 +42,13 @@ const char *http_upgrade_proto_str[] = { "",
 #undef _
 };
 
+#define expect_char(c)                                                        \
+  if (*p++ != c)                                                              \
+    {                                                                         \
+      clib_warning ("unexpected character");                                  \
+      return -1;                                                              \
+    }
+
 static u8 *
 format_http_req_state (u8 *s, va_list *va)
 {
@@ -619,19 +626,21 @@ http_identify_optional_query (http_req_t *req)
 }
 
 static int
-http_get_target_form (http_req_t *req)
+http_parse_target (http_req_t *req)
 {
   int i;
+  u8 *p, *end;
 
-  /* "*" */
+  /* asterisk-form  = "*" */
   if ((req->rx_buf[req->target_path_offset] == '*') &&
       (req->target_path_len == 1))
     {
       req->target_form = HTTP_TARGET_ASTERISK_FORM;
-      return 0;
+      /* we do not support OPTIONS request */
+      return -1;
     }
 
-  /* 1*( "/" segment ) [ "?" query ] */
+  /* origin-form = 1*( "/" segment ) [ "?" query ] */
   if (req->rx_buf[req->target_path_offset] == '/')
     {
       /* drop leading slash */
@@ -639,27 +648,66 @@ http_get_target_form (http_req_t *req)
       req->target_path_offset++;
       req->target_form = HTTP_TARGET_ORIGIN_FORM;
       http_identify_optional_query (req);
-      return 0;
+      /* can't be CONNECT method */
+      return req->method == HTTP_REQ_CONNECT ? -1 : 0;
     }
 
-  /* scheme "://" host [ ":" port ] *( "/" segment ) [ "?" query ] */
-  i = v_find_index (req->rx_buf, req->target_path_offset, req->target_path_len,
-                   "://");
-  if (i > 0)
+  /* absolute-form =
+   * scheme "://" host [ ":" port ] *( "/" segment ) [ "?" query ] */
+  if (req->target_path_len > 8 &&
+      !memcmp (req->rx_buf + req->target_path_offset, "http", 4))
     {
-      req->target_form = HTTP_TARGET_ABSOLUTE_FORM;
-      http_identify_optional_query (req);
-      return 0;
+      req->scheme = HTTP_URL_SCHEME_HTTP;
+      p = req->rx_buf + req->target_path_offset + 4;
+      if (*p == 's')
+       {
+         p++;
+         req->scheme = HTTP_URL_SCHEME_HTTPS;
+       }
+      if (*p++ == ':')
+       {
+         expect_char ('/');
+         expect_char ('/');
+         req->target_form = HTTP_TARGET_ABSOLUTE_FORM;
+         req->target_authority_offset = p - req->rx_buf;
+         req->target_authority_len = 0;
+         end = req->rx_buf + req->target_path_offset + req->target_path_len;
+         while (p < end)
+           {
+             if (*p == '/')
+               {
+                 p++; /* drop leading slash */
+                 req->target_path_offset = p - req->rx_buf;
+                 req->target_path_len = end - p;
+                 break;
+               }
+             req->target_authority_len++;
+             p++;
+           }
+         if (!req->target_path_len)
+           {
+             clib_warning ("zero length host");
+             return -1;
+           }
+         http_identify_optional_query (req);
+         /* can't be CONNECT method */
+         return req->method == HTTP_REQ_CONNECT ? -1 : 0;
+       }
     }
 
-  /* host ":" port */
+  /* authority-form = host ":" port */
   for (i = req->target_path_offset;
        i < (req->target_path_offset + req->target_path_len); i++)
     {
       if ((req->rx_buf[i] == ':') && (isdigit (req->rx_buf[i + 1])))
        {
+         req->target_authority_len = req->target_path_len;
+         req->target_path_len = 0;
+         req->target_authority_offset = req->target_path_offset;
+         req->target_path_offset = 0;
          req->target_form = HTTP_TARGET_AUTHORITY_FORM;
-         return 0;
+         /* "authority-form" is only used for CONNECT requests */
+         return req->method == HTTP_REQ_CONNECT ? 0 : -1;
        }
     }
 
@@ -776,7 +824,9 @@ http_parse_request_line (http_req_t *req, http_status_code_t *ec)
   req->target_path_len = target_len;
   req->target_query_offset = 0;
   req->target_query_len = 0;
-  if (http_get_target_form (req))
+  req->target_authority_len = 0;
+  req->target_authority_offset = 0;
+  if (http_parse_target (req))
     {
       clib_warning ("invalid target");
       *ec = HTTP_STATUS_BAD_REQUEST;
@@ -793,13 +843,6 @@ http_parse_request_line (http_req_t *req, http_status_code_t *ec)
   return 0;
 }
 
-#define expect_char(c)                                                        \
-  if (*p++ != c)                                                              \
-    {                                                                         \
-      clib_warning ("unexpected character");                                  \
-      return -1;                                                              \
-    }
-
 #define parse_int(val, mul)                                                   \
   do                                                                          \
     {                                                                         \
@@ -913,6 +956,7 @@ http_identify_headers (http_req_t *req, http_status_code_t *ec)
   req->content_len_header_index = ~0;
   req->connection_header_index = ~0;
   req->upgrade_header_index = ~0;
+  req->host_header_index = ~0;
   req->headers_offset = req->rx_buf_offset;
 
   /* check if we have any header */
@@ -970,6 +1014,10 @@ http_identify_headers (http_req_t *req, http_status_code_t *ec)
                 (const char *) name_start, name_len,
                 http_header_name_token (HTTP_HEADER_UPGRADE)))
        req->upgrade_header_index = header_index;
+      else if (req->host_header_index == ~0 &&
+              http_token_is_case ((const char *) name_start, name_len,
+                                  http_header_name_token (HTTP_HEADER_HOST)))
+       req->host_header_index = header_index;
 
       /* are we done? */
       if (*p == '\r' && *(p + 1) == '\n')
@@ -1185,6 +1233,30 @@ http_check_connection_upgrade (http_req_t *req)
     }
 }
 
+static void
+http_target_fixup (http_conn_t *hc)
+{
+  http_field_line_t *host;
+
+  if (hc->req.target_form == HTTP_TARGET_ABSOLUTE_FORM)
+    return;
+
+  /* scheme fixup */
+  hc->req.scheme = session_get_transport_proto (session_get_from_handle (
+                    hc->h_tc_session_handle)) == TRANSPORT_PROTO_TLS ?
+                    HTTP_URL_SCHEME_HTTPS :
+                    HTTP_URL_SCHEME_HTTP;
+
+  if (hc->req.target_form == HTTP_TARGET_AUTHORITY_FORM ||
+      hc->req.connection_header_index == ~0)
+    return;
+
+  /* authority fixup */
+  host = vec_elt_at_index (hc->req.headers, hc->req.connection_header_index);
+  hc->req.target_authority_offset = host->value_offset;
+  hc->req.target_authority_len = host->value_len;
+}
+
 static http_sm_result_t
 http_req_state_wait_transport_method (http_conn_t *hc,
                                      transport_send_params_t *sp)
@@ -1219,6 +1291,7 @@ http_req_state_wait_transport_method (http_conn_t *hc,
   if (rv)
     goto error;
 
+  http_target_fixup (hc);
   http_check_connection_upgrade (&hc->req);
 
   rv = http_identify_message_body (&hc->req, &ec);
@@ -1244,7 +1317,9 @@ http_req_state_wait_transport_method (http_conn_t *hc,
   msg.method_type = hc->req.method;
   msg.data.type = HTTP_MSG_DATA_INLINE;
   msg.data.len = len;
-  msg.data.target_form = hc->req.target_form;
+  msg.data.scheme = hc->req.scheme;
+  msg.data.target_authority_offset = hc->req.target_authority_offset;
+  msg.data.target_authority_len = hc->req.target_authority_len;
   msg.data.target_path_offset = hc->req.target_path_offset;
   msg.data.target_path_len = hc->req.target_path_len;
   msg.data.target_query_offset = hc->req.target_query_offset;
index 3bdbc6c..008f663 100644 (file)
@@ -395,11 +395,19 @@ typedef struct http_field_line_
   u32 value_len;
 } http_field_line_t;
 
+typedef enum http_url_scheme_
+{
+  HTTP_URL_SCHEME_HTTP,
+  HTTP_URL_SCHEME_HTTPS,
+} http_url_scheme_t;
+
 typedef struct http_msg_data_
 {
   http_msg_data_type_t type;
   u64 len;
-  http_target_form_t target_form;
+  http_url_scheme_t scheme;
+  u32 target_authority_offset;
+  u32 target_authority_len;
   u32 target_path_offset;
   u32 target_path_len;
   u32 target_query_offset;
@@ -455,6 +463,9 @@ typedef struct http_req_
   };
 
   http_target_form_t target_form;
+  http_url_scheme_t scheme;
+  u32 target_authority_offset;
+  u32 target_authority_len;
   u32 target_path_offset;
   u32 target_path_len;
   u32 target_query_offset;
@@ -470,6 +481,7 @@ typedef struct http_req_
   uword content_len_header_index;
   uword connection_header_index;
   uword upgrade_header_index;
+  uword host_header_index;
 
   http_upgrade_proto_t upgrade_proto;
 } http_req_t;
@@ -553,7 +565,8 @@ format_http_bytes (u8 *s, va_list *va)
 }
 
 always_inline int
-_validate_target_syntax (u8 *target, u32 len, int is_query, int *is_encoded)
+http_validate_target_syntax (u8 *target, u32 len, int is_query,
+                            int *is_encoded)
 {
   int encoded = 0;
   u32 i;
@@ -605,13 +618,13 @@ _validate_target_syntax (u8 *target, u32 len, int is_query, int *is_encoded)
 always_inline int
 http_validate_abs_path_syntax (u8 *path, int *is_encoded)
 {
-  return _validate_target_syntax (path, vec_len (path), 0, is_encoded);
+  return http_validate_target_syntax (path, vec_len (path), 0, is_encoded);
 }
 
 /**
  * A "query" rule validation (RFC3986 section 2.1).
  *
- * @param query      Vector of target query to validate.
+ * @param query      Target query to validate.
  * @param is_encoded Return flag that indicates if percent-encoded (optional).
  *
  * @return @c 0 on success.
@@ -619,7 +632,7 @@ http_validate_abs_path_syntax (u8 *path, int *is_encoded)
 always_inline int
 http_validate_query_syntax (u8 *query, int *is_encoded)
 {
-  return _validate_target_syntax (query, vec_len (query), 1, is_encoded);
+  return http_validate_target_syntax (query, vec_len (query), 1, is_encoded);
 }
 
 #define htoi(x) (isdigit (x) ? (x - '0') : (tolower (x) - 'a' + 10))
@@ -1106,90 +1119,166 @@ http_serialize_headers (http_header_t *headers)
   return headers_buf;
 }
 
+typedef enum http_uri_host_type_
+{
+  HTTP_URI_HOST_TYPE_IP4,
+  HTTP_URI_HOST_TYPE_IP6,
+  HTTP_URI_HOST_TYPE_REG_NAME
+} http_uri_host_type_t;
+
 typedef struct
 {
-  ip46_address_t ip;
+  http_uri_host_type_t host_type;
+  union
+  {
+    ip46_address_t ip;
+    http_token_t reg_name;
+  };
   u16 port;
-  u8 is_ip4;
-} http_uri_t;
+} http_uri_authority_t;
 
-/**
- * An "authority-form" URL parsing.
- *
- * @param target     Target URL to parse.
- * @param target_len Length of URL.
- * @param authority  Parsed URL metadata in case of success.
- *
- * @return @c 0 on success.
- */
 always_inline int
-http_parse_authority_form_target (u8 *target, u32 target_len,
-                                 http_uri_t *authority)
+_http_parse_ip4 (u8 **p, u8 *end, ip4_address_t *ip4)
 {
-  unformat_input_t input;
-  u8 *tmp = 0;
-  u32 port;
+  u8 n_octets = 0, digit, n_digits = 0;
+  u16 dec_octet = 0;
   int rv = 0;
 
-  vec_validate (tmp, target_len - 1);
-  vec_copy (tmp, target);
-  unformat_init_vector (&input, tmp);
-  if (unformat (&input, "[%U]:%d", unformat_ip6_address, &authority->ip.ip6,
-               &port))
-    {
-      authority->port = clib_host_to_net_u16 (port);
-      authority->is_ip4 = 0;
-    }
-  else if (unformat (&input, "%U:%d", unformat_ip4_address, &authority->ip.ip4,
-                    &port))
+  while (*p != end)
     {
-      authority->port = clib_host_to_net_u16 (port);
-      authority->is_ip4 = 1;
-    }
-  /* TODO reg-name resolution */
-  else
-    {
-      clib_warning ("unsupported format '%v'", target);
-      rv = -1;
+      if (**p >= '0' && **p <= '9')
+       {
+         digit = **p - '0';
+         dec_octet = dec_octet * 10 + digit;
+         n_digits++;
+         /* must fit in 8 bits */
+         if (dec_octet > 255)
+           return -1;
+       }
+      else if (**p == '.' && n_digits)
+       {
+         ip4->as_u8[n_octets++] = (u8) dec_octet;
+         dec_octet = 0;
+         n_digits = 0;
+         /* too many octets */
+         if (n_octets >= ARRAY_LEN (ip4->as_u8))
+           return -1;
+       }
+      else
+       {
+         /* probably more data (delimiter) after IPv4 address */
+         rv = **p;
+         break;
+       }
+
+      (*p)++;
     }
-  unformat_free (&input);
+
+  /* must end with octet */
+  if (!n_digits)
+    return -1;
+
+  ip4->as_u8[n_octets++] = (u8) dec_octet;
+
+  /* too few octets */
+  if (n_octets < ARRAY_LEN (ip4->as_u8))
+    return -1;
+
   return rv;
 }
 
-always_inline u8 *
-http_serialize_authority_form_target (http_uri_t *authority)
+/* modified unformat_ip6_address */
+always_inline int
+_http_parse_ip6 (u8 **p, u8 *end, ip6_address_t *ip6)
 {
-  u8 *s;
+  u8 n_hex_digits = 0, n_colon = 0, n_hex_quads = 0;
+  u8 double_colon_index = ~0, i;
+  u16 hex_digit;
+  u32 hex_quad = 0;
+  int rv = 0;
 
-  if (authority->is_ip4)
-    s = format (0, "%U:%d", format_ip4_address, &authority->ip.ip4,
-               clib_net_to_host_u16 (authority->port));
-  else
-    s = format (0, "[%U]:%d", format_ip6_address, &authority->ip.ip6,
-               clib_net_to_host_u16 (authority->port));
+  while (*p != end)
+    {
+      hex_digit = 16;
+      if (**p >= '0' && **p <= '9')
+       hex_digit = **p - '0';
+      else if (**p >= 'a' && **p <= 'f')
+       hex_digit = **p + 10 - 'a';
+      else if (**p >= 'A' && **p <= 'F')
+       hex_digit = **p + 10 - 'A';
+      else if (**p == ':' && n_colon < 2)
+       n_colon++;
+      else
+       {
+         /* probably more data (delimiter) after IPv6 address */
+         rv = **p;
+         break;
+       }
 
-  return s;
-}
+      /* too many hex quads */
+      if (n_hex_quads >= ARRAY_LEN (ip6->as_u16))
+       return -1;
 
-typedef enum http_url_scheme_
-{
-  HTTP_URL_SCHEME_HTTP,
-  HTTP_URL_SCHEME_HTTPS,
-} http_url_scheme_t;
+      if (hex_digit < 16)
+       {
+         hex_quad = (hex_quad << 4) | hex_digit;
 
-typedef struct
-{
-  http_url_scheme_t scheme;
-  u16 port;
-  u32 host_offset;
-  u32 host_len;
-  u32 path_offset;
-  u32 path_len;
-  u8 host_is_ip6;
-} http_url_t;
+         /* must fit in 16 bits */
+         if (n_hex_digits >= 4)
+           return -1;
+
+         n_colon = 0;
+         n_hex_digits++;
+       }
+
+      /* save position of :: */
+      if (n_colon == 2)
+       {
+         /* more than one :: ? */
+         if (double_colon_index < ARRAY_LEN (ip6->as_u16))
+           return -1;
+         double_colon_index = n_hex_quads;
+       }
+
+      if (n_colon > 0 && n_hex_digits > 0)
+       {
+         ip6->as_u16[n_hex_quads++] = clib_host_to_net_u16 ((u16) hex_quad);
+         hex_quad = 0;
+         n_hex_digits = 0;
+       }
+
+      (*p)++;
+    }
+
+  if (n_hex_digits > 0)
+    ip6->as_u16[n_hex_quads++] = clib_host_to_net_u16 ((u16) hex_quad);
+
+  /* expand :: to appropriate number of zero hex quads */
+  if (double_colon_index < ARRAY_LEN (ip6->as_u16))
+    {
+      u8 n_zero = ARRAY_LEN (ip6->as_u16) - n_hex_quads;
+
+      for (i = n_hex_quads - 1; i >= double_colon_index; i--)
+       ip6->as_u16[n_zero + i] = ip6->as_u16[i];
+
+      for (i = 0; i < n_zero; i++)
+       {
+         ASSERT ((double_colon_index + i) < ARRAY_LEN (ip6->as_u16));
+         ip6->as_u16[double_colon_index + i] = 0;
+       }
+
+      n_hex_quads = ARRAY_LEN (ip6->as_u16);
+    }
+
+  /* too few hex quads */
+  if (n_hex_quads < ARRAY_LEN (ip6->as_u16))
+    return -1;
+
+  return rv;
+}
 
 always_inline int
-_parse_port (u8 **pos, u8 *end, u16 *port)
+_http_parse_port (u8 **pos, u8 *end, u16 *port)
 {
   u32 value = 0;
   u8 *p = *pos;
@@ -1214,19 +1303,20 @@ _parse_port (u8 **pos, u8 *end, u16 *port)
 }
 
 /**
- * An "absolute-form" URL parsing.
+ * Parse authority to components.
  *
- * @param url     Target URL to parse.
- * @param url_len Length of URL.
- * @param parsed  Parsed URL metadata in case of success.
+ * @param authority     Target URL to parse.
+ * @param authority_len Length of URL.
+ * @param parsed        Parsed authority (port is se to 0 if not present).
  *
  * @return @c 0 on success.
  */
 always_inline int
-http_parse_absolute_form (u8 *url, u32 url_len, http_url_t *parsed)
+http_parse_authority (u8 *authority, u32 authority_len,
+                     http_uri_authority_t *parsed)
 {
-  u8 *token_start, *token_end, *end;
-  int is_encoded = 0;
+  u8 *token_start, *p, *end;
+  int rv;
 
   static uword valid_chars[4] = {
     /* -.0123456789 */
@@ -1237,111 +1327,102 @@ http_parse_absolute_form (u8 *url, u32 url_len, http_url_t *parsed)
     0x0000000000000000,
   };
 
-  if (url_len < 9)
-    {
-      clib_warning ("uri too short");
-      return -1;
-    }
-
-  clib_memset (parsed, 0, sizeof (*parsed));
+  /* reg-name max 255 chars + colon + port max 5 chars */
+  if (authority_len > 261)
+    return -1;
 
-  end = url + url_len;
+  end = authority + authority_len;
+  token_start = authority;
+  parsed->port = 0;
 
-  /* parse scheme */
-  if (!memcmp (url, "http:// ", 7))
-    {
-      parsed->scheme = HTTP_URL_SCHEME_HTTP;
-      parsed->port = clib_host_to_net_u16 (80);
-      parsed->host_offset = 7;
-    }
-  else if (!memcmp (url, "https:// ", 8))
+  /* parse host */
+  if (*token_start == '[')
     {
-      parsed->scheme = HTTP_URL_SCHEME_HTTPS;
-      parsed->port = clib_host_to_net_u16 (443);
-      parsed->host_offset = 8;
+      /* IPv6 address */
+      if (authority_len < 4)
+       return -1;
+
+      p = ++token_start;
+      rv = _http_parse_ip6 (&p, end, &parsed->ip.ip6);
+      if (rv != ']')
+       return -1;
+
+      parsed->host_type = HTTP_URI_HOST_TYPE_IP6;
+      token_start = ++p;
     }
-  else
+  else if (isdigit (*token_start))
     {
-      clib_warning ("invalid scheme");
-      return -1;
-    }
-  token_start = url + parsed->host_offset;
+      /* maybe IPv4 address */
+      p = token_start;
 
-  /* parse host */
-  if (*token_start == '[')
-    /* IPv6 address */
-    {
-      parsed->host_is_ip6 = 1;
-      parsed->host_offset++;
-      token_end = ++token_start;
-      while (1)
+      if (authority_len < 7)
+       goto reg_name;
+
+      rv = _http_parse_ip4 (&p, end, &parsed->ip.ip4);
+      if (rv == 0 || rv == ':')
        {
-         if (token_end == end)
-           {
-             clib_warning ("invalid host, IPv6 addr not terminated with ']'");
-             return -1;
-           }
-         else if (*token_end == ']')
-           {
-             parsed->host_len = token_end - token_start;
-             token_start = token_end + 1;
-             break;
-           }
-         else if (*token_end != ':' && *token_end != '.' &&
-                  !isxdigit (*token_end))
-           {
-             clib_warning ("invalid character '%u'", *token_end);
-             return -1;
-           }
-         token_end++;
+         parsed->host_type = HTTP_URI_HOST_TYPE_IP4;
+         token_start = p;
        }
+      else
+       goto reg_name;
     }
   else
     {
-      token_end = token_start;
-      while (token_end != end && *token_end != ':' && *token_end != '/')
+      /* registered name */
+      p = token_start;
+    reg_name:
+      while (p != end && *p != ':')
        {
-         if (!clib_bitmap_get_no_check (valid_chars, *token_end))
+         if (!clib_bitmap_get_no_check (valid_chars, *p))
            {
-             clib_warning ("invalid character '%u'", *token_end);
+             clib_warning ("invalid character '%u'", *p);
              return -1;
            }
-         token_end++;
+         p++;
        }
-      parsed->host_len = token_end - token_start;
-      token_start = token_end;
-    }
-
-  if (!parsed->host_len)
-    {
-      clib_warning ("zero length host");
-      return -1;
+      parsed->reg_name.len = p - token_start;
+      if (parsed->reg_name.len > 255)
+       {
+         clib_warning ("reg-name too long");
+         return -1;
+       }
+      parsed->host_type = HTTP_URI_HOST_TYPE_REG_NAME;
+      parsed->reg_name.base = (char *) token_start;
+      token_start = p;
     }
 
   /* parse port, if any */
-  if (token_start != end && *token_start == ':')
+  if ((end - token_start) > 1 && *token_start == ':')
     {
-      token_end = ++token_start;
-      if (_parse_port (&token_end, end, &parsed->port))
+      token_start++;
+      if (_http_parse_port (&token_start, end, &parsed->port))
        {
          clib_warning ("invalid port");
          return -1;
        }
-      token_start = token_end;
     }
 
-  if (token_start == end)
-    return 0;
+  return token_start == end ? 0 : -1;
+}
+
+always_inline u8 *
+http_serialize_authority (http_uri_authority_t *authority)
+{
+  u8 *s;
 
-  token_start++; /* drop leading slash */
-  parsed->path_offset = token_start - url;
-  parsed->path_len = end - token_start;
+  if (authority->host_type == HTTP_URI_HOST_TYPE_IP4)
+    s = format (0, "%U", format_ip4_address, &authority->ip.ip4);
+  else if (authority->host_type == HTTP_URI_HOST_TYPE_IP6)
+    s = format (0, "[%U]", format_ip6_address, &authority->ip.ip6);
+  else
+    s = format (0, "%U", format_http_bytes, authority->reg_name.base,
+               authority->reg_name.len);
 
-  if (parsed->path_len)
-    return _validate_target_syntax (token_start, parsed->path_len, 0,
-                                   &is_encoded);
+  if (authority->port)
+    s = format (s, ":%d", clib_net_to_host_u16 (authority->port));
 
-  return 0;
+  return s;
 }
 
 /**
@@ -1356,11 +1437,11 @@ http_parse_absolute_form (u8 *url, u32 url_len, http_url_t *parsed)
  * @note Only IPv4 literals and IPv6 literals supported.
  */
 always_inline int
-http_parse_masque_host_port (u8 *path, u32 path_len, http_uri_t *parsed)
+http_parse_masque_host_port (u8 *path, u32 path_len,
+                            http_uri_authority_t *parsed)
 {
-  u8 *p, *end, *decoded_host;
+  u8 *p, *end, *decoded_host, *p4, *p6;
   u32 host_len;
-  unformat_input_t input;
 
   p = path;
   end = path + path_len;
@@ -1373,21 +1454,22 @@ http_parse_masque_host_port (u8 *path, u32 path_len, http_uri_t *parsed)
   if (!host_len || (host_len == path_len) || (host_len + 1 == path_len))
     return -1;
   decoded_host = http_percent_decode (path, host_len);
-  unformat_init_vector (&input, decoded_host);
-  if (unformat (&input, "%U", unformat_ip4_address, &parsed->ip.ip4))
-    parsed->is_ip4 = 1;
-  else if (unformat (&input, "%U", unformat_ip6_address, &parsed->ip.ip6))
-    parsed->is_ip4 = 0;
+  p4 = p6 = decoded_host;
+  if (0 == _http_parse_ip6 (&p6, p6 + vec_len (decoded_host), &parsed->ip.ip6))
+    parsed->host_type = HTTP_URI_HOST_TYPE_IP6;
+  else if (0 ==
+          _http_parse_ip4 (&p4, p4 + vec_len (decoded_host), &parsed->ip.ip4))
+    parsed->host_type = HTTP_URI_HOST_TYPE_IP4;
   else
     {
-      unformat_free (&input);
+      vec_free (decoded_host);
       clib_warning ("unsupported target_host format");
       return -1;
     }
-  unformat_free (&input);
+  vec_free (decoded_host);
 
   p++;
-  if (_parse_port (&p, end, &parsed->port))
+  if (_http_parse_port (&p, end, &parsed->port))
     {
       clib_warning ("invalid port");
       return -1;
index 61c7050..90ffb19 100644 (file)
@@ -16,10 +16,10 @@ Usage
 
 The plugin exposes following inline functions: ``http_validate_abs_path_syntax``, ``http_validate_query_syntax``,
 ``http_percent_decode``, ``http_path_remove_dot_segments``, ``http_build_header_table``, ``http_get_header``,
-``http_reset_header_table``, ``http_free_header_table``, ``http_add_header``,
-``http_serialize_headers``, ``http_parse_authority_form_target``, ``http_serialize_authority_form_target``,
-``http_parse_absolute_form``, ``http_parse_masque_host_port``, ``http_decap_udp_payload_datagram``,
-``http_encap_udp_payload_datagram``. ``http_token_is``, ``http_token_is_case``, ``http_token_contains``
+``http_reset_header_table``, ``http_free_header_table``, ``http_add_header``, ``http_validate_target_syntax``,
+``http_serialize_headers``, ``http_parse_authority``, ``http_serialize_authority``, ``http_parse_masque_host_port``,
+``http_decap_udp_payload_datagram``, ``http_encap_udp_payload_datagram``. ``http_token_is``, ``http_token_is_case``,
+``http_token_contains``
 
 It relies on the hoststack constructs and uses ``http_msg_data_t`` data structure for passing metadata to/from applications.
 
@@ -36,7 +36,8 @@ HTTP plugin sends message header with metadata for parsing, in form of offset an
 Application will get pre-parsed following items:
 
 * HTTP method
-* target form
+* scheme (HTTP/HTTPS)
+* target authority offset and length
 * target path offset and length
 * target query offset and length
 * header section offset and length
@@ -65,30 +66,31 @@ Now application can start reading HTTP data. First let's read the target path:
 .. code-block:: C
 
   u8 *target_path;
+  if (msg.data.target_path_len == 0)
+    {
+      /* your error handling */
+    }
   vec_validate (target_path, msg.data.target_path_len - 1);
   rv = svm_fifo_peek (ts->rx_fifo, msg.data.target_path_offset, msg.data.target_path_len, target_path);
   ASSERT (rv == msg.data.target_path_len);
 
-Application might also want to know target form which is stored in ``msg.data.target_form``, you can read more about target forms in RFC9112 section 3.2.
-In case of origin form HTTP plugin always sets ``target_path_offset`` after leading slash character.
+Target path might be in some cases empty (e.g. CONNECT method), you can read more about target forms in RFC9112 section 3.2.
+In case of origin and absolute form HTTP plugin always sets ``target_path_offset`` after leading slash character.
 
-Example bellow validates "absolute-path" rule, as described in RFC9110 section 4.1, in case of target in origin form, additionally application can get information if percent encoding is used and decode path:
+Example bellow validates "absolute-path" rule, as described in RFC9110 section 4.1, additionally application can get information if percent encoding is used and decode path:
 
 .. code-block:: C
 
   int is_encoded = 0;
-  if (msg.data.target_form == HTTP_TARGET_ORIGIN_FORM)
+  if (http_validate_abs_path_syntax (target_path, &is_encoded))
     {
-      if (http_validate_abs_path_syntax (target_path, &is_encoded))
-        {
-          /* your error handling */
-        }
-      if (is_encoded)
-        {
-          u8 *decoded = http_percent_decode (target_path, vec_len (target_path));
-          vec_free (target_path);
-          target_path = decoded;
-        }
+      /* your error handling */
+    }
+  if (is_encoded)
+    {
+      u8 *decoded = http_percent_decode (target_path, vec_len (target_path));
+      vec_free (target_path);
+      target_path = decoded;
     }
 
 More on topic when to decode in RFC3986 section 2.4.
@@ -245,7 +247,6 @@ When server application sends response back to HTTP layer it starts with message
 Application should set following items:
 
 * Status code
-* target form
 * header section offset and length
 * body offset and length
 
@@ -353,7 +354,7 @@ When client application sends message to HTTP layer it starts with message metad
 Application should set following items:
 
 * HTTP method
-* target form, offset and length
+* target offset and length
 * header section offset and length
 * body offset and length
 
@@ -390,7 +391,6 @@ Following example shows how to set message metadata:
   msg.method_type = HTTP_REQ_GET;
   msg.data.headers_offset = 0;
   /* request target */
-  msg.data.target_form = HTTP_TARGET_ORIGIN_FORM;
   msg.data.target_path_offset = 0;
   msg.data.target_path_len = vec_len (target);
   /* custom headers */
index 089f93f..7cf36f8 100644 (file)
   }
 
 static int
-http_test_authority_form (vlib_main_t *vm)
+http_test_parse_authority (vlib_main_t *vm)
 {
-  u8 *target = 0, *formated_target = 0;
-  http_uri_t authority;
+  u8 *authority = 0, *formated = 0;
+  http_uri_authority_t parsed;
   int rv;
 
-  target = format (0, "10.10.2.45:20");
-  rv = http_parse_authority_form_target (target, vec_len (target), &authority);
-  HTTP_TEST ((rv == 0), "'%v' should be valid", target);
-  formated_target = http_serialize_authority_form_target (&authority);
-  rv = vec_cmp (target, formated_target);
-  HTTP_TEST ((rv == 0), "'%v' should match '%v'", target, formated_target);
-  vec_free (target);
-  vec_free (formated_target);
-
-  target = format (0, "[dead:beef::1234]:443");
-  rv = http_parse_authority_form_target (target, vec_len (target), &authority);
-  HTTP_TEST ((rv == 0), "'%v' should be valid", target);
-  formated_target = http_serialize_authority_form_target (&authority);
-  rv = vec_cmp (target, formated_target);
-  HTTP_TEST ((rv == 0), "'%v' should match '%v'", target, formated_target);
-  vec_free (target);
-  vec_free (formated_target);
-
-  target = format (0, "example.com:80");
-  rv = http_parse_authority_form_target (target, vec_len (target), &authority);
-  HTTP_TEST ((rv != 0), "'%v' reg-name not supported", target);
-  vec_free (target);
-
-  target = format (0, "10.10.2.45");
-  rv = http_parse_authority_form_target (target, vec_len (target), &authority);
-  HTTP_TEST ((rv != 0), "'%v' should be invalid", target);
-  vec_free (target);
-
-  target = format (0, "1000.10.2.45:20");
-  rv = http_parse_authority_form_target (target, vec_len (target), &authority);
-  HTTP_TEST ((rv != 0), "'%v' should be invalid", target);
-  vec_free (target);
-
-  target = format (0, "[xyz0::1234]:443");
-  rv = http_parse_authority_form_target (target, vec_len (target), &authority);
-  HTTP_TEST ((rv != 0), "'%v' should be invalid", target);
-  vec_free (target);
-
-  return 0;
-}
-
-static int
-http_test_absolute_form (vlib_main_t *vm)
-{
-  u8 *url = 0;
-  http_url_t parsed_url;
-  int rv;
-
-  url = format (0, "https://example.org/.well-known/masque/udp/1.2.3.4/123/");
-  rv = http_parse_absolute_form (url, vec_len (url), &parsed_url);
-  HTTP_TEST ((rv == 0), "'%v' should be valid", url);
-  HTTP_TEST ((parsed_url.scheme == HTTP_URL_SCHEME_HTTPS),
-            "scheme should be https");
-  HTTP_TEST ((parsed_url.host_is_ip6 == 0), "host_is_ip6=%u should be 0",
-            parsed_url.host_is_ip6);
-  HTTP_TEST ((parsed_url.host_offset == strlen ("https://")),
-            "host_offset=%u should be %u", parsed_url.host_offset,
-            strlen ("https://"));
-  HTTP_TEST ((parsed_url.host_len == strlen ("example.org")),
-            "host_len=%u should be %u", parsed_url.host_len,
-            strlen ("example.org"));
-  HTTP_TEST ((clib_net_to_host_u16 (parsed_url.port) == 443),
-            "port=%u should be 443", clib_net_to_host_u16 (parsed_url.port));
-  HTTP_TEST ((parsed_url.path_offset == strlen ("https://example.org/")),
-            "path_offset=%u should be %u", parsed_url.path_offset,
-            strlen ("https://example.org/"));
-  HTTP_TEST (
-    (parsed_url.path_len == strlen (".well-known/masque/udp/1.2.3.4/123/")),
-    "path_len=%u should be %u", parsed_url.path_len,
-    strlen (".well-known/masque/udp/1.2.3.4/123/"));
-  vec_free (url);
-
-  url = format (0, "http://vpp-example.org");
-  rv = http_parse_absolute_form (url, vec_len (url), &parsed_url);
-  HTTP_TEST ((rv == 0), "'%v' should be valid", url);
-  HTTP_TEST ((parsed_url.scheme == HTTP_URL_SCHEME_HTTP),
-            "scheme should be http");
-  HTTP_TEST ((parsed_url.host_is_ip6 == 0), "host_is_ip6=%u should be 0",
-            parsed_url.host_is_ip6);
-  HTTP_TEST ((parsed_url.host_offset == strlen ("http://")),
-            "host_offset=%u should be %u", parsed_url.host_offset,
-            strlen ("http://"));
-  HTTP_TEST ((parsed_url.host_len == strlen ("vpp-example.org")),
-            "host_len=%u should be %u", parsed_url.host_len,
-            strlen ("vpp-example.org"));
-  HTTP_TEST ((clib_net_to_host_u16 (parsed_url.port) == 80),
-            "port=%u should be 80", clib_net_to_host_u16 (parsed_url.port));
-  HTTP_TEST ((parsed_url.path_len == 0), "path_len=%u should be 0",
-            parsed_url.path_len);
-  vec_free (url);
-
-  url = format (0, "http://1.2.3.4:8080/abcd");
-  rv = http_parse_absolute_form (url, vec_len (url), &parsed_url);
-  HTTP_TEST ((rv == 0), "'%v' should be valid", url);
-  HTTP_TEST ((parsed_url.scheme == HTTP_URL_SCHEME_HTTP),
-            "scheme should be http");
-  HTTP_TEST ((parsed_url.host_is_ip6 == 0), "host_is_ip6=%u should be 0",
-            parsed_url.host_is_ip6);
-  HTTP_TEST ((parsed_url.host_offset == strlen ("http://")),
-            "host_offset=%u should be %u", parsed_url.host_offset,
-            strlen ("http://"));
-  HTTP_TEST ((parsed_url.host_len == strlen ("1.2.3.4")),
-            "host_len=%u should be %u", parsed_url.host_len,
-            strlen ("1.2.3.4"));
-  HTTP_TEST ((clib_net_to_host_u16 (parsed_url.port) == 8080),
-            "port=%u should be 8080", clib_net_to_host_u16 (parsed_url.port));
-  HTTP_TEST ((parsed_url.path_offset == strlen ("http://1.2.3.4:8080/")),
-            "path_offset=%u should be %u", parsed_url.path_offset,
-            strlen ("http://1.2.3.4:8080/"));
-  HTTP_TEST ((parsed_url.path_len == strlen ("abcd")),
-            "path_len=%u should be %u", parsed_url.path_len, strlen ("abcd"));
-  vec_free (url);
-
-  url = format (0, "https://[dead:beef::1234]/abcd");
-  rv = http_parse_absolute_form (url, vec_len (url), &parsed_url);
-  HTTP_TEST ((rv == 0), "'%v' should be valid", url);
-  HTTP_TEST ((parsed_url.scheme == HTTP_URL_SCHEME_HTTPS),
-            "scheme should be https");
-  HTTP_TEST ((parsed_url.host_is_ip6 == 1), "host_is_ip6=%u should be 1",
-            parsed_url.host_is_ip6);
-  HTTP_TEST ((parsed_url.host_offset == strlen ("https://[")),
-            "host_offset=%u should be %u", parsed_url.host_offset,
-            strlen ("https://["));
-  HTTP_TEST ((parsed_url.host_len == strlen ("dead:beef::1234")),
-            "host_len=%u should be %u", parsed_url.host_len,
-            strlen ("dead:beef::1234"));
-  HTTP_TEST ((clib_net_to_host_u16 (parsed_url.port) == 443),
-            "port=%u should be 443", clib_net_to_host_u16 (parsed_url.port));
-  HTTP_TEST ((parsed_url.path_offset == strlen ("https://[dead:beef::1234]/")),
-            "path_offset=%u should be %u", parsed_url.path_offset,
-            strlen ("https://[dead:beef::1234]/"));
-  HTTP_TEST ((parsed_url.path_len == strlen ("abcd")),
-            "path_len=%u should be %u", parsed_url.path_len, strlen ("abcd"));
-  vec_free (url);
-
-  url = format (0, "http://[::ffff:192.0.2.128]:8080/");
-  rv = http_parse_absolute_form (url, vec_len (url), &parsed_url);
-  HTTP_TEST ((rv == 0), "'%v' should be valid", url);
-  HTTP_TEST ((parsed_url.scheme == HTTP_URL_SCHEME_HTTP),
-            "scheme should be http");
-  HTTP_TEST ((parsed_url.host_is_ip6 == 1), "host_is_ip6=%u should be 1",
-            parsed_url.host_is_ip6);
-  HTTP_TEST ((parsed_url.host_offset == strlen ("http://[")),
-            "host_offset=%u should be %u", parsed_url.host_offset,
-            strlen ("http://["));
-  HTTP_TEST ((parsed_url.host_len == strlen ("::ffff:192.0.2.128")),
-            "host_len=%u should be %u", parsed_url.host_len,
-            strlen ("::ffff:192.0.2.128"));
-  HTTP_TEST ((clib_net_to_host_u16 (parsed_url.port) == 8080),
-            "port=%u should be 8080", clib_net_to_host_u16 (parsed_url.port));
-  HTTP_TEST ((parsed_url.path_len == 0), "path_len=%u should be 0",
-            parsed_url.path_len);
-  vec_free (url);
-
-  url = format (0, "http://[dead:beef::1234/abc");
-  rv = http_parse_absolute_form (url, vec_len (url), &parsed_url);
-  HTTP_TEST ((rv != 0), "'%v' should be invalid", url);
-  vec_free (url);
-
-  url = format (0, "http://[dead|beef::1234]/abc");
-  rv = http_parse_absolute_form (url, vec_len (url), &parsed_url);
-  HTTP_TEST ((rv != 0), "'%v' should be invalid", url);
-  vec_free (url);
-
-  url = format (0, "http:example.org:8080/abcd");
-  rv = http_parse_absolute_form (url, vec_len (url), &parsed_url);
-  HTTP_TEST ((rv != 0), "'%v' should be invalid", url);
-  vec_free (url);
-
-  url = format (0, "htt://example.org:8080/abcd");
-  rv = http_parse_absolute_form (url, vec_len (url), &parsed_url);
-  HTTP_TEST ((rv != 0), "'%v' should be invalid", url);
-  vec_free (url);
-
-  url = format (0, "http://");
-  rv = http_parse_absolute_form (url, vec_len (url), &parsed_url);
-  HTTP_TEST ((rv != 0), "'%v' should be invalid", url);
-  vec_free (url);
-
-  url = format (0, "http:///abcd");
-  rv = http_parse_absolute_form (url, vec_len (url), &parsed_url);
-  HTTP_TEST ((rv != 0), "'%v' should be invalid", url);
-  vec_free (url);
-
-  url = format (0, "http://example.org:808080/abcd");
-  rv = http_parse_absolute_form (url, vec_len (url), &parsed_url);
-  HTTP_TEST ((rv != 0), "'%v' should be invalid", url);
-  vec_free (url);
-
-  url = format (0, "http://example.org/a%%3Xbcd");
-  rv = http_parse_absolute_form (url, vec_len (url), &parsed_url);
-  HTTP_TEST ((rv != 0), "'%v' should be invalid", url);
-  vec_free (url);
-
-  url = format (0, "http://example.org/a%%3");
-  rv = http_parse_absolute_form (url, vec_len (url), &parsed_url);
-  HTTP_TEST ((rv != 0), "'%v' should be invalid", url);
-  vec_free (url);
-
-  url = format (0, "http://example.org/a[b]cd");
-  rv = http_parse_absolute_form (url, vec_len (url), &parsed_url);
-  HTTP_TEST ((rv != 0), "'%v' should be invalid", url);
-  vec_free (url);
-
-  url = format (0, "http://exa[m]ple.org/abcd");
-  rv = http_parse_absolute_form (url, vec_len (url), &parsed_url);
-  HTTP_TEST ((rv != 0), "'%v' should be invalid", url);
-  vec_free (url);
+  /* IPv4 address */
+  authority = format (0, "10.10.2.45:20");
+  rv = http_parse_authority (authority, vec_len (authority), &parsed);
+  HTTP_TEST ((rv == 0), "'%v' should be valid", authority);
+  HTTP_TEST ((parsed.host_type == HTTP_URI_HOST_TYPE_IP4),
+            "host_type=%d should be %d", parsed.host_type,
+            HTTP_URI_HOST_TYPE_IP4);
+  HTTP_TEST ((clib_net_to_host_u16 (parsed.port) == 20),
+            "port=%u should be 20", clib_net_to_host_u16 (parsed.port));
+  formated = http_serialize_authority (&parsed);
+  rv = vec_cmp (authority, formated);
+  HTTP_TEST ((rv == 0), "'%v' should match '%v'", authority, formated);
+  vec_free (authority);
+  vec_free (formated);
+
+  authority = format (0, "10.255.2.1");
+  rv = http_parse_authority (authority, vec_len (authority), &parsed);
+  HTTP_TEST ((rv == 0), "'%v' should be valid", authority);
+  HTTP_TEST ((parsed.host_type == HTTP_URI_HOST_TYPE_IP4),
+            "host_type=%d should be %d", parsed.host_type,
+            HTTP_URI_HOST_TYPE_IP4);
+  HTTP_TEST ((parsed.port == 0), "port=%u should be 0", parsed.port);
+  formated = http_serialize_authority (&parsed);
+  rv = vec_cmp (authority, formated);
+  HTTP_TEST ((rv == 0), "'%v' should match '%v'", authority, formated);
+  vec_free (authority);
+  vec_free (formated);
+
+  /* IPv6 address */
+  authority = format (0, "[dead:beef::1234]:443");
+  rv = http_parse_authority (authority, vec_len (authority), &parsed);
+  HTTP_TEST ((rv == 0), "'%v' should be valid", authority);
+  HTTP_TEST ((parsed.host_type == HTTP_URI_HOST_TYPE_IP6),
+            "host_type=%d should be %d", parsed.host_type,
+            HTTP_URI_HOST_TYPE_IP6);
+  HTTP_TEST ((clib_net_to_host_u16 (parsed.port) == 443),
+            "port=%u should be 443", clib_net_to_host_u16 (parsed.port));
+  formated = http_serialize_authority (&parsed);
+  rv = vec_cmp (authority, formated);
+  HTTP_TEST ((rv == 0), "'%v' should match '%v'", authority, formated);
+  vec_free (authority);
+  vec_free (formated);
+
+  /* registered name */
+  authority = format (0, "example.com:80");
+  rv = http_parse_authority (authority, vec_len (authority), &parsed);
+  HTTP_TEST ((rv == 0), "'%v' should be valid", authority);
+  HTTP_TEST ((parsed.host_type == HTTP_URI_HOST_TYPE_REG_NAME),
+            "host_type=%d should be %d", parsed.host_type,
+            HTTP_URI_HOST_TYPE_REG_NAME);
+  HTTP_TEST ((clib_net_to_host_u16 (parsed.port) == 80),
+            "port=%u should be 80", clib_net_to_host_u16 (parsed.port));
+  formated = http_serialize_authority (&parsed);
+  rv = vec_cmp (authority, formated);
+  HTTP_TEST ((rv == 0), "'%v' should match '%v'", authority, formated);
+  vec_free (authority);
+  vec_free (formated);
+
+  authority = format (0, "3xample.com:80");
+  rv = http_parse_authority (authority, vec_len (authority), &parsed);
+  HTTP_TEST ((rv == 0), "'%v' should be valid", authority);
+  HTTP_TEST ((parsed.host_type == HTTP_URI_HOST_TYPE_REG_NAME),
+            "host_type=%d should be %d", parsed.host_type,
+            HTTP_URI_HOST_TYPE_REG_NAME);
+  HTTP_TEST ((clib_net_to_host_u16 (parsed.port) == 80),
+            "port=%u should be 80", clib_net_to_host_u16 (parsed.port));
+  formated = http_serialize_authority (&parsed);
+  rv = vec_cmp (authority, formated);
+  HTTP_TEST ((rv == 0), "'%v' should match '%v'", authority, formated);
+  vec_free (authority);
+  vec_free (formated);
+
+  /* 'invalid IPv4 address' is recognized as registered name */
+  authority = format (0, "1000.10.2.45:80");
+  rv = http_parse_authority (authority, vec_len (authority), &parsed);
+  HTTP_TEST ((rv == 0), "'%v' should be valid", authority);
+  HTTP_TEST ((parsed.host_type == HTTP_URI_HOST_TYPE_REG_NAME),
+            "host_type=%d should be %d", parsed.host_type,
+            HTTP_URI_HOST_TYPE_REG_NAME);
+  HTTP_TEST ((clib_net_to_host_u16 (parsed.port) == 80),
+            "port=%u should be 80", clib_net_to_host_u16 (parsed.port));
+  formated = http_serialize_authority (&parsed);
+  rv = vec_cmp (authority, formated);
+  HTTP_TEST ((rv == 0), "'%v' should match '%v'", authority, formated);
+  vec_free (authority);
+  vec_free (formated);
+
+  authority = format (0, "10.10.20:80");
+  rv = http_parse_authority (authority, vec_len (authority), &parsed);
+  HTTP_TEST ((rv == 0), "'%v' should be valid", authority);
+  HTTP_TEST ((parsed.host_type == HTTP_URI_HOST_TYPE_REG_NAME),
+            "host_type=%d should be %d", parsed.host_type,
+            HTTP_URI_HOST_TYPE_REG_NAME);
+  HTTP_TEST ((clib_net_to_host_u16 (parsed.port) == 80),
+            "port=%u should be 80", clib_net_to_host_u16 (parsed.port));
+  formated = http_serialize_authority (&parsed);
+  rv = vec_cmp (authority, formated);
+  HTTP_TEST ((rv == 0), "'%v' should match '%v'", authority, formated);
+  vec_free (authority);
+  vec_free (formated);
+
+  authority = format (0, "10.10.10.10.2");
+  rv = http_parse_authority (authority, vec_len (authority), &parsed);
+  HTTP_TEST ((rv == 0), "'%v' should be valid", authority);
+  HTTP_TEST ((parsed.host_type == HTTP_URI_HOST_TYPE_REG_NAME),
+            "host_type=%d should be %d", parsed.host_type,
+            HTTP_URI_HOST_TYPE_REG_NAME);
+  HTTP_TEST ((parsed.port == 0), "port=%u should be 0", parsed.port);
+  formated = http_serialize_authority (&parsed);
+  rv = vec_cmp (authority, formated);
+  HTTP_TEST ((rv == 0), "'%v' should match '%v'", authority, formated);
+  vec_free (authority);
+  vec_free (formated);
+
+  /* invalid port */
+  authority = format (0, "example.com:80000000");
+  rv = http_parse_authority (authority, vec_len (authority), &parsed);
+  HTTP_TEST ((rv == -1), "'%v' should be invalid", authority);
+
+  /* no port after colon */
+  authority = format (0, "example.com:");
+  rv = http_parse_authority (authority, vec_len (authority), &parsed);
+  HTTP_TEST ((rv == -1), "'%v' should be invalid", authority);
+
+  /* invalid character in registered name */
+  authority = format (0, "bad#example.com");
+  rv = http_parse_authority (authority, vec_len (authority), &parsed);
+  HTTP_TEST ((rv == -1), "'%v' should be invalid", authority);
+
+  /* invalid IPv6 address not terminated with ']' */
+  authority = format (0, "[dead:beef::1234");
+  rv = http_parse_authority (authority, vec_len (authority), &parsed);
+  HTTP_TEST ((rv == -1), "'%v' should be invalid", authority);
+
+  /* empty IPv6 address */
+  authority = format (0, "[]");
+  rv = http_parse_authority (authority, vec_len (authority), &parsed);
+  HTTP_TEST ((rv == -1), "'%v' should be invalid", authority);
+
+  /* invalid IPv6 address too few hex quads */
+  authority = format (0, "[dead:beef]:80");
+  rv = http_parse_authority (authority, vec_len (authority), &parsed);
+  HTTP_TEST ((rv == -1), "'%v' should be invalid", authority);
+
+  /* invalid IPv6 address more than one :: */
+  authority = format (0, "[dead::beef::1]:80");
+  rv = http_parse_authority (authority, vec_len (authority), &parsed);
+  HTTP_TEST ((rv == -1), "'%v' should be invalid", authority);
+
+  /* invalid IPv6 address too much hex quads */
+  authority = format (0, "[d:e:a:d:b:e:e:f:1:2]:80");
+  rv = http_parse_authority (authority, vec_len (authority), &parsed);
+  HTTP_TEST ((rv == -1), "'%v' should be invalid", authority);
+
+  /* invalid character in IPv6 address */
+  authority = format (0, "[xyz0::1234]:443");
+  rv = http_parse_authority (authority, vec_len (authority), &parsed);
+  HTTP_TEST ((rv == -1), "'%v' should be invalid", authority);
+
+  /* invalid IPv6 address */
+  authority = format (0, "[deadbeef::1234");
+  rv = http_parse_authority (authority, vec_len (authority), &parsed);
+  HTTP_TEST ((rv == -1), "'%v' should be invalid", authority);
 
   return 0;
 }
@@ -251,13 +206,15 @@ static int
 http_test_parse_masque_host_port (vlib_main_t *vm)
 {
   u8 *path = 0;
-  http_uri_t target;
+  http_uri_authority_t target;
   int rv;
 
   path = format (0, "10.10.2.45/443/");
   rv = http_parse_masque_host_port (path, vec_len (path), &target);
   HTTP_TEST ((rv == 0), "'%v' should be valid", path);
-  HTTP_TEST ((target.is_ip4 == 1), "is_ip4=%d should be 1", target.is_ip4);
+  HTTP_TEST ((target.host_type == HTTP_URI_HOST_TYPE_IP4),
+            "host_type=%d should be %d", target.host_type,
+            HTTP_URI_HOST_TYPE_IP4);
   HTTP_TEST ((clib_net_to_host_u16 (target.port) == 443),
             "port=%u should be 443", clib_net_to_host_u16 (target.port));
   HTTP_TEST ((target.ip.ip4.data[0] == 10 && target.ip.ip4.data[1] == 10 &&
@@ -269,7 +226,9 @@ http_test_parse_masque_host_port (vlib_main_t *vm)
   path = format (0, "dead%%3Abeef%%3A%%3A1234/80/");
   rv = http_parse_masque_host_port (path, vec_len (path), &target);
   HTTP_TEST ((rv == 0), "'%v' should be valid", path);
-  HTTP_TEST ((target.is_ip4 == 0), "is_ip4=%d should be 0", target.is_ip4);
+  HTTP_TEST ((target.host_type == HTTP_URI_HOST_TYPE_IP6),
+            "host_type=%d should be %d", target.host_type,
+            HTTP_URI_HOST_TYPE_IP6);
   HTTP_TEST ((clib_net_to_host_u16 (target.port) == 80),
             "port=%u should be 80", clib_net_to_host_u16 (target.port));
   HTTP_TEST ((clib_net_to_host_u16 (target.ip.ip6.as_u16[0]) == 0xdead &&
@@ -398,19 +357,15 @@ test_http_command_fn (vlib_main_t *vm, unformat_input_t *input,
   int res = 0;
   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     {
-      if (unformat (input, "authority-form"))
-       res = http_test_authority_form (vm);
-      else if (unformat (input, "absolute-form"))
-       res = http_test_absolute_form (vm);
+      if (unformat (input, "parse-authority"))
+       res = http_test_parse_authority (vm);
       else if (unformat (input, "parse-masque-host-port"))
        res = http_test_parse_masque_host_port (vm);
       else if (unformat (input, "udp-payload-datagram"))
        res = http_test_udp_payload_datagram (vm);
       else if (unformat (input, "all"))
        {
-         if ((res = http_test_authority_form (vm)))
-           goto done;
-         if ((res = http_test_absolute_form (vm)))
+         if ((res = http_test_parse_authority (vm)))
            goto done;
          if ((res = http_test_parse_masque_host_port (vm)))
            goto done;
index 7afac42..fe5718b 100644 (file)
@@ -546,12 +546,6 @@ hss_ts_rx_callback (session_t *ts)
       goto done;
     }
 
-  if (msg.data.target_form != HTTP_TARGET_ORIGIN_FORM)
-    {
-      start_send_data (hs, HTTP_STATUS_BAD_REQUEST);
-      goto done;
-    }
-
   /* Read target path */
   if (msg.data.target_path_len)
     {