diff --git a/src/WebJobs.Script.Grpc/azure-functions-language-worker-protobuf/src/proto/FunctionRpc.proto b/src/WebJobs.Script.Grpc/azure-functions-language-worker-protobuf/src/proto/FunctionRpc.proto index 67a871de2d..dad7cfd238 100644 --- a/src/WebJobs.Script.Grpc/azure-functions-language-worker-protobuf/src/proto/FunctionRpc.proto +++ b/src/WebJobs.Script.Grpc/azure-functions-language-worker-protobuf/src/proto/FunctionRpc.proto @@ -484,4 +484,7 @@ message RpcHttp { TypedData rawBody = 17; repeated RpcClaimsIdentity identities = 18; repeated RpcHttpCookie cookies = 19; + map nullable_headers = 20; + map nullable_params = 21; + map nullable_query = 22; } diff --git a/src/WebJobs.Script/Workers/Rpc/MessageExtensions/RpcMessageConversionExtensions.cs b/src/WebJobs.Script/Workers/Rpc/MessageExtensions/RpcMessageConversionExtensions.cs index 3e69dbeef5..81924cc13a 100644 --- a/src/WebJobs.Script/Workers/Rpc/MessageExtensions/RpcMessageConversionExtensions.cs +++ b/src/WebJobs.Script/Workers/Rpc/MessageExtensions/RpcMessageConversionExtensions.cs @@ -128,20 +128,34 @@ internal static async Task ToRpcHttp(this HttpRequest request, ILogge foreach (var pair in request.Query) { var value = pair.Value.ToString(); - if (!string.IsNullOrEmpty(value)) + if (ShouldUseNullableValueDictionary(capabilities)) { - http.Query.Add(pair.Key, value); + http.NullableQuery.Add(pair.Key, new NullableString { Value = value }); + } + else + { + if (!string.IsNullOrEmpty(value)) + { + http.Query.Add(pair.Key, value); + } } } foreach (var pair in request.Headers) { - if (ShouldIgnoreEmptyHeaderValues(capabilities) && string.IsNullOrEmpty(pair.Value.ToString())) + if (ShouldUseNullableValueDictionary(capabilities)) { - continue; + http.NullableHeaders.Add(pair.Key.ToLowerInvariant(), new NullableString { Value = pair.Value.ToString() }); } + else + { + if (ShouldIgnoreEmptyHeaderValues(capabilities) && string.IsNullOrEmpty(pair.Value.ToString())) + { + continue; + } - http.Headers.Add(pair.Key.ToLowerInvariant(), pair.Value.ToString()); + http.Headers.Add(pair.Key.ToLowerInvariant(), pair.Value.ToString()); + } } if (request.HttpContext.Items.TryGetValue(HttpExtensionConstants.AzureWebJobsHttpRouteDataKey, out object routeData)) @@ -149,9 +163,16 @@ internal static async Task ToRpcHttp(this HttpRequest request, ILogge Dictionary parameters = (Dictionary)routeData; foreach (var pair in parameters) { - if (pair.Value != null) + if (ShouldUseNullableValueDictionary(capabilities)) + { + http.NullableParams.Add(pair.Key, new NullableString { Value = pair.Value.ToString() }); + } + else { - http.Params.Add(pair.Key, pair.Value.ToString()); + if (pair.Value != null) + { + http.Params.Add(pair.Key, pair.Value.ToString()); + } } } } @@ -364,6 +385,11 @@ private static bool ShouldIgnoreEmptyHeaderValues(Capabilities capabilities) return !string.IsNullOrEmpty(capabilities.GetCapabilityState(RpcWorkerConstants.IgnoreEmptyValuedRpcHttpHeaders)); } + private static bool ShouldUseNullableValueDictionary(Capabilities capabilities) + { + return !string.IsNullOrEmpty(capabilities.GetCapabilityState(RpcWorkerConstants.UseNullableValueDictionaryForHttp)); + } + public static BindingInfo ToBindingInfo(this BindingMetadata bindingMetadata) { BindingInfo bindingInfo = new BindingInfo diff --git a/src/WebJobs.Script/Workers/Rpc/RpcWorkerConstants.cs b/src/WebJobs.Script/Workers/Rpc/RpcWorkerConstants.cs index 7087241396..093939ec8a 100644 --- a/src/WebJobs.Script/Workers/Rpc/RpcWorkerConstants.cs +++ b/src/WebJobs.Script/Workers/Rpc/RpcWorkerConstants.cs @@ -37,6 +37,7 @@ public static class RpcWorkerConstants public const string RpcHttpTriggerMetadataRemoved = "RpcHttpTriggerMetadataRemoved"; public const string IgnoreEmptyValuedRpcHttpHeaders = "IgnoreEmptyValuedRpcHttpHeaders"; public const string WorkerStatus = "WorkerStatus"; + public const string UseNullableValueDictionaryForHttp = "UseNullableValueDictionaryForHttp"; // Host Capabilites public const string V2Compatable = "V2Compatable";