jpath regex timeout support added for a single regex expression, global umbrella for all regex calls, and support for allowing regex calls to get compiled if necessary

require users to set a global cancellation token themselves, to avoid a potential unmanaged memory leak, which cleans up the code a bunch and fixes the failing tests

fix tests so cached regex's don't cause one test to fail using prior tests timeout...

handle the global timeout of multitoken regex internally and test for it
This commit is contained in:
serpentfabric
2021-01-17 18:23:19 +13:00
committed by James Newton-King
parent 1403f5d329
commit 95a6eb3ac5
8 changed files with 199 additions and 18 deletions
+2
View File
@@ -22,5 +22,7 @@
<SystemValueTuplePackageVersion>4.4.0</SystemValueTuplePackageVersion>
<XunitPackageVersion>2.3.1</XunitPackageVersion>
<XunitRunnerVisualStudioPackageVersion>2.3.1</XunitRunnerVisualStudioPackageVersion>
<BogusPackageVersion>32.0.2</BogusPackageVersion>
<AsyncExPackageVersion>5.1.0</AsyncExPackageVersion>
</PropertyGroup>
</Project>
@@ -31,6 +31,13 @@ using System.Numerics;
#endif
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;
using Test = Xunit.FactAttribute;
@@ -44,7 +51,6 @@ using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Utilities.LinqBridge;
#else
using System.Linq;
#endif
namespace Newtonsoft.Json.Tests.Linq.JsonPath
@@ -71,6 +77,75 @@ namespace Newtonsoft.Json.Tests.Linq.JsonPath
Assert.AreEqual(jObj, dd);
}
#if HAVE_REGEX_TIMEOUTS
[Test]
public void BacktrackingRegex_SingleMatch_TimeoutRespected()
{
var RegexBacktrackingPattern = "(?<a>(.*?))[|].*(?<b>(.*?))[|].*(?<c>(.*?))[|].*(?<d>[1-3])[|].*(?<e>(.*?))[|].*[|].*[|].*(?<f>(.*?))[|].*[|].*(?<g>(.*?))[|].*(?<h>(.*))";
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)));
}
Xunit.Assert.Throws<RegexMatchTimeoutException>(() =>
{
var tokens = regexBacktrackingData.SelectTokens(
$"[?(@.b =~ /{RegexBacktrackingPattern}/)]",
errorWhenNoMatch: false,
singleRegexMatchTimeout: TimeSpan.FromSeconds(.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 = "(?<i>(.*?))[|].*(?<b>(.*?))[|].*(?<c>(.*?))[|].*(?<d>[1-3])[|].*(?<e>(.*?))[|].*[|].*[|].*(?<f>(.*?))[|].*[|].*(?<g>(.*?))[|].*(?<h>(.*))";
var jpathExpression = $"[?(@.b =~ /{RegexBacktrackingPattern}/c)]";
var exceptionThrow = Xunit.Assert.ThrowsAny<Exception>(() =>
{
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 = "(?<j>(.*?))[|].*(?<b>(.*?))[|].*(?<c>(.*?))[|].*(?<d>[1-3])[|].*(?<e>(.*?))[|].*[|].*[|].*(?<f>(.*?))[|].*[|].*(?<g>(.*?))[|].*(?<h>(.*))";
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<bool>(cts.Token);
var finishedTask = await Task.WhenAny(selectTokenTask, ctts.Task);
Assert.AreEqual(finishedTask, ctts.Task);
}
#endif
[Test]
public void GreaterThanWithIntegerParameterAndStringValue()
{
@@ -2,7 +2,7 @@
<PropertyGroup>
<TargetFrameworks Condition="'$(TestFrameworks)'==''">net46;net40;net35;net20;net5.0;netcoreapp3.1;netcoreapp2.1</TargetFrameworks>
<TargetFrameworks Condition="'$(TestFrameworks)'!=''">$(TestFrameworks)</TargetFrameworks>
<LangVersion>8.0</LangVersion>
<LangVersion>9.0</LangVersion>
<VersionPrefix>1.0</VersionPrefix>
<Authors>James Newton-King</Authors>
<Company>Newtonsoft</Company>
@@ -76,6 +76,7 @@
<Reference Include="System.ComponentModel.DataAnnotations" />
<Reference Include="System.Web.Extensions" />
<Reference Include="System.Data.DataSetExtensions" />
<PackageReference Include="Bogus" Version="$(BogusPackageVersion)" />
</ItemGroup>
<PropertyGroup Condition="'$(TargetFramework)'=='net40'">
<AssemblyTitle>Json.NET Tests .NET 4.0</AssemblyTitle>
@@ -121,11 +122,14 @@
<PackageReference Include="xunit" Version="$(XunitPackageVersion)" />
<PackageReference Include="xunit.runner.visualstudio" Version="$(XunitRunnerVisualStudioPackageVersion)" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(MicrosoftNETTestSdkPackageVersion)" />
<PackageReference Include="Bogus" Version="$(BogusPackageVersion)" />
<PackageReference Include="Nito.AsyncEx.Tasks" Version="$(AsyncExPackageVersion)" />
</ItemGroup>
<PropertyGroup Condition="'$(TargetFramework)'=='net5.0'">
<AssemblyTitle>Json.NET Tests .NET Standard 2.0</AssemblyTitle>
<ReferringTargetFrameworkForProjectReferences>.NETStandard,Version=v2.0</ReferringTargetFrameworkForProjectReferences>
<DefineConstants>NETSTANDARD2_0;DNXCORE50;PORTABLE;HAVE_BENCHMARKS;$(AdditionalConstants)</DefineConstants>
<DefineConstants>NETSTANDARD2_0;DNXCORE50;PORTABLE;HAVE_BENCHMARKS;HAVE_REGEX_TIMEOUTS;$(AdditionalConstants)</DefineConstants>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)'=='netcoreapp3.1'">
@@ -142,11 +146,13 @@
<PackageReference Include="xunit" Version="$(XunitPackageVersion)" />
<PackageReference Include="xunit.runner.visualstudio" Version="$(XunitRunnerVisualStudioPackageVersion)" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(MicrosoftNETTestSdkPackageVersion)" />
<PackageReference Include="Bogus" Version="$(BogusPackageVersion)" />
<PackageReference Include="Nito.AsyncEx.Tasks" Version="$(AsyncExPackageVersion)" />
</ItemGroup>
<PropertyGroup Condition="'$(TargetFramework)'=='netcoreapp3.1'">
<AssemblyTitle>Json.NET Tests .NET Standard 1.3</AssemblyTitle>
<ReferringTargetFrameworkForProjectReferences>.NETStandard,Version=v1.3</ReferringTargetFrameworkForProjectReferences>
<DefineConstants>NETSTANDARD1_3;DNXCORE50;PORTABLE;HAVE_BENCHMARKS;$(AdditionalConstants)</DefineConstants>
<DefineConstants>NETSTANDARD1_3;DNXCORE50;PORTABLE;HAVE_BENCHMARKS;HAVE_REGEX_TIMEOUTS;$(AdditionalConstants)</DefineConstants>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)'=='netcoreapp2.1'">
@@ -162,10 +168,13 @@
<PackageReference Include="xunit" Version="$(XunitPackageVersion)" />
<PackageReference Include="xunit.runner.visualstudio" Version="$(XunitRunnerVisualStudioPackageVersion)" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(MicrosoftNETTestSdkPackageVersion)" />
<PackageReference Include="Bogus" Version="$(BogusPackageVersion)" />
<PackageReference Include="Nito.AsyncEx.Tasks" Version="$(AsyncExPackageVersion)" />
</ItemGroup>
<PropertyGroup Condition="'$(TargetFramework)'=='netcoreapp2.1'">
<AssemblyTitle>Json.NET Tests .NET Standard 1.0</AssemblyTitle>
<ReferringTargetFrameworkForProjectReferences>.NETStandard,Version=v1.0</ReferringTargetFrameworkForProjectReferences>
<DefineConstants>NETSTANDARD1_0;DNXCORE50;PORTABLE;$(AdditionalConstants)</DefineConstants>
<DefineConstants>NETSTANDARD1_0;DNXCORE50;PORTABLE;HAVE_REGEX_TIMEOUTS;$(AdditionalConstants)</DefineConstants>
</PropertyGroup>
</Project>
+76 -5
View File
@@ -44,6 +44,7 @@ using System.Diagnostics.CodeAnalysis;
using Newtonsoft.Json.Utilities.LinqBridge;
#else
using System.Linq;
using System.Threading;
#endif
namespace Newtonsoft.Json.Linq
@@ -485,7 +486,7 @@ namespace Newtonsoft.Json.Linq
return (Array.IndexOf(validTypes, o.Type) != -1) || (nullable && (o.Type == JTokenType.Null || o.Type == JTokenType.Undefined));
}
#region Cast from operators
#region Cast from operators
/// <summary>
/// Performs an explicit conversion from <see cref="Newtonsoft.Json.Linq.JToken"/> to <see cref="System.Boolean"/>.
/// </summary>
@@ -1497,9 +1498,9 @@ namespace Newtonsoft.Json.Linq
return ConvertUtils.ToBigInteger(v.Value);
}
#endif
#endregion
#endregion
#region Cast to operators
#region Cast to operators
/// <summary>
/// Performs an implicit conversion from <see cref="Boolean"/> to <see cref="JToken"/>.
/// </summary>
@@ -1863,7 +1864,7 @@ namespace Newtonsoft.Json.Linq
{
return new JValue(value);
}
#endregion
#endregion
IEnumerator IEnumerable.GetEnumerator()
{
@@ -2336,6 +2337,35 @@ namespace Newtonsoft.Json.Linq
return token;
}
#if HAVE_REGEX_TIMEOUTS
/// <summary>
/// Selects a <see cref="JToken"/> using a JSONPath expression. Selects the token that matches the object path.
/// </summary>
/// <param name="path">
/// A <see cref="String"/> that contains a JSONPath expression.
/// </param>
/// <param name="errorWhenNoMatch">A flag to indicate whether an error should be thrown if no tokens are found when evaluating part of the expression.</param>
/// <param name="singleMatchTimeout">the time after which a single call to regex.ismatch must complete, default is forever</param>
/// <returns>A <see cref="JToken"/>.</returns>
public JToken? SelectToken(string path, bool errorWhenNoMatch, TimeSpan? singleMatchTimeout = default)
{
JPath p = new JPath(path, singleMatchTimeout);
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;
}
#endif
/// <summary>
/// Selects a collection of elements using a JSONPath expression.
/// </summary>
@@ -2358,10 +2388,51 @@ namespace Newtonsoft.Json.Linq
/// <returns>An <see cref="IEnumerable{T}"/> of <see cref="JToken"/> that contains the selected elements.</returns>
public IEnumerable<JToken> SelectTokens(string path, bool errorWhenNoMatch)
{
JPath p = new JPath(path);
var p = new JPath(path);
return p.Evaluate(this, this, errorWhenNoMatch);
}
#if HAVE_REGEX_TIMEOUTS
/// <summary>
/// Selects a collection of elements using a JSONPath expression.
/// </summary>
/// <param name="path">
/// A <see cref="String"/> that contains a JSONPath expression.
/// </param>
/// <param name="errorWhenNoMatch">A flag to indicate whether an error should be thrown if no tokens are found when evaluating part of the expression.</param>
/// <param name="singleRegexMatchTimeout">
/// for every token that matches a jpath, the time a regex is permitted to run
/// against that token before timeout
/// </param>
/// <param name="globalRegexMatchTimeout">
/// 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)
/// </param>
/// <exception cref="System.Text.RegularExpressions.RegexMatchTimeoutException">if single call timeout exceeded</exception>"
/// <returns>An <see cref="IEnumerable{T}"/> of <see cref="JToken"/> that contains the selected elements.</returns>
public IEnumerable<JToken> SelectTokens(string path,
bool errorWhenNoMatch,
TimeSpan? singleRegexMatchTimeout = default,
TimeSpan? globalRegexMatchTimeout = default)
{
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;
}
}
#endif
#if HAVE_DYNAMIC
/// <summary>
/// Returns the <see cref="DynamicMetaObject"/> responsible for binding operations performed on this object.
+7 -2
View File
@@ -27,6 +27,8 @@ 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
@@ -37,14 +39,16 @@ namespace Newtonsoft.Json.Linq.JsonPath
private readonly string _expression;
public List<PathFilter> Filters { get; }
public readonly TimeSpan? RegexSingleMatchTimeout = default;
private int _currentIndex;
public JPath(string expression)
public JPath(string expression, TimeSpan? regexSingleMatchTimeout = default)
{
ValidationUtils.ArgumentNotNull(expression, nameof(expression));
_expression = expression;
Filters = new List<PathFilter>();
RegexSingleMatchTimeout = regexSingleMatchTimeout;
ParseMain();
}
@@ -509,7 +513,8 @@ namespace Newtonsoft.Json.Linq.JsonPath
right = ParseSide();
}
BooleanQueryExpression booleanExpression = new BooleanQueryExpression(op, left, right);
var booleanExpression = new BooleanQueryExpression(op, left, right, RegexSingleMatchTimeout);
if (_expression[_currentIndex] == ')')
{
@@ -4,6 +4,7 @@ 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
@@ -83,11 +84,17 @@ 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) : base(@operator)
public BooleanQueryExpression(QueryOperator @operator,
object left,
object? right,
TimeSpan? regexSingleMatchTimeout = default)
: base(@operator)
{
Left = left;
Right = right;
SingleMatchTimeout = regexSingleMatchTimeout;
}
private IEnumerable<JToken> GetResult(JToken root, JToken t, object? o)
@@ -143,7 +150,7 @@ namespace Newtonsoft.Json.Linq.JsonPath
switch (Operator)
{
case QueryOperator.RegexEquals:
if (RegexEquals(leftValue, rightValue))
if (RegexEquals(leftValue, rightValue, SingleMatchTimeout))
{
return true;
}
@@ -215,7 +222,9 @@ namespace Newtonsoft.Json.Linq.JsonPath
return false;
}
private static bool RegexEquals(JValue input, JValue pattern)
private static bool RegexEquals(JValue input,
JValue pattern,
TimeSpan? regexMatchTimeout = default)
{
if (input.Type != JTokenType.String || pattern.Type != JTokenType.String)
{
@@ -228,7 +237,12 @@ namespace Newtonsoft.Json.Linq.JsonPath
string patternText = regexText.Substring(1, patternOptionDelimiterIndex - 1);
string optionsText = regexText.Substring(patternOptionDelimiterIndex + 1);
#if HAVE_REGEX_TIMEOUTS
var timeout = 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));
#endif
}
internal static bool EqualsWithStringCoercion(JValue value, JValue queryValue)
+3 -3
View File
@@ -66,7 +66,7 @@
</ItemGroup>
<PropertyGroup Condition="'$(TargetFramework)' == 'netstandard1.0'">
<AssemblyTitle>Json.NET .NET Standard 1.0</AssemblyTitle>
<DefineConstants>NETSTANDARD1_0;PORTABLE;HAVE_ASYNC;HAVE_COVARIANT_GENERICS;HAVE_DATA_CONTRACTS;HAVE_DATE_TIME_OFFSET;HAVE_DYNAMIC;HAVE_EXPRESSIONS;HAVE_FSHARP_TYPES;HAVE_GUID_TRY_PARSE;HAVE_HASH_SET;HAVE_IGNORE_DATA_MEMBER_ATTRIBUTE;HAVE_INOTIFY_COLLECTION_CHANGED;HAVE_ISET;HAVE_LINQ;HAVE_METHOD_IMPL_ATTRIBUTE;HAVE_READ_ONLY_COLLECTIONS;HAVE_REFLECTION_BINDER;HAVE_SERIALIZATION_BINDER_BIND_TO_NAME;HAVE_STRING_JOIN_WITH_ENUMERABLE;HAVE_TIME_SPAN_PARSE_WITH_CULTURE;HAVE_TIME_SPAN_TO_STRING_WITH_CULTURE;HAVE_TIME_ZONE_INFO;HAVE_TYPE_DESCRIPTOR;HAVE_UNICODE_SURROGATE_DETECTION;HAVE_VARIANT_TYPE_PARAMETERS;HAVE_VERSION_TRY_PARSE;HAVE_XLINQ;HAVE_OBSOLETE_FORMATTER_ASSEMBLY_STYLE;$(AdditionalConstants)</DefineConstants>
<DefineConstants>NETSTANDARD1_0;PORTABLE;HAVE_ASYNC;HAVE_COVARIANT_GENERICS;HAVE_DATA_CONTRACTS;HAVE_DATE_TIME_OFFSET;HAVE_DYNAMIC;HAVE_EXPRESSIONS;HAVE_FSHARP_TYPES;HAVE_GUID_TRY_PARSE;HAVE_HASH_SET;HAVE_IGNORE_DATA_MEMBER_ATTRIBUTE;HAVE_INOTIFY_COLLECTION_CHANGED;HAVE_ISET;HAVE_LINQ;HAVE_METHOD_IMPL_ATTRIBUTE;HAVE_READ_ONLY_COLLECTIONS;HAVE_REFLECTION_BINDER;HAVE_SERIALIZATION_BINDER_BIND_TO_NAME;HAVE_STRING_JOIN_WITH_ENUMERABLE;HAVE_TIME_SPAN_PARSE_WITH_CULTURE;HAVE_TIME_SPAN_TO_STRING_WITH_CULTURE;HAVE_TIME_ZONE_INFO;HAVE_TYPE_DESCRIPTOR;HAVE_UNICODE_SURROGATE_DETECTION;HAVE_VARIANT_TYPE_PARAMETERS;HAVE_VERSION_TRY_PARSE;HAVE_XLINQ;HAVE_OBSOLETE_FORMATTER_ASSEMBLY_STYLE;HAVE_REGEX_TIMEOUTS;$(AdditionalConstants)</DefineConstants>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard1.3'">
<PackageReference Include="System.Runtime.Serialization.Formatters" Version="$(SystemRuntimeSerializationFormattersPackageVersion)" />
@@ -74,10 +74,10 @@
</ItemGroup>
<PropertyGroup Condition="'$(TargetFramework)' == 'netstandard1.3'">
<AssemblyTitle>Json.NET .NET Standard 1.3</AssemblyTitle>
<DefineConstants>NETSTANDARD1_3;PORTABLE;HAVE_ASYNC;HAVE_BIG_INTEGER;HAVE_BINARY_SERIALIZATION;HAVE_COVARIANT_GENERICS;HAVE_DATA_CONTRACTS;HAVE_DATE_TIME_OFFSET;HAVE_DYNAMIC;HAVE_EXPRESSIONS;HAVE_FSHARP_TYPES;HAVE_GUID_TRY_PARSE;HAVE_HASH_SET;HAVE_IGNORE_DATA_MEMBER_ATTRIBUTE;HAVE_INOTIFY_COLLECTION_CHANGED;HAVE_INOTIFY_PROPERTY_CHANGING;HAVE_ISET;HAVE_LINQ;HAVE_METHOD_IMPL_ATTRIBUTE;HAVE_NON_SERIALIZED_ATTRIBUTE;HAVE_READ_ONLY_COLLECTIONS;HAVE_REFLECTION_BINDER;HAVE_SERIALIZATION_BINDER_BIND_TO_NAME;HAVE_STRING_JOIN_WITH_ENUMERABLE;HAVE_TIME_SPAN_PARSE_WITH_CULTURE;HAVE_TIME_SPAN_TO_STRING_WITH_CULTURE;HAVE_TIME_ZONE_INFO;HAVE_TYPE_DESCRIPTOR;HAVE_UNICODE_SURROGATE_DETECTION;HAVE_VARIANT_TYPE_PARAMETERS;HAVE_VERSION_TRY_PARSE;HAVE_XLINQ;HAVE_OBSOLETE_FORMATTER_ASSEMBLY_STYLE;HAVE_XML_DOCUMENT;HAVE_CONCURRENT_DICTIONARY;HAVE_ICONVERTIBLE;$(AdditionalConstants)</DefineConstants>
<DefineConstants>NETSTANDARD1_3;PORTABLE;HAVE_ASYNC;HAVE_BIG_INTEGER;HAVE_BINARY_SERIALIZATION;HAVE_COVARIANT_GENERICS;HAVE_DATA_CONTRACTS;HAVE_DATE_TIME_OFFSET;HAVE_DYNAMIC;HAVE_EXPRESSIONS;HAVE_FSHARP_TYPES;HAVE_GUID_TRY_PARSE;HAVE_HASH_SET;HAVE_IGNORE_DATA_MEMBER_ATTRIBUTE;HAVE_INOTIFY_COLLECTION_CHANGED;HAVE_INOTIFY_PROPERTY_CHANGING;HAVE_ISET;HAVE_LINQ;HAVE_METHOD_IMPL_ATTRIBUTE;HAVE_NON_SERIALIZED_ATTRIBUTE;HAVE_READ_ONLY_COLLECTIONS;HAVE_REFLECTION_BINDER;HAVE_SERIALIZATION_BINDER_BIND_TO_NAME;HAVE_STRING_JOIN_WITH_ENUMERABLE;HAVE_TIME_SPAN_PARSE_WITH_CULTURE;HAVE_TIME_SPAN_TO_STRING_WITH_CULTURE;HAVE_TIME_ZONE_INFO;HAVE_TYPE_DESCRIPTOR;HAVE_UNICODE_SURROGATE_DETECTION;HAVE_VARIANT_TYPE_PARAMETERS;HAVE_VERSION_TRY_PARSE;HAVE_XLINQ;HAVE_OBSOLETE_FORMATTER_ASSEMBLY_STYLE;HAVE_XML_DOCUMENT;HAVE_CONCURRENT_DICTIONARY;HAVE_ICONVERTIBLE;HAVE_REGEX_TIMEOUTS;HAVE_REGEX_TIMEOUTS;$(AdditionalConstants)</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<AssemblyTitle>Json.NET .NET Standard 2.0</AssemblyTitle>
<DefineConstants>NETSTANDARD2_0;HAVE_ADO_NET;HAVE_APP_DOMAIN;HAVE_ASYNC;HAVE_BIG_INTEGER;HAVE_BINARY_FORMATTER;HAVE_BINARY_SERIALIZATION;HAVE_BINARY_EXCEPTION_SERIALIZATION;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_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)</DefineConstants>
<DefineConstants>NETSTANDARD2_0;HAVE_ADO_NET;HAVE_APP_DOMAIN;HAVE_ASYNC;HAVE_BIG_INTEGER;HAVE_BINARY_FORMATTER;HAVE_BINARY_SERIALIZATION;HAVE_BINARY_EXCEPTION_SERIALIZATION;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_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;HAVE_REGEX_TIMEOUTS;$(AdditionalConstants)</DefineConstants>
</PropertyGroup>
</Project>
@@ -165,6 +165,11 @@ 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
}
}