From 6f75ddcaad9c6829b3e67ae1b702cb520b7b3282 Mon Sep 17 00:00:00 2001 From: JoshLove-msft <54595583+JoshLove-msft@users.noreply.github.com> Date: Mon, 19 Sep 2022 14:22:01 -0700 Subject: [PATCH 1/5] Fix GZip handling for requests --- .../PlaybackTests.cs | 31 +++++++ .../RecordingHandlerTests.cs | 80 +++++++++++++++++-- ...request_response_with_gzipped_content.json | 48 +++++++++++ .../Common/GZipUtilities.cs | 80 +++++++++++++++++++ .../Properties/launchSettings.json | 1 - .../RecordingHandler.cs | 55 +++---------- 6 files changed, 242 insertions(+), 53 deletions(-) create mode 100644 tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/Test.RecordEntries/request_response_with_gzipped_content.json create mode 100644 tools/test-proxy/Azure.Sdk.Tools.TestProxy/Common/GZipUtilities.cs diff --git a/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/PlaybackTests.cs b/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/PlaybackTests.cs index fa4e8645ee9..126cc2e4d4c 100644 --- a/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/PlaybackTests.cs +++ b/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/PlaybackTests.cs @@ -6,6 +6,7 @@ using System.IO; using System.Linq; using System.Threading.Tasks; +using Azure.Sdk.Tools.TestProxy.Common; using Xunit; namespace Azure.Sdk.Tools.TestProxy.Tests @@ -217,5 +218,35 @@ public async Task TestPlaybackSetsRetryAfterToZero() await testRecordingHandler.HandlePlaybackRequest(recordingId, request, response); Assert.False(response.Headers.ContainsKey("Retry-After")); } + + [Fact] + public async Task TestPlaybackWithGZippedContentPlayback() + { + RecordingHandler testRecordingHandler = new RecordingHandler(Directory.GetCurrentDirectory()); + var httpContext = new DefaultHttpContext(); + var body = "{\"x-recording-file\":\"Test.RecordEntries/request_response_with_gzipped_content.json\"}"; + httpContext.Request.Body = TestHelpers.GenerateStreamRequestBody(body); + httpContext.Request.ContentLength = body.Length; + + var controller = new Playback(testRecordingHandler, new NullLoggerFactory()) + { + ControllerContext = new ControllerContext() + { + HttpContext = httpContext + } + }; + await controller.Start(); + + var recordingId = httpContext.Response.Headers["x-recording-id"].ToString(); + Assert.NotNull(recordingId); + Assert.True(testRecordingHandler.PlaybackSessions.ContainsKey(recordingId)); + var entry = testRecordingHandler.PlaybackSessions[recordingId].Session.Entries[0]; + HttpRequest request = TestHelpers.CreateRequestFromEntry(entry); + + // compress the body to simulate what the request coming from the library will look like + request.Body = new MemoryStream(GZipUtilities.CompressBody(BinaryData.FromStream(request.Body).ToArray(), request.Headers)); + HttpResponse response = new DefaultHttpContext().Response; + await testRecordingHandler.HandlePlaybackRequest(recordingId, request, response); + } } } 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 b56bbc79f65..a1ff192052b 100644 --- a/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/RecordingHandlerTests.cs +++ b/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/RecordingHandlerTests.cs @@ -12,6 +12,7 @@ using System.Linq; using System.Net; using System.Net.Http; +using System.Net.Http.Headers; using System.Text; using System.Text.Json; using System.Threading; @@ -632,7 +633,7 @@ public void TestCreateUpstreamRequestIncludesExpectedHeaders(params string[] inc var recordingHandler = new RecordingHandler(Directory.GetCurrentDirectory()); var upstreamRequestContext = GenerateHttpRequestContext(incomingHeaders); - var output = recordingHandler.CreateUpstreamRequest(upstreamRequestContext.Request, new byte[] { }); + var output = recordingHandler.CreateUpstreamRequest(upstreamRequestContext.Request); // iterate across the set we know about and confirm that GenerateUpstreamRequest worked properly! var setOfHeaders = GenerateHeaderValuesTuples(incomingHeaders); @@ -684,7 +685,7 @@ public async Task TestRecordMaintainsUpstreamOverrideHostHeader(string upstreamH httpContext.Request.Method = "GET"; - var upstreamRequest = testRecordingHandler.CreateUpstreamRequest(httpContext.Request, new byte[] { }); + var upstreamRequest = testRecordingHandler.CreateUpstreamRequest(httpContext.Request); if (!String.IsNullOrWhiteSpace(upstreamHostHeaderValue)) { @@ -696,6 +697,52 @@ public async Task TestRecordMaintainsUpstreamOverrideHostHeader(string upstreamH } } + [Fact] + public async Task TestRecordWithGZippedContent() + { + var httpContext = new DefaultHttpContext(); + var bodyBytes = Encoding.UTF8.GetBytes("{\"hello\":\"world\"}"); + var mockClient = new HttpClient(new MockHttpHandler(bodyBytes, "application/json", "gzip")); + var path = Directory.GetCurrentDirectory(); + var recordingHandler = new RecordingHandler(path) + { + RedirectableClient = mockClient, + RedirectlessClient = mockClient + }; + + var relativePath = "recordings/gzip"; + var fullPathToRecording = Path.Combine(path, relativePath) + ".json"; + + await recordingHandler.StartRecordingAsync(relativePath, httpContext.Response); + + var recordingId = httpContext.Response.Headers["x-recording-id"].ToString(); + + httpContext.Request.ContentType = "application/json"; + httpContext.Request.Headers["Content-Encoding"] = "gzip"; + httpContext.Request.ContentLength = 0; + httpContext.Request.Headers["x-recording-id"] = recordingId; + httpContext.Request.Headers["x-recording-upstream-base-uri"] = "http://example.org"; + httpContext.Request.Method = "GET"; + httpContext.Request.Body = new MemoryStream(GZipUtilities.CompressBody(bodyBytes, httpContext.Request.Headers)); + + await recordingHandler.HandleRecordRequestAsync(recordingId, httpContext.Request, httpContext.Response); + recordingHandler.StopRecording(recordingId); + + try + { + using var fileStream = File.Open(fullPathToRecording, FileMode.Open); + using var doc = JsonDocument.Parse(fileStream); + var record = RecordSession.Deserialize(doc.RootElement); + var entry = record.Entries.First(); + Assert.Equal("{\"hello\":\"world\"}", Encoding.UTF8.GetString(entry.Request.Body)); + Assert.Equal("{\"hello\":\"world\"}", Encoding.UTF8.GetString(entry.Response.Body)); + } + finally + { + File.Delete(fullPathToRecording); + } + } + #region SetRecordingOptions [Theory] [InlineData("{ \"HandleRedirects\": \"true\"}", true)] @@ -979,17 +1026,38 @@ public IgnoreOnLinuxFact() internal class MockHttpHandler : HttpMessageHandler { public const string DefaultResponse = "default response"; + private readonly byte[] _responseContent; + private readonly string _contentType; + private readonly string _contentEncoding; - public MockHttpHandler() + public MockHttpHandler(byte[] responseContent = default, string contentType = default, string contentEncoding = default) { + _responseContent = responseContent ?? Encoding.UTF8.GetBytes(DefaultResponse); + _contentType = contentType ?? "application/json"; + _contentEncoding = contentEncoding; } + protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { + var response = new HttpResponseMessage(HttpStatusCode.OK); + + // we need to set the content before the content headers as otherwise they will be cleared out after setting content. + if (_contentEncoding == "gzip") + { + response.Content = new ByteArrayContent(GZipUtilities.CompressBodyCore(_responseContent)); + } + else + { + response.Content = new ByteArrayContent(_responseContent); + } - return Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK) + response.Content.Headers.ContentType = new MediaTypeHeaderValue(_contentType); + if (_contentEncoding != null) { - Content = new StringContent(DefaultResponse) - }); + response.Content.Headers.ContentEncoding.Add(_contentEncoding); + } + + return Task.FromResult(response); } } } diff --git a/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/Test.RecordEntries/request_response_with_gzipped_content.json b/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/Test.RecordEntries/request_response_with_gzipped_content.json new file mode 100644 index 00000000000..219dc76c031 --- /dev/null +++ b/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/Test.RecordEntries/request_response_with_gzipped_content.json @@ -0,0 +1,48 @@ +{ + "Entries": [ + { + "RequestUri": "https://fakeazsdktestaccount.table.core.windows.net/Tables", + "RequestMethod": "POST", + "RequestHeaders": { + "Accept": "application/json;odata=minimalmetadata", + "Accept-Encoding": "gzip, deflate", + "Authorization": "Sanitized", + "Connection": "keep-alive", + "Content-Length": "34", + "Content-Type": "application/json", + "Content-Encoding": "gzip", + "DataServiceVersion": "3.0", + "Date": "Tue, 18 May 2021 23:27:42 GMT", + "User-Agent": "azsdk-python-data-tables/12.0.0b7 Python/3.8.6 (Windows-10-10.0.19041-SP0)", + "x-ms-client-request-id": "a4c24b7a-b830-11eb-a05e-10e7c6392c5a", + "x-ms-date": "Tue, 18 May 2021 23:27:42 GMT", + "x-ms-version": "2019-02-02" + }, + "RequestBody": "{\u0022TableName\u0022: \u0022listtable09bf2a3d\u0022}", + "StatusCode": 201, + "ResponseHeaders": { + "Cache-Control": "no-cache", + "Content-Type": "application/json", + "Content-Encoding": "gzip", + "Date": "Tue, 18 May 2021 23:27:43 GMT", + "Retry-After": "10", + "Location": "https://fakeazsdktestaccount.table.core.windows.net/Tables(\u0027listtable09bf2a3d\u0027)", + "Server": [ + "Windows-Azure-Table/1.0", + "Microsoft-HTTPAPI/2.0" + ], + "Transfer-Encoding": "chunked", + "X-Content-Type-Options": "nosniff", + "x-ms-client-request-id": "a4c24b7a-b830-11eb-a05e-10e7c6392c5a", + "x-ms-request-id": "d2270777-c002-0072-313d-4ce19f000000", + "x-ms-version": "2019-02-02" + }, + "ResponseBody": { + "odata.metadata": "https://fakeazsdktestaccount.table.core.windows.net/$metadata#Tables/@Element", + "TableName": "listtable09bf2a3d", + "connectionString": null + } + } + ], + "Variables": {} +} diff --git a/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Common/GZipUtilities.cs b/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Common/GZipUtilities.cs new file mode 100644 index 00000000000..be92b5a0888 --- /dev/null +++ b/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Common/GZipUtilities.cs @@ -0,0 +1,80 @@ +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; +using System.Linq; +using System.Net.Http.Headers; +using Microsoft.AspNetCore.Http; + +namespace Azure.Sdk.Tools.TestProxy.Common +{ + /// + /// Utility methods to compress and decompress content to/from GZip. + /// + public static class GZipUtilities + { + private const string Gzip = "gzip"; + private const string ContentEncoding = "Content-Encoding"; + + public static byte[] CompressBody(byte[] incomingBody, IDictionary headers) + { + if (headers.TryGetValue(ContentEncoding, out var values) && values.Contains(Gzip)) + { + return CompressBodyCore(incomingBody); + } + + return incomingBody; + } + + public static byte[] CompressBody(byte[] incomingBody, IHeaderDictionary headers) + { + if (headers.TryGetValue(ContentEncoding, out var values) && values.Contains(Gzip)) + { + return CompressBodyCore(incomingBody); + } + + return incomingBody; + } + + public static byte[] CompressBodyCore(byte[] body) + { + using (var uncompressedStream = new MemoryStream(body)) + using (var resultStream = new MemoryStream()) + { + using (var compressedStream = new GZipStream(resultStream, CompressionMode.Compress)) + { + uncompressedStream.CopyTo(compressedStream); + } + + return resultStream.ToArray(); + } + } + + public static byte[] DecompressBody(MemoryStream incomingBody, HttpContentHeaders headers) + { + if (headers.TryGetValues(ContentEncoding, out var values) && values.Contains(Gzip)) + { + return DecompressBodyCore(incomingBody); + } + + return incomingBody.ToArray(); + } + + public static byte[] DecompressBody(byte[] incomingBody, IHeaderDictionary headers) + { + if (headers.TryGetValue(ContentEncoding, out var values) && values.Contains(Gzip)) + { + return DecompressBodyCore(new MemoryStream(incomingBody)); + } + + return incomingBody; + } + + private static byte[] DecompressBodyCore(MemoryStream stream) + { + using var uncompressedStream = new GZipStream(stream, CompressionMode.Decompress); + using var resultStream = new MemoryStream(); + uncompressedStream.CopyTo(resultStream); + return resultStream.ToArray(); + } + } +} \ No newline at end of file diff --git a/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Properties/launchSettings.json b/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Properties/launchSettings.json index 5341eaf6eca..3bc93e560a3 100644 --- a/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Properties/launchSettings.json +++ b/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Properties/launchSettings.json @@ -10,7 +10,6 @@ "profiles": { "Azure.Sdk.Tools.TestProxy": { "commandName": "Project", - "commandLineArgs": "--help", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development", "Logging__LogLevel__Microsoft": "Information" diff --git a/tools/test-proxy/Azure.Sdk.Tools.TestProxy/RecordingHandler.cs b/tools/test-proxy/Azure.Sdk.Tools.TestProxy/RecordingHandler.cs index 53856c0281e..cd7d0233898 100644 --- a/tools/test-proxy/Azure.Sdk.Tools.TestProxy/RecordingHandler.cs +++ b/tools/test-proxy/Azure.Sdk.Tools.TestProxy/RecordingHandler.cs @@ -200,7 +200,7 @@ public async Task HandleRecordRequestAsync(string recordingId, HttpRequest incom var entry = await CreateEntryAsync(incomingRequest).ConfigureAwait(false); - var upstreamRequest = CreateUpstreamRequest(incomingRequest, entry.Request.Body); + var upstreamRequest = CreateUpstreamRequest(incomingRequest); HttpResponseMessage upstreamResponse = null; @@ -218,7 +218,7 @@ public async Task HandleRecordRequestAsync(string recordingId, HttpRequest incom // HEAD requests do NOT have a body regardless of the value of the Content-Length header if (incomingRequest.Method.ToUpperInvariant() != "HEAD") { - body = DecompressBody((MemoryStream)await upstreamResponse.Content.ReadAsStreamAsync().ConfigureAwait(false), upstreamResponse.Content.Headers); + body = GZipUtilities.DecompressBody((MemoryStream)await upstreamResponse.Content.ReadAsStreamAsync().ConfigureAwait(false), upstreamResponse.Content.Headers); } entry.Response.Body = body.Length == 0 ? null : body; @@ -250,7 +250,7 @@ public async Task HandleRecordRequestAsync(string recordingId, HttpRequest incom if (entry.Response.Body?.Length > 0) { - var bodyData = CompressBody(entry.Response.Body, entry.Response.Headers); + var bodyData = GZipUtilities.CompressBody(entry.Response.Body, entry.Response.Headers); outgoingResponse.ContentLength = bodyData.Length; await outgoingResponse.Body.WriteAsync(bodyData).ConfigureAwait(false); } @@ -290,51 +290,12 @@ public static EntryRecordMode GetRecordMode(HttpRequest request) return mode; } - private byte[] CompressBody(byte[] incomingBody, SortedDictionary headers) - { - if (headers.TryGetValue("Content-Encoding", out var values)) - { - if (values.Contains("gzip")) - { - using (var uncompressedStream = new MemoryStream(incomingBody)) - using (var resultStream = new MemoryStream()) - { - using (var compressedStream = new GZipStream(resultStream, CompressionMode.Compress)) - { - uncompressedStream.CopyTo(compressedStream); - } - return resultStream.ToArray(); - } - } - } - - return incomingBody; - } - - private byte[] DecompressBody(MemoryStream incomingBody, HttpContentHeaders headers) - { - if (headers.TryGetValues("Content-Encoding", out var values)) - { - if (values.Contains("gzip")) - { - using (var uncompressedStream = new GZipStream(incomingBody, CompressionMode.Decompress)) - using (var resultStream = new MemoryStream()) - { - uncompressedStream.CopyTo(resultStream); - return resultStream.ToArray(); - } - } - } - - return incomingBody.ToArray(); - } - - public HttpRequestMessage CreateUpstreamRequest(HttpRequest incomingRequest, byte[] incomingBody) + public HttpRequestMessage CreateUpstreamRequest(HttpRequest incomingRequest) { var upstreamRequest = new HttpRequestMessage(); upstreamRequest.RequestUri = GetRequestUri(incomingRequest); upstreamRequest.Method = new HttpMethod(incomingRequest.Method); - upstreamRequest.Content = new ReadOnlyMemoryContent(incomingBody); + upstreamRequest.Content = new StreamContent(incomingRequest.Body); foreach (var header in incomingRequest.Headers) { @@ -484,7 +445,7 @@ public async Task HandlePlaybackRequest(string recordingId, HttpRequest incoming if (match.Response.Body?.Length > 0) { - var bodyData = CompressBody(match.Response.Body, match.Response.Headers); + var bodyData = GZipUtilities.CompressBody(match.Response.Body, match.Response.Headers); outgoingResponse.ContentLength = bodyData.Length; @@ -506,7 +467,9 @@ public static async Task CreateEntryAsync(HttpRequest request) } } - entry.Request.Body = await ReadAllBytes(request.Body).ConfigureAwait(false); + byte[] bytes = await ReadAllBytes(request.Body).ConfigureAwait(false); + + entry.Request.Body = GZipUtilities.DecompressBody(bytes, request.Headers); return entry; } From e8f30e57ef95b399722eb5d1029260a0267b3a4b Mon Sep 17 00:00:00 2001 From: JoshLove-msft <54595583+JoshLove-msft@users.noreply.github.com> Date: Mon, 19 Sep 2022 16:29:56 -0700 Subject: [PATCH 2/5] Flush GZipStream when compressing. --- .../Common/GZipUtilities.cs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Common/GZipUtilities.cs b/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Common/GZipUtilities.cs index be92b5a0888..6b4326781b8 100644 --- a/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Common/GZipUtilities.cs +++ b/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Common/GZipUtilities.cs @@ -37,16 +37,14 @@ public static byte[] CompressBody(byte[] incomingBody, IHeaderDictionary headers public static byte[] CompressBodyCore(byte[] body) { - using (var uncompressedStream = new MemoryStream(body)) - using (var resultStream = new MemoryStream()) + using var uncompressedStream = new MemoryStream(body); + using var resultStream = new MemoryStream(); + using (var compressedStream = new GZipStream(resultStream, CompressionMode.Compress)) { - using (var compressedStream = new GZipStream(resultStream, CompressionMode.Compress)) - { - uncompressedStream.CopyTo(compressedStream); - } - - return resultStream.ToArray(); + uncompressedStream.CopyTo(compressedStream); + compressedStream.Flush(); } + return resultStream.ToArray(); } public static byte[] DecompressBody(MemoryStream incomingBody, HttpContentHeaders headers) From 1f9b7e77068d689540575866e08eb7b96812178a Mon Sep 17 00:00:00 2001 From: JoshLove-msft <54595583+JoshLove-msft@users.noreply.github.com> Date: Mon, 19 Sep 2022 16:39:00 -0700 Subject: [PATCH 3/5] Removing flush call - not needed for Test Proxy target platforms --- .../test-proxy/Azure.Sdk.Tools.TestProxy/Common/GZipUtilities.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Common/GZipUtilities.cs b/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Common/GZipUtilities.cs index 6b4326781b8..84623ee8b1a 100644 --- a/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Common/GZipUtilities.cs +++ b/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Common/GZipUtilities.cs @@ -42,7 +42,6 @@ public static byte[] CompressBodyCore(byte[] body) using (var compressedStream = new GZipStream(resultStream, CompressionMode.Compress)) { uncompressedStream.CopyTo(compressedStream); - compressedStream.Flush(); } return resultStream.ToArray(); } From 93452c7808de42bced27b547e75c243539cf4fd2 Mon Sep 17 00:00:00 2001 From: scbedd <45376673+scbedd@users.noreply.github.com> Date: Wed, 21 Sep 2022 16:39:57 -0700 Subject: [PATCH 4/5] repair record mode operation. we were exhausting the request body stream. --- .../RecordingHandlerTests.cs | 4 ++-- .../Azure.Sdk.Tools.TestProxy/RecordingHandler.cs | 6 +++--- 2 files changed, 5 insertions(+), 5 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 a1ff192052b..09c24facd4a 100644 --- a/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/RecordingHandlerTests.cs +++ b/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/RecordingHandlerTests.cs @@ -633,7 +633,7 @@ public void TestCreateUpstreamRequestIncludesExpectedHeaders(params string[] inc var recordingHandler = new RecordingHandler(Directory.GetCurrentDirectory()); var upstreamRequestContext = GenerateHttpRequestContext(incomingHeaders); - var output = recordingHandler.CreateUpstreamRequest(upstreamRequestContext.Request); + var output = recordingHandler.CreateUpstreamRequest(upstreamRequestContext.Request, new byte[] { }); // iterate across the set we know about and confirm that GenerateUpstreamRequest worked properly! var setOfHeaders = GenerateHeaderValuesTuples(incomingHeaders); @@ -685,7 +685,7 @@ public async Task TestRecordMaintainsUpstreamOverrideHostHeader(string upstreamH httpContext.Request.Method = "GET"; - var upstreamRequest = testRecordingHandler.CreateUpstreamRequest(httpContext.Request); + var upstreamRequest = testRecordingHandler.CreateUpstreamRequest(httpContext.Request, new byte[] { }); if (!String.IsNullOrWhiteSpace(upstreamHostHeaderValue)) { diff --git a/tools/test-proxy/Azure.Sdk.Tools.TestProxy/RecordingHandler.cs b/tools/test-proxy/Azure.Sdk.Tools.TestProxy/RecordingHandler.cs index cd7d0233898..563cc513767 100644 --- a/tools/test-proxy/Azure.Sdk.Tools.TestProxy/RecordingHandler.cs +++ b/tools/test-proxy/Azure.Sdk.Tools.TestProxy/RecordingHandler.cs @@ -200,7 +200,7 @@ public async Task HandleRecordRequestAsync(string recordingId, HttpRequest incom var entry = await CreateEntryAsync(incomingRequest).ConfigureAwait(false); - var upstreamRequest = CreateUpstreamRequest(incomingRequest); + var upstreamRequest = CreateUpstreamRequest(incomingRequest, GZipUtilities.CompressBody(entry.Request.Body, entry.Request.Headers)); HttpResponseMessage upstreamResponse = null; @@ -290,12 +290,12 @@ public static EntryRecordMode GetRecordMode(HttpRequest request) return mode; } - public HttpRequestMessage CreateUpstreamRequest(HttpRequest incomingRequest) + public HttpRequestMessage CreateUpstreamRequest(HttpRequest incomingRequest, byte[] incomingBody) { var upstreamRequest = new HttpRequestMessage(); upstreamRequest.RequestUri = GetRequestUri(incomingRequest); upstreamRequest.Method = new HttpMethod(incomingRequest.Method); - upstreamRequest.Content = new StreamContent(incomingRequest.Body); + upstreamRequest.Content = new ReadOnlyMemoryContent(incomingBody); foreach (var header in incomingRequest.Headers) { From fe31843227da7ba87ae32afc1d0503138c04d44f Mon Sep 17 00:00:00 2001 From: JoshLove-msft <54595583+JoshLove-msft@users.noreply.github.com> Date: Wed, 21 Sep 2022 16:58:44 -0700 Subject: [PATCH 5/5] Update mock handler --- .../RecordingHandlerTests.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 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 a1ff192052b..70e7677a4a3 100644 --- a/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/RecordingHandlerTests.cs +++ b/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/RecordingHandlerTests.cs @@ -1037,8 +1037,11 @@ public MockHttpHandler(byte[] responseContent = default, string contentType = de _contentEncoding = contentEncoding; } - protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { + // should not throw as stream should not be disposed + var content = await request.Content.ReadAsStringAsync(); + Assert.NotEmpty(content); var response = new HttpResponseMessage(HttpStatusCode.OK); // we need to set the content before the content headers as otherwise they will be cleared out after setting content. @@ -1057,7 +1060,7 @@ protected override Task SendAsync(HttpRequestMessage reques response.Content.Headers.ContentEncoding.Add(_contentEncoding); } - return Task.FromResult(response); + return response; } } }