From 75d32b0a82c4a39ec7963a5bfeaac2a5fd8b24f5 Mon Sep 17 00:00:00 2001 From: Marie Hoeger Date: Thu, 28 May 2020 11:59:19 -0700 Subject: [PATCH] Ignore headers with empty value if capability is enabled (#6100) * Ignore headers with empty value if capability is enabled * nit * format fixes * logic error --- .../RpcMessageConversionExtensions.cs | 10 +++++ .../Workers/Rpc/RpcWorkerConstants.cs | 1 + .../RpcMessageConversionExtensionsTests.cs | 37 +++++++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/src/WebJobs.Script/Workers/Rpc/MessageExtensions/RpcMessageConversionExtensions.cs b/src/WebJobs.Script/Workers/Rpc/MessageExtensions/RpcMessageConversionExtensions.cs index 345ae063fa..58b3c82bb3 100644 --- a/src/WebJobs.Script/Workers/Rpc/MessageExtensions/RpcMessageConversionExtensions.cs +++ b/src/WebJobs.Script/Workers/Rpc/MessageExtensions/RpcMessageConversionExtensions.cs @@ -132,6 +132,11 @@ internal static TypedData ToRpcHttp(this HttpRequest request, ILogger logger, Ca foreach (var pair in request.Headers) { + if (ShouldIgnoreEmptyHeaderValues(capabilities) && string.IsNullOrEmpty(pair.Value.ToString())) + { + continue; + } + http.Headers.Add(pair.Key.ToLowerInvariant(), pair.Value.ToString()); } @@ -346,6 +351,11 @@ private static bool IsTypedDataCollectionSupported(Capabilities capabilities) return !string.IsNullOrEmpty(capabilities.GetCapabilityState(RpcWorkerConstants.TypedDataCollection)); } + private static bool ShouldIgnoreEmptyHeaderValues(Capabilities capabilities) + { + return !string.IsNullOrEmpty(capabilities.GetCapabilityState(RpcWorkerConstants.IgnoreEmptyValuedRpcHttpHeaders)); + } + 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 534f1a2aac..6f0e712ff4 100644 --- a/src/WebJobs.Script/Workers/Rpc/RpcWorkerConstants.cs +++ b/src/WebJobs.Script/Workers/Rpc/RpcWorkerConstants.cs @@ -35,6 +35,7 @@ public static class RpcWorkerConstants public const string TypedDataCollection = "TypedDataCollection"; public const string RpcHttpBodyOnly = "RpcHttpBodyOnly"; public const string RpcHttpTriggerMetadataRemoved = "RpcHttpTriggerMetadataRemoved"; + public const string IgnoreEmptyValuedRpcHttpHeaders = "IgnoreEmptyValuedRpcHttpHeaders"; // Host Capabilites public const string V2Compatable = "V2Compatable"; diff --git a/test/WebJobs.Script.Tests/Workers/Rpc/RpcMessageConversionExtensionsTests.cs b/test/WebJobs.Script.Tests/Workers/Rpc/RpcMessageConversionExtensionsTests.cs index 9fcfd6cf09..f9b18a68d2 100644 --- a/test/WebJobs.Script.Tests/Workers/Rpc/RpcMessageConversionExtensionsTests.cs +++ b/test/WebJobs.Script.Tests/Workers/Rpc/RpcMessageConversionExtensionsTests.cs @@ -160,6 +160,43 @@ public void HttpObjects_Query(string queryString, string[] expectedKeys, string[ } } + [Theory] + [InlineData(true, new string[] { "hello", "x-mx-key" }, new string[] { "world", "value" }, new string[] { "hello", "x-mx-key" }, new string[] { "world", "value" })] + [InlineData(true, new string[] { "hello", "empty", "x-mx-key" }, new string[] { "world", "", "value" }, new string[] { "hello", "x-mx-key" }, new string[] { "world", "value" })] // Removes empty value query params + [InlineData(false, new string[] { "hello", "x-mx-key" }, new string[] { "world", "value" }, new string[] { "hello", "x-mx-key" }, new string[] { "world", "value" })] + [InlineData(false, new string[] { "hello", "empty", "x-mx-key" }, new string[] { "world", "", "value" }, new string[] { "hello", "empty", "x-mx-key" }, new string[] { "world", "", "value" })] + + public void HttpObjects_Headers(bool ignoreEmptyValues, string[] headerKeys, string[] headerValues, string[] expectedKeys, string[] expectedValues) + { + var logger = MockNullLoggerFactory.CreateLogger(); + // Capability must be enabled + var capabilities = new Capabilities(logger); + + if (ignoreEmptyValues) + { + capabilities.UpdateCapabilities(new MapField + { + { RpcWorkerConstants.IgnoreEmptyValuedRpcHttpHeaders, "true" } + }); + } + + var headerDictionary = new HeaderDictionary(); + for (int i = 0; i < headerValues.Length; i++) + { + headerDictionary.Add(headerKeys[i], headerValues[i]); + } + + HttpRequest request = HttpTestHelpers.CreateHttpRequest("GET", $"http://localhost/api/httptrigger-scenarios", headerDictionary); + + var rpcRequestObject = request.ToRpc(logger, capabilities); + // Same key and value strings for each pair + for (int i = 0; i < expectedKeys.Length; i++) + { + Assert.True(rpcRequestObject.Http.Headers.ContainsKey(expectedKeys[i])); + Assert.Equal(expectedValues[i], rpcRequestObject.Http.Headers.GetValueOrDefault(expectedKeys[i])); + } + } + [Theory] [InlineData(BindingDirection.In, "blob", DataType.String)] [InlineData(BindingDirection.Out, "blob", DataType.Binary)]