From baa1e21612cae4fb3d3b495e022e327afa50b946 Mon Sep 17 00:00:00 2001 From: James Newton-King Date: Mon, 30 Sep 2019 16:34:39 +1300 Subject: [PATCH] Fix deserializing incomplete JSON object to JObject (#2181) --- Src/Newtonsoft.Json.Tests/Issues/Issue2165.cs | 83 +++++++++++++++++++ Src/Newtonsoft.Json/JsonWriter.Async.cs | 2 +- Src/Newtonsoft.Json/JsonWriter.cs | 9 +- 3 files changed, 92 insertions(+), 2 deletions(-) create mode 100644 Src/Newtonsoft.Json.Tests/Issues/Issue2165.cs diff --git a/Src/Newtonsoft.Json.Tests/Issues/Issue2165.cs b/Src/Newtonsoft.Json.Tests/Issues/Issue2165.cs new file mode 100644 index 000000000..64071d4e4 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/Issues/Issue2165.cs @@ -0,0 +1,83 @@ +#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 + +using System; +using System.IO; +#if !(NET20 || NET35 || NET40 || PORTABLE40) +using System.Threading.Tasks; +#endif +using Newtonsoft.Json.Linq; +#if DNXCORE50 +using Xunit; +using Test = Xunit.FactAttribute; +using Assert = Newtonsoft.Json.Tests.XUnitAssert; +#else +using NUnit.Framework; +#endif + +namespace Newtonsoft.Json.Tests.Issues +{ + [TestFixture] + public class Issue2165 + { + [Test] + public void Test_Deserializer() + { + ExceptionAssert.Throws( + () => JsonConvert.DeserializeObject("{"), + "Unexpected end when reading token. Path ''."); + } + + [Test] + public void Test() + { + StringWriter w = new StringWriter(); + JsonTextWriter writer = new JsonTextWriter(w); + + var jsonReader = new JsonTextReader(new StringReader("{")); + jsonReader.Read(); + + ExceptionAssert.Throws( + () => writer.WriteToken(jsonReader), + "Unexpected end when reading token. Path ''."); + } + +#if !(NET20 || NET35 || NET40 || PORTABLE40) + [Test] + public async Task TestAsync() + { + StringWriter w = new StringWriter(); + JsonTextWriter writer = new JsonTextWriter(w); + + var jsonReader = new JsonTextReader(new StringReader("{")); + await jsonReader.ReadAsync(); + + await ExceptionAssert.ThrowsAsync( + () => writer.WriteTokenAsync(jsonReader), + "Unexpected end when reading token. Path ''."); + } +#endif + } +} diff --git a/Src/Newtonsoft.Json/JsonWriter.Async.cs b/Src/Newtonsoft.Json/JsonWriter.Async.cs index 47c6325e4..750d29271 100644 --- a/Src/Newtonsoft.Json/JsonWriter.Async.cs +++ b/Src/Newtonsoft.Json/JsonWriter.Async.cs @@ -785,7 +785,7 @@ internal virtual async Task WriteTokenAsync(JsonReader reader, bool writeChildre && writeChildren && await reader.ReadAsync(cancellationToken).ConfigureAwait(false)); - if (initialDepth < CalculateWriteTokenFinalDepth(reader)) + if (IsWriteTokenIncomplete(reader, writeChildren, initialDepth)) { throw JsonWriterException.Create(this, "Unexpected end when reading token.", null); } diff --git a/Src/Newtonsoft.Json/JsonWriter.cs b/Src/Newtonsoft.Json/JsonWriter.cs index 893ecb3f2..b1fbc15cf 100644 --- a/Src/Newtonsoft.Json/JsonWriter.cs +++ b/Src/Newtonsoft.Json/JsonWriter.cs @@ -666,12 +666,19 @@ internal virtual void WriteToken(JsonReader reader, bool writeChildren, bool wri && writeChildren && reader.Read()); - if (initialDepth < CalculateWriteTokenFinalDepth(reader)) + if (IsWriteTokenIncomplete(reader, writeChildren, initialDepth)) { throw JsonWriterException.Create(this, "Unexpected end when reading token.", null); } } + private bool IsWriteTokenIncomplete(JsonReader reader, bool writeChildren, int initialDepth) + { + int finalDepth = CalculateWriteTokenFinalDepth(reader); + return initialDepth < finalDepth || + (writeChildren && initialDepth == finalDepth && JsonTokenUtils.IsStartToken(reader.TokenType)); + } + private int CalculateWriteTokenInitialDepth(JsonReader reader) { JsonToken type = reader.TokenType;