diff --git a/include/libwebsockets/lws-client.h b/include/libwebsockets/lws-client.h index 85b8488d6..e957b3a37 100644 --- a/include/libwebsockets/lws-client.h +++ b/include/libwebsockets/lws-client.h @@ -58,6 +58,7 @@ enum lws_client_connect_ssl_connection_flags { * HTTP/2: always possible... uses parallel streams */ LCCSCF_MUXABLE_STREAM = (1 << 17), + LCCSCF_H2_PRIOR_KNOWLEDGE = (1 << 18) }; /** struct lws_client_connect_info - parameters to connect with when using diff --git a/include/libwebsockets/lws-context-vhost.h b/include/libwebsockets/lws-context-vhost.h index ffb0c8f55..268b3d5a9 100644 --- a/include/libwebsockets/lws-context-vhost.h +++ b/include/libwebsockets/lws-context-vhost.h @@ -221,6 +221,11 @@ #define LWS_SERVER_OPTION_GLIB (1ll << 33) /**< (CTX) Use glib event loop */ +#define LWS_SERVER_OPTION_H2_PRIOR_KNOWLEDGE (1ll << 34) + /**< (VH) Tell the vhost to treat plain text http connections as + * H2 with prior knowledge (no upgrade request involved) + */ + /****** add new things just above ---^ ******/ diff --git a/lib/roles/h1/ops-h1.c b/lib/roles/h1/ops-h1.c index 2b273c830..254e003af 100644 --- a/lib/roles/h1/ops-h1.c +++ b/lib/roles/h1/ops-h1.c @@ -907,11 +907,20 @@ rops_adoption_bind_h1(struct lws *wsi, int type, const char *vh_prot_name) return 1; } - lws_role_transition(wsi, LWSIFR_SERVER, (type & LWS_ADOPT_ALLOW_SSL) ? - LRS_SSL_INIT : LRS_HEADERS, &role_ops_h1); + /* If Non-TLS and HTTP2 prior knowledge is enabled, skip to clear text HTTP2 */ + +#if defined(LWS_WITH_HTTP2) + if ((!(type & LWS_ADOPT_ALLOW_SSL)) && (wsi->vhost->options & LWS_SERVER_OPTION_H2_PRIOR_KNOWLEDGE)) { + lwsl_info("http/2 prior knowledge\n"); + lws_role_call_alpn_negotiated(wsi, "h2"); + } + else +#endif + lws_role_transition(wsi, LWSIFR_SERVER, (type & LWS_ADOPT_ALLOW_SSL) ? + LRS_SSL_INIT : LRS_HEADERS, &role_ops_h1); /* - * We have to bind to h1 as a default even when we're actually going to + * Otherwise, we have to bind to h1 as a default even when we're actually going to * replace it as an h2 bind later. So don't take this seriously if the * default is disabled (ws upgrade caees properly about it) */ diff --git a/lib/roles/h2/http2.c b/lib/roles/h2/http2.c index 3377fb1a7..82f01225a 100644 --- a/lib/roles/h2/http2.c +++ b/lib/roles/h2/http2.c @@ -765,6 +765,11 @@ int lws_h2_do_pps_send(struct lws *wsi) #endif if (lws_is_ssl(lws_get_network_wsi(wsi))) break; + + if (wsi->vhost->options & + LWS_SERVER_OPTION_H2_PRIOR_KNOWLEDGE) + break; + /* * we need to treat the headers from the upgrade as the * first job. So these need to get shifted to sid 1. diff --git a/lib/roles/http/client/client-http.c b/lib/roles/http/client/client-http.c index 2fae41179..8e1b6a3a9 100644 --- a/lib/roles/http/client/client-http.c +++ b/lib/roles/http/client/client-http.c @@ -232,8 +232,13 @@ start_ws_handshake: cce = ebuf; goto bail3; } - } else + } else { wsi->tls.ssl = NULL; + if(wsi->flags & LCCSCF_H2_PRIOR_KNOWLEDGE) { + lwsl_info("h2 prior knowledge\n"); + lws_role_call_alpn_negotiated(wsi, "h2"); + } + } #endif #if defined(LWS_WITH_DETAILED_LATENCY) if (context->detailed_latency_cb) { @@ -248,14 +253,18 @@ start_ws_handshake: #if defined (LWS_WITH_HTTP2) if (wsi->client_h2_alpn) { /* - * We connected to the server and set up tls, and - * negotiated "h2". + * We connected to the server and set up tls and + * negotiated "h2" or connected as clear text + * with http/2 prior knowledge. * * So this is it, we are an h2 master client connection * now, not an h1 client connection. */ + #if defined(LWS_WITH_TLS) - lws_tls_server_conn_alpn(wsi); + if (wsi->tls.use_ssl & LCCSCF_USE_SSL) { + lws_tls_server_conn_alpn(wsi); + } #endif /* send the H2 preface to legitimize the connection */ diff --git a/minimal-examples/http-client/minimal-http-client/minimal-http-client.c b/minimal-examples/http-client/minimal-http-client/minimal-http-client.c index fffe8882a..f75d30422 100644 --- a/minimal-examples/http-client/minimal-http-client/minimal-http-client.c +++ b/minimal-examples/http-client/minimal-http-client/minimal-http-client.c @@ -204,6 +204,9 @@ system_notify_cb(lws_state_manager_t *mgr, lws_state_notify_link_t *link, if (lws_cmdline_option(a->argc, a->argv, "--h1")) i.alpn = "http/1.1"; + if (lws_cmdline_option(a->argc, a->argv, "--h2-prior-knowledge")) + i.ssl_connection |= LCCSCF_H2_PRIOR_KNOWLEDGE; + if ((p = lws_cmdline_option(a->argc, a->argv, "-p"))) i.port = atoi(p); diff --git a/minimal-examples/http-server/minimal-http-server/minimal-http-server.c b/minimal-examples/http-server/minimal-http-server/minimal-http-server.c index 1cd262276..7bd74e2ba 100644 --- a/minimal-examples/http-server/minimal-http-server/minimal-http-server.c +++ b/minimal-examples/http-server/minimal-http-server/minimal-http-server.c @@ -72,6 +72,9 @@ int main(int argc, const char **argv) info.options = LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE; + if (lws_cmdline_option(argc, argv, "--h2-prior-knowledge")) + info.options |= LWS_SERVER_OPTION_H2_PRIOR_KNOWLEDGE; + context = lws_create_context(&info); if (!context) { lwsl_err("lws init failed\n");