Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hyper server violates HTTP/1.0 compatibility (keep-alive, transfer-encoding) #1304

Closed
maghoff opened this issue Sep 4, 2017 · 2 comments
Closed
Labels
A-server Area: server. C-bug Category: bug. Something is wrong. This is bad! E-medium Effort: medium. Some knowledge of how hyper internal works would be useful.

Comments

@maghoff
Copy link

maghoff commented Sep 4, 2017

Hyper will answer an HTTP/1.0 request as if it were an HTTP/1.1 request. This includes the following violations:

  • Hyper server sets the response version to HTTP/1.1 even for HTTP/1.0 requests
  • Hyper server will enter into keep-alive mode without sending Connection: keep-alive to the client
  • Hyper server will use Transfer-Encoding: chunked regardless of client version

All of these items violate backwards compatilbility. An HTTP/1.1 server should be backwards compatible. Failing that I suggest that Hyper instead drops the connection, but I hope backwards compatibility could be achieved without too much trouble.

For keep-alive: HTTP/1.0 has support for parts of the keep-alive functionality, but for backwards compatibility it is sufficient to completely disable it when the request is of version 1.0.

For chunked transfer encoding: This is fundamentally not available in HTTP/1.0. However, streaming responses are possible by sending the body directly and terminating the TCP connection when completed. (This is a hopeless design, which is how we came to HTTP/1.1 in the first place)


Do we still need HTTP/1.0 compatibility? I stumbled onto this problem when benchmarking my server with apachebench, which only supports HTTP/1.0. Nginx also surprisingly defaults to using version 1.0 when talking to backend servers as a reverse proxy, though it can be configured to use HTTP/1.1 (and maybe even 2 these days?)


Are there workarounds? It is possible to run the server behind a reverse proxy that is correctly backwards compatible with clients, but still uses HTTP/1.1 to communicate with the backends. Nginx is an example of this. (If you configure it correctly)

@seanmonstar
Copy link
Member

Hey, thanks for filing this! It's true, hyper does ignore some things about how to deal with HTTP/1.0 peers. It would be nice to fix them.

Do we still need HTTP/1.0 compatibility?

I have wondered the same. I also haven't actually run into an HTTP/1.0 server or client myself.

Some support already exists, and it seems like a good idea to add the rest.

  • Keep-Alive: I had actually thought that this part at least was implemented correctly for 1.0 and 1.1. If a server sees a client talking 1.0, it won't assume keep-alive unless the client sent Connection: keep-alive. What part is incorrect?
  • Responding with the correct version would be a good, not too complicated, fix.
  • Checking the peer version and disabled chunked would be good too. I haven't read how 1.0 is supposed to handle messages without a length. Is it simply either Content-Length, or until EOF and thus keep-alive is disabled?

@maghoff
Copy link
Author

maghoff commented Sep 8, 2017

Thanks for getting back to me :) I'll try to clarify the rest:

  • Connection defaults to close in 1.0 and keep-alive in 1.1, so when the client requests keep-alive, the server has to include Connection: keep-alive in the response to verify support for this. (This is in contrast to 1.1, where both sides can assume keep-alive if nothing else is said) Hyper server is lacking this in the response. I haven't looked at the client, but I assume the converse error here? In any case, the correct behavior for the client is to ask for keep-alive and treat the connection mode as whatever the server responds, dependent on version:

    • The server responds with HTTP/1.0 and no Connection header: Treat the connection as non-pipelined, as if the server had said Connection: close.
    • The server responds with HTTP/1.1 (or 1.x, where x >= 1) and no Connection header: Treat the connection as pipelined, as if the server had said Connection: keep-alive.
    • If the server response includes a Connection header, regardless of HTTP version, respect this header.
  • I think you have understood correctly how to treat messages without a declared Content-Length in 1.0. Either you have Content-Length, or the body is sent and terminated by closing the connection. This means that if the server is planning on replying without a set Content-Length, it must avoid enabling Connection: keep-alive. This probably interacts with how a client would send the body in a POST or PUT request. Perhaps it is impossible to send a body without Content-Length to a 1.0 server? I'm not sure.

@seanmonstar seanmonstar added the C-bug Category: bug. Something is wrong. This is bad! label Sep 8, 2017
@seanmonstar seanmonstar added A-server Area: server. E-medium Effort: medium. Some knowledge of how hyper internal works would be useful. labels Sep 16, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-server Area: server. C-bug Category: bug. Something is wrong. This is bad! E-medium Effort: medium. Some knowledge of how hyper internal works would be useful.
Projects
None yet
Development

No branches or pull requests

2 participants