<div dir="ltr"><div>Hello,</div><div><br></div><div>Observed nginx's
version 1.22.1 questionable behaviour with two virtual hosts, one with H2 - enabled, second without http2 support.</div><div>Both on the same IP and port, with different domain names/server names.</div><div>When browsers make requests to a second domain, h2 being ALPN-negotiated, and data transferred via HTTP/2, in spite of http2 was not configured on that virtual host.<br></div><div></div><div><br></div><div>Sample config snippet:</div><div><br></div><div>http {</div><div>
...
</div><div> server {<br> listen 1985 http2 ssl;<br> server_name '<a href="http://mavr.cp.eu">mavr.cp.eu</a>';<br><br> ssl_certificate domain.cer;<br> ssl_certificate_key domain.key;<br><br> location / {<br> return 302 https://zavr.cp.eu:1985$request_uri;<br> }<br> }<br><br> server {<br> listen 1985 ssl; # NO h2!<br> server_name '<a href="http://zavr.cp.eu">zavr.cp.eu</a>';<br><br> ssl_certificate domain.cer;<br> ssl_certificate_key domain.key;<br><br> location / {</div><div> # Doesn't really matter what's here, for simplicity I've used ngx_lua_module.<br></div><div> echo "Server protocol: $server_protocol H2 connection: $http2 .";<br> }<br> }<br></div><div>...<br></div><div>}</div><div><br></div><div>When I type <a href="https://mavr.cp.eu:1985">https://mavr.cp.eu:1985</a> in browser I see:</div><div><br></div><div>1. Browser negotiates h2 ALPN with the server
with SNI <a href="http://mavr.cp.eu">mavr.cp.eu</a>
;</div><div>2. Server replied with 302 redirect to
<a href="https://zavr.cp.eu:1985">https://zavr.cp.eu:1985</a> (expected)<br></div><div>3. Browser makes NEW TCP-connection with the server with SNI
<a href="http://zavr.cp.eu">zavr.cp.eu</a>;
(expected)
</div><div>4. Server replied with
h2 ALPN (unexpected)<br></div><div>5. Browser shows "Server protocol: HTTP/2.0 H2 connection: h2 ."
<br>
</div><div><br></div><div>When I browsed source code, I spotted following line:<br></div><div><a href="http://hg.nginx.org/nginx/file/tip/src/http/modules/ngx_http_ssl_module.c#l460">http://hg.nginx.org/nginx/file/tip/src/http/modules/ngx_http_ssl_module.c#l460</a></div><div></div><div></div><div>
<pre class="gmail-sourcelines gmail-stripes4 gmail-wrap gmail-bottomline"><span id="gmail-l459" class="gmail-followlines-select">#if (NGX_HTTP_V2)</span><a href="http://hg.nginx.org/nginx/file/tip/src/http/modules/ngx_http_ssl_module.c#l459"></a>
<span id="gmail-l460" class="gmail-followlines-select"> if (hc->addr_conf->http2) {</span><a href="http://hg.nginx.org/nginx/file/tip/src/http/modules/ngx_http_ssl_module.c#l460"></a>
<span id="gmail-l461" class="gmail-followlines-select"> srv = (unsigned char *) NGX_HTTP_V2_ALPN_PROTO NGX_HTTP_ALPN_PROTOS;</span><a href="http://hg.nginx.org/nginx/file/tip/src/http/modules/ngx_http_ssl_module.c#l461"></a>
<span id="gmail-l462" class="gmail-followlines-select"> srvlen = sizeof(NGX_HTTP_V2_ALPN_PROTO NGX_HTTP_ALPN_PROTOS) - 1;</span><a href="http://hg.nginx.org/nginx/file/tip/src/http/modules/ngx_http_ssl_module.c#l462"></a>
<span id="gmail-l463" class="gmail-followlines-select"> } else</span><a href="http://hg.nginx.org/nginx/file/tip/src/http/modules/ngx_http_ssl_module.c#l463"></a>
<span id="gmail-l464" class="gmail-followlines-select">#endif</span></pre>
</div><div><br></div><div>My assumption (could be wrong) that it means, when http2 is enabled on the address, related to (possibly) many virtual hosts, we always add h2 ALPN.</div><div>Regardless of negotiated SNI.</div><div></div><div>At least I see that <span id="gmail-l2236" class="gmail-followlines-select">ngx_http_find_virtual_server()</span> being called here:<br></div><div><a href="http://hg.nginx.org/nginx/file/tip/src/http/ngx_http_request.c#l2236">http://hg.nginx.org/nginx/file/tip/src/http/ngx_http_request.c#l2236</a></div><div>on already established http(s) connection, not during TLS handshake.<br></div><div><br></div><div>This behaviour caused some pain in my neck today, so could please someone <span><span>be so kind to enlighten</span></span>
me, is it like it supposed to be, or is it possible to change this in the way, so http1 and http2 virtual hosts could be served on the same IP:port?</div><div>Is it a bug, feature, or just not needed by anyone?</div><div>Quick Googling did not reveal that anyone had complained about it too much.</div><div><br></div><div>If one will manage to implement a patch, correcting this behaviour, will it be even considered to review?<br></div><div>
<div><br></div><div>--</div><div>Andrey</div>
</div><div><br></div><div>P.S. Under "Browser" here I meant Chrome, Chromium, and Firefox on Windows.</div><div>
But, according to unconfirmed information, "some", yet unidentified, browsers do NOT make a second TCP-connection to another domain after redirection in the provided example.</div><div>And put a second request to the same h2 connection, despite the fact that it was negotiated for different SNI.</div><div>Shame on them.<br></div><br></div>