From 03653790271bf403299f30a02f4b8dd77053edbb Mon Sep 17 00:00:00 2001 From: Michael Render Date: Sat, 16 Nov 2024 12:16:43 -0500 Subject: [PATCH] [dotnet] Make FirefoxProfile AOT-safe (#14742) --- .../src/webdriver/Firefox/FirefoxProfile.cs | 22 +--- dotnet/src/webdriver/Firefox/Preferences.cs | 112 ++++++++++-------- 2 files changed, 68 insertions(+), 66 deletions(-) diff --git a/dotnet/src/webdriver/Firefox/FirefoxProfile.cs b/dotnet/src/webdriver/Firefox/FirefoxProfile.cs index 2e0036a8f2819..cf340826db916 100644 --- a/dotnet/src/webdriver/Firefox/FirefoxProfile.cs +++ b/dotnet/src/webdriver/Firefox/FirefoxProfile.cs @@ -296,24 +296,14 @@ private void UpdateUserPreferences() private void ReadDefaultPreferences() { - var jsonSerializerOptions = new JsonSerializerOptions - { - Converters = - { - new ResponseValueJsonConverter() - } - }; - using (Stream defaultPrefsStream = ResourceUtilities.GetResourceStream("webdriver_prefs.json", "webdriver_prefs.json")) { - using (StreamReader reader = new StreamReader(defaultPrefsStream)) - { - string defaultPreferences = reader.ReadToEnd(); - Dictionary deserializedPreferences = JsonSerializer.Deserialize>(defaultPreferences, jsonSerializerOptions); - Dictionary immutableDefaultPreferences = deserializedPreferences["frozen"] as Dictionary; - Dictionary editableDefaultPreferences = deserializedPreferences["mutable"] as Dictionary; - this.profilePreferences = new Preferences(immutableDefaultPreferences, editableDefaultPreferences); - } + using JsonDocument defaultPreferences = JsonDocument.Parse(defaultPrefsStream); + + JsonElement immutableDefaultPreferences = defaultPreferences.RootElement.GetProperty("frozen"); + JsonElement editableDefaultPreferences = defaultPreferences.RootElement.GetProperty("mutable"); + + this.profilePreferences = new Preferences(immutableDefaultPreferences, editableDefaultPreferences); } } diff --git a/dotnet/src/webdriver/Firefox/Preferences.cs b/dotnet/src/webdriver/Firefox/Preferences.cs index fa767ca5a3589..708d3a201c045 100644 --- a/dotnet/src/webdriver/Firefox/Preferences.cs +++ b/dotnet/src/webdriver/Firefox/Preferences.cs @@ -21,6 +21,9 @@ using System.Collections.Generic; using System.Globalization; using System.IO; +using System.Text.Json; + +#nullable enable namespace OpenQA.Selenium.Firefox { @@ -29,31 +32,27 @@ namespace OpenQA.Selenium.Firefox /// internal class Preferences { - private Dictionary preferences = new Dictionary(); - private Dictionary immutablePreferences = new Dictionary(); + private readonly Dictionary preferences = new Dictionary(); + private readonly HashSet immutablePreferences = new HashSet(); /// /// Initializes a new instance of the class. /// /// A set of preferences that cannot be modified once set. /// A set of default preferences. - public Preferences(Dictionary defaultImmutablePreferences, Dictionary defaultPreferences) + public Preferences(JsonElement defaultImmutablePreferences, JsonElement defaultPreferences) { - if (defaultImmutablePreferences != null) + foreach (JsonProperty pref in defaultImmutablePreferences.EnumerateObject()) { - foreach (KeyValuePair pref in defaultImmutablePreferences) - { - this.SetPreferenceValue(pref.Key, pref.Value); - this.immutablePreferences.Add(pref.Key, pref.Value.ToString()); - } + this.ThrowIfPreferenceIsImmutable(pref.Name, pref.Value); + this.preferences[pref.Name] = pref.Value.GetRawText(); + this.immutablePreferences.Add(pref.Name); } - if (defaultPreferences != null) + foreach (JsonProperty pref in defaultPreferences.EnumerateObject()) { - foreach (KeyValuePair pref in defaultPreferences) - { - this.SetPreferenceValue(pref.Key, pref.Value); - } + this.ThrowIfPreferenceIsImmutable(pref.Name, pref.Value); + this.preferences[pref.Name] = pref.Value.GetRawText(); } } @@ -64,9 +63,31 @@ public Preferences(Dictionary defaultImmutablePreferences, Dicti /// A value give the preference. /// If the preference already exists in the currently-set list of preferences, /// the value will be updated. + /// If or are . + /// + /// If is wrapped with double-quotes. + /// -or- + /// If the specified preference is immutable. + /// internal void SetPreference(string key, string value) { - this.SetPreferenceValue(key, value); + if (key is null) + { + throw new ArgumentNullException(nameof(key)); + } + + if (value is null) + { + throw new ArgumentNullException(nameof(value)); + } + + if (IsWrappedAsString(value)) + { + throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "Preference values must be plain strings: {0}: {1}", key, value)); + } + + this.ThrowIfPreferenceIsImmutable(key, value); + this.preferences[key] = string.Format(CultureInfo.InvariantCulture, "\"{0}\"", value); } /// @@ -76,9 +97,17 @@ internal void SetPreference(string key, string value) /// A value give the preference. /// If the preference already exists in the currently-set list of preferences, /// the value will be updated. + /// If is . + /// If the specified preference is immutable. internal void SetPreference(string key, int value) { - this.SetPreferenceValue(key, value); + if (key is null) + { + throw new ArgumentNullException(nameof(key)); + } + + this.ThrowIfPreferenceIsImmutable(key, value); + this.preferences[key] = value.ToString(CultureInfo.InvariantCulture); } /// @@ -88,9 +117,17 @@ internal void SetPreference(string key, int value) /// A value give the preference. /// If the preference already exists in the currently-set list of preferences, /// the value will be updated. + /// If is . + /// If the specified preference is immutable. internal void SetPreference(string key, bool value) { - this.SetPreferenceValue(key, value); + if (key is null) + { + throw new ArgumentNullException(nameof(key)); + } + + this.ThrowIfPreferenceIsImmutable(key, value); + this.preferences[key] = value ? "true" : "false"; } /// @@ -98,6 +135,7 @@ internal void SetPreference(string key, bool value) /// /// The name of the preference to retrieve. /// The value of the preference, or an empty string if the preference is not set. + /// If is . internal string GetPreference(string preferenceName) { if (this.preferences.ContainsKey(preferenceName)) @@ -151,44 +189,18 @@ private static bool IsWrappedAsString(string value) return value.StartsWith("\"", StringComparison.OrdinalIgnoreCase) && value.EndsWith("\"", StringComparison.OrdinalIgnoreCase); } - private bool IsSettablePreference(string preferenceName) + private void ThrowIfPreferenceIsImmutable(string preferenceName, TValue value) { - return !this.immutablePreferences.ContainsKey(preferenceName); - } - - private void SetPreferenceValue(string key, object value) - { - if (!this.IsSettablePreference(key)) + if (this.immutablePreferences.Contains(preferenceName)) { - string message = string.Format(CultureInfo.InvariantCulture, "Preference {0} may not be overridden: frozen value={1}, requested value={2}", key, this.immutablePreferences[key], value.ToString()); + string message = string.Format(CultureInfo.InvariantCulture, "Preference {0} may not be overridden: frozen value={1}, requested value={2}", preferenceName, this.preferences[preferenceName], value?.ToString()); throw new ArgumentException(message); } + } - string stringValue = value as string; - if (stringValue != null) - { - if (IsWrappedAsString(stringValue)) - { - throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "Preference values must be plain strings: {0}: {1}", key, value)); - } - - this.preferences[key] = string.Format(CultureInfo.InvariantCulture, "\"{0}\"", value); - return; - } - - if (value is bool) - { - this.preferences[key] = Convert.ToBoolean(value, CultureInfo.InvariantCulture).ToString().ToLowerInvariant(); - return; - } - - if (value is int || value is long) - { - this.preferences[key] = Convert.ToInt32(value, CultureInfo.InvariantCulture).ToString(CultureInfo.InvariantCulture); - return; - } - - throw new WebDriverException("Value must be string, int or boolean"); + private bool IsSettablePreference(string preferenceName) + { + return !this.immutablePreferences.Contains(preferenceName); } } }