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

Reconsider enabling HTTP/3 by default in .NET 8 #50131

Closed
adityamandaleeka opened this issue Aug 17, 2023 · 13 comments
Closed

Reconsider enabling HTTP/3 by default in .NET 8 #50131

adityamandaleeka opened this issue Aug 17, 2023 · 13 comments
Labels
area-networking Includes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractions
Milestone

Comments

@adityamandaleeka
Copy link
Member

We've had HTTP/3 enabled by default in Kestrel since .NET 8 Preview 1. As we are about to wrap up .NET 8 we need to decide whether to ship with that left as-is, or go back to having HTTP/3 support being opt-in.

Reasons to reconsider the default

  • On Windows, launching an ASP.NET Core app for the first time with HTTP/3 causes a Defender warning to appear, asking you to confirm if the app should be allowed to communicate on Domain/Private/Public networks. This is added friction that we didn't have before, and is especially annoying if you work with multiple apps (you'll get a pop up for each one).
    image

We believe this occurs because of the way msquic (which .NET's QUIC support is built upon) has to create its listener. It has to grab a wildcard listener up front because of how it supports multiplexing multiple apps on the same UDP port.

  • Getting HTTP/3 actually working locally with a browser takes a few extra steps. Browsers don't allow self-signed certificates on HTTP/3, so there's some effort required to get the end-to-end working anyway, and having to explicitly enable HTTP/3 on the server side isn't a huge added cost.

Options

  1. Do nothing; HTTP/3 will be enabled by default in .NET 8.
    • Developers on Windows will get the above Defender pop-ups the first time they launch a specific app (subsequent launches of the same application will not trigger the pop-up unless it is renamed).
  2. Disable HTTP/3 by default only in Development mode (leave it enabled by default in other modes). Developers who want it will be able to easily enable it.
    • The downside of this is that things will run differently by default during development than how they run in production.
  3. Disable HTTP/3 by default in all modes. Developers who want it will be able to easily enable it.
    • Keep the status quo in .NET 8. People who do nothing to opt into HTTP/3 will continue to get HTTP/1 and /2 by default.
@adityamandaleeka
Copy link
Member Author

I've chatted with a few folks on the team and we're currently leaning towards 3. 2 seemed like a good compromise, but we worry about the consequences of having the default protocol be different between development and production.

@adityamandaleeka adityamandaleeka added area-networking Includes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractions and removed area-runtime labels Aug 17, 2023
@adityamandaleeka
Copy link
Member Author

cc @amcasey @DamianEdwards @JamesNK

@adityamandaleeka adityamandaleeka added this to the 8.0-rc1 milestone Aug 17, 2023
@davidfowl
Copy link
Member

Agree, lets turn it off by default 😄 .

@DamianEdwards
Copy link
Member

Agreed, disable it by default.

@danmoseley
Copy link
Member

@richlander you were just now asking about this but with container size motivation.

@mitchdenny
Copy link
Member

My 2c is that I think we have some level of obligation as the .NET web app dev platfrom to advocate for protocol advancement. That doesn't necessarily mean we have to enable HTTP/3 this time but I do think we need to work with the Defender team so that Windows better handles HTTP/3 endpoints for development and with Chrome/Edge to make sure that the developer experience for inner loop development on HTTP/3 is improved moving forward.

@adityamandaleeka
Copy link
Member Author

Absolutely @mitchdenny. I've kicked off that conversation with the Windows team and we should continue to advocate for the best experience possible here. I'm hopeful that in a future release we'll be able to go HTTP/3 by default without the drawbacks I mentioned above.

@richlander
Copy link
Member

richlander commented Aug 17, 2023

Container tracking issue: dotnet/dotnet-docker#4385 (comment)

Needless to say, if HTTP/3 is disabled by default, we won't seek to add it to any container images. We should also have a discussion with the the msquic team. The size of libmsquic is prohibitive.

@adityamandaleeka
Copy link
Member Author

adityamandaleeka commented Aug 21, 2023

I've opened a PR for this in the RC1 branch since it's not clear to me whether we want to make this change in main for now. I'm open to feedback/thoughts about that.

@adityamandaleeka
Copy link
Member Author

Note: we'll need to update docs as well when this change goes in.

@halter73
Copy link
Member

work with the Defender team so that Windows better handles HTTP/3 endpoints for development

Defender is doing the right thing though, right? If msquic is opening up non-loopback listen sockets at the application layer, it should trigger the firewall. Or is the non-loopback socket really owned by the kernel somehow?

We believe this occurs because of the way msquic (which .NET's QUIC support is built upon) has to create its listener. It has to grab a wildcard listener up front because of how it supports multiplexing multiple apps on the same UDP port.

Does msquic really have to create a wildcard listener up front? Couldn't it bind to only loopback at first if that's all the application needs to listen to, and then "any" IP at a later point only if another application/binding on the same port requires it? For example, if you do:

kestrelServerOptions.ListenLocalhost(5000);

It won't listen for external connections, but if you also do:

kestrelServerOptions.ListenAnyIP(5000);

in another process and start it afterwards while keeping the ListenLocalhost(5000) process still running, both loopback and external connections will work. Loopback connections will go to the first process, and external connections go the second process. The ListenLocalhost is unnecessary, but it still works. I know my examples are using TCP rather than UDP sockets, but does that really make a difference here?

I could see how it could be a pain to deal with multiple bindings for internal and external connections when a single binding should be sufficient, but I don't see what prevents it. It seems worthwhile if it helps avoid legitimate Windows Defender warnings.

@nibanks

@nibanks
Copy link

nibanks commented Aug 21, 2023

I could see how it could be a pain to deal with multiple bindings for internal and external connections when a single binding should be sufficient, but I don't see what prevents it. It seems worthwhile if it helps avoid legitimate Windows Defender warnings.

You are right that theoretically it can be done, but it is very complicated to manage different sockets with dynamically changing requirements from possibly independent applications layers. We'd likely have to support a combination of separate, but related sockets, "upgrading" a socket, and "downgrading" a socket based on different scenario. I'm not convinced the extra complexity and regression risk is worth not getting a popup for localhost only (test?) app.

@adityamandaleeka
Copy link
Member Author

Closing this issue; we went back to having HTTP/3 be opt-in for .NET 8 (in #50243). We should re-evaluate this in the future if we (together with Windows and browsers) can make the experience better.

@ghost ghost locked as resolved and limited conversation to collaborators Oct 25, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-networking Includes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractions
Projects
None yet
Development

No branches or pull requests

8 participants