diff --git a/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/SanitizerTests.cs b/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/SanitizerTests.cs index ca9d1688f42..2ab312b1ed1 100644 --- a/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/SanitizerTests.cs +++ b/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/SanitizerTests.cs @@ -1,4 +1,4 @@ -using Azure.Sdk.Tools.TestProxy.Common; +using Azure.Sdk.Tools.TestProxy.Common; using Azure.Sdk.Tools.TestProxy.Common.Exceptions; using Azure.Sdk.Tools.TestProxy.Sanitizers; using Microsoft.AspNetCore.Http; @@ -277,6 +277,35 @@ public void HeaderRegexSanitizerSimpleReplace() Assert.StartsWith("https://fakeaccount.table.core.windows.net", testValue); } + + [Fact] + public void HeaderRegexSanitizerMultipartReplace() + { + var session = TestHelpers.LoadRecordSession("Test.RecordEntries/multipart_header.json"); + var targetEntry = session.Session.Entries[0]; + var targetKey = "Cookie"; + + var headerRegexSanitizer = new HeaderRegexSanitizer(targetKey, value: "REDACTED", regex: "SuperDifferent"); + session.Session.Sanitize(headerRegexSanitizer); + + Assert.Equal("REDACTEDCookie", targetEntry.Request.Headers[targetKey][0]); + Assert.Equal("KindaDifferentCookie", targetEntry.Request.Headers[targetKey][1]); + } + + [Fact] + public void HeaderRegexSanitizerMultipartReplaceLatterOnly() + { + var session = TestHelpers.LoadRecordSession("Test.RecordEntries/multipart_header.json"); + var targetEntry = session.Session.Entries[0]; + var targetKey = "Cookie"; + + var headerRegexSanitizer = new HeaderRegexSanitizer(targetKey, value: "REDACTED", regex: "KindaDifferent"); + session.Session.Sanitize(headerRegexSanitizer); + + Assert.Equal("SuperDifferentCookie", targetEntry.Request.Headers[targetKey][0]); + Assert.Equal("REDACTEDCookie", targetEntry.Request.Headers[targetKey][1]); + } + [Fact] public void HeaderRegexSanitizerGroupedRegexReplace() { diff --git a/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/Test.RecordEntries/multipart_header.json b/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/Test.RecordEntries/multipart_header.json new file mode 100644 index 00000000000..f5618b28040 --- /dev/null +++ b/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/Test.RecordEntries/multipart_header.json @@ -0,0 +1,39 @@ +{ + "Entries": [ + { + "RequestUri": "http://host.docker.internal:8080/sample_response", + "RequestMethod": "GET", + "RequestHeaders": { + "Accept": "*/*", + "Accept-Encoding": "gzip, deflate, br", + "Accept-Language": "en-US", + "Connection": "keep-alive", + "Content-Length": "11", + "If-None-Match": "W/\u0022d-ua9UN3rfp1JzmLYtPUOjtDq\u002B3co\u0022", + "Referer": "http://localhost:9328/", + "sec-ch-ua": "", + "sec-ch-ua-mobile": "?0", + "sec-ch-ua-platform": "", + "Sec-Fetch-Dest": "empty", + "Sec-Fetch-Mode": "cors", + "Sec-Fetch-Site": "same-site", + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/93.0.4577.0 Safari/537.36", + "x-ms-client-request-id": "7c65aa72-6b12-4b60-bf3b-7a85c174e2ba", + "x-ms-useragent": "core-rest-pipeline/1.3.3 OS/Win32", + "Cookie": [ + "SuperDifferentCookie", + "KindaDifferentCookie" + ] + }, + "RequestBody": "RequestBody=", + "StatusCode": 304, + "ResponseHeaders": { + "Connection": "keep-alive", + "Keep-Alive": "timeout=5", + "X-Powered-By": "Express" + }, + "ResponseBody": null + } + ], + "Variables": {} +} diff --git a/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Sanitizers/HeaderRegexSanitizer.cs b/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Sanitizers/HeaderRegexSanitizer.cs index ae6880de930..fceae19b33b 100644 --- a/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Sanitizers/HeaderRegexSanitizer.cs +++ b/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Sanitizers/HeaderRegexSanitizer.cs @@ -1,5 +1,6 @@ -using Azure.Sdk.Tools.TestProxy.Common; +using Azure.Sdk.Tools.TestProxy.Common; using System.Collections.Generic; +using System.Linq; namespace Azure.Sdk.Tools.TestProxy.Sanitizers { @@ -47,11 +48,7 @@ public override void SanitizeHeaders(IDictionary headers) // We do this because letting .NET split and then reassemble header values introduces a space into the header itself // Ex: "application/json;odata=minimalmetadata" with .NET default header parsing becomes "application/json; odata=minimalmetadata" // Given this breaks signature verification, we have to avoid it. - var originalValue = headers[_targetKey][0]; - - var replacement = StringSanitizer.SanitizeValue(originalValue, _newValue, _regexValue, _groupForReplace); - - headers[_targetKey] = new string[] { replacement }; + headers[_targetKey] = headers[_targetKey].Select(x => StringSanitizer.SanitizeValue(x, _newValue, _regexValue, _groupForReplace)).ToArray(); } } } diff --git a/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Sanitizers/HeaderStringSanitizer.cs b/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Sanitizers/HeaderStringSanitizer.cs index 9b8472aba76..8655f249b7e 100644 --- a/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Sanitizers/HeaderStringSanitizer.cs +++ b/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Sanitizers/HeaderStringSanitizer.cs @@ -1,5 +1,6 @@ -using Azure.Sdk.Tools.TestProxy.Common; +using Azure.Sdk.Tools.TestProxy.Common; using System.Collections.Generic; +using System.Linq; namespace Azure.Sdk.Tools.TestProxy.Sanitizers { @@ -39,11 +40,7 @@ public override void SanitizeHeaders(IDictionary headers) // We do this because letting .NET split and then reassemble header values introduces a space into the header itself // Ex: "application/json;odata=minimalmetadata" with .NET default header parsing becomes "application/json; odata=minimalmetadata" // Given this breaks signature verification, we have to avoid it. - var originalValue = headers[_targetKey][0]; - - var replacement = StringSanitizer.ReplaceValue(inputValue: originalValue, targetValue: _targetValue, replacementValue: _newValue); - - headers[_targetKey] = new string[] { replacement }; + headers[_targetKey] = headers[_targetKey].Select(x => StringSanitizer.ReplaceValue(inputValue: x, targetValue: _targetValue, replacementValue: _newValue)).ToArray(); } } }