summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMatus Fabian <matfabia@cisco.com>2024-12-10 16:15:06 +0100
committerFlorin Coras <florin.coras@gmail.com>2025-01-09 10:59:16 +0000
commitc19cca931af3baf847d66bce9e5dd660861fc92e (patch)
treea36f0ba9f31c379984a3de4dfb54baa8808f5bbe /src
parente89c97a3ee1538f3693fcd298831952d5df19ec2 (diff)
hsa: proxying UDP in HTTP/1.1
Type: feature Change-Id: Ic0ff9b9bfbad9fbc602fbcec0d8906cd21d63a2c Signed-off-by: Matus Fabian <matfabia@cisco.com>
Diffstat (limited to 'src')
-rw-r--r--src/plugins/hs_apps/http_client.c6
-rw-r--r--src/plugins/hs_apps/http_client_cli.c5
-rw-r--r--src/plugins/hs_apps/proxy.c283
-rw-r--r--src/plugins/hs_apps/proxy.h5
-rw-r--r--src/plugins/http/http.c253
-rw-r--r--src/plugins/http/http.h60
-rw-r--r--src/plugins/http/http_plugin.rst33
-rw-r--r--src/plugins/http/test/http_test.c44
-rw-r--r--src/plugins/http_static/static_server.c5
9 files changed, 545 insertions, 149 deletions
diff --git a/src/plugins/hs_apps/http_client.c b/src/plugins/hs_apps/http_client.c
index 35c25d207ec..bfecc9a58fb 100644
--- a/src/plugins/hs_apps/http_client.c
+++ b/src/plugins/hs_apps/http_client.c
@@ -508,6 +508,7 @@ hc_connect_rpc (void *rpc_args)
if (rv > 0)
clib_warning (0, "connect returned: %U", format_session_error, rv);
+ session_endpoint_free_ext_cfgs (&a->sep_ext);
vec_free (a);
return rv;
}
@@ -520,6 +521,7 @@ hc_connect ()
hc_worker_t *wrk;
hc_session_t *hc_session;
transport_endpt_ext_cfg_t *ext_cfg;
+ transport_endpt_cfg_http_t http_cfg = { (u32) hcm->timeout, 0 };
vec_validate (a, 0);
clib_memset (a, 0, sizeof (a[0]));
@@ -528,8 +530,8 @@ hc_connect ()
a->app_index = hcm->app_index;
ext_cfg = session_endpoint_add_ext_cfg (
- &a->sep_ext, TRANSPORT_ENDPT_EXT_CFG_HTTP, sizeof (ext_cfg->opaque));
- ext_cfg->opaque = hcm->timeout;
+ &a->sep_ext, TRANSPORT_ENDPT_EXT_CFG_HTTP, sizeof (http_cfg));
+ clib_memcpy (ext_cfg->data, &http_cfg, sizeof (http_cfg));
/* allocate http session on main thread */
wrk = hc_worker_get (0);
diff --git a/src/plugins/hs_apps/http_client_cli.c b/src/plugins/hs_apps/http_client_cli.c
index 861af7f03e2..b9658ed10d0 100644
--- a/src/plugins/hs_apps/http_client_cli.c
+++ b/src/plugins/hs_apps/http_client_cli.c
@@ -409,9 +409,10 @@ hcc_connect ()
a->app_index = hcm->app_index;
/* set http (response) timeout to 10 seconds */
+ transport_endpt_cfg_http_t http_cfg = { 10, 0 };
ext_cfg = session_endpoint_add_ext_cfg (
- &a->sep_ext, TRANSPORT_ENDPT_EXT_CFG_HTTP, sizeof (ext_cfg->opaque));
- ext_cfg->opaque = 10;
+ &a->sep_ext, TRANSPORT_ENDPT_EXT_CFG_HTTP, sizeof (http_cfg));
+ clib_memcpy (ext_cfg->data, &http_cfg, sizeof (http_cfg));
/* allocate http session on main thread */
wrk = hcc_worker_get (0);
diff --git a/src/plugins/hs_apps/proxy.c b/src/plugins/hs_apps/proxy.c
index 82b904f9f1b..f96940e13af 100644
--- a/src/plugins/hs_apps/proxy.c
+++ b/src/plugins/hs_apps/proxy.c
@@ -19,13 +19,16 @@
#include <vnet/session/application_interface.h>
#include <hs_apps/proxy.h>
#include <vnet/tcp/tcp.h>
-#include <http/http.h>
#include <http/http_header_names.h>
proxy_main_t proxy_main;
#define TCP_MSS 1460
+static const char masque_udp_uri_prefix[] = ".well-known/masque/udp/";
+#define MASQUE_UDP_URI_PREFIX_LEN (sizeof (masque_udp_uri_prefix) - 1)
+#define MASQUE_UDP_URI_MIN_LEN (MASQUE_UDP_URI_PREFIX_LEN + 10)
+
#define PROXY_DEBUG 0
#if PROXY_DEBUG
@@ -59,37 +62,33 @@ proxy_session_side_ctx_get (proxy_worker_t *wrk, u32 ctx_index)
return pool_elt_at_index (wrk->ctx_pool, ctx_index);
}
-static void
-proxy_send_http_resp (session_t *s, http_status_code_t sc,
- http_header_t *resp_headers)
+static_always_inline void
+proxy_send_http_resp (session_t *s, http_status_code_t sc, u8 *headers_buf)
{
http_msg_t msg;
int rv;
- u8 *headers_buf = 0;
+ uword headers_ptr;
ASSERT (s->thread_index == vlib_get_thread_index ());
- if (vec_len (resp_headers))
- {
- headers_buf = http_serialize_headers (resp_headers);
- msg.data.len = msg.data.headers_len = vec_len (headers_buf);
- }
- else
- msg.data.len = msg.data.headers_len = 0;
msg.type = HTTP_MSG_REPLY;
msg.code = sc;
- msg.data.type = HTTP_MSG_DATA_INLINE;
+ msg.data.type = HTTP_MSG_DATA_PTR;
+ msg.data.headers_len = vec_len (headers_buf);
+ msg.data.len = msg.data.headers_len;
msg.data.headers_offset = 0;
msg.data.body_len = 0;
msg.data.body_offset = 0;
- rv = svm_fifo_enqueue (s->tx_fifo, sizeof (msg), (u8 *) &msg);
- ASSERT (rv == sizeof (msg));
- if (msg.data.headers_len)
- {
- rv = svm_fifo_enqueue (s->tx_fifo, vec_len (headers_buf), headers_buf);
- ASSERT (rv == vec_len (headers_buf));
- vec_free (headers_buf);
- }
+
+ headers_ptr = pointer_to_uword (headers_buf);
+ svm_fifo_seg_t seg[2] = {
+ { (u8 *) &msg, sizeof (msg) },
+ { (u8 *) &headers_ptr, sizeof (headers_ptr) },
+ };
+
+ rv = svm_fifo_enqueue_segments (s->tx_fifo, seg, msg.data.len ? 2 : 1,
+ 0 /* allow partial */);
+ ASSERT (rv == (sizeof (msg) + (msg.data.len ? sizeof (headers_ptr) : 0)));
if (svm_fifo_set_event (s->tx_fifo))
session_program_tx_io_evt (s->handle, SESSION_IO_EVT_TX);
@@ -504,6 +503,145 @@ proxy_transport_needs_crypto (transport_proto_t proto)
}
static void
+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;
+ 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));
+
+ ASSERT (msg.type == HTTP_MSG_REQUEST);
+
+ if (PREDICT_FALSE (msg.method_type != HTTP_REQ_CONNECT))
+ {
+ PROXY_DBG ("invalid method");
+ goto bad_req;
+ }
+ if (msg.data.upgrade_proto == HTTP_UPGRADE_PROTO_NA)
+ {
+ /* TCP tunnel (RFC9110 section 9.3.6) */
+ PROXY_DBG ("CONNECT");
+ if (msg.data.target_form != HTTP_TARGET_AUTHORITY_FORM)
+ {
+ PROXY_DBG ("CONNECT target not authority form");
+ 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);
+ if (rv)
+ {
+ PROXY_DBG ("target parsing failed");
+ goto bad_req;
+ }
+ target_sep.transport_proto = TRANSPORT_PROTO_TCP;
+ }
+ else if (msg.data.upgrade_proto == HTTP_UPGRADE_PROTO_CONNECT_UDP)
+ {
+ /* 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)
+ {
+ 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;
+ }
+ else
+ {
+ PROXY_DBG ("invalid target form");
+ goto bad_req;
+ }
+ if (memcmp (rx_buf + target_offset, 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);
+ if (rv)
+ {
+ PROXY_DBG ("masque host/port parsing failed");
+ goto bad_req;
+ }
+
+ /* Capsule-Protocol header is optional, but need to have true value */
+ http_reset_header_table (&req_headers);
+ http_init_header_table_buf (&req_headers, msg);
+ rv = svm_fifo_peek (s->rx_fifo, msg.data.headers_offset,
+ msg.data.headers_len, req_headers.buf);
+ ASSERT (rv == msg.data.headers_len);
+ http_build_header_table (&req_headers, msg);
+ const http_header_t *capsule_protocol = http_get_header (
+ &req_headers, http_header_name_token (HTTP_HEADER_CAPSULE_PROTOCOL));
+ if (capsule_protocol)
+ {
+ PROXY_DBG ("Capsule-Protocol header present");
+ if (!http_token_is (capsule_protocol->value.base,
+ capsule_protocol->value.len,
+ http_token_lit (HTTP_BOOLEAN_TRUE)))
+ {
+ PROXY_DBG ("Capsule-Protocol invalid value");
+ goto bad_req;
+ }
+ }
+ target_sep.transport_proto = TRANSPORT_PROTO_UDP;
+ }
+ else
+ {
+ bad_req:
+ proxy_send_http_resp (s, HTTP_STATUS_BAD_REQUEST, 0);
+ svm_fifo_dequeue_drop_all (s->rx_fifo);
+ 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));
+ svm_fifo_dequeue_drop (s->rx_fifo, msg.data.len);
+ target_sep.is_ip4 = target_uri.is_ip4;
+ target_sep.ip = target_uri.ip;
+ target_sep.port = target_uri.port;
+ clib_memcpy (&a->sep_ext, &target_sep, sizeof (target_sep));
+}
+
+static void
proxy_session_start_connect (proxy_session_side_ctx_t *sc, session_t *s)
{
int actual_transfer __attribute__ ((unused));
@@ -530,59 +668,7 @@ proxy_session_start_connect (proxy_session_side_ctx_t *sc, session_t *s)
clib_spinlock_unlock_if_init (&pm->sessions_lock);
if (tp == TRANSPORT_PROTO_HTTP)
- {
- http_msg_t msg;
- u8 *target_buf = 0;
- http_uri_t target_uri;
- http_header_t *resp_headers = 0;
- session_endpoint_cfg_t target_sep = SESSION_ENDPOINT_CFG_NULL;
- int rv;
-
- rv = svm_fifo_dequeue (s->rx_fifo, sizeof (msg), (u8 *) &msg);
- ASSERT (rv == sizeof (msg));
-
- if (msg.type != HTTP_MSG_REQUEST)
- {
- proxy_send_http_resp (s, HTTP_STATUS_INTERNAL_ERROR, 0);
- return;
- }
- if (msg.method_type != HTTP_REQ_CONNECT)
- {
- http_add_header (&resp_headers,
- http_header_name_token (HTTP_HEADER_ALLOW),
- http_token_lit ("CONNECT"));
- proxy_send_http_resp (s, HTTP_STATUS_METHOD_NOT_ALLOWED,
- resp_headers);
- vec_free (resp_headers);
- return;
- }
-
- if (msg.data.target_form != HTTP_TARGET_AUTHORITY_FORM ||
- msg.data.target_path_len == 0)
- {
- proxy_send_http_resp (s, HTTP_STATUS_BAD_REQUEST, 0);
- return;
- }
-
- /* read target uri */
- target_buf = vec_new (u8, msg.data.target_path_len);
- rv = svm_fifo_peek (s->rx_fifo, msg.data.target_path_offset,
- msg.data.target_path_len, target_buf);
- ASSERT (rv == msg.data.target_path_len);
- svm_fifo_dequeue_drop (s->rx_fifo, msg.data.len);
- rv = http_parse_authority_form_target (target_buf, &target_uri);
- vec_free (target_buf);
- if (rv)
- {
- proxy_send_http_resp (s, HTTP_STATUS_BAD_REQUEST, 0);
- return;
- }
- target_sep.is_ip4 = target_uri.is_ip4;
- target_sep.ip = target_uri.ip;
- target_sep.port = target_uri.port;
- target_sep.transport_proto = TRANSPORT_PROTO_TCP;
- clib_memcpy (&a->sep_ext, &target_sep, sizeof (target_sep));
- }
+ proxy_http_connect (s, a);
else
{
max_dequeue = svm_fifo_max_dequeue_cons (s->rx_fifo);
@@ -786,18 +872,35 @@ active_open_send_http_resp_rpc (void *arg)
u32 ps_index = pointer_to_uword (arg);
proxy_main_t *pm = &proxy_main;
proxy_session_t *ps;
- http_status_code_t sc;
session_t *po_s;
+ transport_proto_t ao_tp;
+ int connect_failed;
+
+ PROXY_DBG ("ps[%xlu] going to send connect response", ps_index);
clib_spinlock_lock_if_init (&pm->sessions_lock);
ps = proxy_session_get (ps_index);
po_s = session_get_from_handle (ps->po.session_handle);
- sc = ps->ao_disconnected ? HTTP_STATUS_BAD_GATEWAY : HTTP_STATUS_OK;
+ connect_failed = ps->ao_disconnected;
- clib_spinlock_unlock_if_init (&pm->sessions_lock);
+ if (!connect_failed)
+ {
+ ao_tp = session_get_transport_proto (
+ session_get_from_handle (ps->ao.session_handle));
+ if (ao_tp == TRANSPORT_PROTO_UDP)
+ proxy_send_http_resp (po_s, HTTP_STATUS_SWITCHING_PROTOCOLS,
+ pm->capsule_proto_header);
+ else
+ proxy_send_http_resp (po_s, HTTP_STATUS_OK, 0);
+ }
+ else
+ {
+ proxy_send_http_resp (po_s, HTTP_STATUS_BAD_GATEWAY, 0);
+ proxy_session_close_po (ps);
+ }
- proxy_send_http_resp (po_s, sc, 0);
+ clib_spinlock_unlock_if_init (&pm->sessions_lock);
}
static int
@@ -817,6 +920,7 @@ active_open_connected_callback (u32 app_index, u32 opaque,
clib_spinlock_lock_if_init (&pm->sessions_lock);
ps = proxy_session_get (opaque);
+ PROXY_DBG ("ps[%lu] connect failed: %d", opaque, err);
ps->ao_disconnected = 1;
if (ps->po.is_http)
{
@@ -825,7 +929,8 @@ active_open_connected_callback (u32 app_index, u32 opaque,
active_open_send_http_resp_rpc,
uword_to_pointer (ps->ps_index, void *));
}
- proxy_session_close_po (ps);
+ else
+ proxy_session_close_po (ps);
clib_spinlock_unlock_if_init (&pm->sessions_lock);
@@ -935,6 +1040,7 @@ active_open_migrate_rpc (void *arg)
ps = proxy_session_get (ps_index);
sc->ps_index = ps->ps_index;
+ sc->state = PROXY_SC_S_ESTABLISHED;
s = session_get_from_handle (ps->ao.session_handle);
s->opaque = sc->sc_index;
@@ -1188,14 +1294,15 @@ proxy_server_listen ()
/* set http timeout for connect-proxy */
if (pm->server_sep.transport_proto == TRANSPORT_PROTO_HTTP)
{
+ transport_endpt_cfg_http_t http_cfg = { pm->idle_timeout,
+ HTTP_UDP_TUNNEL_DGRAM };
transport_endpt_ext_cfg_t *ext_cfg = session_endpoint_add_ext_cfg (
- &a->sep_ext, TRANSPORT_ENDPT_EXT_CFG_HTTP, sizeof (ext_cfg->opaque));
- ext_cfg->opaque = pm->idle_timeout;
+ &a->sep_ext, TRANSPORT_ENDPT_EXT_CFG_HTTP, sizeof (http_cfg));
+ clib_memcpy (ext_cfg->data, &http_cfg, sizeof (http_cfg));
}
rv = vnet_listen (a);
- if (need_crypto)
- session_endpoint_free_ext_cfgs (&a->sep_ext);
+ session_endpoint_free_ext_cfgs (&a->sep_ext);
return rv;
}
@@ -1224,12 +1331,14 @@ proxy_server_create (vlib_main_t * vm)
proxy_worker_t *wrk;
u32 num_threads;
int i;
+ http_header_table_t empty_ht = HTTP_HEADER_TABLE_NULL;
if (vlib_num_workers ())
clib_spinlock_init (&pm->sessions_lock);
num_threads = 1 /* main thread */ + vtm->n_threads;
vec_validate (pm->rx_buf, num_threads - 1);
+ vec_validate_init_empty (pm->req_headers, num_threads - 1, empty_ht);
for (i = 0; i < num_threads; i++)
vec_validate (pm->rx_buf[i], pm->rcv_buffer_size);
@@ -1386,6 +1495,8 @@ VLIB_CLI_COMMAND (proxy_create_command, static) = {
clib_error_t *
proxy_main_init (vlib_main_t * vm)
{
+ http_header_t *headers = 0;
+
proxy_main_t *pm = &proxy_main;
pm->server_client_index = ~0;
pm->active_open_client_index = ~0;
@@ -1393,6 +1504,12 @@ proxy_main_init (vlib_main_t * vm)
pm->idle_timeout = 600; /* connect-proxy default idle timeout 10 minutes */
vec_validate (pm->client_sep, TRANSPORT_N_PROTOS - 1);
+ http_add_header (&headers,
+ http_header_name_token (HTTP_HEADER_CAPSULE_PROTOCOL),
+ http_token_lit (HTTP_BOOLEAN_TRUE));
+ pm->capsule_proto_header = http_serialize_headers (headers);
+ vec_free (headers);
+
return 0;
}
diff --git a/src/plugins/hs_apps/proxy.h b/src/plugins/hs_apps/proxy.h
index 276133ba418..814bebfe6cb 100644
--- a/src/plugins/hs_apps/proxy.h
+++ b/src/plugins/hs_apps/proxy.h
@@ -26,6 +26,8 @@
#include <vnet/session/session.h>
#include <vnet/session/application_interface.h>
+#include <http/http.h>
+
#define foreach_proxy_session_side_state \
_ (CREATED, "created") \
_ (CONNECTING, "connecting") \
@@ -80,6 +82,7 @@ typedef struct
proxy_session_t *sessions; /**< session pool, shared */
clib_spinlock_t sessions_lock; /**< lock for session pool */
u8 **rx_buf; /**< intermediate rx buffers */
+ http_header_table_t *req_headers; /**< HTTP request headers */
u32 server_client_index; /**< server API client handle */
u32 server_app_index; /**< server app index */
@@ -87,6 +90,8 @@ typedef struct
u32 active_open_app_index; /**< active open index after attach */
u32 ckpair_index; /**< certkey pair index for tls */
+ u8 *capsule_proto_header;
+
/*
* Configuration params
*/
diff --git a/src/plugins/http/http.c b/src/plugins/http/http.c
index c5cd894cb59..5a0c6541598 100644
--- a/src/plugins/http/http.c
+++ b/src/plugins/http/http.c
@@ -954,17 +954,21 @@ http_identify_headers (http_req_t *req, http_status_code_t *ec)
header_index = field_line - req->headers;
/* find headers that will be used later in preprocessing */
+ /* names are case-insensitive (RFC9110 section 5.1) */
if (req->content_len_header_index == ~0 &&
- http_token_is ((const char *) name_start, name_len,
- http_header_name_token (HTTP_HEADER_CONTENT_LENGTH)))
+ http_token_is_case (
+ (const char *) name_start, name_len,
+ http_header_name_token (HTTP_HEADER_CONTENT_LENGTH)))
req->content_len_header_index = header_index;
else if (req->connection_header_index == ~0 &&
- http_token_is ((const char *) name_start, name_len,
- http_header_name_token (HTTP_HEADER_CONNECTION)))
+ http_token_is_case (
+ (const char *) name_start, name_len,
+ http_header_name_token (HTTP_HEADER_CONNECTION)))
req->connection_header_index = header_index;
else if (req->upgrade_header_index == ~0 &&
- http_token_is ((const char *) name_start, name_len,
- http_header_name_token (HTTP_HEADER_UPGRADE)))
+ http_token_is_case (
+ (const char *) name_start, name_len,
+ http_header_name_token (HTTP_HEADER_UPGRADE)))
req->upgrade_header_index = header_index;
/* are we done? */
@@ -1166,8 +1170,8 @@ http_check_connection_upgrade (http_req_t *req)
if (0)
;
#define _(sym, str) \
- else if (http_token_is (http_field_line_value_token (upgrade, req), \
- http_token_lit (str))) req->upgrade_proto = \
+ else if (http_token_is_case (http_field_line_value_token (upgrade, req), \
+ http_token_lit (str))) req->upgrade_proto = \
HTTP_UPGRADE_PROTO_##sym;
foreach_http_upgrade_proto
#undef _
@@ -1350,13 +1354,18 @@ http_req_state_wait_app_reply (http_conn_t *hc, transport_send_params_t *sp)
ASSERT (msg.data.body_len == 0);
next_state = HTTP_REQ_STATE_TUNNEL;
if (hc->req.upgrade_proto > HTTP_UPGRADE_PROTO_NA)
- response = format (response, connection_upgrade_template,
- http_upgrade_proto_str[hc->req.upgrade_proto]);
+ {
+ response = format (response, connection_upgrade_template,
+ http_upgrade_proto_str[hc->req.upgrade_proto]);
+ if (hc->req.upgrade_proto == HTTP_UPGRADE_PROTO_CONNECT_UDP &&
+ hc->udp_tunnel_mode == HTTP_UDP_TUNNEL_DGRAM)
+ next_state = HTTP_REQ_STATE_UDP_TUNNEL;
+ }
/* cleanup some stuff we don't need anymore in tunnel mode */
- http_conn_timer_stop (hc);
vec_free (hc->req.rx_buf);
vec_free (hc->req.headers);
http_buffer_free (&hc->req.tx_buf);
+ hc->req.to_skip = 0;
}
else
response = format (response, content_len_template, msg.data.body_len);
@@ -1798,6 +1807,196 @@ check_fifo:
return HTTP_SM_STOP;
}
+static http_sm_result_t
+http_req_state_udp_tunnel_rx (http_conn_t *hc, transport_send_params_t *sp)
+{
+ http_main_t *hm = &http_main;
+ u32 to_deq, capsule_size, dgram_size, n_written = 0;
+ int rv, n_read;
+ session_t *as, *ts;
+ app_worker_t *app_wrk;
+ u8 payload_offset;
+ u64 payload_len;
+ session_dgram_hdr_t hdr;
+ u8 *buf = 0;
+
+ HTTP_DBG (1, "udp tunnel received data from client");
+
+ as = session_get_from_handle (hc->h_pa_session_handle);
+ ts = session_get_from_handle (hc->h_tc_session_handle);
+ buf = hm->rx_bufs[hc->c_thread_index];
+ to_deq = svm_fifo_max_dequeue_cons (ts->rx_fifo);
+
+ while (to_deq > 0)
+ {
+ /* some bytes remaining to skip? */
+ if (PREDICT_FALSE (hc->req.to_skip))
+ {
+ if (hc->req.to_skip >= to_deq)
+ {
+ svm_fifo_dequeue_drop (ts->rx_fifo, to_deq);
+ hc->req.to_skip -= to_deq;
+ goto done;
+ }
+ else
+ {
+ svm_fifo_dequeue_drop (ts->rx_fifo, hc->req.to_skip);
+ hc->req.to_skip = 0;
+ }
+ }
+ n_read =
+ svm_fifo_peek (ts->rx_fifo, 0, HTTP_CAPSULE_HEADER_MAX_SIZE, buf);
+ ASSERT (n_read > 0);
+ rv = http_decap_udp_payload_datagram (buf, n_read, &payload_offset,
+ &payload_len);
+ HTTP_DBG (1, "rv=%d, payload_offset=%u, payload_len=%llu", rv,
+ payload_offset, payload_len);
+ if (PREDICT_FALSE (rv != 0))
+ {
+ if (rv < 0)
+ {
+ /* capsule datagram is invalid (session need to be aborted) */
+ svm_fifo_dequeue_drop_all (ts->rx_fifo);
+ session_transport_closing_notify (&hc->connection);
+ session_transport_closed_notify (&hc->connection);
+ http_disconnect_transport (hc);
+ return HTTP_SM_STOP;
+ }
+ else
+ {
+ /* unknown capsule should be skipped */
+ if (payload_len <= to_deq)
+ {
+ svm_fifo_dequeue_drop (ts->rx_fifo, payload_len);
+ to_deq -= payload_len;
+ continue;
+ }
+ else
+ {
+ svm_fifo_dequeue_drop (ts->rx_fifo, to_deq);
+ hc->req.to_skip = payload_len - to_deq;
+ goto done;
+ }
+ }
+ }
+ capsule_size = payload_offset + payload_len;
+ /* check if we have the full capsule */
+ if (PREDICT_FALSE (to_deq < capsule_size))
+ {
+ HTTP_DBG (1, "capsule not complete");
+ goto done;
+ }
+
+ dgram_size = sizeof (hdr) + payload_len;
+ if (svm_fifo_max_enqueue_prod (as->rx_fifo) < dgram_size)
+ {
+ HTTP_DBG (1, "app's rx fifo full");
+ svm_fifo_add_want_deq_ntf (as->rx_fifo, SVM_FIFO_WANT_DEQ_NOTIF);
+ goto done;
+ }
+
+ /* read capsule payload */
+ rv = svm_fifo_peek (ts->rx_fifo, payload_offset, payload_len, buf);
+ ASSERT (rv == payload_len);
+ svm_fifo_dequeue_drop (ts->rx_fifo, capsule_size);
+
+ hdr.data_length = payload_len;
+ hdr.data_offset = 0;
+
+ /* send datagram header and payload */
+ svm_fifo_seg_t segs[2] = { { (u8 *) &hdr, sizeof (hdr) },
+ { buf, payload_len } };
+ rv = svm_fifo_enqueue_segments (as->rx_fifo, segs, 2, 0);
+ ASSERT (rv > 0);
+
+ n_written += dgram_size;
+ to_deq -= capsule_size;
+ }
+
+done:
+ HTTP_DBG (1, "written %lu bytes", n_written);
+
+ if (n_written)
+ {
+ app_wrk = app_worker_get_if_valid (as->app_wrk_index);
+ if (app_wrk)
+ app_worker_rx_notify (app_wrk, as);
+ }
+ if (svm_fifo_max_dequeue_cons (ts->rx_fifo))
+ session_program_rx_io_evt (session_handle (ts));
+
+ return HTTP_SM_STOP;
+}
+
+static http_sm_result_t
+http_req_state_udp_tunnel_tx (http_conn_t *hc, transport_send_params_t *sp)
+{
+ http_main_t *hm = &http_main;
+ u32 to_deq, capsule_size, dgram_size, n_written = 0;
+ session_t *as, *ts;
+ int rv;
+ session_dgram_pre_hdr_t hdr;
+ u8 *buf;
+ u8 *payload;
+
+ HTTP_DBG (1, "udp tunnel received data from target");
+
+ as = session_get_from_handle (hc->h_pa_session_handle);
+ ts = session_get_from_handle (hc->h_tc_session_handle);
+ buf = hm->tx_bufs[hc->c_thread_index];
+ to_deq = svm_fifo_max_dequeue_cons (as->tx_fifo);
+
+ while (to_deq > 0)
+ {
+ /* read datagram header */
+ rv = svm_fifo_peek (as->tx_fifo, 0, sizeof (hdr), (u8 *) &hdr);
+ ASSERT (rv == sizeof (hdr) &&
+ hdr.data_length <= HTTP_UDP_PAYLOAD_MAX_LEN);
+ ASSERT (to_deq >= hdr.data_length + SESSION_CONN_HDR_LEN);
+ dgram_size = hdr.data_length + SESSION_CONN_HDR_LEN;
+
+ if (svm_fifo_max_enqueue_prod (ts->tx_fifo) <
+ (hdr.data_length + HTTP_UDP_PROXY_DATAGRAM_CAPSULE_OVERHEAD))
+ {
+ HTTP_DBG (1, "ts tx fifo full");
+ goto done;
+ }
+
+ /* create capsule header */
+ payload = http_encap_udp_payload_datagram (buf, hdr.data_length);
+ capsule_size = (payload - buf) + hdr.data_length;
+ /* read payload */
+ rv = svm_fifo_peek (as->tx_fifo, SESSION_CONN_HDR_LEN, hdr.data_length,
+ payload);
+ ASSERT (rv == hdr.data_length);
+ svm_fifo_dequeue_drop (as->tx_fifo, dgram_size);
+ /* send capsule */
+ rv = svm_fifo_enqueue (ts->tx_fifo, capsule_size, buf);
+ ASSERT (rv == capsule_size);
+
+ n_written += capsule_size;
+ to_deq -= dgram_size;
+ }
+
+done:
+ HTTP_DBG (1, "written %lu bytes", n_written);
+ if (n_written)
+ {
+ if (svm_fifo_set_event (ts->tx_fifo))
+ session_program_tx_io_evt (ts->handle, SESSION_IO_EVT_TX);
+ }
+
+ /* Deschedule and wait for deq notification if ts fifo is almost full */
+ if (svm_fifo_max_enqueue (ts->tx_fifo) < HTTP_FIFO_THRESH)
+ {
+ svm_fifo_add_want_deq_ntf (ts->tx_fifo, SVM_FIFO_WANT_DEQ_NOTIF);
+ transport_connection_deschedule (&hc->connection);
+ sp->flags |= TRANSPORT_SND_F_DESCHED;
+ }
+
+ return HTTP_SM_STOP;
+}
+
typedef http_sm_result_t (*http_sm_handler) (http_conn_t *,
transport_send_params_t *sp);
@@ -1810,6 +2009,7 @@ static http_sm_handler tx_state_funcs[HTTP_REQ_N_STATES] = {
http_req_state_wait_app_reply,
http_req_state_app_io_more_data,
http_req_state_tunnel_tx,
+ http_req_state_udp_tunnel_tx,
};
static_always_inline int
@@ -1827,6 +2027,7 @@ static http_sm_handler rx_state_funcs[HTTP_REQ_N_STATES] = {
0, /* wait app reply */
0, /* app io more data */
http_req_state_tunnel_rx,
+ http_req_state_udp_tunnel_rx,
};
static_always_inline int
@@ -1977,10 +2178,12 @@ static session_cb_vft_t http_app_cb_vft = {
static clib_error_t *
http_transport_enable (vlib_main_t *vm, u8 is_en)
{
+ vlib_thread_main_t *vtm = vlib_get_thread_main ();
vnet_app_detach_args_t _da, *da = &_da;
vnet_app_attach_args_t _a, *a = &_a;
u64 options[APP_OPTIONS_N_OPTIONS];
http_main_t *hm = &http_main;
+ u32 num_threads, i;
if (!is_en)
{
@@ -1990,6 +2193,8 @@ http_transport_enable (vlib_main_t *vm, u8 is_en)
return 0;
}
+ num_threads = 1 /* main thread */ + vtm->n_threads;
+
clib_memset (a, 0, sizeof (*a));
clib_memset (options, 0, sizeof (options));
@@ -2014,7 +2219,18 @@ http_transport_enable (vlib_main_t *vm, u8 is_en)
if (hm->is_init)
return 0;
- vec_validate (hm->wrk, vlib_num_workers ());
+ vec_validate (hm->wrk, num_threads - 1);
+ vec_validate (hm->rx_bufs, num_threads - 1);
+ vec_validate (hm->tx_bufs, num_threads - 1);
+ for (i = 0; i < num_threads; i++)
+ {
+ vec_validate (hm->rx_bufs[i],
+ HTTP_UDP_PAYLOAD_MAX_LEN +
+ HTTP_UDP_PROXY_DATAGRAM_CAPSULE_OVERHEAD);
+ vec_validate (hm->tx_bufs[i],
+ HTTP_UDP_PAYLOAD_MAX_LEN +
+ HTTP_UDP_PROXY_DATAGRAM_CAPSULE_OVERHEAD);
+ }
clib_timebase_init (&hm->timebase, 0 /* GMT */, CLIB_TIMEBASE_DAYLIGHT_NONE,
&vm->clib_time /* share the system clock */);
@@ -2056,8 +2272,10 @@ http_transport_connect (transport_endpoint_cfg_t *tep)
ext_cfg = session_endpoint_get_ext_cfg (sep, TRANSPORT_ENDPT_EXT_CFG_HTTP);
if (ext_cfg)
{
- HTTP_DBG (1, "app set timeout %u", ext_cfg->opaque);
- hc->timeout = ext_cfg->opaque;
+ transport_endpt_cfg_http_t *http_cfg =
+ (transport_endpt_cfg_http_t *) ext_cfg->data;
+ HTTP_DBG (1, "app set timeout %u", http_cfg->timeout);
+ hc->timeout = http_cfg->timeout;
}
hc->is_server = 0;
@@ -2132,8 +2350,11 @@ http_start_listen (u32 app_listener_index, transport_endpoint_cfg_t *tep)
ext_cfg = session_endpoint_get_ext_cfg (sep, TRANSPORT_ENDPT_EXT_CFG_HTTP);
if (ext_cfg && ext_cfg->opaque)
{
- HTTP_DBG (1, "app set timeout %u", ext_cfg->opaque);
- lhc->timeout = ext_cfg->opaque;
+ transport_endpt_cfg_http_t *http_cfg =
+ (transport_endpt_cfg_http_t *) ext_cfg->data;
+ HTTP_DBG (1, "app set timeout %u", http_cfg->timeout);
+ lhc->timeout = http_cfg->timeout;
+ lhc->udp_tunnel_mode = http_cfg->udp_tunnel_mode;
}
/* Grab transport connection listener and link to http listener */
diff --git a/src/plugins/http/http.h b/src/plugins/http/http.h
index 7405d3d3bf7..3bdbc6cfdda 100644
--- a/src/plugins/http/http.h
+++ b/src/plugins/http/http.h
@@ -37,6 +37,18 @@
#define HTTP_DBG(_lvl, _fmt, _args...)
#endif
+typedef enum http_udp_tunnel_mode_
+{
+ HTTP_UDP_TUNNEL_CAPSULE, /**< app receive raw capsule */
+ HTTP_UDP_TUNNEL_DGRAM, /**< convert capsule to datagram (zc proxy) */
+} http_udp_tunnel_mode_t;
+
+typedef struct transport_endpt_cfg_http
+{
+ u32 timeout; /**< HTTP session timeout in seconds */
+ http_udp_tunnel_mode_t udp_tunnel_mode; /**< connect-udp mode */
+} transport_endpt_cfg_http_t;
+
typedef struct http_conn_id_
{
union
@@ -82,7 +94,8 @@ typedef enum http_conn_state_
_ (4, WAIT_TRANSPORT_METHOD, "wait transport method") \
_ (5, WAIT_APP_REPLY, "wait app reply") \
_ (6, APP_IO_MORE_DATA, "app io more data") \
- _ (7, TUNNEL, "tunnel")
+ _ (7, TUNNEL, "tunnel") \
+ _ (8, UDP_TUNNEL, "udp tunnel")
typedef enum http_req_state_
{
@@ -424,7 +437,11 @@ typedef struct http_req_
u32 rx_buf_offset; /* current offset during parsing */
u32 control_data_len; /* start line + headers + empty line */
- u64 to_recv; /* remaining bytes of message body to receive from transport */
+ union
+ {
+ u64 to_recv; /* remaining bytes of body to receive from transport */
+ u64 to_skip; /* remaining bytes of capsule to skip */
+ };
u8 is_tunnel;
@@ -477,6 +494,7 @@ typedef struct http_tc_
u8 *app_name;
u8 *host;
u8 is_server;
+ http_udp_tunnel_mode_t udp_tunnel_mode;
http_req_t req;
} http_conn_t;
@@ -493,6 +511,9 @@ typedef struct http_main_
http_conn_t *ho_conn_pool;
u32 app_index;
+ u8 **rx_bufs;
+ u8 **tx_bufs;
+
clib_timebase_t timebase;
u16 *sc_by_u16;
@@ -858,7 +879,7 @@ http_token_is_case (const char *actual, uword actual_len, const char *expected,
return 0;
for (i = 0; i < expected_len; i++)
{
- if (tolower (actual[i]) != expected[i])
+ if (tolower (actual[i]) != tolower (expected[i]))
return 0;
}
return 1;
@@ -994,8 +1015,6 @@ http_build_header_table (http_header_table_t *ht, http_msg_t msg)
header->name.len = name.len;
header->value.base = (char *) (ht->buf + field_line->value_offset);
header->value.len = field_line->value_len;
- HTTP_DBG (1, "value: %U", format_http_bytes, header->value.base,
- header->value.len);
hash_set_mem (ht->value_by_name, &header->name, header - ht->headers);
}
}
@@ -1006,7 +1025,7 @@ http_build_header_table (http_header_table_t *ht, http_msg_t msg)
* @param header_table Header table to search.
* @param name Header name to match.
*
- * @return Header's value in case of success, @c 0 otherwise.
+ * @return Header in case of success, @c 0 otherwise.
*/
always_inline const http_header_t *
http_get_header (http_header_table_t *header_table, const char *name,
@@ -1094,14 +1113,27 @@ typedef struct
u8 is_ip4;
} http_uri_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, http_uri_t *authority)
+http_parse_authority_form_target (u8 *target, u32 target_len,
+ http_uri_t *authority)
{
unformat_input_t input;
+ u8 *tmp = 0;
u32 port;
int rv = 0;
- unformat_init_vector (&input, vec_dup (target));
+ 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))
{
@@ -1184,13 +1216,14 @@ _parse_port (u8 **pos, u8 *end, u16 *port)
/**
* An "absolute-form" URL parsing.
*
- * @param url Vector of target URL to validate.
- * @param parsed Parsed URL metadata in case of success.
+ * @param url Target URL to parse.
+ * @param url_len Length of URL.
+ * @param parsed Parsed URL metadata in case of success.
*
* @return @c 0 on success.
*/
always_inline int
-http_parse_absolute_form (u8 *url, http_url_t *parsed)
+http_parse_absolute_form (u8 *url, u32 url_len, http_url_t *parsed)
{
u8 *token_start, *token_end, *end;
int is_encoded = 0;
@@ -1204,7 +1237,7 @@ http_parse_absolute_form (u8 *url, http_url_t *parsed)
0x0000000000000000,
};
- if (vec_len (url) < 9)
+ if (url_len < 9)
{
clib_warning ("uri too short");
return -1;
@@ -1212,7 +1245,7 @@ http_parse_absolute_form (u8 *url, http_url_t *parsed)
clib_memset (parsed, 0, sizeof (*parsed));
- end = url + vec_len (url);
+ end = url + url_len;
/* parse scheme */
if (!memcmp (url, "http:// ", 7))
@@ -1367,6 +1400,7 @@ http_parse_masque_host_port (u8 *path, u32 path_len, http_uri_t *parsed)
}
#define HTTP_INVALID_VARINT ((u64) ~0)
+#define HTTP_CAPSULE_HEADER_MAX_SIZE 8
#define HTTP_UDP_PROXY_DATAGRAM_CAPSULE_OVERHEAD 5
#define HTTP_UDP_PAYLOAD_MAX_LEN 65527
diff --git a/src/plugins/http/http_plugin.rst b/src/plugins/http/http_plugin.rst
index bf414cf96ef..61c70503e54 100644
--- a/src/plugins/http/http_plugin.rst
+++ b/src/plugins/http/http_plugin.rst
@@ -128,17 +128,22 @@ Following example shows how to parse headers:
if (msg.data.headers_len)
{
http_header_table_t ht = HTTP_HEADER_TABLE_NULL;
+ /* initialize header table buffer */
http_init_header_table_buf (&ht, msg);
+ /* read raw headers into buffer */
rv = svm_fifo_peek (ts->rx_fifo, msg.data.headers_offset,
msg.data.headers_len, ht.buf);
ASSERT (rv == msg.data.headers_len);
+ /* build header table */
http_build_header_table (&ht, msg);
/* get Accept header */
- const http_header_t *accept = http_get_header (&ht, http_header_name_token (HTTP_HEADER_ACCEPT));
+ const http_header_t *accept = http_get_header (&ht,
+ http_header_name_token (HTTP_HEADER_ACCEPT));
if (accept_value)
{
/* do something interesting */
}
+ /* free header table */
http_free_header_table (&ht);
}
@@ -166,17 +171,22 @@ Modified example above:
.. code-block:: C
#include <http/http_header_names.h>
+ /* reset header table before reuse */
http_reset_header_table (&ctx->ht);
/* ... */
if (msg.data.headers_len)
{
+ /* initialize header table buffer */
http_init_header_table_buf (&ctx->ht, msg);
+ /* read raw headers into buffer */
rv = svm_fifo_peek (ts->rx_fifo, msg.data.headers_offset,
msg.data.headers_len, ctx->ht.buf);
ASSERT (rv == msg.data.headers_len);
+ /* build header table */
http_build_header_table (&ctx->ht, msg);
/* get Accept header */
- const http_header_t *accept = http_get_header (&ctx->ht, http_header_name_token (HTTP_HEADER_ACCEPT));
+ const http_header_t *accept = http_get_header (&ctx->ht,
+ http_header_name_token (HTTP_HEADER_ACCEPT));
if (accept_value)
{
/* do something interesting */
@@ -245,7 +255,7 @@ Well known header names are predefined.
The list is serialized just before you send buffer to HTTP layer.
.. note::
- Following headers are added at protocol layer and **MUST NOT** be set by application: Date, Server, Content-Length
+ Following headers are added at protocol layer and **MUST NOT** be set by application: Date, Server, Content-Length, Connection, Upgrade
Following example shows how to create headers section:
@@ -476,17 +486,22 @@ Following example shows how to parse headers:
if (msg.data.headers_len)
{
http_header_table_t ht = HTTP_HEADER_TABLE_NULL;
+ /* initialize header table buffer */
http_init_header_table_buf (&ht, msg);
+ /* read raw headers into buffer */
rv = svm_fifo_peek (ts->rx_fifo, msg.data.headers_offset,
msg.data.headers_len, ht.buf);
ASSERT (rv == msg.data.headers_len);
+ /* build header table */
http_build_header_table (&ht, msg);
/* get Content-Type header */
- const http_header_t *content_type = http_get_header (&ht, http_header_name_token (HTTP_HEADER_CONTENT_TYPE));
+ const http_header_t *content_type = http_get_header (&ht,
+ http_header_name_token (HTTP_HEADER_CONTENT_TYPE));
if (content_type)
{
/* do something interesting */
}
+ /* free header table */
http_free_header_table (&ht);
}
@@ -546,23 +561,23 @@ HTTP timeout
HTTP plugin sets session inactivity timeout by default to 60 seconds.
Client and server applications can pass custom timeout value (in seconds) using extended configuration when doing connect or start listening respectively.
You just need to add extended configuration to session endpoint configuration which is part of ``vnet_connect_args_t`` and ``vnet_listen_args_t``.
-HTTP plugin use ``opaque`` member of ``transport_endpt_ext_cfg_t``, unsigned 32bit integer seems to be sufficient (allowing the timeout to be set up to 136 years).
+HTTP plugin use ``timeout`` member of ``transport_endpt_cfg_http_t``, unsigned 32bit integer seems to be sufficient (allowing the timeout to be set up to 136 years).
The example below sets HTTP session timeout to 30 seconds (server application):
.. code-block:: C
vnet_listen_args_t _a, *a = &_a;
- session_endpoint_cfg_t sep = SESSION_ENDPOINT_CFG_NULL;
transport_endpt_ext_cfg_t *ext_cfg;
int rv;
clib_memset (a, 0, sizeof (*a));
clib_memcpy (&a->sep_ext, &sep, sizeof (sep));
+ /* your custom timeout value in seconds, unused parameters are set to zero */
+ transport_endpt_cfg_http_t http_cfg = { 30, 0 };
/* add new extended config entry */
ext_cfg = session_endpoint_add_ext_cfg (
- &a->sep_ext, TRANSPORT_ENDPT_EXT_CFG_HTTP, sizeof (ext_cfg->opaque));
- /* your custom timeout value in seconds */
- ext_cfg->opaque = 30;
+ &a->sep_ext, TRANSPORT_ENDPT_EXT_CFG_HTTP, sizeof (http_cfg));
+ clib_memcpy (ext_cfg->data, &http_cfg, sizeof (http_cfg));
/* rest of the settings omitted for brevity */
rv = vnet_listen (a);
/* don't forget to free extended config */
diff --git a/src/plugins/http/test/http_test.c b/src/plugins/http/test/http_test.c
index 40fd4463b61..089f93ff574 100644
--- a/src/plugins/http/test/http_test.c
+++ b/src/plugins/http/test/http_test.c
@@ -36,7 +36,7 @@ http_test_authority_form (vlib_main_t *vm)
int rv;
target = format (0, "10.10.2.45:20");
- rv = http_parse_authority_form_target (target, &authority);
+ 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);
@@ -45,7 +45,7 @@ http_test_authority_form (vlib_main_t *vm)
vec_free (formated_target);
target = format (0, "[dead:beef::1234]:443");
- rv = http_parse_authority_form_target (target, &authority);
+ 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);
@@ -54,22 +54,22 @@ http_test_authority_form (vlib_main_t *vm)
vec_free (formated_target);
target = format (0, "example.com:80");
- rv = http_parse_authority_form_target (target, &authority);
+ 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, &authority);
+ 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, &authority);
+ 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, &authority);
+ rv = http_parse_authority_form_target (target, vec_len (target), &authority);
HTTP_TEST ((rv != 0), "'%v' should be invalid", target);
vec_free (target);
@@ -84,7 +84,7 @@ http_test_absolute_form (vlib_main_t *vm)
int rv;
url = format (0, "https://example.org/.well-known/masque/udp/1.2.3.4/123/");
- rv = http_parse_absolute_form (url, &parsed_url);
+ 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");
@@ -108,7 +108,7 @@ http_test_absolute_form (vlib_main_t *vm)
vec_free (url);
url = format (0, "http://vpp-example.org");
- rv = http_parse_absolute_form (url, &parsed_url);
+ 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");
@@ -127,7 +127,7 @@ http_test_absolute_form (vlib_main_t *vm)
vec_free (url);
url = format (0, "http://1.2.3.4:8080/abcd");
- rv = http_parse_absolute_form (url, &parsed_url);
+ 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");
@@ -149,7 +149,7 @@ http_test_absolute_form (vlib_main_t *vm)
vec_free (url);
url = format (0, "https://[dead:beef::1234]/abcd");
- rv = http_parse_absolute_form (url, &parsed_url);
+ 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");
@@ -171,7 +171,7 @@ http_test_absolute_form (vlib_main_t *vm)
vec_free (url);
url = format (0, "http://[::ffff:192.0.2.128]:8080/");
- rv = http_parse_absolute_form (url, &parsed_url);
+ 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");
@@ -190,57 +190,57 @@ http_test_absolute_form (vlib_main_t *vm)
vec_free (url);
url = format (0, "http://[dead:beef::1234/abc");
- rv = http_parse_absolute_form (url, &parsed_url);
+ 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, &parsed_url);
+ 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, &parsed_url);
+ 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, &parsed_url);
+ 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, &parsed_url);
+ 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, &parsed_url);
+ 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, &parsed_url);
+ 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, &parsed_url);
+ 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, &parsed_url);
+ 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, &parsed_url);
+ 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, &parsed_url);
+ rv = http_parse_absolute_form (url, vec_len (url), &parsed_url);
HTTP_TEST ((rv != 0), "'%v' should be invalid", url);
vec_free (url);
diff --git a/src/plugins/http_static/static_server.c b/src/plugins/http_static/static_server.c
index 9cc3f5dd658..ae42fd53762 100644
--- a/src/plugins/http_static/static_server.c
+++ b/src/plugins/http_static/static_server.c
@@ -809,6 +809,7 @@ hss_listen (void)
u8 need_crypto;
transport_endpt_ext_cfg_t *ext_cfg;
int rv;
+ transport_endpt_cfg_http_t http_cfg = { hsm->keepalive_timeout, 0 };
clib_memset (a, 0, sizeof (*a));
a->app_index = hsm->app_index;
@@ -825,8 +826,8 @@ hss_listen (void)
clib_memcpy (&a->sep_ext, &sep, sizeof (sep));
ext_cfg = session_endpoint_add_ext_cfg (
- &a->sep_ext, TRANSPORT_ENDPT_EXT_CFG_HTTP, sizeof (ext_cfg->opaque));
- ext_cfg->opaque = hsm->keepalive_timeout;
+ &a->sep_ext, TRANSPORT_ENDPT_EXT_CFG_HTTP, sizeof (http_cfg));
+ clib_memcpy (ext_cfg->data, &http_cfg, sizeof (http_cfg));
if (need_crypto)
{