Skip to content

Commit 65f5db5

Browse files
authored
Fix overaggressive escaping (#8054)
* Update RecordingHandler to use the same encoder as the one that exists within RecordEntry. This has the effect of properly serializing json bodies, without unicode encoding common symbols like '+' and '&'
1 parent 4fa4ac8 commit 65f5db5

3 files changed

Lines changed: 57 additions & 15 deletions

File tree

tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/RecordSessionTests.cs

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
// Copyright (c) Microsoft Corporation. All rights reserved.
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the MIT License.
33

44
using System;
55
using System.Buffers;
6+
using System.Collections.Generic;
67
using System.IO;
78
using System.Linq;
89
using System.Text;
10+
using System.Text.Encodings.Web;
911
using System.Text.Json;
1012
using Azure.Core;
1113
using Azure.Core.Pipeline;
@@ -33,7 +35,8 @@ public class RecordSessionTests
3335
[InlineData("19", "application/json")]
3436
[InlineData("true", "application/json")]
3537
[InlineData("false", "application/json")]
36-
[InlineData("{ \"json\": \"value\" }", "unknown")]
38+
[InlineData("{\"a-key\":\"akeywith+inthemiddle\"}", "application/json")]
39+
[InlineData("{\"json\":\"value\"}", "unknown")]
3740
[InlineData("multi\rline", "application/xml")]
3841
[InlineData("multi\r\nline", "application/xml")]
3942
[InlineData("multi\n\rline\n", "application/xml")]
@@ -65,7 +68,7 @@ public void CanRoundtripSessionRecord(string body, string contentType)
6568
var arrayBufferWriter = new ArrayBufferWriter<byte>();
6669
using var jsonWriter = new Utf8JsonWriter(arrayBufferWriter, new JsonWriterOptions()
6770
{
68-
Indented = true
71+
Indented = true, Encoder = RecordEntry.WriterOptions.Encoder
6972
});
7073
session.Serialize(jsonWriter);
7174
jsonWriter.Flush();
@@ -92,6 +95,51 @@ public void CanRoundtripSessionRecord(string body, string contentType)
9295
Assert.Equal(bodyBytes, deserializedRecord.Response.Body);
9396
}
9497

98+
[Fact]
99+
public void EnsureJsonEscaping()
100+
{
101+
var shouldNotExist = new string[] {
102+
"\\u0026", "\\u002B"
103+
};
104+
105+
var body = "{\"tags\":{\"hidden-link:/app-insights-resource-id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/Lwm_Rg/providers/microsoft.insights/components/FunctionApp1Lwm\"}"
106+
+ ",\"properties\":{\"WEBSITE_CONTENTAZUREFILECONNECTIONSTRING\":\"DefaultEndpointsProtocol=https;AccountName=anaccountname!;AccountKey=aBase64&String+Fake==;EndpointSuffix=core.windows.net\"}}";
107+
108+
var session = new RecordSession();
109+
session.Entries.Add(new RecordEntry()
110+
{
111+
Response = new RequestOrResponse()
112+
{
113+
Headers = new SortedDictionary<string, string[]>()
114+
{
115+
{
116+
"Content-Type", new string[] { "application/json" }
117+
}
118+
},
119+
Body = Encoding.UTF8.GetBytes(body),
120+
}
121+
});
122+
123+
var tmpDir = Path.GetTempPath();
124+
var recordSession = Path.Combine(tmpDir, $"{Guid.NewGuid()}.json");
125+
using var stream = System.IO.File.Create(recordSession);
126+
var options = new JsonWriterOptions { Indented = true, Encoder = RecordEntry.WriterOptions.Encoder };
127+
var writer = new Utf8JsonWriter(stream, options);
128+
129+
session.Serialize(writer);
130+
writer.Flush();
131+
stream.Close();
132+
133+
var text = File.ReadAllText(recordSession);
134+
135+
foreach(var unicodeChar in shouldNotExist)
136+
{
137+
Assert.DoesNotContain(unicodeChar, text);
138+
}
139+
}
140+
141+
142+
95143
[Theory]
96144
[InlineData("{\"json\":\"value\"}", "application/json")]
97145
[InlineData("{\"json\":\"\\\"value\\\"\"}", "application/json")]

tools/test-proxy/Azure.Sdk.Tools.TestProxy/Common/RecordEntry.cs

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
1-
// Copyright (c) Microsoft Corporation. All rights reserved.
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the MIT License.
33

44
using Azure.Core;
55
using System;
66
using System.Collections.Generic;
77
using System.IO;
8-
using System.Linq;
98
using System.Text;
109
using System.Text.Encodings.Web;
1110
using System.Text.Json;
11+
using System.Text.Unicode;
1212

1313
namespace Azure.Sdk.Tools.TestProxy.Common
1414
{
1515
public class RecordEntry
1616
{
1717
// Requests and responses are usually formatted using Newtonsoft.Json that has more relaxed encoding rules
1818
// To enable us to store more responses as JSON instead of string in Recording files use
19-
// relaxed settings for roundtrip
20-
private static readonly JsonWriterOptions WriterOptions = new JsonWriterOptions()
19+
// relaxed settings for roundtrip.
20+
public static readonly JsonWriterOptions WriterOptions = new JsonWriterOptions()
2121
{
2222
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
2323
};
@@ -217,13 +217,6 @@ private void SerializeBody(Utf8JsonWriter jsonWriter, string name, byte[] reques
217217
document.RootElement.ValueKind != JsonValueKind.String &&
218218
document.RootElement.ValueKind != JsonValueKind.Null)
219219
{
220-
using var memoryStream = new MemoryStream();
221-
// Settings of this writer should be in sync with the one used in deserialization
222-
using (var reformattedWriter = new Utf8JsonWriter(memoryStream, WriterOptions))
223-
{
224-
document.RootElement.WriteTo(reformattedWriter);
225-
}
226-
227220
jsonWriter.WritePropertyName(name.AsSpan());
228221
document.RootElement.WriteTo(jsonWriter);
229222
return;

tools/test-proxy/Azure.Sdk.Tools.TestProxy/RecordingHandler.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
using System.Net.Security;
1919
using System.Security.Cryptography.X509Certificates;
2020
using System.Text;
21+
using System.Text.Encodings.Web;
2122
using System.Text.Json;
2223
using System.Threading;
2324
using System.Threading.Tasks;
@@ -146,7 +147,7 @@ public void StopRecording(string sessionId, IDictionary<string, string> variable
146147
}
147148

148149
using var stream = System.IO.File.Create(recordingSession.Path);
149-
var options = new JsonWriterOptions { Indented = true };
150+
var options = new JsonWriterOptions { Indented = true, Encoder = RecordEntry.WriterOptions.Encoder };
150151
var writer = new Utf8JsonWriter(stream, options);
151152
recordingSession.Session.Serialize(writer);
152153
writer.Flush();

0 commit comments

Comments
 (0)