diff --git a/dotnet/src/webdriver/DevTools/Json/DevToolsJsonOptions.cs b/dotnet/src/webdriver/DevTools/Json/DevToolsJsonOptions.cs new file mode 100644 index 0000000000000..4b624a9f6b43e --- /dev/null +++ b/dotnet/src/webdriver/DevTools/Json/DevToolsJsonOptions.cs @@ -0,0 +1,35 @@ +// +// Licensed to the Software Freedom Conservancy (SFC) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The SFC licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +using System.Text.Json; + +#nullable enable + +namespace OpenQA.Selenium.DevTools.Json; + +internal static class DevToolsJsonOptions +{ + public static JsonSerializerOptions Default { get; } = new JsonSerializerOptions() + { + Converters = + { + new StringConverter(), + } + }; +} diff --git a/dotnet/src/webdriver/DevTools/Json/StringConverter.cs b/dotnet/src/webdriver/DevTools/Json/StringConverter.cs new file mode 100644 index 0000000000000..0ba9a9627fc7f --- /dev/null +++ b/dotnet/src/webdriver/DevTools/Json/StringConverter.cs @@ -0,0 +1,61 @@ +// +// Licensed to the Software Freedom Conservancy (SFC) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The SFC licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +using System; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; + +#nullable enable + +namespace OpenQA.Selenium.DevTools.Json; + +internal sealed class StringConverter : JsonConverter +{ + public override bool HandleNull => true; + + public override string? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + try + { + return reader.GetString(); + } + catch (InvalidOperationException) + { + // Fallback to read the value as bytes instead of string. + // System.Text.Json library throws exception when CDP remote end sends non-encoded string as binary data. + // Using JavaScriptEncoder.UnsafeRelaxedJsonEscaping doesn't help because the string actually is byte[]. + // https://chromedevtools.github.io/devtools-protocol/tot/Network/#type-Request - here "postData" property + // is a string, which we cannot deserialize properly. This property is marked as deprecated, and new "postDataEntries" + // is suggested for using, where most likely it is base64 encoded. + + var bytes = reader.ValueSpan; + var sb = new StringBuilder(bytes.Length); + foreach (byte b in bytes) + { + sb.Append(Convert.ToChar(b)); + } + + return sb.ToString(); + } + } + + public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options) => + writer.WriteStringValue(value); +} diff --git a/dotnet/src/webdriver/cdp/README.md b/dotnet/src/webdriver/cdp/README.md index f78d0b3d04ba4..20c23edd23a22 100644 --- a/dotnet/src/webdriver/cdp/README.md +++ b/dotnet/src/webdriver/cdp/README.md @@ -17,7 +17,7 @@ add an entry for version `` to the `SupportedDevToolsVersions` dictionary ini 6. In [`//dotnet/src/webdriver:WebDriver.csproj.prebuild.cmd`](https://github.com/SeleniumHQ/selenium/blob/trunk/dotnet/src/webdriver/WebDriver.csproj.prebuild.cmd), add the following block (substituting the proper value for ``): -``` +```bash if not exist "%1..\..\..\bazel-bin\dotnet\src\webdriver\cdp\v\DevToolsSessionDomains.cs" ( echo Generating CDP code for version pushd "%1..\..\.." @@ -29,7 +29,7 @@ if not exist "%1..\..\..\bazel-bin\dotnet\src\webdriver\cdp\v\DevToolsSessio 7. In [`//dotnet/src/webdriver:WebDriver.csproj.prebuild.sh`](https://github.com/SeleniumHQ/selenium/blob/trunk/dotnet/src/webdriver/WebDriver.csproj.prebuild.sh), add the following block (substituting the proper value for ``): -``` +```bash if [[ ! -f "$1../../../bazel-bin/dotnet/src/webdriver/cdp/v/DevToolsSessionDomains.cs" ]] then echo "Generating CDP code for version " diff --git a/third_party/dotnet/devtools/src/generator/Templates/domain.hbs b/third_party/dotnet/devtools/src/generator/Templates/domain.hbs index 1fc6271239b39..8dc01ba4fb8ea 100644 --- a/third_party/dotnet/devtools/src/generator/Templates/domain.hbs +++ b/third_party/dotnet/devtools/src/generator/Templates/domain.hbs @@ -61,7 +61,7 @@ namespace {{rootNamespace}}.{{domain.Name}} if (m_eventMap.ContainsKey(e.EventName)) { var eventData = m_eventMap[e.EventName]; - var eventArgs = e.EventData.Deserialize(eventData.EventArgsType); + var eventArgs = e.EventData.Deserialize(eventData.EventArgsType, global::OpenQA.Selenium.DevTools.Json.DevToolsJsonOptions.Default); eventData.EventInvoker(eventArgs); } }