Преглед на файлове

Merge pull request #3538 from Ullmie02/api-fix

Fix value parsing in Jellyfin.Api
Bond-009 преди 4 години
родител
ревизия
ab9c1295ce

+ 4 - 1
Jellyfin.Api/Controllers/ConfigurationController.cs

@@ -2,6 +2,7 @@ using System.Text.Json;
 using System.Threading.Tasks;
 using Jellyfin.Api.Constants;
 using Jellyfin.Api.Models.ConfigurationDtos;
+using MediaBrowser.Common.Json;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.MediaEncoding;
 using MediaBrowser.Model.Configuration;
@@ -22,6 +23,8 @@ namespace Jellyfin.Api.Controllers
         private readonly IServerConfigurationManager _configurationManager;
         private readonly IMediaEncoder _mediaEncoder;
 
+        private readonly JsonSerializerOptions _serializerOptions = JsonDefaults.GetOptions();
+
         /// <summary>
         /// Initializes a new instance of the <see cref="ConfigurationController"/> class.
         /// </summary>
@@ -87,7 +90,7 @@ namespace Jellyfin.Api.Controllers
         public async Task<ActionResult> UpdateNamedConfiguration([FromRoute] string? key)
         {
             var configurationType = _configurationManager.GetConfigurationType(key);
-            var configuration = await JsonSerializer.DeserializeAsync(Request.Body, configurationType).ConfigureAwait(false);
+            var configuration = await JsonSerializer.DeserializeAsync(Request.Body, configurationType, _serializerOptions).ConfigureAwait(false);
             _configurationManager.SaveConfiguration(key, configuration);
             return NoContent();
         }

+ 4 - 1
Jellyfin.Api/Controllers/PluginsController.cs

@@ -6,6 +6,7 @@ using System.Threading.Tasks;
 using Jellyfin.Api.Constants;
 using Jellyfin.Api.Models.PluginDtos;
 using MediaBrowser.Common;
+using MediaBrowser.Common.Json;
 using MediaBrowser.Common.Plugins;
 using MediaBrowser.Common.Updates;
 using MediaBrowser.Model.Plugins;
@@ -25,6 +26,8 @@ namespace Jellyfin.Api.Controllers
         private readonly IApplicationHost _appHost;
         private readonly IInstallationManager _installationManager;
 
+        private readonly JsonSerializerOptions _serializerOptions = JsonDefaults.GetOptions();
+
         /// <summary>
         /// Initializes a new instance of the <see cref="PluginsController"/> class.
         /// </summary>
@@ -117,7 +120,7 @@ namespace Jellyfin.Api.Controllers
                 return NotFound();
             }
 
-            var configuration = (BasePluginConfiguration)await JsonSerializer.DeserializeAsync(Request.Body, plugin.ConfigurationType)
+            var configuration = (BasePluginConfiguration)await JsonSerializer.DeserializeAsync(Request.Body, plugin.ConfigurationType, _serializerOptions)
                 .ConfigureAwait(false);
 
             plugin.UpdateConfiguration(configuration);

+ 56 - 0
MediaBrowser.Common/Json/Converters/JsonDoubleConverter.cs

@@ -0,0 +1,56 @@
+using System;
+using System.Buffers;
+using System.Buffers.Text;
+using System.Globalization;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+
+namespace MediaBrowser.Common.Json.Converters
+{
+    /// <summary>
+    /// Double to String JSON converter.
+    /// Web client send quoted doubles.
+    /// </summary>
+    public class JsonDoubleConverter : JsonConverter<double>
+    {
+        /// <summary>
+        /// Read JSON string as double.
+        /// </summary>
+        /// <param name="reader"><see cref="Utf8JsonReader"/>.</param>
+        /// <param name="typeToConvert">Type.</param>
+        /// <param name="options">Options.</param>
+        /// <returns>Parsed value.</returns>
+        public override double Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+        {
+            if (reader.TokenType == JsonTokenType.String)
+            {
+                // try to parse number directly from bytes
+                var span = reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan;
+                if (Utf8Parser.TryParse(span, out double number, out var bytesConsumed) && span.Length == bytesConsumed)
+                {
+                    return number;
+                }
+
+                // try to parse from a string if the above failed, this covers cases with other escaped/UTF characters
+                if (double.TryParse(reader.GetString(), out number))
+                {
+                    return number;
+                }
+            }
+
+            // fallback to default handling
+            return reader.GetDouble();
+        }
+
+        /// <summary>
+        /// Write double to JSON string.
+        /// </summary>
+        /// <param name="writer"><see cref="Utf8JsonWriter"/>.</param>
+        /// <param name="value">Value to write.</param>
+        /// <param name="options">Options.</param>
+        public override void Write(Utf8JsonWriter writer, double value, JsonSerializerOptions options)
+        {
+            writer.WriteStringValue(value.ToString(NumberFormatInfo.InvariantInfo));
+        }
+    }
+}

+ 1 - 0
MediaBrowser.Common/Json/JsonDefaults.cs

@@ -32,6 +32,7 @@ namespace MediaBrowser.Common.Json
             options.Converters.Add(new JsonStringEnumConverter());
             options.Converters.Add(new JsonNonStringKeyDictionaryConverterFactory());
             options.Converters.Add(new JsonInt64Converter());
+            options.Converters.Add(new JsonDoubleConverter());
 
             return options;
         }

+ 7 - 1
MediaBrowser.Model/Configuration/BaseApplicationConfiguration.cs

@@ -52,7 +52,13 @@ namespace MediaBrowser.Model.Configuration
         public string PreviousVersionStr
         {
             get => PreviousVersion?.ToString();
-            set => PreviousVersion = Version.Parse(value);
+            set
+            {
+                if (Version.TryParse(value, out var version))
+                {
+                    PreviousVersion = version;
+                }
+            }
         }
     }
 }