diff --git a/Src/Directory.Build.props b/Src/Directory.Build.props
index cfaf3745..11ecc418 100644
--- a/Src/Directory.Build.props
+++ b/Src/Directory.Build.props
@@ -22,7 +22,5 @@
4.4.0
2.3.1
2.3.1
- 32.0.2
- 5.1.0
diff --git a/Src/Newtonsoft.Json.Tests/Linq/JsonPath/JPathExecuteTests.cs b/Src/Newtonsoft.Json.Tests/Linq/JsonPath/JPathExecuteTests.cs
index 6b3a512e..10611fed 100644
--- a/Src/Newtonsoft.Json.Tests/Linq/JsonPath/JPathExecuteTests.cs
+++ b/Src/Newtonsoft.Json.Tests/Linq/JsonPath/JPathExecuteTests.cs
@@ -32,11 +32,7 @@ using System.Numerics;
using Newtonsoft.Json.Linq.JsonPath;
using Newtonsoft.Json.Tests.Bson;
#if HAVE_REGEX_TIMEOUTS
-using Bogus;
-using Nito.AsyncEx;
using System.Text.RegularExpressions;
-using System.Threading.Tasks;
-using System.Threading;
#endif
#if DNXCORE50
using Xunit;
@@ -81,69 +77,21 @@ namespace Newtonsoft.Json.Tests.Linq.JsonPath
[Test]
public void BacktrackingRegex_SingleMatch_TimeoutRespected()
{
- var RegexBacktrackingPattern = "(?(.*?))[|].*(?(.*?))[|].*(?(.*?))[|].*(?[1-3])[|].*(?(.*?))[|].*[|].*[|].*(?(.*?))[|].*[|].*(?(.*?))[|].*(?(.*))";
+ const string RegexBacktrackingPattern = "(?(.*?))[|].*(?(.*?))[|].*(?(.*?))[|].*(?[1-3])[|].*(?(.*?))[|].*[|].*[|].*(?(.*?))[|].*[|].*(?(.*?))[|].*(?(.*))";
- var faker = new Faker();
var regexBacktrackingData = new JArray();
+ regexBacktrackingData.Add(new JObject(new JProperty("b", @"15/04/2020 8:18:03 PM|1|System.String[]|3|Libero eligendi magnam ut inventore.. Quaerat et sit voluptatibus repellendus blanditiis aliquam ut.. Quidem qui ut sint in ex et tempore.|||.\iste.cpp||46018|-1")));
- for (var i = 0; i < 1000; i++)
+ ExceptionAssert.Throws(() =>
{
- var value = $"{faker.Date.Past()}|1|{faker.Lorem.Words()}|3|{faker.Lorem.Sentences(3, ". ")}|||.\\{faker.Lorem.Word()}.cpp||{faker.Random.UShort()}|-1";
- regexBacktrackingData.Add(new JObject(new JProperty("b", value)));
- }
-
- Xunit.Assert.Throws(() =>
- {
- var tokens = regexBacktrackingData.SelectTokens(
+ regexBacktrackingData.SelectTokens(
$"[?(@.b =~ /{RegexBacktrackingPattern}/)]",
- errorWhenNoMatch: false,
- singleRegexMatchTimeout: TimeSpan.FromSeconds(.01)).ToArray();
+ new JsonSelectSettings
+ {
+ RegexMatchTimeout = TimeSpan.FromSeconds(0.01)
+ }).ToArray();
});
}
-
- [Test]
- public void BacktrackingRegex_GlobalMatch_TimeoutRespected()
- {
- var faker = new Faker();
- var regexBacktrackingData = new JArray();
- for (var i = 0; i < 1000; i++)
- {
- var value = $"{faker.Date.Past()}|1|{faker.Lorem.Words()}|3|{faker.Lorem.Sentences(3, ". ")}|||.\\{faker.Lorem.Word()}.cpp||{faker.Random.UShort()}|-1";
- regexBacktrackingData.Add(new JObject(new JProperty("b", value)));
- }
- var RegexBacktrackingPattern = "(?(.*?))[|].*(?(.*?))[|].*(?(.*?))[|].*(?[1-3])[|].*(?(.*?))[|].*[|].*[|].*(?(.*?))[|].*[|].*(?(.*?))[|].*(?(.*))";
- var jpathExpression = $"[?(@.b =~ /{RegexBacktrackingPattern}/c)]";
-
- var exceptionThrow = Xunit.Assert.ThrowsAny(() =>
- {
- var tokens = regexBacktrackingData.SelectTokens(
- jpathExpression,
- errorWhenNoMatch: false,
- singleRegexMatchTimeout: TimeSpan.FromSeconds(2),
- globalRegexMatchTimeout: TimeSpan.FromSeconds(.5)).ToArray();
- });
- Assert.IsTrue(exceptionThrow is OperationCanceledException or RegexMatchTimeoutException);
- }
-
- [Test]
- public async Task BacktrackingRegexCanBeVerySlowWithoutTimeouts()
- {
- var RegexBacktrackingPattern = "(?(.*?))[|].*(?(.*?))[|].*(?(.*?))[|].*(?[1-3])[|].*(?(.*?))[|].*[|].*[|].*(?(.*?))[|].*[|].*(?(.*?))[|].*(?(.*))";
- var faker = new Faker();
- var regexBacktrackingData = new JArray();
-
- for (var i = 0; i < 10; i++)
- {
- var value = $"{faker.Date.Past()}|1|{faker.Lorem.Words()}|3|{faker.Lorem.Sentences(3, ". ")}|||.\\{faker.Lorem.Word()}.cpp||{faker.Random.UShort()}|-1";
- regexBacktrackingData.Add(new JObject(new JProperty("b", value)));
- }
-
- var selectTokenTask = Task.Run(() => regexBacktrackingData.SelectTokens($"[?(@.b =~ /{RegexBacktrackingPattern}/)]").ToArray());
- using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(.3));
- using var ctts = new CancellationTokenTaskSource(cts.Token);
- var finishedTask = await Task.WhenAny(selectTokenTask, ctts.Task);
- Assert.AreEqual(finishedTask, ctts.Task);
- }
#endif
[Test]
diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj
index 7989fe9f..c074971d 100644
--- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj
+++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj
@@ -62,7 +62,7 @@
Json.NET Tests
.NETFramework,Version=v4.5
- NET45;HAVE_BENCHMARKS;$(AdditionalConstants)
+ NET45;HAVE_BENCHMARKS;HAVE_REGEX_TIMEOUTS;$(AdditionalConstants)
@@ -76,7 +76,6 @@
-
Json.NET Tests .NET 4.0
@@ -122,10 +121,7 @@
-
-
-
Json.NET Tests .NET Standard 2.0
.NETStandard,Version=v2.0
@@ -146,8 +142,6 @@
-
-
Json.NET Tests .NET Standard 1.3
@@ -168,10 +162,7 @@
-
-
-
Json.NET Tests .NET Standard 1.0
.NETStandard,Version=v1.0
diff --git a/Src/Newtonsoft.Json/Linq/JToken.cs b/Src/Newtonsoft.Json/Linq/JToken.cs
index 252f846c..31b7fb36 100644
--- a/Src/Newtonsoft.Json/Linq/JToken.cs
+++ b/Src/Newtonsoft.Json/Linq/JToken.cs
@@ -44,7 +44,6 @@ using System.Diagnostics.CodeAnalysis;
using Newtonsoft.Json.Utilities.LinqBridge;
#else
using System.Linq;
-using System.Threading;
#endif
namespace Newtonsoft.Json.Linq
@@ -2308,7 +2307,7 @@ namespace Newtonsoft.Json.Linq
/// A , or null.
public JToken? SelectToken(string path)
{
- return SelectToken(path, false);
+ return SelectToken(path, settings: null);
}
///
@@ -2321,38 +2320,27 @@ namespace Newtonsoft.Json.Linq
/// A .
public JToken? SelectToken(string path, bool errorWhenNoMatch)
{
- JPath p = new JPath(path);
+ JsonSelectSettings? settings = errorWhenNoMatch
+ ? new JsonSelectSettings { ErrorWhenNoMatch = true }
+ : null;
- JToken? token = null;
- foreach (JToken t in p.Evaluate(this, this, errorWhenNoMatch))
- {
- if (token != null)
- {
- throw new JsonException("Path returned multiple tokens.");
- }
-
- token = t;
- }
-
- return token;
+ return SelectToken(path, settings);
}
-#if HAVE_REGEX_TIMEOUTS
///
/// Selects a using a JSONPath expression. Selects the token that matches the object path.
///
///
/// A that contains a JSONPath expression.
///
- /// A flag to indicate whether an error should be thrown if no tokens are found when evaluating part of the expression.
- /// the time after which a single call to regex.ismatch must complete, default is forever
+ /// The used to select tokens.
/// A .
- public JToken? SelectToken(string path, bool errorWhenNoMatch, TimeSpan? singleMatchTimeout = default)
+ public JToken? SelectToken(string path, JsonSelectSettings? settings)
{
- JPath p = new JPath(path, singleMatchTimeout);
+ JPath p = new JPath(path);
JToken? token = null;
- foreach (JToken t in p.Evaluate(this, this, errorWhenNoMatch))
+ foreach (JToken t in p.Evaluate(this, this, settings))
{
if (token != null)
{
@@ -2364,7 +2352,6 @@ namespace Newtonsoft.Json.Linq
return token;
}
-#endif
///
/// Selects a collection of elements using a JSONPath expression.
@@ -2375,7 +2362,7 @@ namespace Newtonsoft.Json.Linq
/// An of that contains the selected elements.
public IEnumerable SelectTokens(string path)
{
- return SelectTokens(path, false);
+ return SelectTokens(path, settings: null);
}
///
@@ -2388,50 +2375,26 @@ namespace Newtonsoft.Json.Linq
/// An of that contains the selected elements.
public IEnumerable SelectTokens(string path, bool errorWhenNoMatch)
{
- var p = new JPath(path);
- return p.Evaluate(this, this, errorWhenNoMatch);
+ JsonSelectSettings? settings = errorWhenNoMatch
+ ? new JsonSelectSettings { ErrorWhenNoMatch = true }
+ : null;
+
+ return SelectTokens(path, settings);
}
-#if HAVE_REGEX_TIMEOUTS
///
/// Selects a collection of elements using a JSONPath expression.
///
///
/// A that contains a JSONPath expression.
///
- /// A flag to indicate whether an error should be thrown if no tokens are found when evaluating part of the expression.
- ///
- /// for every token that matches a jpath, the time a regex is permitted to run
- /// against that token before timeout
- ///
- ///
- /// the time this method should wait for the given jpath regex to match all tokens.
- /// worst case expected execution time roughly globalRegexMatchTimeout + Min(singleRegexMatchTimeout, globalRegexMatchTimeout)
- ///
- /// if single call timeout exceeded"
+ /// The used to select tokens.
/// An of that contains the selected elements.
- public IEnumerable SelectTokens(string path,
- bool errorWhenNoMatch,
- TimeSpan? singleRegexMatchTimeout = default,
- TimeSpan? globalRegexMatchTimeout = default)
+ public IEnumerable SelectTokens(string path, JsonSelectSettings? settings)
{
- var singleTimeout = singleRegexMatchTimeout ?? Timeout.InfiniteTimeSpan;
- var globalTimeout = globalRegexMatchTimeout ?? Timeout.InfiniteTimeSpan;
- if (globalTimeout != Timeout.InfiniteTimeSpan && globalTimeout < singleTimeout)
- {
- singleTimeout = globalTimeout;
- }
-
- using var cts = new CancellationTokenSource(globalTimeout);
- var p = new JPath(path, singleTimeout);
- var results = p.Evaluate(this, this, errorWhenNoMatch);
- foreach (var result in results)
- {
- cts.Token.ThrowIfCancellationRequested();
- yield return result;
- }
+ var p = new JPath(path);
+ return p.Evaluate(this, this, settings);
}
-#endif
#if HAVE_DYNAMIC
///
diff --git a/Src/Newtonsoft.Json/Linq/JsonPath/ArrayIndexFilter.cs b/Src/Newtonsoft.Json/Linq/JsonPath/ArrayIndexFilter.cs
index 653a2ea6..0378713d 100644
--- a/Src/Newtonsoft.Json/Linq/JsonPath/ArrayIndexFilter.cs
+++ b/Src/Newtonsoft.Json/Linq/JsonPath/ArrayIndexFilter.cs
@@ -8,13 +8,13 @@ namespace Newtonsoft.Json.Linq.JsonPath
{
public int? Index { get; set; }
- public override IEnumerable ExecuteFilter(JToken root, IEnumerable current, bool errorWhenNoMatch)
+ public override IEnumerable ExecuteFilter(JToken root, IEnumerable current, JsonSelectSettings? settings)
{
foreach (JToken t in current)
{
if (Index != null)
{
- JToken? v = GetTokenIndex(t, errorWhenNoMatch, Index.GetValueOrDefault());
+ JToken? v = GetTokenIndex(t, settings, Index.GetValueOrDefault());
if (v != null)
{
@@ -32,7 +32,7 @@ namespace Newtonsoft.Json.Linq.JsonPath
}
else
{
- if (errorWhenNoMatch)
+ if (settings?.ErrorWhenNoMatch ?? false)
{
throw new JsonException("Index * not valid on {0}.".FormatWith(CultureInfo.InvariantCulture, t.GetType().Name));
}
diff --git a/Src/Newtonsoft.Json/Linq/JsonPath/ArrayMultipleIndexFilter.cs b/Src/Newtonsoft.Json/Linq/JsonPath/ArrayMultipleIndexFilter.cs
index ddf15206..e1492298 100644
--- a/Src/Newtonsoft.Json/Linq/JsonPath/ArrayMultipleIndexFilter.cs
+++ b/Src/Newtonsoft.Json/Linq/JsonPath/ArrayMultipleIndexFilter.cs
@@ -11,13 +11,13 @@ namespace Newtonsoft.Json.Linq.JsonPath
Indexes = indexes;
}
- public override IEnumerable ExecuteFilter(JToken root, IEnumerable current, bool errorWhenNoMatch)
+ public override IEnumerable ExecuteFilter(JToken root, IEnumerable current, JsonSelectSettings? settings)
{
foreach (JToken t in current)
{
foreach (int i in Indexes)
{
- JToken? v = GetTokenIndex(t, errorWhenNoMatch, i);
+ JToken? v = GetTokenIndex(t, settings, i);
if (v != null)
{
diff --git a/Src/Newtonsoft.Json/Linq/JsonPath/ArraySliceFilter.cs b/Src/Newtonsoft.Json/Linq/JsonPath/ArraySliceFilter.cs
index e6ee0b7b..c948b5e0 100644
--- a/Src/Newtonsoft.Json/Linq/JsonPath/ArraySliceFilter.cs
+++ b/Src/Newtonsoft.Json/Linq/JsonPath/ArraySliceFilter.cs
@@ -11,7 +11,7 @@ namespace Newtonsoft.Json.Linq.JsonPath
public int? End { get; set; }
public int? Step { get; set; }
- public override IEnumerable ExecuteFilter(JToken root, IEnumerable current, bool errorWhenNoMatch)
+ public override IEnumerable ExecuteFilter(JToken root, IEnumerable current, JsonSelectSettings? settings)
{
if (Step == 0)
{
@@ -56,7 +56,7 @@ namespace Newtonsoft.Json.Linq.JsonPath
}
else
{
- if (errorWhenNoMatch)
+ if (settings?.ErrorWhenNoMatch ?? false)
{
throw new JsonException("Array slice of {0} to {1} returned no results.".FormatWith(CultureInfo.InvariantCulture,
Start != null ? Start.GetValueOrDefault().ToString(CultureInfo.InvariantCulture) : "*",
@@ -66,7 +66,7 @@ namespace Newtonsoft.Json.Linq.JsonPath
}
else
{
- if (errorWhenNoMatch)
+ if (settings?.ErrorWhenNoMatch ?? false)
{
throw new JsonException("Array slice is not valid on {0}.".FormatWith(CultureInfo.InvariantCulture, t.GetType().Name));
}
diff --git a/Src/Newtonsoft.Json/Linq/JsonPath/FieldFilter.cs b/Src/Newtonsoft.Json/Linq/JsonPath/FieldFilter.cs
index d1374e5a..97f63816 100644
--- a/Src/Newtonsoft.Json/Linq/JsonPath/FieldFilter.cs
+++ b/Src/Newtonsoft.Json/Linq/JsonPath/FieldFilter.cs
@@ -13,7 +13,7 @@ namespace Newtonsoft.Json.Linq.JsonPath
Name = name;
}
- public override IEnumerable ExecuteFilter(JToken root, IEnumerable current, bool errorWhenNoMatch)
+ public override IEnumerable ExecuteFilter(JToken root, IEnumerable current, JsonSelectSettings? settings)
{
foreach (JToken t in current)
{
@@ -27,7 +27,7 @@ namespace Newtonsoft.Json.Linq.JsonPath
{
yield return v;
}
- else if (errorWhenNoMatch)
+ else if (settings?.ErrorWhenNoMatch ?? false)
{
throw new JsonException("Property '{0}' does not exist on JObject.".FormatWith(CultureInfo.InvariantCulture, Name));
}
@@ -42,7 +42,7 @@ namespace Newtonsoft.Json.Linq.JsonPath
}
else
{
- if (errorWhenNoMatch)
+ if (settings?.ErrorWhenNoMatch ?? false)
{
throw new JsonException("Property '{0}' not valid on {1}.".FormatWith(CultureInfo.InvariantCulture, Name ?? "*", t.GetType().Name));
}
diff --git a/Src/Newtonsoft.Json/Linq/JsonPath/FieldMultipleFilter.cs b/Src/Newtonsoft.Json/Linq/JsonPath/FieldMultipleFilter.cs
index 20cd0688..c3eb7033 100644
--- a/Src/Newtonsoft.Json/Linq/JsonPath/FieldMultipleFilter.cs
+++ b/Src/Newtonsoft.Json/Linq/JsonPath/FieldMultipleFilter.cs
@@ -18,7 +18,7 @@ namespace Newtonsoft.Json.Linq.JsonPath
Names = names;
}
- public override IEnumerable ExecuteFilter(JToken root, IEnumerable current, bool errorWhenNoMatch)
+ public override IEnumerable ExecuteFilter(JToken root, IEnumerable current, JsonSelectSettings? settings)
{
foreach (JToken t in current)
{
@@ -33,7 +33,7 @@ namespace Newtonsoft.Json.Linq.JsonPath
yield return v;
}
- if (errorWhenNoMatch)
+ if (settings?.ErrorWhenNoMatch ?? false)
{
throw new JsonException("Property '{0}' does not exist on JObject.".FormatWith(CultureInfo.InvariantCulture, name));
}
@@ -41,7 +41,7 @@ namespace Newtonsoft.Json.Linq.JsonPath
}
else
{
- if (errorWhenNoMatch)
+ if (settings?.ErrorWhenNoMatch ?? false)
{
throw new JsonException("Properties {0} not valid on {1}.".FormatWith(CultureInfo.InvariantCulture, string.Join(", ", Names.Select(n => "'" + n + "'")
#if !HAVE_STRING_JOIN_WITH_ENUMERABLE
diff --git a/Src/Newtonsoft.Json/Linq/JsonPath/JPath.cs b/Src/Newtonsoft.Json/Linq/JsonPath/JPath.cs
index d5bc4e89..c29fcd06 100644
--- a/Src/Newtonsoft.Json/Linq/JsonPath/JPath.cs
+++ b/Src/Newtonsoft.Json/Linq/JsonPath/JPath.cs
@@ -27,8 +27,6 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
-using System.Text.RegularExpressions;
-using System.Threading;
using Newtonsoft.Json.Utilities;
namespace Newtonsoft.Json.Linq.JsonPath
@@ -39,16 +37,14 @@ namespace Newtonsoft.Json.Linq.JsonPath
private readonly string _expression;
public List Filters { get; }
- public readonly TimeSpan? RegexSingleMatchTimeout = default;
private int _currentIndex;
- public JPath(string expression, TimeSpan? regexSingleMatchTimeout = default)
+ public JPath(string expression)
{
ValidationUtils.ArgumentNotNull(expression, nameof(expression));
_expression = expression;
Filters = new List();
- RegexSingleMatchTimeout = regexSingleMatchTimeout;
ParseMain();
}
@@ -513,8 +509,7 @@ namespace Newtonsoft.Json.Linq.JsonPath
right = ParseSide();
}
-
- var booleanExpression = new BooleanQueryExpression(op, left, right, RegexSingleMatchTimeout);
+ BooleanQueryExpression booleanExpression = new BooleanQueryExpression(op, left, right);
if (_expression[_currentIndex] == ')')
{
@@ -879,17 +874,17 @@ namespace Newtonsoft.Json.Linq.JsonPath
}
}
- internal IEnumerable Evaluate(JToken root, JToken t, bool errorWhenNoMatch)
+ internal IEnumerable Evaluate(JToken root, JToken t, JsonSelectSettings? settings)
{
- return Evaluate(Filters, root, t, errorWhenNoMatch);
+ return Evaluate(Filters, root, t, settings);
}
- internal static IEnumerable Evaluate(List filters, JToken root, JToken t, bool errorWhenNoMatch)
+ internal static IEnumerable Evaluate(List filters, JToken root, JToken t, JsonSelectSettings? settings)
{
IEnumerable current = new[] { t };
foreach (PathFilter filter in filters)
{
- current = filter.ExecuteFilter(root, current, errorWhenNoMatch);
+ current = filter.ExecuteFilter(root, current, settings);
}
return current;
diff --git a/Src/Newtonsoft.Json/Linq/JsonPath/PathFilter.cs b/Src/Newtonsoft.Json/Linq/JsonPath/PathFilter.cs
index abba44ee..45a1683e 100644
--- a/Src/Newtonsoft.Json/Linq/JsonPath/PathFilter.cs
+++ b/Src/Newtonsoft.Json/Linq/JsonPath/PathFilter.cs
@@ -6,15 +6,15 @@ namespace Newtonsoft.Json.Linq.JsonPath
{
internal abstract class PathFilter
{
- public abstract IEnumerable ExecuteFilter(JToken root, IEnumerable current, bool errorWhenNoMatch);
+ public abstract IEnumerable ExecuteFilter(JToken root, IEnumerable current, JsonSelectSettings? settings);
- protected static JToken? GetTokenIndex(JToken t, bool errorWhenNoMatch, int index)
+ protected static JToken? GetTokenIndex(JToken t, JsonSelectSettings? settings, int index)
{
if (t is JArray a)
{
if (a.Count <= index)
{
- if (errorWhenNoMatch)
+ if (settings?.ErrorWhenNoMatch ?? false)
{
throw new JsonException("Index {0} outside the bounds of JArray.".FormatWith(CultureInfo.InvariantCulture, index));
}
@@ -28,7 +28,7 @@ namespace Newtonsoft.Json.Linq.JsonPath
{
if (c.Count <= index)
{
- if (errorWhenNoMatch)
+ if (settings?.ErrorWhenNoMatch ?? false)
{
throw new JsonException("Index {0} outside the bounds of JConstructor.".FormatWith(CultureInfo.InvariantCulture, index));
}
@@ -40,7 +40,7 @@ namespace Newtonsoft.Json.Linq.JsonPath
}
else
{
- if (errorWhenNoMatch)
+ if (settings?.ErrorWhenNoMatch ?? false)
{
throw new JsonException("Index {0} not valid on {1}.".FormatWith(CultureInfo.InvariantCulture, index, t.GetType().Name));
}
diff --git a/Src/Newtonsoft.Json/Linq/JsonPath/QueryExpression.cs b/Src/Newtonsoft.Json/Linq/JsonPath/QueryExpression.cs
index f9aa84d1..1ab97041 100644
--- a/Src/Newtonsoft.Json/Linq/JsonPath/QueryExpression.cs
+++ b/Src/Newtonsoft.Json/Linq/JsonPath/QueryExpression.cs
@@ -4,7 +4,6 @@ using System.Globalization;
using System.IO;
using System.Text.RegularExpressions;
using System.Diagnostics;
-using System.Threading;
#if !HAVE_LINQ
using Newtonsoft.Json.Utilities.LinqBridge;
#else
@@ -40,7 +39,13 @@ namespace Newtonsoft.Json.Linq.JsonPath
Operator = @operator;
}
- public abstract bool IsMatch(JToken root, JToken t);
+ // For unit tests
+ public bool IsMatch(JToken root, JToken t)
+ {
+ return IsMatch(root, t, null);
+ }
+
+ public abstract bool IsMatch(JToken root, JToken t, JsonSelectSettings? settings);
}
internal class CompositeExpression : QueryExpression
@@ -52,14 +57,14 @@ namespace Newtonsoft.Json.Linq.JsonPath
Expressions = new List();
}
- public override bool IsMatch(JToken root, JToken t)
+ public override bool IsMatch(JToken root, JToken t, JsonSelectSettings? settings)
{
switch (Operator)
{
case QueryOperator.And:
foreach (QueryExpression e in Expressions)
{
- if (!e.IsMatch(root, t))
+ if (!e.IsMatch(root, t, settings))
{
return false;
}
@@ -68,7 +73,7 @@ namespace Newtonsoft.Json.Linq.JsonPath
case QueryOperator.Or:
foreach (QueryExpression e in Expressions)
{
- if (e.IsMatch(root, t))
+ if (e.IsMatch(root, t, settings))
{
return true;
}
@@ -84,17 +89,11 @@ namespace Newtonsoft.Json.Linq.JsonPath
{
public readonly object Left;
public readonly object? Right;
- public readonly TimeSpan? SingleMatchTimeout;
- public BooleanQueryExpression(QueryOperator @operator,
- object left,
- object? right,
- TimeSpan? regexSingleMatchTimeout = default)
- : base(@operator)
+ public BooleanQueryExpression(QueryOperator @operator, object left, object? right) : base(@operator)
{
Left = left;
Right = right;
- SingleMatchTimeout = regexSingleMatchTimeout;
}
private IEnumerable GetResult(JToken root, JToken t, object? o)
@@ -106,13 +105,13 @@ namespace Newtonsoft.Json.Linq.JsonPath
if (o is List pathFilters)
{
- return JPath.Evaluate(pathFilters, root, t, false);
+ return JPath.Evaluate(pathFilters, root, t, null);
}
return CollectionUtils.ArrayEmpty();
}
- public override bool IsMatch(JToken root, JToken t)
+ public override bool IsMatch(JToken root, JToken t, JsonSelectSettings? settings)
{
if (Operator == QueryOperator.Exists)
{
@@ -131,7 +130,7 @@ namespace Newtonsoft.Json.Linq.JsonPath
JToken leftResult = leftResults.Current;
foreach (JToken rightResult in rightResults)
{
- if (MatchTokens(leftResult, rightResult))
+ if (MatchTokens(leftResult, rightResult, settings))
{
return true;
}
@@ -143,14 +142,14 @@ namespace Newtonsoft.Json.Linq.JsonPath
return false;
}
- private bool MatchTokens(JToken leftResult, JToken rightResult)
+ private bool MatchTokens(JToken leftResult, JToken rightResult, JsonSelectSettings? settings)
{
if (leftResult is JValue leftValue && rightResult is JValue rightValue)
{
switch (Operator)
{
case QueryOperator.RegexEquals:
- if (RegexEquals(leftValue, rightValue, SingleMatchTimeout))
+ if (RegexEquals(leftValue, rightValue, settings))
{
return true;
}
@@ -222,9 +221,7 @@ namespace Newtonsoft.Json.Linq.JsonPath
return false;
}
- private static bool RegexEquals(JValue input,
- JValue pattern,
- TimeSpan? regexMatchTimeout = default)
+ private static bool RegexEquals(JValue input, JValue pattern, JsonSelectSettings? settings)
{
if (input.Type != JTokenType.String || pattern.Type != JTokenType.String)
{
@@ -238,7 +235,7 @@ namespace Newtonsoft.Json.Linq.JsonPath
string optionsText = regexText.Substring(patternOptionDelimiterIndex + 1);
#if HAVE_REGEX_TIMEOUTS
- var timeout = regexMatchTimeout ?? Regex.InfiniteMatchTimeout;
+ TimeSpan timeout = settings?.RegexMatchTimeout ?? Regex.InfiniteMatchTimeout;
return Regex.IsMatch((string)input.Value!, patternText, MiscellaneousUtils.GetRegexOptions(optionsText), timeout);
#else
return Regex.IsMatch((string)input.Value!, patternText, MiscellaneousUtils.GetRegexOptions(optionsText));
diff --git a/Src/Newtonsoft.Json/Linq/JsonPath/QueryFilter.cs b/Src/Newtonsoft.Json/Linq/JsonPath/QueryFilter.cs
index c528623f..e844e113 100644
--- a/Src/Newtonsoft.Json/Linq/JsonPath/QueryFilter.cs
+++ b/Src/Newtonsoft.Json/Linq/JsonPath/QueryFilter.cs
@@ -12,13 +12,13 @@ namespace Newtonsoft.Json.Linq.JsonPath
Expression = expression;
}
- public override IEnumerable ExecuteFilter(JToken root, IEnumerable current, bool errorWhenNoMatch)
+ public override IEnumerable ExecuteFilter(JToken root, IEnumerable current, JsonSelectSettings? settings)
{
foreach (JToken t in current)
{
foreach (JToken v in t)
{
- if (Expression.IsMatch(root, v))
+ if (Expression.IsMatch(root, v, settings))
{
yield return v;
}
diff --git a/Src/Newtonsoft.Json/Linq/JsonPath/QueryScanFilter.cs b/Src/Newtonsoft.Json/Linq/JsonPath/QueryScanFilter.cs
index 42237671..a1b5270a 100644
--- a/Src/Newtonsoft.Json/Linq/JsonPath/QueryScanFilter.cs
+++ b/Src/Newtonsoft.Json/Linq/JsonPath/QueryScanFilter.cs
@@ -12,7 +12,7 @@ namespace Newtonsoft.Json.Linq.JsonPath
Expression = expression;
}
- public override IEnumerable ExecuteFilter(JToken root, IEnumerable current, bool errorWhenNoMatch)
+ public override IEnumerable ExecuteFilter(JToken root, IEnumerable current, JsonSelectSettings? settings)
{
foreach (JToken t in current)
{
@@ -20,7 +20,7 @@ namespace Newtonsoft.Json.Linq.JsonPath
{
foreach (JToken d in c.DescendantsAndSelf())
{
- if (Expression.IsMatch(root, d))
+ if (Expression.IsMatch(root, d, settings))
{
yield return d;
}
@@ -28,7 +28,7 @@ namespace Newtonsoft.Json.Linq.JsonPath
}
else
{
- if (Expression.IsMatch(root, t))
+ if (Expression.IsMatch(root, t, settings))
{
yield return t;
}
diff --git a/Src/Newtonsoft.Json/Linq/JsonPath/RootFilter.cs b/Src/Newtonsoft.Json/Linq/JsonPath/RootFilter.cs
index 00f5b725..164ba0c0 100644
--- a/Src/Newtonsoft.Json/Linq/JsonPath/RootFilter.cs
+++ b/Src/Newtonsoft.Json/Linq/JsonPath/RootFilter.cs
@@ -10,7 +10,7 @@ namespace Newtonsoft.Json.Linq.JsonPath
{
}
- public override IEnumerable ExecuteFilter(JToken root, IEnumerable current, bool errorWhenNoMatch)
+ public override IEnumerable ExecuteFilter(JToken root, IEnumerable current, JsonSelectSettings? settings)
{
return new[] { root };
}
diff --git a/Src/Newtonsoft.Json/Linq/JsonPath/ScanFilter.cs b/Src/Newtonsoft.Json/Linq/JsonPath/ScanFilter.cs
index 1938c1b0..a3f6adcc 100644
--- a/Src/Newtonsoft.Json/Linq/JsonPath/ScanFilter.cs
+++ b/Src/Newtonsoft.Json/Linq/JsonPath/ScanFilter.cs
@@ -11,7 +11,7 @@ namespace Newtonsoft.Json.Linq.JsonPath
Name = name;
}
- public override IEnumerable ExecuteFilter(JToken root, IEnumerable current, bool errorWhenNoMatch)
+ public override IEnumerable ExecuteFilter(JToken root, IEnumerable current, JsonSelectSettings? settings)
{
foreach (JToken c in current)
{
diff --git a/Src/Newtonsoft.Json/Linq/JsonPath/ScanMultipleFilter.cs b/Src/Newtonsoft.Json/Linq/JsonPath/ScanMultipleFilter.cs
index ff9a560a..40e9334a 100644
--- a/Src/Newtonsoft.Json/Linq/JsonPath/ScanMultipleFilter.cs
+++ b/Src/Newtonsoft.Json/Linq/JsonPath/ScanMultipleFilter.cs
@@ -11,7 +11,7 @@ namespace Newtonsoft.Json.Linq.JsonPath
_names = names;
}
- public override IEnumerable ExecuteFilter(JToken root, IEnumerable current, bool errorWhenNoMatch)
+ public override IEnumerable ExecuteFilter(JToken root, IEnumerable current, JsonSelectSettings? settings)
{
foreach (JToken c in current)
{
diff --git a/Src/Newtonsoft.Json/Linq/JsonSelectSettings.cs b/Src/Newtonsoft.Json/Linq/JsonSelectSettings.cs
new file mode 100644
index 00000000..495b2dc0
--- /dev/null
+++ b/Src/Newtonsoft.Json/Linq/JsonSelectSettings.cs
@@ -0,0 +1,28 @@
+using System;
+
+namespace Newtonsoft.Json.Linq
+{
+ ///
+ /// Specifies the settings used when selecting JSON.
+ ///
+ public class JsonSelectSettings
+ {
+#if HAVE_REGEX_TIMEOUTS
+ ///
+ /// Gets or sets a timeout that will be used when executing regular expressions.
+ ///
+ /// The timeout that will be used when executing regular expressions.
+ public TimeSpan? RegexMatchTimeout { get; set; }
+#endif
+
+ ///
+ /// Gets or sets a flag that indicates whether an error should be thrown if
+ /// no tokens are found when evaluating part of the expression.
+ ///
+ ///
+ /// A flag that indicates whether an error should be thrown if
+ /// no tokens are found when evaluating part of the expression.
+ ///
+ public bool ErrorWhenNoMatch { get; set; }
+ }
+}
diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.csproj
index f6cc6cc7..dfac4a04 100644
--- a/Src/Newtonsoft.Json/Newtonsoft.Json.csproj
+++ b/Src/Newtonsoft.Json/Newtonsoft.Json.csproj
@@ -45,7 +45,7 @@
Json.NET
- HAVE_ADO_NET;HAVE_APP_DOMAIN;HAVE_ASYNC;HAVE_BIG_INTEGER;HAVE_BINARY_FORMATTER;HAVE_BINARY_SERIALIZATION;HAVE_BINARY_EXCEPTION_SERIALIZATION;HAVE_CAS;HAVE_CHAR_TO_LOWER_WITH_CULTURE;HAVE_CHAR_TO_STRING_WITH_CULTURE;HAVE_COM_ATTRIBUTES;HAVE_COMPONENT_MODEL;HAVE_CONCURRENT_COLLECTIONS;HAVE_COVARIANT_GENERICS;HAVE_DATA_CONTRACTS;HAVE_DATE_TIME_OFFSET;HAVE_DB_NULL_TYPE_CODE;HAVE_DYNAMIC;HAVE_EMPTY_TYPES;HAVE_ENTITY_FRAMEWORK;HAVE_EXPRESSIONS;HAVE_FAST_REVERSE;HAVE_FSHARP_TYPES;HAVE_FULL_REFLECTION;HAVE_GUID_TRY_PARSE;HAVE_HASH_SET;HAVE_ICLONEABLE;HAVE_ICONVERTIBLE;HAVE_IGNORE_DATA_MEMBER_ATTRIBUTE;HAVE_INOTIFY_COLLECTION_CHANGED;HAVE_INOTIFY_PROPERTY_CHANGING;HAVE_ISET;HAVE_LINQ;HAVE_MEMORY_BARRIER;HAVE_METHOD_IMPL_ATTRIBUTE;HAVE_NON_SERIALIZED_ATTRIBUTE;HAVE_READ_ONLY_COLLECTIONS;HAVE_REFLECTION_EMIT;HAVE_SECURITY_SAFE_CRITICAL_ATTRIBUTE;HAVE_SERIALIZATION_BINDER_BIND_TO_NAME;HAVE_STREAM_READER_WRITER_CLOSE;HAVE_STRING_JOIN_WITH_ENUMERABLE;HAVE_TIME_SPAN_PARSE_WITH_CULTURE;HAVE_TIME_SPAN_TO_STRING_WITH_CULTURE;HAVE_TIME_ZONE_INFO;HAVE_TRACE_WRITER;HAVE_TYPE_DESCRIPTOR;HAVE_UNICODE_SURROGATE_DETECTION;HAVE_VARIANT_TYPE_PARAMETERS;HAVE_VERSION_TRY_PARSE;HAVE_XLINQ;HAVE_XML_DOCUMENT;HAVE_XML_DOCUMENT_TYPE;HAVE_CONCURRENT_DICTIONARY;$(AdditionalConstants)
+ HAVE_ADO_NET;HAVE_APP_DOMAIN;HAVE_ASYNC;HAVE_BIG_INTEGER;HAVE_BINARY_FORMATTER;HAVE_BINARY_SERIALIZATION;HAVE_BINARY_EXCEPTION_SERIALIZATION;HAVE_CAS;HAVE_CHAR_TO_LOWER_WITH_CULTURE;HAVE_CHAR_TO_STRING_WITH_CULTURE;HAVE_COM_ATTRIBUTES;HAVE_COMPONENT_MODEL;HAVE_CONCURRENT_COLLECTIONS;HAVE_COVARIANT_GENERICS;HAVE_DATA_CONTRACTS;HAVE_DATE_TIME_OFFSET;HAVE_DB_NULL_TYPE_CODE;HAVE_DYNAMIC;HAVE_EMPTY_TYPES;HAVE_ENTITY_FRAMEWORK;HAVE_EXPRESSIONS;HAVE_FAST_REVERSE;HAVE_FSHARP_TYPES;HAVE_FULL_REFLECTION;HAVE_GUID_TRY_PARSE;HAVE_HASH_SET;HAVE_ICLONEABLE;HAVE_ICONVERTIBLE;HAVE_IGNORE_DATA_MEMBER_ATTRIBUTE;HAVE_INOTIFY_COLLECTION_CHANGED;HAVE_INOTIFY_PROPERTY_CHANGING;HAVE_ISET;HAVE_LINQ;HAVE_MEMORY_BARRIER;HAVE_METHOD_IMPL_ATTRIBUTE;HAVE_NON_SERIALIZED_ATTRIBUTE;HAVE_READ_ONLY_COLLECTIONS;HAVE_REFLECTION_EMIT;HAVE_REGEX_TIMEOUTS;HAVE_SECURITY_SAFE_CRITICAL_ATTRIBUTE;HAVE_SERIALIZATION_BINDER_BIND_TO_NAME;HAVE_STREAM_READER_WRITER_CLOSE;HAVE_STRING_JOIN_WITH_ENUMERABLE;HAVE_TIME_SPAN_PARSE_WITH_CULTURE;HAVE_TIME_SPAN_TO_STRING_WITH_CULTURE;HAVE_TIME_ZONE_INFO;HAVE_TRACE_WRITER;HAVE_TYPE_DESCRIPTOR;HAVE_UNICODE_SURROGATE_DETECTION;HAVE_VARIANT_TYPE_PARAMETERS;HAVE_VERSION_TRY_PARSE;HAVE_XLINQ;HAVE_XML_DOCUMENT;HAVE_XML_DOCUMENT_TYPE;HAVE_CONCURRENT_DICTIONARY;$(AdditionalConstants)
Json.NET .NET 4.0
diff --git a/Src/Newtonsoft.Json/Utilities/MiscellaneousUtils.cs b/Src/Newtonsoft.Json/Utilities/MiscellaneousUtils.cs
index d61ea5d7..137ec445 100644
--- a/Src/Newtonsoft.Json/Utilities/MiscellaneousUtils.cs
+++ b/Src/Newtonsoft.Json/Utilities/MiscellaneousUtils.cs
@@ -165,11 +165,6 @@ namespace Newtonsoft.Json.Utilities
case 'x':
options |= RegexOptions.ExplicitCapture;
break;
-#if HAVE_REGEX_TIMEOUTS && (NETSTANDARD1_3 || NETSTANDARD2_0)
- case 'c':
- options |= RegexOptions.Compiled;
- break;
-#endif
}
}