Opened 6 years ago

Closed 6 years ago

Last modified 6 years ago

#1551 closed defect (invalid)

nginx returns 400 beacuse of missing host header when receiving HTTP2 :authory pseudo field

Reported by: https://stackoverflow.com/users/795910/ottavio-campana Owned by:
Priority: minor Milestone:
Component: other Version: 1.13.x
Keywords: Cc:
uname -a: Linux beaglebone 4.9.78-ti-r94 #1 SMP PREEMPT Fri Jan 26 21:26:24 UTC 2018 armv7l GNU/Linux
nginx -V: nginx version: nginx/1.13.12
built with OpenSSL 1.1.0f 25 May 2017
TLS SNI support enabled
configure arguments: --with-cc-opt='-g -O2 -fdebug-prefix-map=/root/nginx=. -fstack-protector-strong -Wformat -Werror=format-security -fPIC -Wdate-time -D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-z,relro -Wl,-z,now -fPIC' --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --modules-path=/usr/lib/nginx/modules --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-debug --with-pcre-jit --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_v2_module --with-http_dav_module --with-http_slice_module --with-threads --with-http_addition_module --with-http_flv_module --with-http_geoip_module=dynamic --with-http_gunzip_module --with-http_gzip_static_module --with-http_image_filter_module=dynamic --with-http_mp4_module --with-http_perl_module=dynamic --with-http_random_index_module --with-http_secure_link_module --with-http_sub_module --with-http_xslt_module=dynamic --with-mail=dynamic --with-mail_ssl_module --with-stream=dynamic --with-stream_ssl_module --with-stream_ssl_preread_module --add-dynamic-module=/root/nginx/debian/modules/http-headers-more-filter --add-dynamic-module=/root/nginx/debian/modules/http-auth-pam --add-dynamic-module=/root/nginx/debian/modules/http-auth-digest --add-dynamic-module=/root/nginx/debian/modules/http-cache-purge --add-dynamic-module=/root/nginx/debian/modules/http-dav-ext --add-dynamic-module=/root/nginx/debian/modules/http-ndk --add-dynamic-module=/root/nginx/debian/modules/http-echo --add-dynamic-module=/root/nginx/debian/modules/http-fancyindex --add-dynamic-module=/root/nginx/debian/modules/nchan --add-dynamic-module=/root/nginx/debian/modules/http-lua --add-dynamic-module=/root/nginx/debian/modules/rtmp --add-dynamic-module=/root/nginx/debian/modules/http-uploadprogress --add-dynamic-module=/root/nginx/debian/modules/http-upstream-fair --add-dynamic-module=/root/nginx/debian/modules/http-subs-filter

Description

I have a client that connects to the webserver. After sending the magic to upgrade to HTTP2, I have an exchange of settings and one request is POSTed to the server.

Nignx returns 400 and by checking in the error file; I find this

client sent invalid host header while reading client request headers, client: 127.0.0.1, server: localhost, host: ""

It's true, the Host: header is missing. But this is no longer an HTTP/1.1 session, it is an upgraded HTTP/2 connection now. The client sends in the SETTINGS packet the :authority pseudo-field.

In section §8.1.2.3 of https://tools.ietf.org/html/rfc7540 it is written

Clients that generate HTTP/2 requests directly SHOULD use the ":authority" pseudo-header field instead of the Host header field.

Therefore I think that in this case Nginx should:

  • check that :authority is present
  • recognize as valid the empty :authory pseudo-field according to RFC3986
  • not give an error because the Host: header is missing.

Attachments (1)

1551.pcap (175.0 KB ) - added by https://stackoverflow.com/users/795910/ottavio-campana 6 years ago.

Download all attachments as: .zip

Change History (6)

by https://stackoverflow.com/users/795910/ottavio-campana, 6 years ago

Attachment: 1551.pcap added

comment:1 by Maxim Dounin, 6 years ago

Resolution: invalid
Status: newclosed

For missing header, nginx will log that client sent HTTP/1.1 request without "Host" header instead. The error quoted is about _invalid_ host header, not missing one. The message itself prefers the HTTP/1.1 name as it is more generic one, yet it is actually used for both Host and :authority.

Both Host and :authority headers cannot be empty. In particular, the :authority header is defined as follows:

   o  The ":authority" pseudo-header field includes the authority
      portion of the target URI ([RFC3986], Section 3.2).  The authority
      MUST NOT include the deprecated "userinfo" subcomponent for "http"
      or "https" schemed URIs.

In RFC 3986 the authority portion is defined as:

      authority   = [ userinfo "@" ] host [ ":" port ]
      host        = IP-literal / IPv4address / reg-name
      reg-name    = *( unreserved / pct-encoded / sub-delims )

The reg-name can be empty only if specifically premitted by the URI scheme:

   If the URI scheme defines a default for host, then that default
   applies when the host subcomponent is undefined or when the
   registered name is empty (zero length).  For example, the "file" URI
   scheme is defined so that no authority, an empty host, and
   "localhost" all mean the end-user's machine, whereas the "http"
   scheme considers a missing authority or empty host invalid.

As explicitly stated in the above quote from RFC 3986, the "http" scheme does not permit empty reg-name. Normative text is in RFC 7230:

   A sender MUST NOT generate an "http" URI with an empty host
   identifier.  A recipient that processes such a URI reference MUST
   reject it as invalid.

Summing the above: if your client uses an empty :authority header, you have to fix your client.

comment:2 by https://stackoverflow.com/users/795910/ottavio-campana, 6 years ago

Excuse me if I am pedantic, but I am not 100% sure that your explaination is correct.

RFP3986 states:

whereas the "http" scheme considers a missing authority or empty host invalid.

For my understanding, this sentence covers two cases:

  • the case of HTTP/1.1, where empty Host: is invalid
  • the case of HTTP/2, where the missing :authority is invalid

But, a missing :authority field is different from a present-but-empty pseudo-field.

Furthermore, RFC7230 is about HTTP/1.1, not about HTTP/2. The client I am using supports only HTTP/2, it will never send an HTTP/1.1 request.

So, I follow your explanation, I agree on most of it, but I think that you are not interpreting correctly missing :authority as empty :authority . I see no support in the RFCs you quoted about the equivalence missing == empty.

comment:3 by https://stackoverflow.com/users/795910/ottavio-campana, 6 years ago

Resolution: invalid
Status: closedreopened

comment:4 by Maxim Dounin, 6 years ago

Resolution: invalid
Status: reopenedclosed

RFC 3986 talks about syntax components authority and host, not about headers or pseudo headers. And the wording is pretty clear.

Moreover, RFC 7540, which is about HTTP/2, is pretty clear that RFC 7230 is what defines "http" and "https" URI schemes for both HTTP/1.x and HTTP/2.

   Selected portions of HTTP/1.1 Message Syntax
   and Routing [RFC7230], such as the HTTP and HTTPS URI schemes, are
   also applicable in HTTP/2, but the expression of those semantics for
   this protocol are defined in the sections below.

If you are still not 100% sure, I can't help, sorry.

comment:5 by https://stackoverflow.com/users/795910/ottavio-campana, 6 years ago

Ok, thank you for your feedback.

It's correct to close the bug as invalid.

Note: See TracTickets for help on using tickets.