Skip to content

Commit 8614841

Browse files
authored
Fix low surrogate on post data (#2887)
* Fix low surrogate on post data * bump version * fix and tests * ignore some tests in firefox * fix test * fallback to string
1 parent 6ab434f commit 8614841

File tree

6 files changed

+90
-8
lines changed

6 files changed

+90
-8
lines changed

lib/PuppeteerSharp.Nunit/TestExpectations/TestExpectations.local.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
11
[
2+
{
3+
"testIdPattern": "[network.spec] PuppeteerSharp network*",
4+
"platforms": ["darwin", "linux", "win32"],
5+
"parameters": ["cdp", "firefox"],
6+
"expectations": ["FAIL"],
7+
"comment": "The should work tests are being ignore upstream, the PuppeteerSharp ones are based on the same one."
8+
},
29
{
310
"comment": "We have a different test that needs to run on windows",
411
"testIdPattern": "[chrome-data.spec] Chrome should resolve system executable path (windows)",

lib/PuppeteerSharp.Tests/NetworkTests/RequestPostDataTests.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,30 @@ public async Task ShouldWork()
1919
Assert.That(request.PostData, Is.EqualTo("{\"foo\":\"bar\"}"));
2020
}
2121

22+
[Test, Retry(2), PuppeteerTest("network.spec", "PuppeteerSharp network Request.postData", "should work plain text")]
23+
public async Task ShouldWorkPlainText()
24+
{
25+
await Page.GoToAsync(TestConstants.EmptyPage);
26+
Server.SetRoute("/post", _ => Task.CompletedTask);
27+
var requestTask = Page.WaitForRequestAsync((request) => !TestUtils.IsFavicon(request));
28+
await Page.EvaluateExpressionHandleAsync("fetch('./post', { method: 'POST', body: 'Hello, world!'})");
29+
var request = await requestTask.WithTimeout();
30+
Assert.That(request, Is.Not.Null);
31+
Assert.That(request.PostData, Is.EqualTo("Hello, world!"));
32+
}
33+
34+
[Test, Retry(2), PuppeteerTest("network.spec", "PuppeteerSharp network Request.postData", "should work with low surrogate")]
35+
public async Task ShouldWorkWithLowSurrogate()
36+
{
37+
await Page.GoToAsync(TestConstants.EmptyPage);
38+
Server.SetRoute("/post", _ => Task.CompletedTask);
39+
var requestTask = Page.WaitForRequestAsync((request) => !TestUtils.IsFavicon(request));
40+
await Page.EvaluateExpressionHandleAsync("fetch('./post', { method: 'POST', body: 'Hello, world!\uDD71'})");
41+
var request = await requestTask.WithTimeout();
42+
Assert.That(request, Is.Not.Null);
43+
Assert.That(request.PostData, Is.EqualTo("Hello, world!\uFFFD"));
44+
}
45+
2246
[Test, Retry(2), PuppeteerTest("network.spec", "network Request.postData", "should be |undefined| when there is no post data")]
2347
public async Task ShouldBeUndefinedWhenThereIsNoPostData()
2448
{

lib/PuppeteerSharp/Cdp/Messaging/Request.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,19 @@
2020
// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2121
// * SOFTWARE.
2222

23+
using PuppeteerSharp.Helpers.Json;
24+
2325
namespace PuppeteerSharp.Cdp.Messaging;
2426

2527
using System.Collections.Generic;
2628
using System.Net.Http;
29+
using System.Text.Json.Serialization;
2730

2831
internal class Request
2932
{
3033
public HttpMethod Method { get; set; }
3134

35+
[JsonConverter(typeof(LowSurrogateConverter))]
3236
public string PostData { get; set; }
3337

3438
public Dictionary<string, string> Headers { get; set; } = [];
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
using System;
2+
using System.Buffers;
3+
using System.Text;
4+
using System.Text.Json;
5+
using System.Text.Json.Serialization;
6+
7+
namespace PuppeteerSharp.Helpers.Json;
8+
9+
internal class LowSurrogateConverter : JsonConverter<string>
10+
{
11+
public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
12+
{
13+
if (reader.TokenType != JsonTokenType.String)
14+
{
15+
return null;
16+
}
17+
18+
var span = reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan.ToArray();
19+
var value = Encoding.UTF8.GetString(span);
20+
21+
try
22+
{
23+
if (reader.ValueIsEscaped)
24+
{
25+
value = JsonUnescape(value);
26+
}
27+
28+
return value;
29+
}
30+
catch
31+
{
32+
return value;
33+
}
34+
}
35+
36+
public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options)
37+
{
38+
writer.WriteStringValue(value);
39+
}
40+
41+
private static string JsonUnescape(string jsonString)
42+
{
43+
using var doc = JsonDocument.Parse($"\"{jsonString}\"");
44+
return doc.RootElement.GetString();
45+
}
46+
}

lib/PuppeteerSharp/PageCoverage/JSCoverage.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections.Concurrent;
23
using System.Collections.Generic;
34
using System.Linq;
45
using System.Threading.Tasks;
@@ -10,8 +11,8 @@ namespace PuppeteerSharp.PageCoverage
1011
{
1112
internal class JSCoverage
1213
{
13-
private readonly Dictionary<string, string> _scriptURLs = new();
14-
private readonly Dictionary<string, string> _scriptSources = new();
14+
private readonly ConcurrentDictionary<string, string> _scriptURLs = new();
15+
private readonly ConcurrentDictionary<string, string> _scriptSources = new();
1516
private readonly ILogger _logger;
1617

1718
private CDPSession _client;
@@ -140,8 +141,8 @@ private async Task OnScriptParsedAsync(DebuggerScriptParsedResponse scriptParseR
140141
{
141142
ScriptId = scriptParseResponse.ScriptId,
142143
}).ConfigureAwait(false);
143-
_scriptURLs.Add(scriptParseResponse.ScriptId, scriptParseResponse.Url);
144-
_scriptSources.Add(scriptParseResponse.ScriptId, response.ScriptSource);
144+
_scriptURLs.TryAdd(scriptParseResponse.ScriptId, scriptParseResponse.Url);
145+
_scriptSources.TryAdd(scriptParseResponse.ScriptId, response.ScriptSource);
145146
}
146147
catch (Exception ex)
147148
{

lib/PuppeteerSharp/PuppeteerSharp.csproj

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@
1212
<Description>Headless Browser .NET API</Description>
1313
<PackageId>PuppeteerSharp</PackageId>
1414
<PackageReleaseNotes></PackageReleaseNotes>
15-
<PackageVersion>20.1.1</PackageVersion>
16-
<ReleaseVersion>20.1.1</ReleaseVersion>
17-
<AssemblyVersion>20.1.1</AssemblyVersion>
18-
<FileVersion>20.1.1</FileVersion>
15+
<PackageVersion>20.1.2</PackageVersion>
16+
<ReleaseVersion>20.1.2</ReleaseVersion>
17+
<AssemblyVersion>20.1.2</AssemblyVersion>
18+
<FileVersion>20.1.2</FileVersion>
1919
<SynchReleaseVersion>false</SynchReleaseVersion>
2020
<StyleCopTreatErrorsAsWarnings>false</StyleCopTreatErrorsAsWarnings>
2121
<DebugType>embedded</DebugType>

0 commit comments

Comments
 (0)