func init() {
RegisterH2Tests(Http2TcpGetTest, Http2TcpPostTest, Http2MultiplexingTest, Http2TlsTest, Http2ContinuationTxTest, Http2ServerMemLeakTest,
- Http2ClientGetTest, Http2ClientPostTest, Http2ClientPostPtrTest, Http2ClientGetRepeatTest, Http2ClientMultiplexingTest)
+ Http2ClientGetTest, Http2ClientPostTest, Http2ClientPostPtrTest, Http2ClientGetRepeatTest, Http2ClientMultiplexingTest,
+ Http2ClientH2cTest)
RegisterH2MWTests(Http2MultiplexingMWTest, Http2ClientMultiplexingMWTest)
RegisterVethTests(Http2CliTlsTest, Http2ClientContinuationTest)
}
s.Log(o)
s.AssertContains(o, "HTTP/2 200 OK")
s.AssertContains(o, "10000000 bytes saved to file")
+
+ logPath := s.Containers.NginxServer.GetHostWorkDir() + "/" + s.Containers.NginxServer.Name + "-access.log"
+ logContents, err := exechelper.Output("cat " + logPath)
+ s.AssertNil(err)
+ s.AssertContains(string(logContents), "HTTP/2")
+ s.AssertContains(string(logContents), "scheme=https conn=")
+}
+
+func Http2ClientH2cTest(s *Http2Suite) {
+ vpp := s.Containers.Vpp.VppInstance
+ serverAddress := s.HostAddr() + ":" + s.Ports.Port1
+
+ s.CreateNginxServer()
+ s.AssertNil(s.Containers.NginxServer.Start())
+
+ uri := "http://" + serverAddress + "/httpTestFile"
+ o := vpp.Vppctl("http client http2 save-to response.txt verbose uri " + uri)
+ s.Log(o)
+ s.AssertContains(o, "HTTP/2 200 OK")
+ s.AssertContains(o, "10000000 bytes saved to file")
+
+ logPath := s.Containers.NginxServer.GetHostWorkDir() + "/" + s.Containers.NginxServer.Name + "-access.log"
+ logContents, err := exechelper.Output("cat " + logPath)
+ s.AssertNil(err)
+ s.AssertContains(string(logContents), "HTTP/2")
+ s.AssertContains(string(logContents), "scheme=http conn=")
}
func http2ClientPostFile(s *Http2Suite, usePtr bool, fileSize int) {
http {
log_format access_log_fmt '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
- '"$http_referer" "$http_user_agent" conn=$connection conn_reqs=$connection_requests';
+ '"$http_referer" "$http_user_agent" '
+ 'scheme=$scheme conn=$connection conn_reqs=$connection_requests';
keepalive_timeout 300s;
keepalive_requests 1000000;
client_body_timeout {{.Timeout}}s;
hc_main_t *hcm = &hc_main;
vnet_connect_args_t *a = 0;
transport_endpt_ext_cfg_t *ext_cfg;
- transport_endpt_cfg_http_t http_cfg = { (u32) hcm->timeout, 0 };
+ transport_endpt_cfg_http_t http_cfg = { (u32) hcm->timeout, 0, 0 };
vec_validate (a, 0);
clib_memset (a, 0, sizeof (a[0]));
clib_memcpy (&a->sep_ext, &hcm->connect_sep, sizeof (hcm->connect_sep));
a->app_index = hcm->app_index;
- ext_cfg = session_endpoint_add_ext_cfg (
- &a->sep_ext, TRANSPORT_ENDPT_EXT_CFG_HTTP, sizeof (http_cfg));
- clib_memcpy (ext_cfg->data, &http_cfg, sizeof (http_cfg));
-
if (hcm->connect_sep.flags & SESSION_ENDPT_CFG_F_SECURE)
{
ext_cfg = session_endpoint_add_ext_cfg (
break;
}
}
+ else
+ {
+ if (hcm->http_version == HTTP_VERSION_2)
+ http_cfg.flags |= HTTP_ENDPT_CFG_F_HTTP2_PRIOR_KNOWLEDGE;
+ }
+
+ ext_cfg = session_endpoint_add_ext_cfg (
+ &a->sep_ext, TRANSPORT_ENDPT_EXT_CFG_HTTP, sizeof (http_cfg));
+ clib_memcpy (ext_cfg->data, &http_cfg, sizeof (http_cfg));
session_send_rpc_evt_to_thread_force (transport_cl_thread (), hc_connect_rpc,
a);
vec_add1 (hm->postponed_ho_free, ho_hc_index);
}
-static inline http_conn_t *
+http_conn_t *
http_ho_conn_get (u32 ho_hc_index)
{
http_main_t *hm = &http_main;
clib_memcpy_fast (hc, ho_hc, sizeof (*hc));
- /* in chain with TLS there is race on half-open cleanup */
- __atomic_fetch_or (&ho_hc->flags, HTTP_CONN_F_HO_DONE, __ATOMIC_RELEASE);
-
hc->timer_handle = HTTP_TIMER_HANDLE_INVALID;
hc->c_thread_index = ts->thread_index;
hc->hc_tc_session_handle = session_handle (ts);
hc->state = HTTP_CONN_STATE_ESTABLISHED;
ts->session_state = SESSION_STATE_READY;
hc->flags |= HTTP_CONN_F_NO_APP_SESSION;
+ hc->ho_index = ho_hc_index;
tp = session_get_transport_proto (ts);
/* TLS set by ALPN result, TCP: prior knowledge (set in ho) */
if (tp == TRANSPORT_PROTO_TLS)
{
case TLS_ALPN_PROTO_HTTP_2:
hc->version = HTTP_VERSION_2;
- http_vfts[hc->version].conn_accept_callback (hc);
break;
case TLS_ALPN_PROTO_HTTP_1_1:
case TLS_ALPN_PROTO_NONE:
if ((rv = http_vfts[hc->version].transport_connected_callback (hc)))
{
clib_warning ("transport_connected_callback failed, rv=%d", rv);
+ __atomic_fetch_or (&ho_hc->flags, HTTP_CONN_F_HO_DONE, __ATOMIC_RELEASE);
return rv;
}
(transport_endpt_cfg_http_t *) ext_cfg->data;
HTTP_DBG (1, "app set timeout %u", http_cfg->timeout);
hc->timeout = http_cfg->timeout;
+ if (http_cfg->flags & HTTP_ENDPT_CFG_F_HTTP2_PRIOR_KNOWLEDGE)
+ {
+ HTTP_DBG (1, "app want http2 with prior knowledge");
+ hc->version = HTTP_VERSION_2;
+ }
}
ext_cfg = session_endpoint_get_ext_cfg (sep, TRANSPORT_ENDPT_EXT_CFG_CRYPTO);
HTTP_UDP_TUNNEL_DGRAM, /**< convert capsule to datagram (zc proxy) */
} http_udp_tunnel_mode_t;
+#define foreach_http_endpt_cfg_flags \
+ _ (HTTP2_PRIOR_KNOWLEDGE) /**< HTTP/2 connections over cleartext TCP */
+
+typedef enum http_endpt_cfg_flags_bit_
+{
+#define _(sym) HTTP_ENDPT_CFG_F_BIT_##sym,
+ foreach_http_endpt_cfg_flags
+#undef _
+} http_endpt_cfg_flags_bit_t;
+
+typedef enum http_endpt_cfg_flags_
+{
+#define _(sym) HTTP_ENDPT_CFG_F_##sym = 1 << HTTP_ENDPT_CFG_F_BIT_##sym,
+ foreach_http_endpt_cfg_flags
+#undef _
+} __clib_packed http_endpt_cfg_flags_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 */
+ u8 flags;
} transport_endpt_cfg_http_t;
typedef struct
u32 timer_handle;
u32 timeout;
u32 app_rx_fifo_size;
+ u32 ho_index;
u8 *app_name;
u8 *host;
http_conn_flags_t flags;
http_conn_t *http_conn_get_w_thread (u32 hc_index,
clib_thread_index_t thread_index);
+http_conn_t *http_ho_conn_get (u32 ho_hc_index);
+
/**
* @brief Find the first occurrence of the string in the vector.
*
session_t *as;
app_worker_t *app_wrk;
session_t *ts;
+ http_conn_t *ho_hc;
int rv;
+ ho_hc = http_ho_conn_get (hc->ho_index);
+ /* in chain with TLS there is race on half-open cleanup */
+ __atomic_fetch_or (&ho_hc->flags, HTTP_CONN_F_HO_DONE, __ATOMIC_RELEASE);
+
/* allocate app session and initialize */
as = session_alloc (hc->c_thread_index);
HTTP_DBG (1, "allocated session 0x%lx", session_handle (as));