From 2520f577ba2f8d78bab097c8a8e4f944639a5452 Mon Sep 17 00:00:00 2001 From: Matt Ellis Date: Tue, 25 May 2021 13:53:39 -0700 Subject: [PATCH] [Core] Don't throw from `Response.Content` if memory stream is private Relax our constraint that the underlying buffer of the MemoryStream backing a buffered response be publicly visible. There are cases today where `RequestBodyPolicy` will not allocate a new MemoryStream. One example is if the response stream is already seekable (as is the case in our PlaybackTransport) nd we've observed that there are likely cases where `HttpClient` itself may use a MemoryStream as the response stream without allowing the underling buffer to be exposed. In cases where we can not extract the underlying body, just make a copy of it. Since we know the underlying stream is a memory stream, we don't need to worry about hidden IO. Fixes #21048 --- sdk/core/Azure.Core/CHANGELOG.md | 4 ++++ sdk/core/Azure.Core/src/Response.cs | 2 +- sdk/core/Azure.Core/tests/ResponseTests.cs | 9 ++++++--- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/sdk/core/Azure.Core/CHANGELOG.md b/sdk/core/Azure.Core/CHANGELOG.md index d448e3d13166d..f15313457678d 100644 --- a/sdk/core/Azure.Core/CHANGELOG.md +++ b/sdk/core/Azure.Core/CHANGELOG.md @@ -6,6 +6,10 @@ - Types to represent `GeoJson` primitives. +### Changed + +- `Response.Content` no longer throws `InvalidOperationException` when the response is backed by a `MemoryStream` with a non publicly visible buffer. + ## 1.14.0 (2021-05-11) ### Features Added diff --git a/sdk/core/Azure.Core/src/Response.cs b/sdk/core/Azure.Core/src/Response.cs index a1d9c20680b02..af2c3596a955a 100644 --- a/sdk/core/Azure.Core/src/Response.cs +++ b/sdk/core/Azure.Core/src/Response.cs @@ -72,7 +72,7 @@ public virtual BinaryData Content } else { - throw new InvalidOperationException($"The {nameof(ContentStream)}'s internal buffer cannot be accessed."); + return new BinaryData(memoryContent.ToArray()); } } } diff --git a/sdk/core/Azure.Core/tests/ResponseTests.cs b/sdk/core/Azure.Core/tests/ResponseTests.cs index cf2d906ad34e9..4ed4373797bc9 100644 --- a/sdk/core/Azure.Core/tests/ResponseTests.cs +++ b/sdk/core/Azure.Core/tests/ResponseTests.cs @@ -123,12 +123,15 @@ public void ContentPropertyThrowsForNonMemoryStream() Assert.Throws(() => { BinaryData d = response.Content; }); } - public void ContentPropertyThrowsForNotExposableMemoryStream() + [Test] + public void ContentPropertyWorksForMemoryStreamsWithPrivateBuffers() { var response = new MockResponse(200); - response.ContentStream = new MemoryStream(new byte[100], 0, 100, writable: false, publiclyVisible: false); + var responseBody = new byte[100]; + response.ContentStream = new MemoryStream(responseBody, 0, responseBody.Length, writable: false, publiclyVisible: false); - Assert.Throws(() => { BinaryData d = response.Content; }); + Assert.DoesNotThrow(() => { BinaryData d = response.Content; }); + CollectionAssert.AreEqual(responseBody, response.Content.ToArray()); } internal class TestPayload