From 173943a405b2d1e787199b4dcc0dd17e927893cb Mon Sep 17 00:00:00 2001 From: Andy Green Date: Sun, 12 May 2019 08:01:50 +0100 Subject: [PATCH] h2: align h1 upgrade to work same as alpn upgrade https://github.com/warmcat/libwebsockets/issues/1571 Although the code exists for non-tls h1 upgrade to h2, it hasn't been looked after since all expected uses for h2 are going to be via h2 / alpn. This patch aligns its upgrade actions with alpn upgrade path so it works OK via $ curl --http2 http://localhost:7681/ -v -w "\n" ie, without tls. Operation via tls is unaffected. To use the non-tls upgrade path, you have to be listening without tls, ie with the test server without -s. If you're listening in a way that requires tls, this can't be used to bypass that (or, eg, client certs) in itself, since you have to be able to talk to it in h1 in the first place to attempt the upgrade to h2. The common h2 path has some code to dropping the ah unconditionally it looks like after the first service... this is too aggressive since the first thing coming on the upgrade path is WINDOW_UPDATE. It looks wrong anyway, transaction / stream completion will drop the ah and should be enough. --- lib/roles/h2/ops-h2.c | 51 +++++++++++++++++++++------------- lib/roles/http/server/server.c | 13 +++++++-- 2 files changed, 41 insertions(+), 23 deletions(-) diff --git a/lib/roles/h2/ops-h2.c b/lib/roles/h2/ops-h2.c index 804176a1a..a63520d44 100644 --- a/lib/roles/h2/ops-h2.c +++ b/lib/roles/h2/ops-h2.c @@ -296,12 +296,24 @@ drain: // lws_buflist_describe(&wsi->buflist, wsi); +#if 0 + + /* + * This seems to be too aggressive... we don't want the ah stuck + * there but eg, WINDOW_UPDATE may come and detach it if we leave + * it like that... it will get detached at stream close + */ + if (wsi->http.ah #if !defined(LWS_NO_CLIENT) && !wsi->client_h2_alpn #endif - ) + ) { + lwsl_err("xxx\n"); + lws_header_table_detach(wsi, 0); + } +#endif pending = lws_ssl_pending(wsi); if (pending) { @@ -1148,34 +1160,33 @@ rops_alpn_negotiated_h2(struct lws *wsi, const char *alpn) } #endif - wsi->upgraded_to_http2 = 1; - wsi->vhost->conn_stats.h2_alpn++; + wsi->upgraded_to_http2 = 1; + wsi->vhost->conn_stats.h2_alpn++; - /* adopt the header info */ + /* adopt the header info */ - ah = wsi->http.ah; + ah = wsi->http.ah; - lws_role_transition(wsi, LWSIFR_SERVER, LRS_H2_AWAIT_PREFACE, - &role_ops_h2); + lws_role_transition(wsi, LWSIFR_SERVER, LRS_H2_AWAIT_PREFACE, + &role_ops_h2); - /* http2 union member has http union struct at start */ - wsi->http.ah = ah; + /* http2 union member has http union struct at start */ + wsi->http.ah = ah; - if (!wsi->h2.h2n) - wsi->h2.h2n = lws_zalloc(sizeof(*wsi->h2.h2n), "h2n"); - if (!wsi->h2.h2n) - return 1; + if (!wsi->h2.h2n) + wsi->h2.h2n = lws_zalloc(sizeof(*wsi->h2.h2n), "h2n"); + if (!wsi->h2.h2n) + return 1; - lws_h2_init(wsi); + lws_h2_init(wsi); - /* HTTP2 union */ + /* HTTP2 union */ - lws_hpack_dynamic_size(wsi, - wsi->h2.h2n->set.s[H2SET_HEADER_TABLE_SIZE]); - wsi->h2.tx_cr = 65535; - - lwsl_info("%s: wsi %p: configured for h2\n", __func__, wsi); + lws_hpack_dynamic_size(wsi, + wsi->h2.h2n->set.s[H2SET_HEADER_TABLE_SIZE]); + wsi->h2.tx_cr = 65535; + lwsl_info("%s: wsi %p: configured for h2\n", __func__, wsi); return 0; } diff --git a/lib/roles/http/server/server.c b/lib/roles/http/server/server.c index 434648521..6ec3c57cb 100644 --- a/lib/roles/http/server/server.c +++ b/lib/roles/http/server/server.c @@ -1812,6 +1812,7 @@ int lws_handshake_server(struct lws *wsi, unsigned char **buf, size_t len) { struct lws_context *context = lws_get_context(wsi); + struct allocated_headers *ah; unsigned char *obuf = *buf; #if defined(LWS_WITH_HTTP2) char tbuf[128], *p; @@ -2045,8 +2046,17 @@ upgrade_h2c: return 1; } + wsi->upgraded_to_http2 = 1; + /* adopt the header info */ + ah = wsi->http.ah; + lws_role_transition(wsi, LWSIFR_SERVER, LRS_H2_AWAIT_PREFACE, + &role_ops_h2); + + /* http2 union member has http union struct at start */ + wsi->http.ah = ah; + if (!wsi->h2.h2n) { wsi->h2.h2n = lws_zalloc(sizeof(*wsi->h2.h2n), "h2n"); @@ -2073,9 +2083,6 @@ upgrade_h2c: return 1; } - lwsi_set_state(wsi, LRS_H2_AWAIT_PREFACE); - wsi->upgraded_to_http2 = 1; - return 0; #endif #if defined(LWS_ROLE_WS)