summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatus Fabian <matfabia@cisco.com>2025-01-12 22:18:56 +0100
committerMatus Fabian <matfabia@cisco.com>2025-01-21 13:47:28 -0500
commit98d1264fcdb81c1213e1d0ac02098a3f6673631a (patch)
tree71fa5fe3da48681c64419bc6ceab24e2f442fb42
parent98028dd4c475f8929cf07a87114e857bfc6bda93 (diff)
http: target parsing improvement
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 <matfabia@cisco.com>
-rw-r--r--extras/hs-test/http_test.go68
-rw-r--r--extras/hs-test/infra/connect_udp_client.go1
-rw-r--r--extras/hs-test/proxy_test.go25
-rw-r--r--src/plugins/hs_apps/http_cli.c3
-rw-r--r--src/plugins/hs_apps/http_client.c1
-rw-r--r--src/plugins/hs_apps/http_client_cli.c1
-rw-r--r--src/plugins/hs_apps/http_tps.c3
-rw-r--r--src/plugins/hs_apps/proxy.c81
-rw-r--r--src/plugins/hs_apps/vcl/vcl_test_protos.c8
-rw-r--r--src/plugins/http/http.c121
-rw-r--r--src/plugins/http/http.h408
-rw-r--r--src/plugins/http/http_plugin.rst44
-rw-r--r--src/plugins/http/test/http_test.c397
-rw-r--r--src/plugins/http_static/static_server.c6
14 files changed, 666 insertions, 501 deletions
diff --git a/extras/hs-test/http_test.go b/extras/hs-test/http_test.go
index 4b67d274882..4cbcdeb1b21 100644
--- a/extras/hs-test/http_test.go
+++ b/extras/hs-test/http_test.go
@@ -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()
diff --git a/extras/hs-test/infra/connect_udp_client.go b/extras/hs-test/infra/connect_udp_client.go
index 595f7e7f2e6..a30ad3a769a 100644
--- a/extras/hs-test/infra/connect_udp_client.go
+++ b/extras/hs-test/infra/connect_udp_client.go
@@ -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")
}
diff --git a/extras/hs-test/proxy_test.go b/extras/hs-test/proxy_test.go
index ec90d24ba36..192451fe8f4 100644
--- a/extras/hs-test/proxy_test.go
+++ b/extras/hs-test/proxy_test.go
@@ -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()
diff --git a/src/plugins/hs_apps/http_cli.c b/src/plugins/hs_apps/http_cli.c
index 3ca86d24673..89eb49c8ec7 100644
--- a/src/plugins/hs_apps/http_cli.c
+++ b/src/plugins/hs_apps/http_cli.c
@@ -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;
diff --git a/src/plugins/hs_apps/http_client.c b/src/plugins/hs_apps/http_client.c
index bfecc9a58fb..91ac6cf0032 100644
--- a/src/plugins/hs_apps/http_client.c
+++ b/src/plugins/hs_apps/http_client.c
@@ -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);
diff --git a/src/plugins/hs_apps/http_client_cli.c b/src/plugins/hs_apps/http_client_cli.c
index b9658ed10d0..3c50e24c9fd 100644
--- a/src/plugins/hs_apps/http_client_cli.c
+++ b/src/plugins/hs_apps/http_client_cli.c
@@ -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 */
diff --git a/src/plugins/hs_apps/http_tps.c b/src/plugins/hs_apps/http_tps.c
index a40a31caf63..f4ef808e410 100644
--- a/src/plugins/hs_apps/http_tps.c
+++ b/src/plugins/hs_apps/http_tps.c
@@ -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;
diff --git a/src/plugins/hs_apps/proxy.c b/src/plugins/hs_apps/proxy.c
index f96940e13af..f3b1fdce48c 100644
--- a/src/plugins/hs_apps/proxy.c
+++ b/src/plugins/hs_apps/proxy.c
@@ -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));
diff --git a/src/plugins/hs_apps/vcl/vcl_test_protos.c b/src/plugins/hs_apps/vcl/vcl_test_protos.c
index 9c81c5f17a1..da4b6997ec1 100644
--- a/src/plugins/hs_apps/vcl/vcl_test_protos.c
+++ b/src/plugins/hs_apps/vcl/vcl_test_protos.c
@@ -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);
diff --git a/src/plugins/http/http.c b/src/plugins/http/http.c
index c33c85a303e..666f45c7d8f 100644
--- a/src/plugins/http/http.c
+++ b/src/plugins/http/http.c
@@ -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;
diff --git a/src/plugins/http/http.h b/src/plugins/http/http.h
index 3bdbc6cfdda..008f6634ea9 100644
--- a/src/plugins/http/http.h
+++ b/src/plugins/http/http.h
@@ -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;
diff --git a/src/plugins/http/http_plugin.rst b/src/plugins/http/http_plugin.rst
index 61c70503e54..90ffb1919e6 100644
--- a/src/plugins/http/http_plugin.rst
+++ b/src/plugins/http/http_plugin.rst
@@ -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 */
diff --git a/src/plugins/http/test/http_test.c b/src/plugins/http/test/http_test.c
index 089f93ff574..7cf36f82577 100644
--- a/src/plugins/http/test/http_test.c
+++ b/src/plugins/http/test/http_test.c
@@ -29,220 +29,175 @@
}
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;
diff --git a/src/plugins/http_static/static_server.c b/src/plugins/http_static/static_server.c
index 7afac4229c3..fe5718b7e0f 100644
--- a/src/plugins/http_static/static_server.c
+++ b/src/plugins/http_static/static_server.c
@@ -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)
{