Opened 2 years ago

Closed 2 years ago

#1549 closed defect (fixed)

HTTP2 push does not work due to incorrect scheme in proxy_protocol mode

Reported by: Roel van Duijnhoven Owned by: Ruslan Ermilov <ru@…>
Priority: minor Milestone:
Component: other Version:
Keywords: http2 push Cc:
uname -a: Linux haproxy-machine 3.10.0-693.21.1.el7.x86_64 #1 SMP Wed Mar 7 19:03:37 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
nginx -V: nginx version: nginx/1.14.0
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-16) (GCC)
built with OpenSSL 1.0.2k-fips 26 Jan 2017
TLS SNI support enabled
configure arguments: --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib64/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -fPIC' --with-ld-opt='-Wl,-z,relro -Wl,-z,now -pie'

Description

I use the proxy_protocol because I send the tcp traffic via HaProxy to nginX. However HTTP2 push does not work with this set-up.

When I debug the difference between non-proxy and proxy mode using nghttp I get the following difference:

https://i.stack.imgur.com/OEU3H.png

The resource *is* pushed, but has the wrong scheme.

Sample of configuration used:

    http {
        # This is the one I would like to use
        server {
            listen       8002 http2 proxy_protocol;

            server_name  _;
            root         /usr/share/nginx/html;

            location / {
                http2_push /image.jpg;
            }
        }

        # This one can be accessed directly; and *does* work
        server {
            listen       8004 http2 ssl;

            ssl_certificate certificate.pem;
            ssl_certificate_key private.key;

            server_name  _;
            root         /usr/share/nginx/html;

            location / {
                http2_push /image.jpg;
            }
        }
    }

I could not find a way to overwrite the scheme in nginX in a way that would solve this issue.

I first placed this issue on StackOverflow. That can be found here: https://stackoverflow.com/questions/50022621/using-http2-push-with-nginx-in-conjunction-with-haproxy-does-not-work

Thanks!

Attachments (2)

patch (1.0 KB ) - added by Ruslan Ermilov 2 years ago.
https.patch (709 bytes ) - added by Roel van Duijnhoven 2 years ago.
Patch that sets https scheme correctly when using proxy protocol

Download all attachments as: .zip

Change History (10)

by Ruslan Ermilov, 2 years ago

Attachment: patch added

comment:1 by Ruslan Ermilov, 2 years ago

Please try the attached patch.

comment:2 by Roel van Duijnhoven, 2 years ago

I can verify that this fixes the problem! Thank you very much :).


On a related note: there is also the problem that the $scheme variable is incorrect when using proxy_protocol. So I quickly verified if this patch also mitigates that situation: that is however not the case.

I tested that by adding:

add_header X-scheme $scheme;

The $scheme variable is http; although the incoming request is definitely https.


Ps: I had some trouble getting a clean Vagrant CentOs/7 working using https://docs.nginx.com/nginx/admin-guide/installing-nginx/installing-nginx-open-source. Would it be worth creating an issue for this as well (with steps taken to make it work)? But finally got it working :).


Thanks again for your work!

by Roel van Duijnhoven, 2 years ago

Attachment: https.patch added

Patch that sets https scheme correctly when using proxy protocol

comment:3 by Roel van Duijnhoven, 2 years ago

An update.

I did an attempt to update the source code myself. And after compiling found it to work! It now correctly reports the HTTPS scheme only when the actual request has that set as its scheme.

You can find the patch attached!

Note: I am a mere n00b to the nginx code-base. So please review before merging.

comment:4 by Ruslan Ermilov, 2 years ago

See also #711.

in reply to:  3 ; comment:5 by Ruslan Ermilov, 2 years ago

Replying to roelvanduijnhoven@…:

An update.

I did an attempt to update the source code myself. And after compiling found it to work! It now correctly reports the HTTPS scheme only when the actual request has that set as its scheme.

You can find the patch attached!

Note: I am a mere n00b to the nginx code-base. So please review before merging.

While in HTTP/2 the scheme is required, in HTTP/1 it is generally not present (https://tools.ietf.org/html/rfc7230#section-5.3.1) so your patch won't work for HTTP/1.

The original request scheme can be obtained either from the X-Forwarded-Proto header, or derived from the PROXY protocol v2 PP2_TYPE_SSL TLV, but nginx currently lacks support of the latter.

We've also discussed about adding support for XFP and PP2_TYPE_SSL to the realip module with the effect that the $scheme and $https variables will match the original request.

comment:6 by Roel van Duijnhoven, 2 years ago

.. duplicate content

Last edited 2 years ago by Roel van Duijnhoven (previous) (diff)

in reply to:  5 comment:7 by Roel van Duijnhoven, 2 years ago

@ru It is hard for me to contribute in this discussion in a meaningful way. But I think the use case I describe is not _that_ special. I'll drop some thoughts in the other issue.
Regarding the original issue: you can fix that issue with the patch you gave earlier. I verified that it worked!

Replying to ru:

Replying to roelvanduijnhoven@…:

An update.

I did an attempt to update the source code myself. And after compiling found it to work! It now correctly reports the HTTPS scheme only when the actual request has that set as its scheme.

You can find the patch attached!

Note: I am a mere n00b to the nginx code-base. So please review before merging.

While in HTTP/2 the scheme is required, in HTTP/1 it is generally not present (https://tools.ietf.org/html/rfc7230#section-5.3.1) so your patch won't work for HTTP/1.

The original request scheme can be obtained either from the X-Forwarded-Proto header, or derived from the PROXY protocol v2 PP2_TYPE_SSL TLV, but nginx currently lacks support of the latter.

We've also discussed about adding support for XFP and PP2_TYPE_SSL to the realip module with the effect that the $scheme and $https variables will match the original request.

comment:8 by Ruslan Ermilov <ru@…>, 2 years ago

Owner: set to Ruslan Ermilov <ru@…>
Resolution: fixed
Status: newclosed

In 7296:8e6bb4e6045f/nginx:

HTTP/2: use scheme from original request for pushes (closes #1549).

Instead of the connection scheme, use scheme from the original request.
This fixes pushes when SSL is terminated by a proxy server in front of
nginx.

Note: See TracTickets for help on using tickets.