Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
0707479
Merge commit 'ee3d0caf035711df24023971b5809dde766ac5d9'
May 5, 2026
70f4a8f
Update dependencies from https://dev.azure.com/dnceng/internal/_git/d…
dotnet-bot May 6, 2026
fe96db5
Merged PR 60176: [release/9.0] gRPC transcoding: respecting json-name…
DeagleGross May 8, 2026
2549c15
Merged PR 60124: [release/9.0] fix http2/3 path header ASCII symbols …
DeagleGross May 8, 2026
fed29b1
Merged PR 60873: Avoid caching responses for authenticated users
BrennanConroy May 12, 2026
52e2ba2
Update dependencies from https://dev.azure.com/dnceng/internal/_git/d…
dotnet-bot May 13, 2026
f4bfb64
Update dependencies from https://dev.azure.com/dnceng/internal/_git/d…
dotnet-bot May 13, 2026
1227183
Merge commit '757815b4ea8bab0aa6e4edabdf283dfd1b341600'
May 13, 2026
0f0e5a4
Update dependencies from https://dev.azure.com/dnceng/internal/_git/d…
dotnet-bot May 13, 2026
9221f3f
Update dependencies from https://dev.azure.com/dnceng/internal/_git/d…
dotnet-bot May 14, 2026
cce4af3
Update dependencies from https://dev.azure.com/dnceng/internal/_git/d…
dotnet-bot May 15, 2026
0619179
Update dependencies from https://dev.azure.com/dnceng/internal/_git/d…
dotnet-bot May 16, 2026
5d6e334
Merged PR 60795: [internal/release/9.0] Update dependencies from dnce…
May 18, 2026
5edf41b
Merged PR 61248: Update messagepack
BrennanConroy May 19, 2026
99075db
Merge commit '5edf41b9c09952f18e404ad38e25670991c1b513' into internal…
vseanreesermsft Jun 9, 2026
166c138
Revert "Merged PR 61248: Update messagepack"
wtgodbe Jun 9, 2026
cb3fd9e
Redo MessagePack changes
wtgodbe Jun 9, 2026
3740839
Update SDK
wtgodbe Jun 9, 2026
23e16ad
Update MessagePackVersion to 2.5.302
wtgodbe Jun 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions NuGet.config
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@
<!-- Begin: Package sources from dotnet-extensions -->
<!-- End: Package sources from dotnet-extensions -->
<!-- Begin: Package sources from dotnet-runtime -->
<add key="darc-int-dotnet-runtime-f2c8152" value="https://pkgs.dev.azure.com/dnceng/internal/_packaging/darc-int-dotnet-runtime-f2c8152e/nuget/v3/index.json" />
<!-- End: Package sources from dotnet-runtime -->
<!-- Begin: Package sources from dotnet-efcore -->
<add key="darc-int-dotnet-efcore-46c88f8" value="https://pkgs.dev.azure.com/dnceng/internal/_packaging/darc-int-dotnet-efcore-46c88f8c/nuget/v3/index.json" />
<!-- End: Package sources from dotnet-efcore -->
<!--End: Package sources managed by Dependency Flow automation. Do not edit the sources above.-->
<add key="dotnet-eng" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json" />
Expand All @@ -30,8 +32,10 @@
<clear />
<!--Begin: Package sources managed by Dependency Flow automation. Do not edit the sources below.-->
<!-- Begin: Package sources from dotnet-efcore -->
<add key="darc-int-dotnet-efcore-46c88f8" value="true" />
<!-- End: Package sources from dotnet-efcore -->
<!-- Begin: Package sources from dotnet-runtime -->
<add key="darc-int-dotnet-runtime-f2c8152" value="true" />
<!-- End: Package sources from dotnet-runtime -->
<!--End: Package sources managed by Dependency Flow automation. Do not edit the sources above.-->
</disabledPackageSources>
Expand Down
320 changes: 160 additions & 160 deletions eng/Version.Details.xml

Large diffs are not rendered by default.

