Closed ChiefInnovator closed 4 years ago
You're getting that error in a browser? That's a client limitation, not a server issue.
Most clients require https (TLS+ALPN) to negotiate Http/2, that's right in the spec. When you tell the server to do Http/2 without Https that's an alternative mode called "prior knowledge", which most clients (and servers) don't support. You would have to set a similar setting on the client for it to work because there's no way to negotiate the version without ALPN.
Your suggestion is that this is a browser issue which I understand why you would say that. So I coded up a sample using the new HttpClient with Http/2 support (see below). So using the new HttpClient and setting the version to Http/2 still fails with an unsecure url. I am using the latest .NET Core 3.x. Unfortunately it still fails.
var httpClient = new HttpClient();
var req = new HttpRequestMessage(HttpMethod.Get, url)
{
Version = HttpVersion.Version20,
};
var resp = await httpClient.SendAsync(req);
Console.WriteLine($"Version: {resp.Version}");
I just tested my client code against a known endpoint that supports HTTP/2 with unsecure URLs. It works fine. So this does not seem to be a client issue, but a server side issue with ASP.NET Core.
var client = new HttpClient();
var req = new HttpRequestMessage(HttpMethod.Get, "http://http2.akamai.com/demo"){ Version = new Version(2, 0) };
var x = await client.SendAsync(req); var version = x.Version;
Console.WriteLine(version);
I figured out a workaround.
Note HttpClient treats HttpRequestMessage.Version as a maximum version, not an exact version. See https://github.com/dotnet/runtime/issues/987
HttpClient currently requires an AppContext switch in order to support HTTP/2 without https. https://github.com/dotnet/aspnetcore/blob/fae3dd12aeba7c9995f69bfaa1c9b74d82307ef1/src/Servers/Kestrel/test/Interop.FunctionalTests/HttpClientHttp2InteropTests.cs#L32-L33
http://http2.akamai.com/demo redirects to https://http2.akamai.com/demo in order to support HTTP/2.
Tratcher, Thanks for all the help. I figured out that Akamai was redirecting. Ugh! My bad. 👍
Also, thanks for the update for the client support.
Requests fail with unsecure URLs (http://) and HTTP/2
We are trying to host both gRPC services and MapGet [or WebApi] endpoints. Interestingly, the gRPC template does exactly this. When you use the sample out-of-the-box, it works. But when we change to use an unsecure applicationUrl in launchSettings MapGet [or WebApi] stops working. The MapGet("/") fails with an unsecure URL (ex. http://localhost:5000). This does not make sense. It worked fine over https://localhost:5001 just fine. The only difference is TLS.
NOTE: We are using unsecure services due to these services being hosted in a private vnet and us doing TLS offloading. This is also happening in Kubernetes inside of containers.
Scenario #1 - Secure URL (https://localhost:5001), Http2 Protocol MapGet Succeeds, gRPC Succeeds
Scenario #2 - Unsecure URL (http://localhost:5000), Http2 Protocol MapGet Fails, gRPC Succeeds
What operating system (Linux, Windows,...) and version?
Windows 10
What did you do?
Start with ASP.NET Core gRPC template.
dotnet new grpc -o HelloGrpc
Change launchSettings to unsecure URL breaks MapGet
Kestrel is using HTTP/2 "Kestrel": {
What did you expect to see? MapGet should just work when using an insecure URL and protocol Http2.
What did you see instead? MapGet fails with with ERR_INVALID_HTTP_RESPONSE. Changing the URL back to https://localhost:5001 fixes the issue. Unfortunately we definitely need unsecure URLs.
To Reproduce
I create a sample project that shows the issue ... https://github.com/ChiefInnovator/repro_http2_http_issue
It is currently setup to fail by using the launchSettings: applicationUrl of "http://localhost:5000" to demonstrate the issue. If you change the URL to "https://localhost:5001", it works fine.
Further technical details