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...
I mean the same applies if an HTTP/1 response is a 505, right..? If the intent is to completely unsupport an HTTP version then the appropriate response is none at all. But I don't think that's what 505 is for, or at least that's not its main purpose (it can be a way to slowly remove HTTP/1 for whatever reason while not leaving users in the dark). All a 505 is is a signal to the client that it will not produce a response for the requested HTTP version other than for this 505. And indeed that's what the spec says:
The 505 (HTTP Version Not Supported) status code indicates that the server does not support, or refuses to support, the major version of HTTP that was used in the request message. The server is indicating that it is unable or unwilling to complete the request using the same major version as the client, as described in Section 2.5, other than with this error message. The server SHOULD generate a representation for the 505 response that describes why that version is not supported and what other protocols are supported by that server.
I think my (questionable usecase) example link fits within the "unwilling" and "other than" parts, and the requested path (which is / in my example) is a part of the "request message".
I can also think of a reasonably valid reason why a server would choose to 505 in a HTTP/2 response instead of not offering support at all. Perhaps one is using a third-party nginx module that doesn't support HTTP/2 (though why one would still use it in 2024 is a good question), and the webmaster is trying to find a way to disable HTTP/2 just for a specific location where that module is used. It's not actually possible without putting it in another server block with a different hostname (or in older versions of nginx, listening to another IP address!). The only other workaround right now is to put the location behind a proxy where you can force HTTP/1; that way the whole site can still use HTTP/2 and the user wouldn't even notice it in devtools. But tbh even if it does result in a nice and transparent HTTP/2 for the user, it still would be simpler if nginx just returned a 505 for HTTP/2 requests and the client automatically retried the request in HTTP/1.
I just wish the HTTP/2 and HTTP/3 spec writers found the time to write another MAY or SHOULD for 505 to make it a hint for the client to downgrade its HTTP version... Or even add a new header like Version-Allow as in the Allow header required by a 405 to indicate in a machine-readable format of what major HTTP versions it supports (instead of just putting it in the body which is ultimately not required)
Btw if you try to set the HTTP version to something absurd like 1.6, the server will still return 200 OK. I really read the spec. ;) 505 is only meant for major versions, and the HTTP version that appears in the server's response can also signal the maximum HTTP minor version it can support (so if you sent a HTTP/1.0 request and the server responds with HTTP/1.1 before the status code, it's telling you that it can support HTTP/1.1, and vice versa)! HTTP/1 is really ahead of its time
Tbf on you the Active sorting wasn't available in the old version of Postmill that jstpst was stuck with for years. It only became available after the migration off of Heroku and the subsequent Postmill upgrade
Finally, another 100 days finished! Only took 10 months... :P
Maybe I should do a different daily (partly because it's hard to track which images I've already posted here lol)... Perhaps Takane next? Or a daily of Nitori theme arranges I've found on the internet. Or both! ;)
Ah I see, thanks. In nginx I always use return instead of rewrite (which seems to be the closest to Caddy's redir) so I have to always specify the http response code.
but it won't take effect until I restart it.
Does Caddy not have a reload command like nginx does where you don't have to restart the server to apply the config changes?
nitori OP wrote (edited )
Reply to comment by emma in Why are browsers not automatically downgrading to HTTP/1 when they encounter a 505 in HTTP/2 or HTTP/3 by nitori
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:
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..
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.
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
orcurl --http2-prior-knowledge
against a server that only supports HTTP/1An 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.
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...