Fix MaxDepth when used with ToObject inside of a JsonConverter (#2505)
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
#region License
|
||||
// Copyright (c) 2007 James Newton-King
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without
|
||||
// restriction, including without limitation the rights to use,
|
||||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following
|
||||
// conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
#endregion
|
||||
|
||||
#if (NET45 || NET50)
|
||||
#if DNXCORE50
|
||||
using Xunit;
|
||||
using Test = Xunit.FactAttribute;
|
||||
using Assert = Newtonsoft.Json.Tests.XUnitAssert;
|
||||
#else
|
||||
using NUnit.Framework;
|
||||
#endif
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using System.Collections;
|
||||
using System;
|
||||
using System.IO;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Newtonsoft.Json.Tests.Issues
|
||||
{
|
||||
[TestFixture]
|
||||
public class Issue2504 : TestFixtureBase
|
||||
{
|
||||
[Test]
|
||||
public void Test()
|
||||
{
|
||||
string jsontext = GetNestedJson(150);
|
||||
|
||||
var o = JsonConvert.DeserializeObject<TestObject>(jsontext, new JsonSerializerSettings
|
||||
{
|
||||
Converters = new List<JsonConverter> { new TestConverter() },
|
||||
MaxDepth = 150
|
||||
});
|
||||
|
||||
Assert.AreEqual(150, GetDepth(o.Children));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Test_Failure()
|
||||
{
|
||||
string jsontext = GetNestedJson(150);
|
||||
|
||||
string expectedMessage = @"The reader's MaxDepth of 100 has been exceeded. Path '0.1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.48.49.50.51.52.53.54.55.56.57.58.59.60.61.62.63.64.65.66.67.68.69.70.71.72.73.74.75.76.77.78.79.80.81.82.83.84.85.86.87.88.89.90.91.92.93.94.95.96.97.98.99', line 101, position 207.";
|
||||
|
||||
ExceptionAssert.Throws<JsonReaderException>(() => JsonConvert.DeserializeObject<TestObject>(jsontext, new JsonSerializerSettings
|
||||
{
|
||||
Converters = new List<JsonConverter> { new TestConverter() },
|
||||
MaxDepth = 100
|
||||
}), expectedMessage);
|
||||
}
|
||||
|
||||
private static int GetDepth(JToken o)
|
||||
{
|
||||
int depth = 1;
|
||||
while (o.First != null)
|
||||
{
|
||||
o = o.First;
|
||||
if (o.Type == JTokenType.Object)
|
||||
{
|
||||
depth++;
|
||||
}
|
||||
}
|
||||
|
||||
return depth;
|
||||
}
|
||||
|
||||
private class TestObject
|
||||
{
|
||||
public JToken Children { get; set; }
|
||||
}
|
||||
|
||||
private class TestConverter : JsonConverter
|
||||
{
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return objectType == typeof(TestObject);
|
||||
}
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
JToken token = JToken.Load(reader);
|
||||
|
||||
var newToken = token.ToObject<JObject>(serializer);
|
||||
|
||||
return new TestObject
|
||||
{
|
||||
Children = newToken
|
||||
};
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1776,6 +1776,45 @@ third line", jsonTextReader.Value);
|
||||
JsonTextReader reader = new JsonTextReader(new StringReader(json));
|
||||
await ExceptionAssert.ThrowsAsync<JsonReaderException>(async () => await JToken.ReadFromAsync(reader, settings));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task MaxDepth_GreaterThanDefaultAsync()
|
||||
{
|
||||
string json = GetNestedJson(150);
|
||||
|
||||
JsonTextReader reader = new JsonTextReader(new StringReader(json));
|
||||
reader.MaxDepth = 150;
|
||||
|
||||
while (await reader.ReadAsync())
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task MaxDepth_NullAsync()
|
||||
{
|
||||
string json = GetNestedJson(150);
|
||||
|
||||
JsonTextReader reader = new JsonTextReader(new StringReader(json));
|
||||
reader.MaxDepth = null;
|
||||
|
||||
while (await reader.ReadAsync())
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task MaxDepth_MaxValueAsync()
|
||||
{
|
||||
string json = GetNestedJson(150);
|
||||
|
||||
JsonTextReader reader = new JsonTextReader(new StringReader(json));
|
||||
reader.MaxDepth = int.MaxValue;
|
||||
|
||||
while (await reader.ReadAsync())
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1770,5 +1770,44 @@ third line", jsonTextReader.Value);
|
||||
JToken.ReadFrom(reader, settings);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void MaxDepth_GreaterThanDefault()
|
||||
{
|
||||
string json = GetNestedJson(150);
|
||||
|
||||
JsonTextReader reader = new JsonTextReader(new StringReader(json));
|
||||
reader.MaxDepth = 150;
|
||||
|
||||
while (reader.Read())
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void MaxDepth_Null()
|
||||
{
|
||||
string json = GetNestedJson(150);
|
||||
|
||||
JsonTextReader reader = new JsonTextReader(new StringReader(json));
|
||||
reader.MaxDepth = null;
|
||||
|
||||
while (reader.Read())
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void MaxDepth_MaxValue()
|
||||
{
|
||||
string json = GetNestedJson(150);
|
||||
|
||||
JsonTextReader reader = new JsonTextReader(new StringReader(json));
|
||||
reader.MaxDepth = int.MaxValue;
|
||||
|
||||
while (reader.Read())
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8032,5 +8032,63 @@ This is just junk, though.";
|
||||
|
||||
Assert.AreEqual(64, reader.MaxDepth);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SetMaxDepth_DefaultDepthExceeded()
|
||||
{
|
||||
string json = GetNestedJson(150);
|
||||
|
||||
ExceptionAssert.Throws<JsonReaderException>(
|
||||
() => JsonConvert.DeserializeObject<JObject>(json),
|
||||
"The reader's MaxDepth of 64 has been exceeded. Path '0.1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.48.49.50.51.52.53.54.55.56.57.58.59.60.61.62.63', line 65, position 135.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SetMaxDepth_IncreasedDepthNotExceeded()
|
||||
{
|
||||
string json = GetNestedJson(150);
|
||||
|
||||
JObject o = JsonConvert.DeserializeObject<JObject>(json, new JsonSerializerSettings { MaxDepth = 150 });
|
||||
int depth = GetDepth(o);
|
||||
|
||||
Assert.AreEqual(150, depth);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SetMaxDepth_NullDepthNotExceeded()
|
||||
{
|
||||
string json = GetNestedJson(150);
|
||||
|
||||
JObject o = JsonConvert.DeserializeObject<JObject>(json, new JsonSerializerSettings { MaxDepth = null });
|
||||
int depth = GetDepth(o);
|
||||
|
||||
Assert.AreEqual(150, depth);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SetMaxDepth_MaxValueDepthNotExceeded()
|
||||
{
|
||||
string json = GetNestedJson(150);
|
||||
|
||||
JObject o = JsonConvert.DeserializeObject<JObject>(json, new JsonSerializerSettings { MaxDepth = int.MaxValue });
|
||||
int depth = GetDepth(o);
|
||||
|
||||
Assert.AreEqual(150, depth);
|
||||
}
|
||||
|
||||
private static int GetDepth(JToken o)
|
||||
{
|
||||
int depth = 1;
|
||||
while (o.First != null)
|
||||
{
|
||||
o = o.First;
|
||||
if (o.Type == JTokenType.Object)
|
||||
{
|
||||
depth++;
|
||||
}
|
||||
}
|
||||
|
||||
return depth;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ using System.Runtime.Serialization.Json;
|
||||
#endif
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using Newtonsoft.Json.Linq;
|
||||
#if DNXCORE50
|
||||
using Xunit;
|
||||
using Assert = Newtonsoft.Json.Tests.XUnitAssert;
|
||||
@@ -306,6 +307,21 @@ namespace Newtonsoft.Json.Tests
|
||||
{
|
||||
return @"@""" + json.Replace(@"""", @"""""") + @"""";
|
||||
}
|
||||
|
||||
protected string GetNestedJson(int depth)
|
||||
{
|
||||
JObject root = new JObject();
|
||||
JObject current = root;
|
||||
for (int i = 0; i < depth - 1; i++)
|
||||
{
|
||||
JObject nested = new JObject();
|
||||
current[i.ToString()] = nested;
|
||||
|
||||
current = nested;
|
||||
}
|
||||
|
||||
return root.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public static class CustomAssert
|
||||
|
||||
@@ -228,7 +228,7 @@ namespace Newtonsoft.Json
|
||||
/// <summary>
|
||||
/// Gets or sets the maximum depth allowed when reading JSON. Reading past this depth will throw a <see cref="JsonReaderException"/>.
|
||||
/// A null value means there is no maximum.
|
||||
/// The default value is <c>128</c>.
|
||||
/// The default value is <c>64</c>.
|
||||
/// </summary>
|
||||
public int? MaxDepth
|
||||
{
|
||||
|
||||
@@ -514,7 +514,7 @@ namespace Newtonsoft.Json
|
||||
/// <summary>
|
||||
/// Gets or sets the maximum depth allowed when reading JSON. Reading past this depth will throw a <see cref="JsonReaderException"/>.
|
||||
/// A null value means there is no maximum.
|
||||
/// The default value is <c>128</c>.
|
||||
/// The default value is <c>64</c>.
|
||||
/// </summary>
|
||||
public virtual int? MaxDepth
|
||||
{
|
||||
@@ -913,7 +913,7 @@ namespace Newtonsoft.Json
|
||||
return value;
|
||||
}
|
||||
|
||||
private void SetupReader(JsonReader reader, out CultureInfo? previousCulture, out DateTimeZoneHandling? previousDateTimeZoneHandling, out DateParseHandling? previousDateParseHandling, out FloatParseHandling? previousFloatParseHandling, out int? previousMaxDepth, out string? previousDateFormatString)
|
||||
internal void SetupReader(JsonReader reader, out CultureInfo? previousCulture, out DateTimeZoneHandling? previousDateTimeZoneHandling, out DateParseHandling? previousDateParseHandling, out FloatParseHandling? previousFloatParseHandling, out int? previousMaxDepth, out string? previousDateFormatString)
|
||||
{
|
||||
if (_culture != null && !_culture.Equals(reader.Culture))
|
||||
{
|
||||
|
||||
@@ -326,7 +326,7 @@ namespace Newtonsoft.Json
|
||||
/// <summary>
|
||||
/// Gets or sets the maximum depth allowed when reading JSON. Reading past this depth will throw a <see cref="JsonReaderException"/>.
|
||||
/// A null value means there is no maximum.
|
||||
/// The default value is <c>128</c>.
|
||||
/// The default value is <c>64</c>.
|
||||
/// </summary>
|
||||
public int? MaxDepth
|
||||
{
|
||||
|
||||
@@ -45,6 +45,7 @@ using Newtonsoft.Json.Utilities.LinqBridge;
|
||||
#else
|
||||
using System.Linq;
|
||||
#endif
|
||||
using Newtonsoft.Json.Serialization;
|
||||
|
||||
namespace Newtonsoft.Json.Linq
|
||||
{
|
||||
@@ -2079,6 +2080,13 @@ namespace Newtonsoft.Json.Linq
|
||||
|
||||
using (JTokenReader jsonReader = new JTokenReader(this))
|
||||
{
|
||||
// Hacky fix to ensure the serializer settings are set onto the new reader.
|
||||
// This is required because the serializer won't update settings when used inside of a converter.
|
||||
if (jsonSerializer is JsonSerializerProxy proxy)
|
||||
{
|
||||
proxy._serializer.SetupReader(jsonReader, out _, out _, out _, out _, out _, out _);
|
||||
}
|
||||
|
||||
return jsonSerializer.Deserialize(jsonReader, objectType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace Newtonsoft.Json.Serialization
|
||||
{
|
||||
private readonly JsonSerializerInternalReader? _serializerReader;
|
||||
private readonly JsonSerializerInternalWriter? _serializerWriter;
|
||||
private readonly JsonSerializer _serializer;
|
||||
internal readonly JsonSerializer _serializer;
|
||||
|
||||
public override event EventHandler<ErrorEventArgs>? Error
|
||||
{
|
||||
|
||||
@@ -138,7 +138,7 @@ namespace Newtonsoft.Json.Serialization
|
||||
|
||||
public override object? Value => _innerReader.Value;
|
||||
|
||||
public override Type ?ValueType => _innerReader.ValueType;
|
||||
public override Type? ValueType => _innerReader.ValueType;
|
||||
|
||||
public override void Close()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user