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

grpc-dotnet + Blazor sets Safari and Firefox User-Agent to "grpc-dotnet/$assemblyVersion" #29183

Closed
LukasReschke opened this issue Jan 9, 2021 · 8 comments · Fixed by grpc/grpc-dotnet#1165 or #30764
Labels
area-signalr Includes: SignalR clients and servers
Milestone

Comments

@LukasReschke
Copy link

LukasReschke commented Jan 9, 2021

Describe the bug

When using grpc-dotnet and Blazor together to call a GRPC API, the User-Agent is set to "grpc-dotnet/$assemblyVersion" in Safari and Firefox. In Chrome and Edge it is the actual browser User-Agent.

https://docs.microsoft.com/en-us/aspnet/core/grpc/services?view=aspnetcore-5.0 for example describes how to read the User-Agent:

public override Task<ExampleResponse> UnaryCall(ExampleRequest request, ServerCallContext context)
{
    var userAgent = context.RequestHeaders.GetValue("user-agent");
    // ...

    return Task.FromResult(new ExampleResponse());
}

(Migrated from dotnet/AspNetCore.Docs#21178)

To Reproduce

Use GRPC with Blazor as described at https://docs.microsoft.com/en-us/aspnet/core/grpc/browser?view=aspnetcore-5.0 and look at the traffic in Safari. The User-Agent will be for example "grpc-dotnet/2.34.0.0".

You can also check out https://our.gatekeeper.page in Safari or Firefox and look at the request to the "WhoAmI" endpoint to see the header being wrong. The code for this can be found at https://github.com/getgatekeeper/server.

The Blazor example from https://github.com/grpc/grpc-dotnet/tree/master/examples/Blazor should also have the same issue.

The issue seems potentially related to the following piece of code in Grpc.Net.Client/Internal/GrpcCall.cs. I wonder if Chrome/Edge just ignore the header being overwritten whilst Safari and Firefox obeys it:

// User agent is optional but recommended.
headers.TryAddWithoutValidation(GrpcProtocolConstants.UserAgentHeader, GrpcProtocolConstants.UserAgentHeaderValue);

Test plan

Browser Sends correct User-Agent Screenshot
Safari image
Firefox image
Chrome image
Edge image
@LukasReschke LukasReschke changed the title grpc-dotnet + Blazor sets Safari User-Agent to "grpc-dotnet/$assemblyVersion" grpc-dotnet + Blazor sets Safari and Firefox User-Agent to "grpc-dotnet/$assemblyVersion" Jan 9, 2021
@JamesNK
Copy link
Member

JamesNK commented Jan 10, 2021

Thanks for the detailed issue. I'll investigate what the client should do here.

@BrennanConroy Does the SignalR JS client set a user-agent?

@JamesNK
Copy link
Member

JamesNK commented Jan 10, 2021

@JamesNK JamesNK added the area-grpc Includes: GRPC wire-up, templates label Jan 10, 2021
@BrennanConroy
Copy link
Member

SignalR sets the "X-SignalR-User-Agent" header.

let userAgentHeaderName = "X-SignalR-User-Agent";

I believe the reason we don't set "User-Agent" is because it used to be a forbidden header but no longer is. Also, Chrome just drops the header? https://bugs.chromium.org/p/chromium/issues/detail?id=571722

@BrennanConroy
Copy link
Member

BrennanConroy commented Jan 10, 2021

Oh, I guess this is about WASM, in the .NET client we set the User Agent

httpClient.DefaultRequestHeaders.Add(Constants.UserAgent, Constants.UserAgentHeader);

But you can provide a User Agent header to overwrite. And an empty string will remove the header we set.
if (string.Equals(header.Key, Constants.UserAgent, StringComparison.OrdinalIgnoreCase))

@JamesNK
Copy link
Member

JamesNK commented Jan 10, 2021

Does SignalR .NET library also run in Blazor WASM? If so, I wonder if gRPC and SignalR .NET libraries should have special logic for how they set headers in Blazor WASM.

@pranavkm Is there a way for a library to detect whether it is running inside the browser? Like something on Environment e.g.

if (!IsBlazorWasm)
{
    headers.Add("user-agent", "library/1.2");
}
else
{
    // Don't set user-agent when calling from the browser. It is a protected header in Chrome/Edge.
    headers.Add("x-user-agent", "library/1.2");
}

@BrennanConroy
Copy link
Member

Yes it runs in the browser, you can use OperatingSystem.IsBrowser()

if (httpConnectionOptions.Transports == HttpTransportType.ServerSentEvents && OperatingSystem.IsBrowser())

https://github.com/dotnet/aspnetcore/blob/2ceca7fb89a4021166b32f18612bc490d3146fe2/src/Shared/OperatingSystem.cs

@ghost
Copy link

ghost commented Jan 11, 2021

Thanks for contacting us.
We're moving this issue to the Next sprint planning milestone for future evaluation / consideration. We will evaluate the request when we are planning the work for the next milestone. To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.

@JamesNK
Copy link
Member

JamesNK commented Jan 12, 2021

gRPC fixed. Re-opening for SignalR.

@JamesNK JamesNK reopened this Jan 12, 2021
@JamesNK JamesNK removed the area-grpc Includes: GRPC wire-up, templates label Jan 12, 2021
@ghost ghost locked as resolved and limited conversation to collaborators Apr 14, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-signalr Includes: SignalR clients and servers
Projects
None yet
3 participants