Opened 8 years ago

Closed 8 years ago

Last modified 10 months ago

#808 closed defect

Defining http2 without ssl leads to HTTP/1.1 client failure

Reported by: LPardue@… Owned by:
Priority: minor Milestone:
Component: nginx-core Version: 1.9.x
Keywords: http2 Cc:
uname -a: Linux 3.10.0-123.9.3.el7.x86_64 #1 SMP Thu Nov 6 15:06:03 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
nginx -V: nginx version: nginx/1.9.5

Description

This issue probably relates to support of HTTP/2 over cleartext (h2c). Note that I have successfully tested HTTP/2 over TLS on this server.

I have a simple server setup using an out of the box config, if I use a HTTP/1.1 client then I see what I would expect e.g:

curl -v http://localhost/index.html
* About to connect() to localhost port 80 (#0)
*   Trying ::1...
* Connection refused
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 80 (#0)
> GET /index.html HTTP/1.1
> User-Agent: curl/7.29.0
> Host: localhost
> Accept: */*
>
< HTTP/1.1 200 OK
< Server: nginx/1.9.5
< Date: Fri, 09 Oct 2015 15:53:40 GMT
< Content-Type: text/html
< Content-Length: 612
< Last-Modified: Wed, 07 Oct 2015 10:41:07 GMT
< Connection: keep-alive
< ETag: "5614f6c3-264"
< Accept-Ranges: bytes
<
<!DOCTYPE html>
...
* Connection #0 to host localhost left intact

If I add http2 to the config, e.g.

server {
  listen 80 http2;
  server_name localhost;
...

Then I see this

curl -v http://localhost/index.html

* About to connect() to localhost port 80 (#0)
*   Trying ::1...
* Connection refused
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 80 (#0)
> GET /index.html HTTP/1.1
> User-Agent: curl/7.29.0
> Host: localhost
> Accept: */*
>
* Connection #0 to host localhost left intact

Nothing is reported in the server logs.

So my questions are:

  • Is h2c supported?
    • If not, why am I allowed to attempt such a configuration without some error/warnings.
    • If so, what am I doing incorrectly? Shouldn't a HTTP/1.1 client continue to work if it offers no upgrade header or "prior knowledge" magic?

Change History (14)

comment:1 by Valentin V. Bartenev, 8 years ago

Status: newclosed

NGINX supports HTTP/2 over plain TCP using prior knowledge. See RFC RFC 7540 Section 3.4 for details.

It is useful for configurations where TLS termination is done somewhere else. In this case you should configure your load balancer to send all HTTP/2 traffic to specific port.

comment:2 by Valentin V. Bartenev, 8 years ago

If you have use cases where separation between HTTP/1.1 and HTTP/2.0 over plain TCP is useful, then we may consider to add such functionality. But at the moment HTTP/1.1 requests to h2c listen socket just look like a misconfiguration.

comment:3 by LPardue@…, 8 years ago

It is useful for configurations where TLS termination is done somewhere else. In this case you should configure your load balancer to send all HTTP/2 traffic to specific port.

Are you suggesting h2c (in its current form) is not really intended to be used directly by 'client' user agents?

If you have use cases where separation between HTTP/1.1 and HTTP/2.0 over plain TCP is useful, then we may consider to add such functionality.

I'm not sure separation is the correct word, other server implementations I have tested with are able to offer support for HTTP/1.1 and h2c on the same plain TCP port. The selection of protocol within such servers is based on the request line, either a standard one in HTTP/1.1 form (including Upgrade header, allowing negotiation without additional round trips) or the HTTP/2 connection preface.

This issue has occurred due the inconsistency between defining listen port_num http2 ssl (which supports HTTP/1.1 and h2, with the protocol being selected via ALPN) and listen port_num http2 (which only supports h2c, via prior knowledge).

But at the moment HTTP/1.1 requests to h2c listen socket just look like a misconfiguration.

I agree in principal and I can workaround my current issue by offering different protocol listening sockets on different ports. However, there is no in-band identification of the listening socket protocol and this approach is not very robust. A more robust method would be to support HTTP Upgrade, prior knowledge and HTTP/1.1 fallback. I would be happy to create a feature request for such capability.

Last edited 8 years ago by LPardue@… (previous) (diff)

comment:4 by Valentin V. Bartenev, 8 years ago

Yes, creating a feature request is the way to go. At the moment nginx can work with h2c in HTTP/2 only mode and cannot receive HTTP/1.x requests on the same port. The rationale here is that it was the easiest to implement and it worked fine with SPDY before.

Are you suggesting h2c (in its current form) is not really intended to be used directly by 'client' user agents?

I see no really good reasons for h2c in this area, and it seems browsers' developers agree. Could you name one?

comment:5 by LPardue@…, 8 years ago

I see no really good reasons for h2c in this area, and it seems browsers' developers agree. Could you name one?

Lets take curl (and libcurl) as an example. For versions that are built with HTTP/2 support the documentation states that HTTP/2 over http:// (h2c) is only currently supported via HTTP/1.1 upgrade.

Testing this with curl -v --http2 http://localhost/index.html I see the client fail as reported before.

Curl (and libcurl) can be used for a variety of client applications. Thinking more about machine-to-machine interactions, it would be nice to be able to benefit from HTTP/2 over http:// without worrying about specifying a port-to-protocol relationship out-of-band.

Last edited 8 years ago by LPardue@… (previous) (diff)

comment:6 by LPardue@…, 8 years ago

A feature request has been created under #816

comment:7 by Maxim Dounin, 7 years ago

See also #1266.

comment:8 by Maxim Dounin, 6 years ago

Keywords: http2 added

See also #1561.

comment:9 by Maxim Dounin, 5 years ago

See also #1755.

comment:10 by Maxim Dounin, 4 years ago

See also #1979.

comment:11 by Maxim Dounin, 4 years ago

See also #1981.

comment:12 by Maxim Dounin, 2 years ago

See also #2327.

comment:13 by stefankaerst.web.de@…, 2 years ago

3.2. Starting HTTP/2 for "http" URIs
https://datatracker.ietf.org/doc/html/rfc7540#section-3.2

A server that supports HTTP/2 accepts the upgrade with a 101
(Switching Protocols) response. After the empty line that terminates
the 101 response, the server can begin sending HTTP/2 frames. These
frames MUST include a response to the request that initiated the
upgrade.

HTH

Last edited 2 years ago by stefankaerst.web.de@… (previous) (diff)

comment:14 by Maxim Dounin, 10 months ago

See also #2502.

Note: See TracTickets for help on using tickets.