Skip to content

gRPC JSON transcoding fails for HTTP paths containing ':' #2054

@mikeas1

Description

@mikeas1

What version of gRPC and what language are you using?

C# .NET 7.0
gRPC.Core 2.46.5
Microsoft.AspNetCore.Grpc.JsonTranscoding 7.0.3

What operating system (Linux, Windows,...) and version?

Debian Linux

What runtime / compiler are you using (e.g. .NET Core SDK version dotnet --info)

dotnet --info
.NET SDK:
Version: 7.0.102
Commit: 4bbdd14480

Runtime Environment:
OS Name: debian
OS Version: rodete
OS Platform: Linux
RID: linux-x64
Base Path: /usr/share/dotnet/sdk/7.0.102/

Host:
Version: 7.0.2
Architecture: x64
Commit: d037e070eb

.NET SDKs installed:
6.0.405 [/usr/share/dotnet/sdk]
7.0.102 [/usr/share/dotnet/sdk]

.NET runtimes installed:
Microsoft.AspNetCore.App 6.0.13 [/usr/share/dotnet/shared/Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 7.0.2 [/usr/share/dotnet/shared/Microsoft.AspNetCore.App]
Microsoft.NETCore.App 6.0.13 [/usr/share/dotnet/shared/Microsoft.NETCore.App]
Microsoft.NETCore.App 7.0.2 [/usr/share/dotnet/shared/Microsoft.NETCore.App]

What did you do?

Annotate a gRPC method using the recommended "custom method" syntax, which includes a : in the path. Example:

  rpc StartFrameImport(StartFrameImportRequest)
      returns (StartFrameImportResponse) {
    option (google.api.http) = {
      post: "/v1/frames:startFrameImport",
      body: "*",
    };
  }
  rpc GetFrameImport(GetFrameImportRequest) returns (GetFrameImportResponse) {
    option (google.api.http) = {
      post: "/v1/frames:getFrameImport",
      body: "*",
    };
  }

Call the gRPC endpoint with JSON transcoding:

$ curl -v http://localhost:5001/v1/frames:startFrameImport -x POST

Receive 404 response

info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
      Request finished HTTP/1.1 GET http://localhost:5001/v1/frames:startFrameImport - - - 404 0 - 93.2833ms

Call the incorrectly parsed endpoint with JSON transcoding:

$ curl -v http://localhost:5001/v1/frames -x POST

Receive an error:

Microsoft.AspNetCore.Routing.Matching.AmbiguousMatchException: The request matched multiple endpoints. Matches: 
                                                                      
gRPC - /v1/frames
gRPC - /v1/frames 
   at Microsoft.AspNetCore.Routing.Matching.DefaultEndpointSelector.ReportAmbiguity(CandidateState[] candidateState)
   at Microsoft.AspNetCore.Routing.Matching.DefaultEndpointSelector.ProcessFinalCandidates(HttpContext httpContext, CandidateState[] candidateState)
   at Microsoft.AspNetCore.Routing.Matching.DfaMatcher.MatchAsync(HttpContext httpContext)
   at Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware.Invoke(HttpContext httpContext)

What did you expect to see?

Request should be correctly routed to the gRPC method with that path.

What did you see instead?

Request returns 404 due to incorrectly parsed HTTP paths.

I believe the underlying problem is that the custom verb is dropped when converting from a Grpc.Shared.HttpRoutePattern (which correctly parses the :myMethod suffix) to a Microsoft.AspNetCore.Grpc.JsonTranscoding.Internal.JsonTranscodingRouteAdapter.

Anything else we should know about your project / environment?

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions