Q: http2 and http1 virtual hosts both works via HTTP/2 - bug of feature?

Andrey Kulikov amdeich at gmail.com
Tue May 23 22:07:00 UTC 2023


Hello,

Observed nginx's version 1.22.1 questionable behaviour with two virtual
hosts, one with H2 - enabled, second without http2 support.
Both on the same IP and port, with different domain names/server names.
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.

Sample config snippet:

http {
...
    server {
        listen          1985 http2 ssl;
        server_name     'mavr.cp.eu';

        ssl_certificate     domain.cer;
        ssl_certificate_key domain.key;

        location / {
            return 302 https://zavr.cp.eu:1985$request_uri;
        }
    }

    server {
        listen          1985 ssl; # NO h2!
        server_name     'zavr.cp.eu';

        ssl_certificate     domain.cer;
        ssl_certificate_key domain.key;

        location / {
            # Doesn't really matter what's here, for simplicity I've used
ngx_lua_module.
            echo "Server protocol: $server_protocol H2 connection: $http2
.";
        }
    }
...
}

When I type https://mavr.cp.eu:1985 in browser I see:

1. Browser negotiates h2 ALPN with the server with SNI mavr.cp.eu ;
2. Server replied with 302 redirect to https://zavr.cp.eu:1985 (expected)
3. Browser makes NEW TCP-connection with the server with SNI zavr.cp.eu;
(expected)
4. Server replied with h2 ALPN (unexpected)
5. Browser shows "Server protocol: HTTP/2.0 H2 connection: h2 ."

When I browsed source code, I spotted following line:
http://hg.nginx.org/nginx/file/tip/src/http/modules/ngx_http_ssl_module.c#l460

#if (NGX_HTTP_V2)
<http://hg.nginx.org/nginx/file/tip/src/http/modules/ngx_http_ssl_module.c#l459>
   if (hc->addr_conf->http2) {
<http://hg.nginx.org/nginx/file/tip/src/http/modules/ngx_http_ssl_module.c#l460>
       srv = (unsigned char *) NGX_HTTP_V2_ALPN_PROTO
NGX_HTTP_ALPN_PROTOS;
<http://hg.nginx.org/nginx/file/tip/src/http/modules/ngx_http_ssl_module.c#l461>
       srvlen = sizeof(NGX_HTTP_V2_ALPN_PROTO NGX_HTTP_ALPN_PROTOS) -
1; <http://hg.nginx.org/nginx/file/tip/src/http/modules/ngx_http_ssl_module.c#l462>
   } else <http://hg.nginx.org/nginx/file/tip/src/http/modules/ngx_http_ssl_module.c#l463>#endif


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.
Regardless of negotiated SNI.
At least I see that ngx_http_find_virtual_server() being called here:
http://hg.nginx.org/nginx/file/tip/src/http/ngx_http_request.c#l2236
on already established http(s) connection, not during TLS handshake.

This behaviour caused some pain in my neck today, so could please someone be
so kind to enlighten 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?
Is it a bug, feature, or just not needed by anyone?
Quick Googling did not reveal that anyone had complained about it too much.

If one will manage to implement a patch, correcting this behaviour, will it
be even considered to review?

--
Andrey

P.S. Under "Browser" here I meant Chrome, Chromium, and Firefox on Windows.
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.
And put a second request to the same h2 connection, despite the fact that
it was negotiated for different SNI.
Shame on them.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.nginx.org/pipermail/nginx-devel/attachments/20230524/e7b41a53/attachment.htm>


More information about the nginx-devel mailing list