Skip to content

Commit

Permalink
Add support for HttpRule types to gRPC JSON transcoding (dotnet#48194)
Browse files Browse the repository at this point in the history
  • Loading branch information
JamesNK authored May 12, 2023
1 parent 0625a17 commit 514210d
Show file tree
Hide file tree
Showing 6 changed files with 485 additions and 3 deletions.
19 changes: 18 additions & 1 deletion src/Grpc/JsonTranscoding/src/Shared/ServiceDescriptorHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -324,10 +324,27 @@ public static void SetValue(IMessage message, FieldDescriptor field, object? val
}
}

// Transcoding assumes that the app is referencing Google.Api.CommonProtos and HttpRule is from that assembly.
// However, it's possible the app has compiled http.proto with Grpc.Tools, so the extension value is HttpRule from a different assembly.
// This custom extension uses the HttpRule field number but has a return type of object.
// The method always returns the extension value, and the calling code can convert it to the expected type.
// See https://github.com/protocolbuffers/protobuf/issues/9626 for more details.
private static readonly Extension<MethodOptions, object> UntypedHttpExtension =
new Extension<MethodOptions, object>(AnnotationsExtensions.Http.FieldNumber, codec: null);

public static bool TryGetHttpRule(MethodDescriptor methodDescriptor, [NotNullWhen(true)] out HttpRule? httpRule)
{
var options = methodDescriptor.GetOptions();
httpRule = options?.GetExtension(AnnotationsExtensions.Http);

// The untyped extension always returns the extension value. If the type is already the expected HttpRule then use it directly.
// A different message indicates a custom HttpRule was used. Convert the message to bytes and reparse it to the known HttpRule type.
var extensionValue = options?.GetExtension(UntypedHttpExtension);
httpRule = extensionValue switch
{
HttpRule rule => rule,
IMessage message => HttpRule.Parser.ParseFrom(message.ToByteArray()),
_ => null
};

return httpRule != null;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<Protobuf Include="Proto\httpbody.proto" GrpcServices="Both" />
<Protobuf Include="Proto\Issue047349\message.proto" GrpcServices="Both" />
<Protobuf Include="Proto\transcoding.proto" GrpcServices="Both" />

<Protobuf Include="Proto\Issue045270\hello.proto" GrpcServices="Both" />
<Protobuf Include="Proto\Issue045270\country.proto" GrpcServices="Both" />
<Protobuf Include="Proto\Issue047349\message.proto" GrpcServices="Both" />
<Protobuf Include="Proto\Issue048192\hello.proto" GrpcServices="Both" />
<Protobuf Include="Proto\Issue048192\customhttp.proto" GrpcServices="Both" />
<Protobuf Include="Proto\Issue048192\customannotations.proto" GrpcServices="Both" />

<Compile Include="..\Shared\TestGrpcServiceActivator.cs" Link="Infrastructure\TestGrpcServiceActivator.cs" />

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright (c) 2015, Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

syntax = "proto3";

// This is a copy of annotations.proto and is used to test loading the HttpRule for a
// message when the .NET type doesn't match the version in Google.Api.CommonProtos.
option csharp_namespace = "CustomHttpRule";

package google.api;

import "Proto/Issue048192/customhttp.proto";
import "google/protobuf/descriptor.proto";

option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations";
option java_multiple_files = true;
option java_outer_classname = "AnnotationsProto";
option java_package = "com.google.api";
option objc_class_prefix = "GAPI";

extend google.protobuf.MethodOptions {
// See `HttpRule`.
HttpRule http = 72295728;
}
Loading

0 comments on commit 514210d

Please sign in to comment.