From 3ec96521828b554e0e006ae0b647a9b61b4d02d2 Mon Sep 17 00:00:00 2001 From: scbedd <45376673+scbedd@users.noreply.github.com> Date: Wed, 1 Feb 2023 10:46:38 -0800 Subject: [PATCH 1/6] during recording, replay the body as it is exactly --- .../RecordingHandlerTests.cs | 2 +- .../RecordingHandler.cs | 20 +++++++++++-------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/RecordingHandlerTests.cs b/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/RecordingHandlerTests.cs index b08ea728633..ecb358b91c5 100644 --- a/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/RecordingHandlerTests.cs +++ b/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/RecordingHandlerTests.cs @@ -618,7 +618,7 @@ public async Task CreateEntryUsesAbsoluteUri() request.Path = uri.PathAndQuery; request.Headers["x-recording-upstream-base-uri"] = uri.AbsoluteUri; - var entry = await RecordingHandler.CreateEntryAsync(request); + var entry = (await RecordingHandler.CreateEntryAsync(request)).Item1; Assert.Equal(uri.AbsoluteUri, entry.RequestUri); } diff --git a/tools/test-proxy/Azure.Sdk.Tools.TestProxy/RecordingHandler.cs b/tools/test-proxy/Azure.Sdk.Tools.TestProxy/RecordingHandler.cs index 0206a7ad844..80984d64e7a 100644 --- a/tools/test-proxy/Azure.Sdk.Tools.TestProxy/RecordingHandler.cs +++ b/tools/test-proxy/Azure.Sdk.Tools.TestProxy/RecordingHandler.cs @@ -194,9 +194,10 @@ public async Task HandleRecordRequestAsync(string recordingId, HttpRequest incom throw new HttpException(HttpStatusCode.BadRequest, $"There is no active recording session under id {recordingId}."); } - var entry = await CreateEntryAsync(incomingRequest).ConfigureAwait(false); + var entryTuple = await CreateEntryAsync(incomingRequest).ConfigureAwait(false); + var entry = entryTuple.Item1; - var upstreamRequest = CreateUpstreamRequest(incomingRequest, CompressionUtilities.CompressBody(entry.Request.Body, entry.Request.Headers)); + var upstreamRequest = CreateUpstreamRequest(incomingRequest, entryTuple.Item2); HttpResponseMessage upstreamResponse = null; @@ -432,7 +433,7 @@ public async Task HandlePlaybackRequest(string recordingId, HttpRequest incoming throw new HttpException(HttpStatusCode.BadRequest, $"There is no active playback session under recording id {recordingId}."); } - var entry = await CreateEntryAsync(incomingRequest).ConfigureAwait(false); + var entry = (await CreateEntryAsync(incomingRequest).ConfigureAwait(false)).Item1; // If request contains "x-recording-remove: false", then request is not removed from session after playback. // Used by perf tests to play back the same request multiple times. @@ -470,24 +471,27 @@ public async Task HandlePlaybackRequest(string recordingId, HttpRequest incoming } } - public static async Task CreateEntryAsync(HttpRequest request) + public static async Task> CreateEntryAsync(HttpRequest request) { var entry = new RecordEntry(); entry.RequestUri = GetRequestUri(request).AbsoluteUri; entry.RequestMethod = new RequestMethod(request.Method); - foreach (var header in request.Headers) + lock (request.Headers) { - if (IncludeHeader(header.Key)) + foreach (var header in request.Headers) { - entry.Request.Headers.Add(header.Key, header.Value.ToArray()); + if (IncludeHeader(header.Key)) + { + entry.Request.Headers.Add(header.Key, header.Value.ToArray()); + } } } byte[] bytes = await ReadAllBytes(request.Body).ConfigureAwait(false); entry.Request.Body = CompressionUtilities.DecompressBody(bytes, request.Headers); - return entry; + return new Tuple(entry, bytes); } #endregion From 87c86733aee086ab8e67773833552c77c69c534c Mon Sep 17 00:00:00 2001 From: scbedd <45376673+scbedd@users.noreply.github.com> Date: Wed, 1 Feb 2023 10:54:19 -0800 Subject: [PATCH 2/6] remove lock --- .../Azure.Sdk.Tools.TestProxy/RecordingHandler.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/tools/test-proxy/Azure.Sdk.Tools.TestProxy/RecordingHandler.cs b/tools/test-proxy/Azure.Sdk.Tools.TestProxy/RecordingHandler.cs index 80984d64e7a..2fca151d598 100644 --- a/tools/test-proxy/Azure.Sdk.Tools.TestProxy/RecordingHandler.cs +++ b/tools/test-proxy/Azure.Sdk.Tools.TestProxy/RecordingHandler.cs @@ -477,14 +477,11 @@ public static async Task> CreateEntryAsync(HttpReques entry.RequestUri = GetRequestUri(request).AbsoluteUri; entry.RequestMethod = new RequestMethod(request.Method); - lock (request.Headers) + foreach (var header in request.Headers) { - foreach (var header in request.Headers) + if (IncludeHeader(header.Key)) { - if (IncludeHeader(header.Key)) - { - entry.Request.Headers.Add(header.Key, header.Value.ToArray()); - } + entry.Request.Headers.Add(header.Key, header.Value.ToArray()); } } From 611830d8c53aacd14367ee251b3026e45a404de2 Mon Sep 17 00:00:00 2001 From: scbedd <45376673+scbedd@users.noreply.github.com> Date: Wed, 1 Feb 2023 10:56:56 -0800 Subject: [PATCH 3/6] necessary updates so we can publish a demo version of this thing that is usable by dotnet --- .../Azure.Sdk.Tools.TestProxy.csproj | 1 - tools/test-proxy/ci.yml | 22 +++++++++---------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Azure.Sdk.Tools.TestProxy.csproj b/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Azure.Sdk.Tools.TestProxy.csproj index 1fa934582d3..274d5a4c52e 100644 --- a/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Azure.Sdk.Tools.TestProxy.csproj +++ b/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Azure.Sdk.Tools.TestProxy.csproj @@ -9,7 +9,6 @@ preview $(OfficialBuildId) false - test-proxy diff --git a/tools/test-proxy/ci.yml b/tools/test-proxy/ci.yml index dd45c7298bd..e9c1e20f523 100644 --- a/tools/test-proxy/ci.yml +++ b/tools/test-proxy/ci.yml @@ -50,14 +50,14 @@ extends: stableTags: - 'latest' ReleaseBinaries: true - StandaloneExeMatrix: - - rid: osx-x64 - framework: net6.0 - - rid: osx-arm64 - framework: net6.0 - - rid: win-x64 - framework: net6.0 - - rid: linux-x64 - framework: net6.0 - - rid: linux-arm64 - framework: net6.0 + # StandaloneExeMatrix: + # - rid: osx-x64 + # framework: net6.0 + # - rid: osx-arm64 + # framework: net6.0 + # - rid: win-x64 + # framework: net6.0 + # - rid: linux-x64 + # framework: net6.0 + # - rid: linux-arm64 + # framework: net6.0 From d70dd48a9470d7315b3cca3ff9aa4c3e981a20d8 Mon Sep 17 00:00:00 2001 From: Scott Beddall <45376673+scbedd@users.noreply.github.com> Date: Wed, 1 Feb 2023 10:57:52 -0800 Subject: [PATCH 4/6] Update tools/test-proxy/Azure.Sdk.Tools.TestProxy/RecordingHandler.cs Co-authored-by: JoshLove-msft <54595583+JoshLove-msft@users.noreply.github.com> --- tools/test-proxy/Azure.Sdk.Tools.TestProxy/RecordingHandler.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/test-proxy/Azure.Sdk.Tools.TestProxy/RecordingHandler.cs b/tools/test-proxy/Azure.Sdk.Tools.TestProxy/RecordingHandler.cs index 2fca151d598..adc259ccdcc 100644 --- a/tools/test-proxy/Azure.Sdk.Tools.TestProxy/RecordingHandler.cs +++ b/tools/test-proxy/Azure.Sdk.Tools.TestProxy/RecordingHandler.cs @@ -194,7 +194,7 @@ public async Task HandleRecordRequestAsync(string recordingId, HttpRequest incom throw new HttpException(HttpStatusCode.BadRequest, $"There is no active recording session under id {recordingId}."); } - var entryTuple = await CreateEntryAsync(incomingRequest).ConfigureAwait(false); + (RecordEntry entry, byte[] bytes) = await CreateEntryAsync(incomingRequest).ConfigureAwait(false); var entry = entryTuple.Item1; var upstreamRequest = CreateUpstreamRequest(incomingRequest, entryTuple.Item2); From 7327f0d9013c6e57f3d16e5403c88e97e86e3831 Mon Sep 17 00:00:00 2001 From: scbedd <45376673+scbedd@users.noreply.github.com> Date: Wed, 1 Feb 2023 11:06:53 -0800 Subject: [PATCH 5/6] fit/finish --- .../Azure.Sdk.Tools.TestProxy/RecordingHandler.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tools/test-proxy/Azure.Sdk.Tools.TestProxy/RecordingHandler.cs b/tools/test-proxy/Azure.Sdk.Tools.TestProxy/RecordingHandler.cs index adc259ccdcc..7544c55114c 100644 --- a/tools/test-proxy/Azure.Sdk.Tools.TestProxy/RecordingHandler.cs +++ b/tools/test-proxy/Azure.Sdk.Tools.TestProxy/RecordingHandler.cs @@ -194,10 +194,9 @@ public async Task HandleRecordRequestAsync(string recordingId, HttpRequest incom throw new HttpException(HttpStatusCode.BadRequest, $"There is no active recording session under id {recordingId}."); } - (RecordEntry entry, byte[] bytes) = await CreateEntryAsync(incomingRequest).ConfigureAwait(false); - var entry = entryTuple.Item1; + (RecordEntry entry, byte[] requestBody) = await CreateEntryAsync(incomingRequest).ConfigureAwait(false); - var upstreamRequest = CreateUpstreamRequest(incomingRequest, entryTuple.Item2); + var upstreamRequest = CreateUpstreamRequest(incomingRequest, requestBody); HttpResponseMessage upstreamResponse = null; @@ -471,7 +470,7 @@ public async Task HandlePlaybackRequest(string recordingId, HttpRequest incoming } } - public static async Task> CreateEntryAsync(HttpRequest request) + public static async Task<(RecordEntry, byte[])> CreateEntryAsync(HttpRequest request) { var entry = new RecordEntry(); entry.RequestUri = GetRequestUri(request).AbsoluteUri; @@ -488,7 +487,7 @@ public static async Task> CreateEntryAsync(HttpReques byte[] bytes = await ReadAllBytes(request.Body).ConfigureAwait(false); entry.Request.Body = CompressionUtilities.DecompressBody(bytes, request.Headers); - return new Tuple(entry, bytes); + return (entry, bytes); } #endregion From 25e0d4532904e66cf662c779aeb576dd6abf6578 Mon Sep 17 00:00:00 2001 From: scbedd <45376673+scbedd@users.noreply.github.com> Date: Wed, 1 Feb 2023 12:25:44 -0800 Subject: [PATCH 6/6] ensure that our decompression doesn't accidentally manipulate an array --- .../CompressionTests.cs | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/CompressionTests.cs diff --git a/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/CompressionTests.cs b/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/CompressionTests.cs new file mode 100644 index 00000000000..f85d569bafa --- /dev/null +++ b/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/CompressionTests.cs @@ -0,0 +1,41 @@ +using Azure.Sdk.Tools.TestProxy.Common; +using Azure.Sdk.Tools.TestProxy.Models; +using Azure.Sdk.Tools.TestProxy.Sanitizers; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using Xunit; + +namespace Azure.Sdk.Tools.TestProxy.Tests +{ + public class CompressionUtilityTests + { + [Fact] + public void EnsureDecompressionPristineBytes() + { + // generate + byte[] uncompressedBody = Encoding.UTF8.GetBytes("\"{\\u0022TableName\\u0022: \\u0022listtable09bf2a3d\\u0022}\""); + byte[] compressedBody = CompressionUtilities.CompressBodyCore(uncompressedBody, new string[] { "gzip" }); + + byte[] savedCompressedBody = new byte[compressedBody.Length]; + compressedBody.CopyTo(savedCompressedBody, 0); + + var headerDict = new HeaderDictionary(); + headerDict.Add("Content-Encoding", new string[1] { "gzip" }); + + // intentionally testing DecompressBody vs DecompressBodyCore, as that is where the header values are intercepted and treated differently + byte[] decompressedResult = CompressionUtilities.DecompressBody(compressedBody, headerDict); + + + Assert.Equal(compressedBody, savedCompressedBody); + Assert.NotEqual(decompressedResult, compressedBody); + } + + } +}