Skip to content

[Feature Request] gRPC does not have HTTP protocol version negotiation in unencrypted environments #42948

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

Closed
1 task done
pars-dev opened this issue Jul 27, 2022 · 8 comments
Closed
1 task done
Labels
area-networking Includes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractions

Comments

@pars-dev
Copy link

Is there an existing issue for this?

  • I have searched the existing issues

Is your feature request related to a problem? Please describe the problem.

Imagine a few ASP.NET Core micro-services that are in a docker compose environment, these micro-services do not publish any ports but some of them are accessible from a gateway (YARP or nginx for example). All public traffics come to the gateway first (with HTTPS) and after that they will be forwarded to the correct micro-service with HTTP (unencrypted). These micro-services do not face the internet directly and in order for faster internal communications, they do not use TLS.

Now if a micro-service has only REST APIs or only gRPC APIs, it can be successfully configured. For example a micro-service that only serves gRPC APIs can be configured to listen on port 80 without TLS:

builder.WebHost.ConfigureKestrel(options =>
{
    // Setup a HTTP/2 endpoint without TLS.
    options.ListenAnyIP(80, o => o.Protocols = HttpProtocols.Http2);
});

But when a micro-service has both REST and gRPC APIs, we have a problem, because there is no HTTP version negotiation for unencrypted gRPC traffic and the following configuration

builder.WebHost.ConfigureKestrel(options =>
{
    options.ListenAnyIP(80, o => o.Protocols = HttpProtocols.Http1AndHttp2);
});

does not work because connections to the unsecured endpoint default to HTTP/1.1, and gRPC calls fail.

The solution is to use another port for gRPC:

builder.WebHost.ConfigureKestrel(options =>
{
    // For REST
    options.ListenAnyIP(80, o => o.Protocols = HttpProtocols.Http1AndHttp2);   
    // For gRPC
    options.ListenAnyIP(8080, o => o.Protocols = HttpProtocols.Http2);   
});

And then configure the clients to connect to that port.

This problem is mentioned in the Microsoft docs and there is also a related issue for it.

Describe the solution you'd like

It would be great if an ASP.NET Core server could serve unencrypted REST and gRPC APIs on the same port without any issue.

Additional context

No response

@TanayParikh TanayParikh added the area-grpc Includes: GRPC wire-up, templates label Jul 27, 2022
@davidfowl
Copy link
Member

I think to do something here we’d need to find the pattern that grpc clients typically use for this (if there’s any). Doing something that would only work for the C# client and server would be less than ideal.

@JamesNK
Copy link
Member

JamesNK commented Jul 27, 2022

gRPC clients either use TLS+ALPN for protocol negotiation or prenegotiated H2C. The problem is that prenegotiated H2C doesn't work when the server is configured for HTTP/1.1 or HTTP/2.

The linked issue mentions https://en.wikipedia.org/wiki/HTTP/1.1_Upgrade_header. No one uses this, including gRPC clients. gRPC clients all use prenegotiated H2C when TLS isn't used.

The only way to make this work is for Kestrel to look for the https://httpwg.org/specs/rfc7540.html#ConnectionHeader when starting a new connection. I'm guessing http.sys and IIS would need lower-level changes to support this behavior, which is unlikely ever to happen.

@JamesNK JamesNK added area-runtime and removed area-grpc Includes: GRPC wire-up, templates labels Jul 27, 2022
@JamesNK
Copy link
Member

JamesNK commented Jul 27, 2022

FYI, I added extra logging to detect an HTTP/2 request sent to an HTTP/1.1 connection in .NET 7 - #39402

@adityamandaleeka
Copy link
Member

adityamandaleeka commented Jul 27, 2022

Triage: Do other servers support this?

@Tratcher @blowdart Do you have any thoughts about this?

Tentatively putting this into the .NET 8 milestone, but we should think about this more before committing to doing it.

@adityamandaleeka adityamandaleeka added this to the .NET 8 Planning milestone Jul 27, 2022
@davidfowl
Copy link
Member

davidfowl commented Jul 28, 2022

Do other grpc clients support this upgrade? I guess my point is that we shouldn't (ideally) do something server side that no other clients support (the browser doesn't matter here).

@blowdart
Copy link
Contributor

No one uses this, including gRPC clients. gRPC clients all use prenegotiated H2C when TLS isn't used.

If no-one does it, we shouldn't do it.

@davidfowl
Copy link
Member

davidfowl commented Jul 30, 2022

No one uses this, including gRPC clients. gRPC clients all use prenegotiated H2C when TLS isn't used.

Agree.

The only way to make this work is for Kestrel to look for the https://httpwg.org/specs/rfc7540.html#ConnectionHeader when starting a new connection. I'm guessing http.sys and IIS would need lower-level changes to support this behavior, which is unlikely ever to happen.

This seems like a good candidate for something in AspLabs while we gauge interest. We did something similar for the proxy protocol. This will also make sure it's possible we have the hooks the make it work. This issue has an implementation?

Related: We've also had requests to support HTTP and HTTPS on the same endpoint.

@Tratcher
Copy link
Member

Tratcher commented Aug 8, 2022

https://www.rfc-editor.org/rfc/rfc9113#name-changes-from-rfc-7540

The HTTP/1.1 Upgrade mechanism is deprecated and no longer specified in this document. It was never widely deployed, with plaintext HTTP/2 users choosing to use the prior-knowledge implementation instead.

Closing.

@Tratcher Tratcher closed this as not planned Won't fix, can't repro, duplicate, stale Aug 8, 2022
@ghost ghost locked as resolved and limited conversation to collaborators Sep 8, 2022
@amcasey amcasey added area-networking Includes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractions and removed area-runtime labels Aug 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