diff --git a/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/RecordSessionTests.cs b/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/RecordSessionTests.cs index 03d3e12bd6a..4e5a8ee765b 100644 --- a/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/RecordSessionTests.cs +++ b/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/RecordSessionTests.cs @@ -7,16 +7,13 @@ using System.IO; using System.Linq; using System.Text; -using System.Text.Encodings.Web; using System.Text.Json; using System.Threading.Tasks; using Azure.Core; using Azure.Core.Pipeline; using Azure.Sdk.Tools.TestProxy.Common; using Microsoft.AspNetCore.Http; -using Microsoft.VisualBasic; -using Moq; -using NuGet.ContentModel; +using Microsoft.AspNetCore.Http.Features; using Xunit; namespace Azure.Sdk.Tools.TestProxy.Tests @@ -175,6 +172,71 @@ public async Task CanRoundTripDockerDigest() Assert.Equal(sampleExpected, content); } + [Fact] + public async Task CheckDigestNotNormalized() + { + var session = TestHelpers.LoadRecordSession("Test.RecordEntries/response_with_content_digest.json"); + + DefaultHttpContext ctx = new DefaultHttpContext(); + DefaultHttpContext requestCtx = new DefaultHttpContext(); + + var handler = new RecordingHandler(Directory.GetCurrentDirectory()); + var guid = Guid.NewGuid().ToString(); + + handler.PlaybackSessions.AddOrUpdate( + guid, + session, + (key, oldValue) => session + ); + + // we know that on disk and when loaded from memory these bytes are totally untouached + // we need to make certain this is the case during matching as well + var untouchedBytes = session.Session.Entries[1].Request.Body; + + // define all this stuff where it's easy to observe it + var testEntry = new RecordEntry() + { + RequestUri = "\"https://Sanitized.azurecr.io/v2/hello-world/manifests/test", + RequestMethod = RequestMethod.Put, + Request = new RequestOrResponse() + { + Headers = new SortedDictionary() + { + { "Accept", new string[]{ "application/json" } }, + { "Accept-Encoding", new string[]{ "gzip" } }, + { "Authorization", new string[]{ "Sanitized" } }, + { "Content-Length", new string[] { "11387" } }, + { "User-Agent", new string[]{ "azsdk-go-azcontainerregistry/v0.2.2 (go1.22.2; Windows_NT)" } }, + { "Content-Type", new string[] { "application/vnd.oci.image.index.v1+json" } }, + { "x-recording-upstream-base-uri", new string[] { "https://Sanitized.azurecr.io" } } + }, + Body = untouchedBytes, + } + }; + + // now pull it into where it HAS to be, but is a fairly awkward preparation + var httpRequest = requestCtx.Request; + var httpResponse = requestCtx.Response; + httpRequest.Method = testEntry.RequestMethod.ToString(); + httpRequest.Scheme = "https"; + httpRequest.Host = new HostString("Sanitized.azurecr.io"); + httpRequest.Path = "/v2/hello-world/manifests/test"; + foreach (var header in testEntry.Request.Headers) + { + httpRequest.Headers[header.Key] = header.Value; + } + httpRequest.Body = new MemoryStream(testEntry.Request.Body); + + var requestFeature = requestCtx.Features.Get(); + if (requestFeature != null) + { + requestFeature.RawTarget = httpRequest.Path; + } + + // if we successfully match, the test is working as expected + await handler.HandlePlaybackRequest(guid, httpRequest, httpResponse); + } + [Fact] public void EnsureJsonEscaping() { diff --git a/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/Test.RecordEntries/response_with_content_digest.json b/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/Test.RecordEntries/response_with_content_digest.json index f89b903eeb9..5f69daf95c7 100644 --- a/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/Test.RecordEntries/response_with_content_digest.json +++ b/tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/Test.RecordEntries/response_with_content_digest.json @@ -10,7 +10,7 @@ ], "Accept-Encoding": "gzip", "Authorization": "Sanitized", - "User-Agent": "azsdk-go-azcontainerregistry/v0.2.2 (go1.22.2; Windows_NT)" + "User-Agent": "azsdk-go-azcontainerregistry/v0.2.2 (go1.21.6; linux)" }, "RequestBody": null, "StatusCode": 200, @@ -24,7 +24,7 @@ "Connection": "keep-alive", "Content-Length": "528", "Content-Type": "application/vnd.docker.distribution.manifest.v2+json", - "Date": "Wed, 22 May 2024 20:40:43 GMT", + "Date": "Fri, 17 May 2024 21:42:34 GMT", "Docker-Content-Digest": "sha256:93d5a28ff72d288d69b5997b8ba47396d2cbb62a72b5d87cd3351094b5d578a0", "Docker-Distribution-Api-Version": "registry/2.0", "ETag": "\"sha256:93d5a28ff72d288d69b5997b8ba47396d2cbb62a72b5d87cd3351094b5d578a0\"", @@ -35,22 +35,62 @@ ], "X-Content-Type-Options": "nosniff", "X-Ms-Client-Request-Id": "", - "X-Ms-Correlation-Request-Id": "19affbee-3510-45b1-8248-9dc23982613b", + "X-Ms-Correlation-Request-Id": "caf56438-d3ba-469d-a30c-360a4ff536c1", "X-Ms-Request-Id": "Sanitized" }, + "ResponseBody": "ewogICAic2NoZW1hVmVyc2lvbiI6IDIsCiAgICJtZWRpYVR5cGUiOiAiYXBwbGljYXRpb24vdm5kLmRvY2tlci5kaXN0cmlidXRpb24ubWFuaWZlc3QudjIranNvbiIsCiAgICJjb25maWciOiB7CiAgICAgICJtZWRpYVR5cGUiOiAiYXBwbGljYXRpb24vdm5kLmRvY2tlci5jb250YWluZXIuaW1hZ2UudjEranNvbiIsCiAgICAgICJzaXplIjogMTQ3MiwKICAgICAgImRpZ2VzdCI6ICJzaGEyNTY6MDQyYTgxNjgwOWFhYzhkMGY3ZDdjYWNhYzc5NjU3ODJlZTJlY2FjM2YyMWJjZjlmMjRiMWRlMWE3Mzg3Yjc2OSIKICAgfSwKICAgImxheWVycyI6IFsKICAgICAgewogICAgICAgICAibWVkaWFUeXBlIjogImFwcGxpY2F0aW9uL3ZuZC5kb2NrZXIuaW1hZ2Uucm9vdGZzLmRpZmYudGFyLmd6aXAiLAogICAgICAgICAic2l6ZSI6IDMzNzA2MjgsCiAgICAgICAgICJkaWdlc3QiOiAic2hhMjU2Ojg5MjFkYjI3ZGYyODMxZmE2ZWFhODUzMjEyMDVhMjQ3MGM2NjliODU1ZjNlYzk1ZDVhM2MyYjQ2ZGUwNDQyYzkiCiAgICAgIH0KICAgXQp9" + }, + { + "RequestUri": "https://Sanitized.azurecr.io/v2/hello-world/manifests/test", + "RequestMethod": "PUT", + "RequestHeaders": { + "Accept": "application/json", + "Accept-Encoding": "gzip", + "Authorization": "Sanitized", + "Content-Length": "11387", + "Content-Type": "application/vnd.oci.image.index.v1+json", + "User-Agent": "azsdk-go-azcontainerregistry/v0.2.2 (go1.22.2; Windows_NT)" + }, + "RequestBody": "eyJtYW5pZmVzdHMiOlt7ImFubm90YXRpb25zIjp7ImNvbS5kb2NrZXIub2ZmaWNpYWwtaW1hZ2VzLmJhc2hicmV3LmFyY2giOiJhbWQ2NCIsIm9yZy5vcGVuY29udGFpbmVycy5pbWFnZS5yZXZpc2lvbiI6IjNmYjZlYmNhNDE2M2JmNWI5Y2M0OTZhYzNlOGYxMWNiMWU3NTRhZWUiLCJvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2Uuc291cmNlIjoiaHR0cHM6XC9cL2dpdGh1Yi5jb21cL2RvY2tlci1saWJyYXJ5XC9oZWxsby13b3JsZC5naXQjM2ZiNmViY2E0MTYzYmY1YjljYzQ5NmFjM2U4ZjExY2IxZTc1NGFlZTphbWQ2NFwvaGVsbG8td29ybGQiLCJvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudXJsIjoiaHR0cHM6XC9cL2h1Yi5kb2NrZXIuY29tXC9fXC9oZWxsby13b3JsZCIsIm9yZy5vcGVuY29udGFpbmVycy5pbWFnZS52ZXJzaW9uIjoibGludXgifSwiZGlnZXN0Ijoic2hhMjU2OmUyZmM0ZTUwMTJkMTZlN2ZlNDY2ZjUyOTFjNDc2NDMxYmVhYTFmOWI5MGE1YzIxMjViNDkzZWQyOGUyYWJhNTciLCJtZWRpYVR5cGUiOiJhcHBsaWNhdGlvblwvdm5kLm9jaS5pbWFnZS5tYW5pZmVzdC52MStqc29uIiwicGxhdGZvcm0iOnsiYXJjaGl0ZWN0dXJlIjoiYW1kNjQiLCJvcyI6ImxpbnV4In0sInNpemUiOjg2MX0seyJhbm5vdGF0aW9ucyI6eyJjb20uZG9ja2VyLm9mZmljaWFsLWltYWdlcy5iYXNoYnJldy5hcmNoIjoiYW1kNjQiLCJ2bmQuZG9ja2VyLnJlZmVyZW5jZS5kaWdlc3QiOiJzaGEyNTY6ZTJmYzRlNTAxMmQxNmU3ZmU0NjZmNTI5MWM0NzY0MzFiZWFhMWY5YjkwYTVjMjEyNWI0OTNlZDI4ZTJhYmE1NyIsInZuZC5kb2NrZXIucmVmZXJlbmNlLnR5cGUiOiJhdHRlc3RhdGlvbi1tYW5pZmVzdCJ9LCJkaWdlc3QiOiJzaGEyNTY6NTc5YjM3MjRhN2IxODlmNmRjYTU5OWE0NmYxNmQ4MDFhNDNkNWRlZjE4NWRlMGI3YmNkNWZiOWQxZTMxMmMyNyIsIm1lZGlhVHlwZSI6ImFwcGxpY2F0aW9uXC92bmQub2NpLmltYWdlLm1hbmlmZXN0LnYxK2pzb24iLCJwbGF0Zm9ybSI6eyJhcmNoaXRlY3R1cmUiOiJ1bmtub3duIiwib3MiOiJ1bmtub3duIn0sInNpemUiOjgzN30seyJhbm5vdGF0aW9ucyI6eyJjb20uZG9ja2VyLm9mZmljaWFsLWltYWdlcy5iYXNoYnJldy5hcmNoIjoiYXJtMzJ2NSIsIm9yZy5vcGVuY29udGFpbmVycy5pbWFnZS5yZXZpc2lvbiI6IjNmYjZlYmNhNDE2M2JmNWI5Y2M0OTZhYzNlOGYxMWNiMWU3NTRhZWUiLCJvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2Uuc291cmNlIjoiaHR0cHM6XC9cL2dpdGh1Yi5jb21cL2RvY2tlci1saWJyYXJ5XC9oZWxsby13b3JsZC5naXQjM2ZiNmViY2E0MTYzYmY1YjljYzQ5NmFjM2U4ZjExY2IxZTc1NGFlZTphcm0zMnY1XC9oZWxsby13b3JsZCIsIm9yZy5vcGVuY29udGFpbmVycy5pbWFnZS51cmwiOiJodHRwczpcL1wvaHViLmRvY2tlci5jb21cL19cL2hlbGxvLXdvcmxkIiwib3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlcnNpb24iOiJsaW51eCJ9LCJkaWdlc3QiOiJzaGEyNTY6YzJkODkxZTVjMmZiNGM3MjNlZmI3MmIwNjRiZTMzNTExODlmNjIyMjJiZDM2ODFjZTdlNTdmMmExNTI3MzYyYyIsIm1lZGlhVHlwZSI6ImFwcGxpY2F0aW9uXC92bmQub2NpLmltYWdlLm1hbmlmZXN0LnYxK2pzb24iLCJwbGF0Zm9ybSI6eyJhcmNoaXRlY3R1cmUiOiJhcm0iLCJvcyI6ImxpbnV4IiwidmFyaWFudCI6InY1In0sInNpemUiOjg2M30seyJhbm5vdGF0aW9ucyI6eyJjb20uZG9ja2VyLm9mZmljaWFsLWltYWdlcy5iYXNoYnJldy5hcmNoIjoiYXJtMzJ2NSIsInZuZC5kb2NrZXIucmVmZXJlbmNlLmRpZ2VzdCI6InNoYTI1NjpjMmQ4OTFlNWMyZmI0YzcyM2VmYjcyYjA2NGJlMzM1MTE4OWY2MjIyMmJkMzY4MWNlN2U1N2YyYTE1MjczNjJjIiwidm5kLmRvY2tlci5yZWZlcmVuY2UudHlwZSI6ImF0dGVzdGF0aW9uLW1hbmlmZXN0In0sImRpZ2VzdCI6InNoYTI1Njo2OTAxZDZhODhlZWU2ZTkwZjBiYWE2MmIwMjBiYjYxYzRmMTMxOTRjYmNkOWJmNTY4YWI2NmU4Y2MzZjk0MGRkIiwibWVkaWFUeXBlIjoiYXBwbGljYXRpb25cL3ZuZC5vY2kuaW1hZ2UubWFuaWZlc3QudjEranNvbiIsInBsYXRmb3JtIjp7ImFyY2hpdGVjdHVyZSI6InVua25vd24iLCJvcyI6InVua25vd24ifSwic2l6ZSI6NTY2fSx7ImFubm90YXRpb25zIjp7ImNvbS5kb2NrZXIub2ZmaWNpYWwtaW1hZ2VzLmJhc2hicmV3LmFyY2giOiJhcm0zMnY2Iiwib3JnLm9wZW5jb250YWluZXJzLmltYWdlLmJhc2UubmFtZSI6InNjcmF0Y2giLCJvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UuY3JlYXRlZCI6IjIwMjQtMDMtMTFUMjI6NDk6MTlaIiwib3JnLm9wZW5jb250YWluZXJzLmltYWdlLnJldmlzaW9uIjoiNjFmM2JhMjZmZTFkMDI3YjViNDQzYzA0YWMyYjA2OTBmZDk3NTYxYSIsIm9yZy5vcGVuY29udGFpbmVycy5pbWFnZS5zb3VyY2UiOiJodHRwczpcL1wvZ2l0aHViLmNvbVwvZG9ja2VyLWxpYnJhcnlcL2hlbGxvLXdvcmxkLmdpdCM2MWYzYmEyNmZlMWQwMjdiNWI0NDNjMDRhYzJiMDY5MGZkOTc1NjFhOmFybTMydjZcL2hlbGxvLXdvcmxkIiwib3JnLm9wZW5jb250YWluZXJzLmltYWdlLnVybCI6Imh0dHBzOlwvXC9odWIuZG9ja2VyLmNvbVwvX1wvaGVsbG8td29ybGQiLCJvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudmVyc2lvbiI6ImxpbnV4In0sImRpZ2VzdCI6InNoYTI1NjoxMzYzYzgxMGNjMzlhNTYzYzZmMzE1ZTI2OTUxZDJlZDllOTNmM2JmOTI5ZmRlODIyMzYzM2VjZjgxYTRhNDMwIiwibWVkaWFUeXBlIjoiYXBwbGljYXRpb25cL3ZuZC5vY2kuaW1hZ2UubWFuaWZlc3QudjEranNvbiIsInBsYXRmb3JtIjp7ImFyY2hpdGVjdHVyZSI6ImFybSIsIm9zIjoibGludXgiLCJ2YXJpYW50IjoidjYifSwic2l6ZSI6MTAzOX0seyJhbm5vdGF0aW9ucyI6eyJjb20uZG9ja2VyLm9mZmljaWFsLWltYWdlcy5iYXNoYnJldy5hcmNoIjoiYXJtMzJ2NiIsInZuZC5kb2NrZXIucmVmZXJlbmNlLmRpZ2VzdCI6InNoYTI1NjoxMzYzYzgxMGNjMzlhNTYzYzZmMzE1ZTI2OTUxZDJlZDllOTNmM2JmOTI5ZmRlODIyMzYzM2VjZjgxYTRhNDMwIiwidm5kLmRvY2tlci5yZWZlcmVuY2UudHlwZSI6ImF0dGVzdGF0aW9uLW1hbmlmZXN0In0sImRpZ2VzdCI6InNoYTI1NjowODVlODc5NTE5NTBhYzYyYTc3MWFmMTU4ZDRkODI3NTUwNTA4ODg5N2EwZTUyMGE4YTViZDU4MjM0MzYzMWIwIiwibWVkaWFUeXBlIjoiYXBwbGljYXRpb25cL3ZuZC5vY2kuaW1hZ2UubWFuaWZlc3QudjEranNvbiIsInBsYXRmb3JtIjp7ImFyY2hpdGVjdHVyZSI6InVua25vd24iLCJvcyI6InVua25vd24ifSwic2l6ZSI6NTY2fSx7ImFubm90YXRpb25zIjp7ImNvbS5kb2NrZXIub2ZmaWNpYWwtaW1hZ2VzLmJhc2hicmV3LmFyY2giOiJhcm0zMnY3Iiwib3JnLm9wZW5jb250YWluZXJzLmltYWdlLnJldmlzaW9uIjoiM2ZiNmViY2E0MTYzYmY1YjljYzQ5NmFjM2U4ZjExY2IxZTc1NGFlZSIsIm9yZy5vcGVuY29udGFpbmVycy5pbWFnZS5zb3VyY2UiOiJodHRwczpcL1wvZ2l0aHViLmNvbVwvZG9ja2VyLWxpYnJhcnlcL2hlbGxvLXdvcmxkLmdpdCMzZmI2ZWJjYTQxNjNiZjViOWNjNDk2YWMzZThmMTFjYjFlNzU0YWVlOmFybTMydjdcL2hlbGxvLXdvcmxkIiwib3JnLm9wZW5jb250YWluZXJzLmltYWdlLnVybCI6Imh0dHBzOlwvXC9odWIuZG9ja2VyLmNvbVwvX1wvaGVsbG8td29ybGQiLCJvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudmVyc2lvbiI6ImxpbnV4In0sImRpZ2VzdCI6InNoYTI1NjoyMGFlYTFjNjNjOTBkNWUxMTdkYjc4N2M5ZmUxYThjZDBhZDk4YmVkYjVmZDcxMTI3M2ZmZTA1YzA4NGZmMThhIiwibWVkaWFUeXBlIjoiYXBwbGljYXRpb25cL3ZuZC5vY2kuaW1hZ2UubWFuaWZlc3QudjEranNvbiIsInBsYXRmb3JtIjp7ImFyY2hpdGVjdHVyZSI6ImFybSIsIm9zIjoibGludXgiLCJ2YXJpYW50IjoidjcifSwic2l6ZSI6ODYzfSx7ImFubm90YXRpb25zIjp7ImNvbS5kb2NrZXIub2ZmaWNpYWwtaW1hZ2VzLmJhc2hicmV3LmFyY2giOiJhcm0zMnY3Iiwidm5kLmRvY2tlci5yZWZlcmVuY2UuZGlnZXN0Ijoic2hhMjU2OjIwYWVhMWM2M2M5MGQ1ZTExN2RiNzg3YzlmZTFhOGNkMGFkOThiZWRiNWZkNzExMjczZmZlMDVjMDg0ZmYxOGEiLCJ2bmQuZG9ja2VyLnJlZmVyZW5jZS50eXBlIjoiYXR0ZXN0YXRpb24tbWFuaWZlc3QifSwiZGlnZXN0Ijoic2hhMjU2OjcwMzA0YzMxNGQ4YTYxYmExYjM2NTE4NjI0YmIwMGJmZmY4ZDRiNjAxNjE1Mzc5MjA0MmRlNDNmMDQ1M2NhNjEiLCJtZWRpYVR5cGUiOiJhcHBsaWNhdGlvblwvdm5kLm9jaS5pbWFnZS5tYW5pZmVzdC52MStqc29uIiwicGxhdGZvcm0iOnsiYXJjaGl0ZWN0dXJlIjoidW5rbm93biIsIm9zIjoidW5rbm93biJ9LCJzaXplIjo4Mzd9LHsiYW5ub3RhdGlvbnMiOnsiY29tLmRvY2tlci5vZmZpY2lhbC1pbWFnZXMuYmFzaGJyZXcuYXJjaCI6ImFybTY0djgiLCJvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UucmV2aXNpb24iOiIzZmI2ZWJjYTQxNjNiZjViOWNjNDk2YWMzZThmMTFjYjFlNzU0YWVlIiwib3JnLm9wZW5jb250YWluZXJzLmltYWdlLnNvdXJjZSI6Imh0dHBzOlwvXC9naXRodWIuY29tXC9kb2NrZXItbGlicmFyeVwvaGVsbG8td29ybGQuZ2l0IzNmYjZlYmNhNDE2M2JmNWI5Y2M0OTZhYzNlOGYxMWNiMWU3NTRhZWU6YXJtNjR2OFwvaGVsbG8td29ybGQiLCJvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudXJsIjoiaHR0cHM6XC9cL2h1Yi5kb2NrZXIuY29tXC9fXC9oZWxsby13b3JsZCIsIm9yZy5vcGVuY29udGFpbmVycy5pbWFnZS52ZXJzaW9uIjoibGludXgifSwiZGlnZXN0Ijoic2hhMjU2OjJkNGU0NTlmNGVjYjUzMjk0MDdhZTNlNDdjYmMxMDdhMmZiYWNlMjIxMzU0Y2E3NTk2MGFmNGMwNDdiM2NiMTMiLCJtZWRpYVR5cGUiOiJhcHBsaWNhdGlvblwvdm5kLm9jaS5pbWFnZS5tYW5pZmVzdC52MStqc29uIiwicGxhdGZvcm0iOnsiYXJjaGl0ZWN0dXJlIjoiYXJtNjQiLCJvcyI6ImxpbnV4IiwidmFyaWFudCI6InY4In0sInNpemUiOjg2M30seyJhbm5vdGF0aW9ucyI6eyJjb20uZG9ja2VyLm9mZmljaWFsLWltYWdlcy5iYXNoYnJldy5hcmNoIjoiYXJtNjR2OCIsInZuZC5kb2NrZXIucmVmZXJlbmNlLmRpZ2VzdCI6InNoYTI1NjoyZDRlNDU5ZjRlY2I1MzI5NDA3YWUzZTQ3Y2JjMTA3YTJmYmFjZTIyMTM1NGNhNzU5NjBhZjRjMDQ3YjNjYjEzIiwidm5kLmRvY2tlci5yZWZlcmVuY2UudHlwZSI6ImF0dGVzdGF0aW9uLW1hbmlmZXN0In0sImRpZ2VzdCI6InNoYTI1NjoxZjExZmJkMTcyMGZjYWUzZTQwMmZjM2VlY2I3ZDU3YzY3MDIzZDJkMWUxMWJlY2M5OWFkOWM3ZmU5N2Q2NWNhIiwibWVkaWFUeXBlIjoiYXBwbGljYXRpb25cL3ZuZC5vY2kuaW1hZ2UubWFuaWZlc3QudjEranNvbiIsInBsYXRmb3JtIjp7ImFyY2hpdGVjdHVyZSI6InVua25vd24iLCJvcyI6InVua25vd24ifSwic2l6ZSI6ODM3fSx7ImFubm90YXRpb25zIjp7ImNvbS5kb2NrZXIub2ZmaWNpYWwtaW1hZ2VzLmJhc2hicmV3LmFyY2giOiJpMzg2Iiwib3JnLm9wZW5jb250YWluZXJzLmltYWdlLnJldmlzaW9uIjoiM2ZiNmViY2E0MTYzYmY1YjljYzQ5NmFjM2U4ZjExY2IxZTc1NGFlZSIsIm9yZy5vcGVuY29udGFpbmVycy5pbWFnZS5zb3VyY2UiOiJodHRwczpcL1wvZ2l0aHViLmNvbVwvZG9ja2VyLWxpYnJhcnlcL2hlbGxvLXdvcmxkLmdpdCMzZmI2ZWJjYTQxNjNiZjViOWNjNDk2YWMzZThmMTFjYjFlNzU0YWVlOmkzODZcL2hlbGxvLXdvcmxkIiwib3JnLm9wZW5jb250YWluZXJzLmltYWdlLnVybCI6Imh0dHBzOlwvXC9odWIuZG9ja2VyLmNvbVwvX1wvaGVsbG8td29ybGQiLCJvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudmVyc2lvbiI6ImxpbnV4In0sImRpZ2VzdCI6InNoYTI1NjpkYmJkM2NmNjY2MzExYWQ1MjZmYWQ5ZDE3NDYxNzc0NjkyNjhmMzJmZDkxYjM3MWRmMmViZDFjODRlYjIyZjIzIiwibWVkaWFUeXBlIjoiYXBwbGljYXRpb25cL3ZuZC5vY2kuaW1hZ2UubWFuaWZlc3QudjEranNvbiIsInBsYXRmb3JtIjp7ImFyY2hpdGVjdHVyZSI6IjM4NiIsIm9zIjoibGludXgifSwic2l6ZSI6ODYwfSx7ImFubm90YXRpb25zIjp7ImNvbS5kb2NrZXIub2ZmaWNpYWwtaW1hZ2VzLmJhc2hicmV3LmFyY2giOiJpMzg2Iiwidm5kLmRvY2tlci5yZWZlcmVuY2UuZGlnZXN0Ijoic2hhMjU2OmRiYmQzY2Y2NjYzMTFhZDUyNmZhZDlkMTc0NjE3NzQ2OTI2OGYzMmZkOTFiMzcxZGYyZWJkMWM4NGViMjJmMjMiLCJ2bmQuZG9ja2VyLnJlZmVyZW5jZS50eXBlIjoiYXR0ZXN0YXRpb24tbWFuaWZlc3QifSwiZGlnZXN0Ijoic2hhMjU2OjE4YjFjOTJkZTM2ZDQyYzc1NDQwYzZmZDZiMjU2MDVjYzkxNzA5ZDE3NmZhYWNjY2E4YWZlNThiMzE3YmMzM2EiLCJtZWRpYVR5cGUiOiJhcHBsaWNhdGlvblwvdm5kLm9jaS5pbWFnZS5tYW5pZmVzdC52MStqc29uIiwicGxhdGZvcm0iOnsiYXJjaGl0ZWN0dXJlIjoidW5rbm93biIsIm9zIjoidW5rbm93biJ9LCJzaXplIjo1NjZ9LHsiYW5ub3RhdGlvbnMiOnsiY29tLmRvY2tlci5vZmZpY2lhbC1pbWFnZXMuYmFzaGJyZXcuYXJjaCI6Im1pcHM2NGxlIiwib3JnLm9wZW5jb250YWluZXJzLmltYWdlLnJldmlzaW9uIjoiM2ZiNmViY2E0MTYzYmY1YjljYzQ5NmFjM2U4ZjExY2IxZTc1NGFlZSIsIm9yZy5vcGVuY29udGFpbmVycy5pbWFnZS5zb3VyY2UiOiJodHRwczpcL1wvZ2l0aHViLmNvbVwvZG9ja2VyLWxpYnJhcnlcL2hlbGxvLXdvcmxkLmdpdCMzZmI2ZWJjYTQxNjNiZjViOWNjNDk2YWMzZThmMTFjYjFlNzU0YWVlOm1pcHM2NGxlXC9oZWxsby13b3JsZCIsIm9yZy5vcGVuY29udGFpbmVycy5pbWFnZS51cmwiOiJodHRwczpcL1wvaHViLmRvY2tlci5jb21cL19cL2hlbGxvLXdvcmxkIiwib3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlcnNpb24iOiJsaW51eCJ9LCJkaWdlc3QiOiJzaGEyNTY6YzE5Nzg0MDM0ZDQ2ZGE0ODU1MDQ4N2M1YzQ0NjM5ZjVmOTJkNDhiZTdiOWJhZjRkNjdiNTM3N2E0NTRkOTJhZiIsIm1lZGlhVHlwZSI6ImFwcGxpY2F0aW9uXC92bmQub2NpLmltYWdlLm1hbmlmZXN0LnYxK2pzb24iLCJwbGF0Zm9ybSI6eyJhcmNoaXRlY3R1cmUiOiJtaXBzNjRsZSIsIm9zIjoibGludXgifSwic2l6ZSI6ODY0fSx7ImFubm90YXRpb25zIjp7ImNvbS5kb2NrZXIub2ZmaWNpYWwtaW1hZ2VzLmJhc2hicmV3LmFyY2giOiJtaXBzNjRsZSIsInZuZC5kb2NrZXIucmVmZXJlbmNlLmRpZ2VzdCI6InNoYTI1NjpjMTk3ODQwMzRkNDZkYTQ4NTUwNDg3YzVjNDQ2MzlmNWY5MmQ0OGJlN2I5YmFmNGQ2N2I1Mzc3YTQ1NGQ5MmFmIiwidm5kLmRvY2tlci5yZWZlcmVuY2UudHlwZSI6ImF0dGVzdGF0aW9uLW1hbmlmZXN0In0sImRpZ2VzdCI6InNoYTI1Njo5NTFiY2QxNDRkZGNjZDFlZTkwMmRjMTgwYjQzNWZhYWJhYWE2YTg3NDdlNzBjYmM4OTNmMmRjYTE2YmFkYjk0IiwibWVkaWFUeXBlIjoiYXBwbGljYXRpb25cL3ZuZC5vY2kuaW1hZ2UubWFuaWZlc3QudjEranNvbiIsInBsYXRmb3JtIjp7ImFyY2hpdGVjdHVyZSI6InVua25vd24iLCJvcyI6InVua25vd24ifSwic2l6ZSI6NTY2fSx7ImFubm90YXRpb25zIjp7ImNvbS5kb2NrZXIub2ZmaWNpYWwtaW1hZ2VzLmJhc2hicmV3LmFyY2giOiJwcGM2NGxlIiwib3JnLm9wZW5jb250YWluZXJzLmltYWdlLnJldmlzaW9uIjoiM2ZiNmViY2E0MTYzYmY1YjljYzQ5NmFjM2U4ZjExY2IxZTc1NGFlZSIsIm9yZy5vcGVuY29udGFpbmVycy5pbWFnZS5zb3VyY2UiOiJodHRwczpcL1wvZ2l0aHViLmNvbVwvZG9ja2VyLWxpYnJhcnlcL2hlbGxvLXdvcmxkLmdpdCMzZmI2ZWJjYTQxNjNiZjViOWNjNDk2YWMzZThmMTFjYjFlNzU0YWVlOnBwYzY0bGVcL2hlbGxvLXdvcmxkIiwib3JnLm9wZW5jb250YWluZXJzLmltYWdlLnVybCI6Imh0dHBzOlwvXC9odWIuZG9ja2VyLmNvbVwvX1wvaGVsbG8td29ybGQiLCJvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudmVyc2lvbiI6ImxpbnV4In0sImRpZ2VzdCI6InNoYTI1NjpmMGM5NWYxZWJiNTBjOWIwYjNlMzQxNmZiOWRkNGQxZDE5NzM4NmEwNzZjNDY0Y2NlZWEzZDFmOTRjMzIxYjhmIiwibWVkaWFUeXBlIjoiYXBwbGljYXRpb25cL3ZuZC5vY2kuaW1hZ2UubWFuaWZlc3QudjEranNvbiIsInBsYXRmb3JtIjp7ImFyY2hpdGVjdHVyZSI6InBwYzY0bGUiLCJvcyI6ImxpbnV4In0sInNpemUiOjg2M30seyJhbm5vdGF0aW9ucyI6eyJjb20uZG9ja2VyLm9mZmljaWFsLWltYWdlcy5iYXNoYnJldy5hcmNoIjoicHBjNjRsZSIsInZuZC5kb2NrZXIucmVmZXJlbmNlLmRpZ2VzdCI6InNoYTI1NjpmMGM5NWYxZWJiNTBjOWIwYjNlMzQxNmZiOWRkNGQxZDE5NzM4NmEwNzZjNDY0Y2NlZWEzZDFmOTRjMzIxYjhmIiwidm5kLmRvY2tlci5yZWZlcmVuY2UudHlwZSI6ImF0dGVzdGF0aW9uLW1hbmlmZXN0In0sImRpZ2VzdCI6InNoYTI1Njo4MzhkMTkxYmNhMzk4ZTQ2Y2RkZWJjNDhlODE2ZGE4M2IwMzg5ZDRlZDJkNjRmNDA4ZDYxODUyMWI4ZmQxYTU3IiwibWVkaWFUeXBlIjoiYXBwbGljYXRpb25cL3ZuZC5vY2kuaW1hZ2UubWFuaWZlc3QudjEranNvbiIsInBsYXRmb3JtIjp7ImFyY2hpdGVjdHVyZSI6InVua25vd24iLCJvcyI6InVua25vd24ifSwic2l6ZSI6ODM3fSx7ImFubm90YXRpb25zIjp7ImNvbS5kb2NrZXIub2ZmaWNpYWwtaW1hZ2VzLmJhc2hicmV3LmFyY2giOiJyaXNjdjY0Iiwib3JnLm9wZW5jb250YWluZXJzLmltYWdlLnJldmlzaW9uIjoiM2ZiNmViY2E0MTYzYmY1YjljYzQ5NmFjM2U4ZjExY2IxZTc1NGFlZSIsIm9yZy5vcGVuY29udGFpbmVycy5pbWFnZS5zb3VyY2UiOiJodHRwczpcL1wvZ2l0aHViLmNvbVwvZG9ja2VyLWxpYnJhcnlcL2hlbGxvLXdvcmxkLmdpdCMzZmI2ZWJjYTQxNjNiZjViOWNjNDk2YWMzZThmMTFjYjFlNzU0YWVlOnJpc2N2NjRcL2hlbGxvLXdvcmxkIiwib3JnLm9wZW5jb250YWluZXJzLmltYWdlLnVybCI6Imh0dHBzOlwvXC9odWIuZG9ja2VyLmNvbVwvX1wvaGVsbG8td29ybGQiLCJvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudmVyc2lvbiI6ImxpbnV4In0sImRpZ2VzdCI6InNoYTI1Njo4ZDA2NGE2ZmMyN2ZkNWU5N2ZhODIyNTk5NGExYWRkZDg3MjM5NjIzNjM2Nzc0NWJlYTMwYzkyZDZjMDMyZmEzIiwibWVkaWFUeXBlIjoiYXBwbGljYXRpb25cL3ZuZC5vY2kuaW1hZ2UubWFuaWZlc3QudjEranNvbiIsInBsYXRmb3JtIjp7ImFyY2hpdGVjdHVyZSI6InJpc2N2NjQiLCJvcyI6ImxpbnV4In0sInNpemUiOjg2M30seyJhbm5vdGF0aW9ucyI6eyJjb20uZG9ja2VyLm9mZmljaWFsLWltYWdlcy5iYXNoYnJldy5hcmNoIjoicmlzY3Y2NCIsInZuZC5kb2NrZXIucmVmZXJlbmNlLmRpZ2VzdCI6InNoYTI1Njo4ZDA2NGE2ZmMyN2ZkNWU5N2ZhODIyNTk5NGExYWRkZDg3MjM5NjIzNjM2Nzc0NWJlYTMwYzkyZDZjMDMyZmEzIiwidm5kLmRvY2tlci5yZWZlcmVuY2UudHlwZSI6ImF0dGVzdGF0aW9uLW1hbmlmZXN0In0sImRpZ2VzdCI6InNoYTI1Njo0ODE0NzQwN2M0NTk0ZTQ1YjdjM2YwYmUxMDE5YmIwZjQ0ZDc4ZDdmMDM3Y2U2M2UwZTNkYTc1YjI1NmY4NDllIiwibWVkaWFUeXBlIjoiYXBwbGljYXRpb25cL3ZuZC5vY2kuaW1hZ2UubWFuaWZlc3QudjEranNvbiIsInBsYXRmb3JtIjp7ImFyY2hpdGVjdHVyZSI6InVua25vd24iLCJvcyI6InVua25vd24ifSwic2l6ZSI6ODM3fSx7ImFubm90YXRpb25zIjp7ImNvbS5kb2NrZXIub2ZmaWNpYWwtaW1hZ2VzLmJhc2hicmV3LmFyY2giOiJzMzkweCIsIm9yZy5vcGVuY29udGFpbmVycy5pbWFnZS5yZXZpc2lvbiI6IjNmYjZlYmNhNDE2M2JmNWI5Y2M0OTZhYzNlOGYxMWNiMWU3NTRhZWUiLCJvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2Uuc291cmNlIjoiaHR0cHM6XC9cL2dpdGh1Yi5jb21cL2RvY2tlci1saWJyYXJ5XC9oZWxsby13b3JsZC5naXQjM2ZiNmViY2E0MTYzYmY1YjljYzQ5NmFjM2U4ZjExY2IxZTc1NGFlZTpzMzkweFwvaGVsbG8td29ybGQiLCJvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudXJsIjoiaHR0cHM6XC9cL2h1Yi5kb2NrZXIuY29tXC9fXC9oZWxsby13b3JsZCIsIm9yZy5vcGVuY29udGFpbmVycy5pbWFnZS52ZXJzaW9uIjoibGludXgifSwiZGlnZXN0Ijoic2hhMjU2OjY1ZjRiMGQxODAyNTg5YjQxOGJiNjc3NGQ4NWRlM2QxYTExZDViZDk3MWVlNzNjYjg1Njk1MDRkOTI4YmI1ZDkiLCJtZWRpYVR5cGUiOiJhcHBsaWNhdGlvblwvdm5kLm9jaS5pbWFnZS5tYW5pZmVzdC52MStqc29uIiwicGxhdGZvcm0iOnsiYXJjaGl0ZWN0dXJlIjoiczM5MHgiLCJvcyI6ImxpbnV4In0sInNpemUiOjg2MX0seyJhbm5vdGF0aW9ucyI6eyJjb20uZG9ja2VyLm9mZmljaWFsLWltYWdlcy5iYXNoYnJldy5hcmNoIjoiczM5MHgiLCJ2bmQuZG9ja2VyLnJlZmVyZW5jZS5kaWdlc3QiOiJzaGEyNTY6NjVmNGIwZDE4MDI1ODliNDE4YmI2Nzc0ZDg1ZGUzZDFhMTFkNWJkOTcxZWU3M2NiODU2OTUwNGQ5MjhiYjVkOSIsInZuZC5kb2NrZXIucmVmZXJlbmNlLnR5cGUiOiJhdHRlc3RhdGlvbi1tYW5pZmVzdCJ9LCJkaWdlc3QiOiJzaGEyNTY6NTBmNDIwZTg3MTA2NzZkYTAzNjY4ZTQ0NmYxZjUxMDk3Yjc0NWUzZTJjOTgwN2IwMThlNTY5ZDI2ZDRmNjVmNyIsIm1lZGlhVHlwZSI6ImFwcGxpY2F0aW9uXC92bmQub2NpLmltYWdlLm1hbmlmZXN0LnYxK2pzb24iLCJwbGF0Zm9ybSI6eyJhcmNoaXRlY3R1cmUiOiJ1bmtub3duIiwib3MiOiJ1bmtub3duIn0sInNpemUiOjgzN30seyJhbm5vdGF0aW9ucyI6eyJjb20uZG9ja2VyLm9mZmljaWFsLWltYWdlcy5iYXNoYnJldy5hcmNoIjoid2luZG93cy1hbWQ2NCJ9LCJkaWdlc3QiOiJzaGEyNTY6YmVkZDkyZjIwMTMxMzY2ZjE3MjY3NWFhOGQyMjdmMDU3NDQxMGRmOTRmN2Y0NDlkOGFiYjQwNjM4YjlhZDc3NCIsIm1lZGlhVHlwZSI6ImFwcGxpY2F0aW9uXC92bmQuZG9ja2VyLmRpc3RyaWJ1dGlvbi5tYW5pZmVzdC52Mitqc29uIiwicGxhdGZvcm0iOnsiYXJjaGl0ZWN0dXJlIjoiYW1kNjQiLCJvcyI6IndpbmRvd3MiLCJvcy52ZXJzaW9uIjoiMTAuMC4yMDM0OC4yNTI3In0sInNpemUiOjk0Nn0seyJhbm5vdGF0aW9ucyI6eyJjb20uZG9ja2VyLm9mZmljaWFsLWltYWdlcy5iYXNoYnJldy5hcmNoIjoid2luZG93cy1hbWQ2NCJ9LCJkaWdlc3QiOiJzaGEyNTY6OGE5Y2RiYjdkODdhNWI5NmQ1MWFjYzJmOTg4YjY3MjY0OTg2NTA4ZjI4NDMwMmIxMDZmNDUzNDI5YmE4OGI4MyIsIm1lZGlhVHlwZSI6ImFwcGxpY2F0aW9uXC92bmQuZG9ja2VyLmRpc3RyaWJ1dGlvbi5tYW5pZmVzdC52Mitqc29uIiwicGxhdGZvcm0iOnsiYXJjaGl0ZWN0dXJlIjoiYW1kNjQiLCJvcyI6IndpbmRvd3MiLCJvcy52ZXJzaW9uIjoiMTAuMC4xNzc2My41OTM2In0sInNpemUiOjk0Nn1dLCJtZWRpYVR5cGUiOiJhcHBsaWNhdGlvblwvdm5kLm9jaS5pbWFnZS5pbmRleC52MStqc29uIiwic2NoZW1hVmVyc2lvbiI6Mn0=", + "StatusCode": 401, + "ResponseHeaders": { + "Access-Control-Expose-Headers": [ + "Docker-Content-Digest", + "WWW-Authenticate", + "Link", + "X-Ms-Correlation-Request-Id" + ], + "Connection": "keep-alive", + "Content-Length": "264", + "Content-Type": "application/json; charset=utf-8", + "Date": "Tue, 18 Jun 2024 20:54:11 GMT", + "Docker-Distribution-Api-Version": "registry/2.0", + "Server": "AzureContainerRegistry", + "Strict-Transport-Security": [ + "max-age=31536000; includeSubDomains", + "max-age=31536000; includeSubDomains" + ], + "WWW-Authenticate": "Bearer realm=\"https://Sanitized.azurecr.io/oauth2/token\",service=\"Sanitized.azurecr.io\",scope=\"repository:hello-world:pull,push\",error=\"insufficient_scope\"", + "X-Content-Type-Options": "nosniff", + "X-Ms-Correlation-Request-Id": "bcd1db6c-05b3-421f-9a36-969ff4a8f625" + }, "ResponseBody": { - "schemaVersion": 2, - "mediaType": "application/vnd.docker.distribution.manifest.v2+json", - "config": { - "mediaType": "application/vnd.docker.container.image.v1+json", - "size": 1472, - "digest": "sha256:042a816809aac8d0f7d7cacac7965782ee2ecac3f21bcf9f24b1de1a7387b769" - }, - "layers": [ + "errors": [ { - "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", - "size": 3370628, - "digest": "sha256:8921db27df2831fa6eaa85321205a2470c669b855f3ec95d5a3c2b46de0442c9" + "code": "UNAUTHORIZED", + "message": "authentication required, visit https://aka.ms/acr/authorization for more information.", + "detail": [ + { + "Type": "repository", + "Name": "hello-world", + "Action": "pull" + }, + { + "Type": "repository", + "Name": "hello-world", + "Action": "push" + } + ] } ] } diff --git a/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Common/ContentTypeUtilities.cs b/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Common/ContentTypeUtilities.cs index 3decf6be096..2dbb3421941 100644 --- a/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Common/ContentTypeUtilities.cs +++ b/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Common/ContentTypeUtilities.cs @@ -10,6 +10,15 @@ namespace Azure.Sdk.Tools.TestProxy.Common { internal static class ContentTypeUtilities { + + public static bool IsManifestContentType(string contentType) + { + const string dockerManifest = "application/vnd.docker.distribution.manifest.v"; + const string dockerIndex = "application/vnd.oci.image.index.v"; + + return contentType.Contains(dockerManifest) || contentType.Contains(dockerIndex); + } + public static bool TryGetTextEncoding(string contentType, out Encoding encoding) { const string charsetMarker = "; charset="; @@ -22,7 +31,6 @@ public static bool TryGetTextEncoding(string contentType, out Encoding encoding) // Default is technically US-ASCII, but will default to UTF-8 which is a superset. const string appFormUrlEncoded = "application/x-www-form-urlencoded"; - const string dockerManifest = "application/vnd.docker.distribution.manifest.v2"; if (contentType == null) { @@ -41,7 +49,6 @@ public static bool TryGetTextEncoding(string contentType, out Encoding encoding) } } - if ( ( contentType.StartsWith(textContentTypePrefix, StringComparison.OrdinalIgnoreCase) || @@ -50,7 +57,7 @@ public static bool TryGetTextEncoding(string contentType, out Encoding encoding) contentType.EndsWith(urlEncodedSuffix, StringComparison.OrdinalIgnoreCase) || contentType.StartsWith(appJsonPrefix, StringComparison.OrdinalIgnoreCase) || contentType.StartsWith(appFormUrlEncoded, StringComparison.OrdinalIgnoreCase) - ) && !contentType.Contains(dockerManifest) + ) && !ContentTypeUtilities.IsManifestContentType(contentType) ) { encoding = Encoding.UTF8; diff --git a/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Common/RecordEntry.cs b/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Common/RecordEntry.cs index 8e35ee47974..235780323c0 100644 --- a/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Common/RecordEntry.cs +++ b/tools/test-proxy/Azure.Sdk.Tools.TestProxy/Common/RecordEntry.cs @@ -126,7 +126,7 @@ private static void DeserializeBody(RequestOrResponse requestOrResponse, in Json public static void NormalizeJsonBody(RequestOrResponse requestOrResponse) { - if (requestOrResponse.TryGetContentType(out string contentType) && contentType.Contains("json")) + if (requestOrResponse.TryGetContentType(out string contentType) && contentType.Contains("json") && !ContentTypeUtilities.IsManifestContentType(contentType)) { try {