162 changes: 81 additions & 81 deletions eng/Versions.props

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions global.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{
"sdk": {
"version": "9.0.116"
"version": "9.0.118"
},
"tools": {
"dotnet": "9.0.116",
"dotnet": "9.0.118",
"runtimes": {
"dotnet/x86": [
"$(MicrosoftNETCoreBrowserDebugHostTransportVersion)"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,14 @@ public CallHandlerDescriptorInfo(
BodyFieldDescriptor = bodyFieldDescriptor;
RouteParameterDescriptors = routeParameterDescriptors;
RouteAdapter = routeAdapter;
PathDescriptorsCache = new ConcurrentDictionary<string, List<FieldDescriptor>?>();
PathDescriptorsCache = new ConcurrentDictionary<string, List<FieldDescriptor>>();

var jsonPaths = new HashSet<string>(StringComparer.Ordinal);
foreach (var routeParameter in routeParameterDescriptors.Values)
{
jsonPaths.Add(routeParameter.JsonPath);
}
RouteParameterJsonPaths = jsonPaths;
}

public FieldDescriptor? ResponseBodyDescriptor { get; }
Expand All @@ -34,5 +41,6 @@ public CallHandlerDescriptorInfo(
public FieldDescriptor? BodyFieldDescriptor { get; }
public Dictionary<string, RouteParameter> RouteParameterDescriptors { get; }
public JsonTranscodingRouteAdapter RouteAdapter { get; }
public ConcurrentDictionary<string, List<FieldDescriptor>?> PathDescriptorsCache { get; }
public HashSet<string> RouteParameterJsonPaths { get; }
public ConcurrentDictionary<string, List<FieldDescriptor>> PathDescriptorsCache { get; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -361,11 +361,18 @@ private static async ValueTask<byte[]> ReadDataAsync(JsonTranscodingServerCallCo

private static List<FieldDescriptor>? GetPathDescriptors(JsonTranscodingServerCallContext serverCallContext, IMessage requestMessage, string path)
{
return serverCallContext.DescriptorInfo.PathDescriptorsCache.GetOrAdd(path, p =>
// Must not add null values for paths that don't resolve to a descriptor
var cache = serverCallContext.DescriptorInfo.PathDescriptorsCache;
if (cache.TryGetValue(path, out var pathDescriptors))
{
ServiceDescriptorHelpers.TryResolveDescriptors(requestMessage.Descriptor, p.Split('.'), allowJsonName: true, out var pathDescriptors);
return pathDescriptors;
});
}
if (ServiceDescriptorHelpers.TryResolveDescriptors(requestMessage.Descriptor, path.Split('.'), allowJsonName: true, out pathDescriptors))
{
cache.TryAdd(path, pathDescriptors);
return pathDescriptors;
}
return null;
}

public static async ValueTask SendMessage<TResponse>(JsonTranscodingServerCallContext serverCallContext, JsonSerializerOptions serializerOptions, TResponse message, CancellationToken cancellationToken) where TResponse : class
Expand Down Expand Up @@ -408,24 +415,25 @@ private static bool CanBindQueryStringVariable(JsonTranscodingServerCallContext
{
if (serverCallContext.DescriptorInfo.BodyDescriptor != null)
{
var bodyFieldName = serverCallContext.DescriptorInfo.BodyFieldDescriptor?.Name;
var bodyFieldDescriptor = serverCallContext.DescriptorInfo.BodyFieldDescriptor;

// Null field name indicates "*" which means the entire message is bound to the body.
if (bodyFieldName == null)
// Null field descriptor indicates "*" which means the entire message is bound to the body.
if (bodyFieldDescriptor?.Name is null)
{
return false;
}

// Exact match
if (variable == bodyFieldName)
var bodyFieldName = bodyFieldDescriptor.Name;
var bodyFieldJsonName = bodyFieldDescriptor.JsonName;

// Exact match (proto name or JSON name)
if (variable == bodyFieldName || variable == bodyFieldJsonName)
{
return false;
}

// Nested field of field name.
if (bodyFieldName.Length + 1 < variable.Length &&
variable.StartsWith(bodyFieldName, StringComparison.Ordinal) &&
variable[bodyFieldName.Length] == '.')
// Nested field of body field (proto name prefix or JSON name prefix).
if (IsNestedBodyField(variable, bodyFieldName) || IsNestedBodyField(variable, bodyFieldJsonName))
{
return false;
}
Expand All @@ -436,6 +444,20 @@ private static bool CanBindQueryStringVariable(JsonTranscodingServerCallContext
return false;
}

// Also check JSON name aliases. Route parameter keys use proto names (e.g. "user_id"),
// but query parameters can use JSON names (e.g. "userId") which resolve to the same field.
if (serverCallContext.DescriptorInfo.RouteParameterJsonPaths.Contains(variable))
{
return false;
}

return true;
}

private static bool IsNestedBodyField(string variable, string bodyFieldName)
{
return bodyFieldName.Length + 1 < variable.Length &&
variable.StartsWith(bodyFieldName, StringComparison.Ordinal) &&
variable[bodyFieldName.Length] == '.';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,37 @@ Task<HelloReply> UnaryMethod(ComplextHelloRequest request, ServerCallContext con
Assert.Equal("Hello complex_greeter/test2/b last_name!", result.RootElement.GetProperty("message").GetString());
}

[Fact]
public async Task ComplexParameter_NestedJsonNameQueryString_DoesNotOverwriteRouteValue()
{
// Arrange
Task<HelloReply> UnaryMethod(ComplextHelloRequest request, ServerCallContext context)
{
return Task.FromResult(new HelloReply { Message = $"Hello {request.Name.FirstName} {request.Name.LastName}!" });
}
var method = Fixture.DynamicGrpc.AddUnaryMethod<ComplextHelloRequest, HelloReply>(
UnaryMethod,
Greeter.Descriptor.FindMethodByName("SayHelloComplexCatchAll3"));

var client = new HttpClient(Fixture.Handler) { BaseAddress = new Uri("http://localhost") };

// route.binding sets
// request.Name.LastName = "last_name";
// request.Name.FirstName = "complex_greeter/test2/b"
// ----
// query binding tries to overwrite with
// name.firstName=query_first
// name.lastName=query_last

// Act
var response = await client.GetAsync("/v1/last_name/complex_greeter/test2/b/c/d/two?name.firstName=query_first&name.lastName=query_last").DefaultTimeout();
var responseStream = await response.Content.ReadAsStreamAsync();
using var result = await JsonDocument.ParseAsync(responseStream);

// Assert
Assert.Equal("Hello complex_greeter/test2/b last_name!", result.RootElement.GetProperty("message").GetString());
}

[Fact]
public async Task SimpleCatchAllParameter_PrefixSuffixSlashes_MatchUrl_SuccessResult()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ message HelloRequest {
string hiding_field_name = 24 [json_name="field_name"];
repeated SubMessage repeated_messages = 25;
map<int32, int32> map_keyint_valueint = 26;
SubMessage sub_data = 27;
}

message HelloReply {
Expand Down
Loading
Loading