Viewing a single comment thread. View all comments

emma wrote

I mean the same applies if an HTTP/1 response is a 505, right..?

no, since http/1 requests are sent preemptively without knowing if the server accepts them. http/2+ requests are sent after negotiation, at which point it's established they are accepted. this obsoletes the need for a 505.

505 would have been useful for a future where http/2 requests might be preemptively sent to http/1-only servers. if i send GET / HTTP/2.0 (or any non-1.x version) to nginx, it indeed responds with that status code. but as things turned out, the negotiation mechanism in http/2+ just sidesteps this problem altogether, so 505 ends up being little more than a relic from a time when people didn't know what the future of http held.

since you very much have to opt in for http/2+, incompatibilities with it can be resolved by just not enabling it, and the use cases where one would want partial http/2 support on any given host are extremely contrived, i would argue it's a good thing that support for it is declared on the connection level. it's one less special case for clients to deal with.

3

nitori OP wrote (edited )

Hmm I don't think nginx is correct to send a 505 in that case. I actually thought as well before that it was correct, but rereading the spec, you're supposed to send a 505 in the representation used by the major version requested by the client. But nginx does it in 1.1's representation instead of 2.0:

GET / HTTP/2.0

HTTP/1.1 505 HTTP Version Not Supported
Server: nginx
[...]

A more appropriate response might be 400 or 500, since HTTP/2 obviously isn't plain text, and the client is trying to do a HTTP/2 request in HTTP/1 format which is wrong.

Having said that..

http/2+ requests are sent after negotiation, at which point it's established they are accepted. this obsoletes the need for a 505.

An HTTP/2 request can be sent without negotiation; this is how h2c (HTTP/2 over cleartext) reliably works for me (for some reason I couldn't get Upgrade from http/1.1 to h2c working). It's called "prior knowledge", and curl supports this.

Even if negotiation becomes strictly required (which Google and Mozilla wanted by requiring TLS) in all of HTTP/2, I don't think 505 is obsolete. If for some reason you want to sunset HTTP/2 and have users use HTTP/5+, while not leaving those still stuck with HTTP/2 in the dark, how would you signal to them that you refuse to support HTTP/2? A 505 would be able to fulfill that role, and indeed this is one of its intended purposes when it was first proposed.

505 would have been useful for a future where http/2 requests might be preemptively sent to http/1-only servers.

No, 505 wouldn't be useful because an HTTP/2 request to an HTTP/1-only server would only result in the client just closing the connection itself. You can see this by using nghttp or curl --http2-prior-knowledge against a server that only supports HTTP/1

An HTTP/2-only client (which those two commands earlier are) would not bother to process an HTTP/1 response (if it even gets one) whether that'd be a 505 or 200.

since you very much have to opt in for http/2+, incompatibilities with it can be resolved by just not enabling it, and the use cases where one would want partial http/2 support on any given host are extremely contrived

Heh, perhaps. :D Maybe in an earlier time where a webmaster really wants (or needs, because maybe some impatient stockholder is forcing their client to deploy h2 even if they're not fully ready) the benefits of HTTP/2 (multiplexing is pretty cool after all) as soon as possible but have parts of their website not yet ready for the new version, this could've been pretty relevant...

2

emma wrote (edited )

but rereading the spec, you're supposed to send a 505 in the representation used by the major version requested by the client

GET / HTTP/2.0 is parsed with http/1 semantics, so i think it makes sense to give any >= 2.x version the HTTP/1.1 505 treatment.

An HTTP/2 request can be sent without negotiation; this is how h2c (HTTP/2 over cleartext) reliably works for me (for some reason I couldn't get Upgrade from http/1.1 to h2c working). It's called "prior knowledge", and curl supports this.

yeah, but as the name implies, you somehow know in advance that the server's gonna accept HTTP/2 if you send those. i suppose 505 here would make sense, if the HTTP/2 support was ever removed. as i understand it, this mode is never going to happen under normal browsing, though.

No, 505 wouldn't be useful because an HTTP/2 request to an HTTP/1-only server would only result in the client just closing the connection itself. You can see this by using nghttp or curl --http2-prior-knowledge against a server that only supports HTTP/1

An HTTP/2-only client (which those two commands earlier are) would not bother to process an HTTP/1 response (if it even gets one) whether that'd be a 505 or 200.

i meant a hypothetical http/2 that's more http/1-like, not the actual http/2 that came into existence which made it very hard to accidentally use the wrong protocol.

anyway, the solution to your woes is apparently to send an error packet or whatever:

HTTP_1_1_REQUIRED (0x0d):
The endpoint requires that HTTP/1.1 be used instead of HTTP/2.

it sounds like it does what you want, but i have no idea if this applies on the stream or the connection level or what.

3

nitori OP wrote (edited )

as i understand it, this mode is never going to happen under normal browsing, though.

I don't think any of my scenarios are normal at all lol :P

HTTP_1_1_REQUIRED (0x0d)

I definitely did not know about this until now, thanks! And searching online it seems like curl does retry its request in HTTP/1.1 if it encounters this. Personally I think it still would've made more sense for the HTTP/2 authors to extend 505 instead, especially since they kept the 1.1 response codes from 2xx-5xx (except 426) anyway, and you can explain to the user why you can't support HTTP/2 for the request in a 505's body... But glad to know there's an error code that can signal to the client to downgrade

3