From 9308e69a91d710bccd102bf7f48ee1bbcc843dd0 Mon Sep 17 00:00:00 2001 From: Aditya Kotalwar Date: Thu, 15 Jun 2023 14:44:00 -0700 Subject: [PATCH 1/7] Fixed malformed continuation token issue where Exception was not CosmosExceptionan and did not have the correct Status and Sub Status codes. --- .../src/CosmosElements/CosmosElement.cs | 25 ++++++++++++++++++- .../CosmosItemLinqTests.cs | 24 +++++++++++++++++- 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/CosmosElements/CosmosElement.cs b/Microsoft.Azure.Cosmos/src/CosmosElements/CosmosElement.cs index 24d1fa78d5..1a11eb01bd 100644 --- a/Microsoft.Azure.Cosmos/src/CosmosElements/CosmosElement.cs +++ b/Microsoft.Azure.Cosmos/src/CosmosElements/CosmosElement.cs @@ -11,7 +11,9 @@ namespace Microsoft.Azure.Cosmos.CosmosElements using Microsoft.Azure.Cosmos.CosmosElements.Numbers; using Microsoft.Azure.Cosmos.Json; using Microsoft.Azure.Cosmos.Json.Interop; + using Microsoft.Azure.Cosmos.Query.Core.Exceptions; using Microsoft.Azure.Cosmos.Query.Core.Monads; + using Microsoft.Azure.Cosmos.Resource.CosmosExceptions; [Newtonsoft.Json.JsonConverter(typeof(CosmosElementJsonConverter))] #if INTERNAL @@ -187,7 +189,28 @@ public static bool TryCreateFromBuffer(ReadOnlyMemory buff public static CosmosElement Parse(string json) { TryCatch tryParse = CosmosElement.Monadic.Parse(json); - tryParse.ThrowIfFailed(); + bool isMalformedJSON = tryParse.InnerMostException.Message.Contains("Encountered an element that is not a valid JSON") + || tryParse.InnerMostException.Message.Contains("Encountered an unexpected JSON token"); + if (tryParse.Failed && isMalformedJSON) + { + MalformedContinuationTokenException malformedContinuationTokenException = new MalformedContinuationTokenException(tryParse.InnerMostException.Message); + + throw CosmosExceptionFactory.CreateBadRequestException( + message: $"Malformed Continuation Token: {json}.", + headers: CosmosQueryResponseMessageHeaders.ConvertToQueryHeaders( + new Headers(), + default, + default, + 20007, + default), + stackTrace: malformedContinuationTokenException.StackTrace, + innerException: malformedContinuationTokenException, + trace: null); + } + else + { + tryParse.ThrowIfFailed(); + } return tryParse.Result; } diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemLinqTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemLinqTests.cs index 28fc3ec61c..ec33d55776 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemLinqTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemLinqTests.cs @@ -123,7 +123,7 @@ public async Task ItemLinqReadFeedTest(bool useStatelessIterator) Assert.AreEqual(itemIds.Count, 0); } - [TestMethod] + [TestMethod] [DataRow(false)] [DataRow(true)] [ExpectedException(typeof(ArgumentOutOfRangeException))] @@ -211,6 +211,28 @@ public async Task ItemLINQQueryTest() Assert.AreEqual(itemList[1].id, queriable.ToList()[0].id); } + [TestMethod] + public void ItemLINQQueryWithInvalidContinuationTokenTest() + { + FeedIterator feedIterator = this.Container.GetItemLinqQueryable().ToFeedIterator(); + + while (feedIterator.HasMoreResults) + { + IOrderedQueryable querable = this.Container.GetItemLinqQueryable( + continuationToken: "Malformed String"); + try + { + FeedIterator iterator = querable.ToFeedIterator(); + } + catch (CosmosException exception) + { + Assert.IsTrue(exception.StatusCode == System.Net.HttpStatusCode.BadRequest); + Assert.IsTrue(exception.SubStatusCode == 20007); + return; + } + } + } + [TestMethod] public async Task ItemLINQQueryWithContinuationTokenTest() { From 97c928bdcc36c95eb3d011436406a054d0a77c10 Mon Sep 17 00:00:00 2001 From: Aditya Kotalwar Date: Thu, 15 Jun 2023 14:52:05 -0700 Subject: [PATCH 2/7] Fixed incorrect indentation --- .../Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemLinqTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemLinqTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemLinqTests.cs index ec33d55776..58dcffee37 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemLinqTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemLinqTests.cs @@ -123,7 +123,7 @@ public async Task ItemLinqReadFeedTest(bool useStatelessIterator) Assert.AreEqual(itemIds.Count, 0); } - [TestMethod] + [TestMethod] [DataRow(false)] [DataRow(true)] [ExpectedException(typeof(ArgumentOutOfRangeException))] From 457423160cbad0461e04853a5325333973f0e42c Mon Sep 17 00:00:00 2001 From: Aditya Kotalwar Date: Fri, 16 Jun 2023 13:22:19 -0700 Subject: [PATCH 3/7] Added type check for incoming exception --- .../src/CosmosElements/CosmosElement.cs | 42 ++++++++++--------- .../CosmosItemLinqTests.cs | 3 ++ 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/CosmosElements/CosmosElement.cs b/Microsoft.Azure.Cosmos/src/CosmosElements/CosmosElement.cs index 1a11eb01bd..f46bb11e4b 100644 --- a/Microsoft.Azure.Cosmos/src/CosmosElements/CosmosElement.cs +++ b/Microsoft.Azure.Cosmos/src/CosmosElements/CosmosElement.cs @@ -189,28 +189,32 @@ public static bool TryCreateFromBuffer(ReadOnlyMemory buff public static CosmosElement Parse(string json) { TryCatch tryParse = CosmosElement.Monadic.Parse(json); - bool isMalformedJSON = tryParse.InnerMostException.Message.Contains("Encountered an element that is not a valid JSON") - || tryParse.InnerMostException.Message.Contains("Encountered an unexpected JSON token"); - if (tryParse.Failed && isMalformedJSON) - { - MalformedContinuationTokenException malformedContinuationTokenException = new MalformedContinuationTokenException(tryParse.InnerMostException.Message); - - throw CosmosExceptionFactory.CreateBadRequestException( - message: $"Malformed Continuation Token: {json}.", - headers: CosmosQueryResponseMessageHeaders.ConvertToQueryHeaders( - new Headers(), - default, - default, - 20007, - default), - stackTrace: malformedContinuationTokenException.StackTrace, - innerException: malformedContinuationTokenException, - trace: null); - } - else + try { tryParse.ThrowIfFailed(); } + catch (Exception exception) + { + if (exception.InnerException is JsonParseException) + { + MalformedContinuationTokenException malformedContinuationTokenException = new MalformedContinuationTokenException(exception.Message); + throw CosmosExceptionFactory.CreateBadRequestException( + message: $"Malformed Continuation Token: {json}.", + headers: CosmosQueryResponseMessageHeaders.ConvertToQueryHeaders( + new Headers(), + default, + default, + 20007, + default), + stackTrace: malformedContinuationTokenException.StackTrace, + innerException: malformedContinuationTokenException, + trace: null); + } + else + { + throw exception; + } + } return tryParse.Result; } diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemLinqTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemLinqTests.cs index 58dcffee37..f7cf1386c5 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemLinqTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemLinqTests.cs @@ -228,8 +228,11 @@ public void ItemLINQQueryWithInvalidContinuationTokenTest() { Assert.IsTrue(exception.StatusCode == System.Net.HttpStatusCode.BadRequest); Assert.IsTrue(exception.SubStatusCode == 20007); + Assert.IsTrue(exception.Message.Contains("Malformed String")); return; } + + Assert.IsFalse(true, "Should never reach till here, hence ensuring that an exception is always recieved"); } } From f7d91e9f6bf6503df5bbce0e819ebcd78d9bdb33 Mon Sep 17 00:00:00 2001 From: Aditya Kotalwar Date: Fri, 16 Jun 2023 16:43:24 -0700 Subject: [PATCH 4/7] Replaced if/else with extra catch block --- .../src/CosmosElements/CosmosElement.cs | 36 +++++++++---------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/CosmosElements/CosmosElement.cs b/Microsoft.Azure.Cosmos/src/CosmosElements/CosmosElement.cs index f46bb11e4b..3201f1821c 100644 --- a/Microsoft.Azure.Cosmos/src/CosmosElements/CosmosElement.cs +++ b/Microsoft.Azure.Cosmos/src/CosmosElements/CosmosElement.cs @@ -14,6 +14,7 @@ namespace Microsoft.Azure.Cosmos.CosmosElements using Microsoft.Azure.Cosmos.Query.Core.Exceptions; using Microsoft.Azure.Cosmos.Query.Core.Monads; using Microsoft.Azure.Cosmos.Resource.CosmosExceptions; + using Microsoft.Azure.Documents; [Newtonsoft.Json.JsonConverter(typeof(CosmosElementJsonConverter))] #if INTERNAL @@ -193,27 +194,24 @@ public static CosmosElement Parse(string json) { tryParse.ThrowIfFailed(); } + catch (Exception exception) when (exception.InnerException is JsonParseException) + { + MalformedContinuationTokenException malformedContinuationTokenException = new MalformedContinuationTokenException(exception.Message); + throw CosmosExceptionFactory.CreateBadRequestException( + message: $"Malformed Continuation Token: {json}.", + headers: CosmosQueryResponseMessageHeaders.ConvertToQueryHeaders( + new Headers(), + default, + default, + (int)SubStatusCodes.MalformedContinuationToken, + default), + stackTrace: malformedContinuationTokenException.StackTrace, + innerException: malformedContinuationTokenException, + trace: null); + } catch (Exception exception) { - if (exception.InnerException is JsonParseException) - { - MalformedContinuationTokenException malformedContinuationTokenException = new MalformedContinuationTokenException(exception.Message); - throw CosmosExceptionFactory.CreateBadRequestException( - message: $"Malformed Continuation Token: {json}.", - headers: CosmosQueryResponseMessageHeaders.ConvertToQueryHeaders( - new Headers(), - default, - default, - 20007, - default), - stackTrace: malformedContinuationTokenException.StackTrace, - innerException: malformedContinuationTokenException, - trace: null); - } - else - { - throw exception; - } + throw exception; } return tryParse.Result; From 176d9da46dc861d7f86d276a9de705a2836bfb02 Mon Sep 17 00:00:00 2001 From: Aditya Kotalwar Date: Sun, 25 Jun 2023 19:26:31 -0700 Subject: [PATCH 5/7] Moved fix to a higher point in the call stack --- .../src/CosmosElements/CosmosElement.cs | 24 +----------------- .../src/ReadFeed/ReadFeedIteratorCore.cs | 25 +++++++++++++++++-- .../CosmosItemLinqTests.cs | 2 +- 3 files changed, 25 insertions(+), 26 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/CosmosElements/CosmosElement.cs b/Microsoft.Azure.Cosmos/src/CosmosElements/CosmosElement.cs index 3201f1821c..283c15095a 100644 --- a/Microsoft.Azure.Cosmos/src/CosmosElements/CosmosElement.cs +++ b/Microsoft.Azure.Cosmos/src/CosmosElements/CosmosElement.cs @@ -190,29 +190,7 @@ public static bool TryCreateFromBuffer(ReadOnlyMemory buff public static CosmosElement Parse(string json) { TryCatch tryParse = CosmosElement.Monadic.Parse(json); - try - { - tryParse.ThrowIfFailed(); - } - catch (Exception exception) when (exception.InnerException is JsonParseException) - { - MalformedContinuationTokenException malformedContinuationTokenException = new MalformedContinuationTokenException(exception.Message); - throw CosmosExceptionFactory.CreateBadRequestException( - message: $"Malformed Continuation Token: {json}.", - headers: CosmosQueryResponseMessageHeaders.ConvertToQueryHeaders( - new Headers(), - default, - default, - (int)SubStatusCodes.MalformedContinuationToken, - default), - stackTrace: malformedContinuationTokenException.StackTrace, - innerException: malformedContinuationTokenException, - trace: null); - } - catch (Exception exception) - { - throw exception; - } + tryParse.ThrowIfFailed(); return tryParse.Result; } diff --git a/Microsoft.Azure.Cosmos/src/ReadFeed/ReadFeedIteratorCore.cs b/Microsoft.Azure.Cosmos/src/ReadFeed/ReadFeedIteratorCore.cs index d9b935e758..8a46196a56 100644 --- a/Microsoft.Azure.Cosmos/src/ReadFeed/ReadFeedIteratorCore.cs +++ b/Microsoft.Azure.Cosmos/src/ReadFeed/ReadFeedIteratorCore.cs @@ -9,13 +9,16 @@ namespace Microsoft.Azure.Cosmos.ReadFeed using System.Threading; using System.Threading.Tasks; using Microsoft.Azure.Cosmos.CosmosElements; - using Microsoft.Azure.Cosmos.Diagnostics; + using Microsoft.Azure.Cosmos.Json; using Microsoft.Azure.Cosmos.Pagination; using Microsoft.Azure.Cosmos.Query.Core; + using Microsoft.Azure.Cosmos.Query.Core.Exceptions; using Microsoft.Azure.Cosmos.Query.Core.Monads; using Microsoft.Azure.Cosmos.ReadFeed.Pagination; + using Microsoft.Azure.Cosmos.Resource.CosmosExceptions; using Microsoft.Azure.Cosmos.Routing; using Microsoft.Azure.Cosmos.Tracing; + using Microsoft.Azure.Documents; /// /// Cosmos feed stream iterator. This is used to get the query responses with a Stream content @@ -113,7 +116,25 @@ public ReadFeedIteratorCore( else { CosmosString tokenAsString = (CosmosString)token; - state = ReadFeedState.Continuation(CosmosElement.Parse(tokenAsString.Value)); + try + { + state = ReadFeedState.Continuation(CosmosElement.Parse(tokenAsString.Value)); + } + catch (Exception exception) when (exception.InnerException is JsonParseException) + { + MalformedContinuationTokenException malformedContinuationTokenException = new MalformedContinuationTokenException(exception.Message); + throw CosmosExceptionFactory.CreateBadRequestException( + message: $"Malformed Continuation Token: {tokenAsString}.", + headers: CosmosQueryResponseMessageHeaders.ConvertToQueryHeaders( + new Headers(), + default, + default, + (int)SubStatusCodes.MalformedContinuationToken, + default), + stackTrace: exception.StackTrace, + innerException: malformedContinuationTokenException, + trace: null); + } } FeedRangeState feedRangeState = new FeedRangeState(feedRange, state); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemLinqTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemLinqTests.cs index f7cf1386c5..5b56e72d44 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemLinqTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemLinqTests.cs @@ -232,7 +232,7 @@ public void ItemLINQQueryWithInvalidContinuationTokenTest() return; } - Assert.IsFalse(true, "Should never reach till here, hence ensuring that an exception is always recieved"); + Assert.Fail("Should never reach till here, hence ensuring that an exception is always recieved"); } } From a96930da2a390a62da3295469fde7a5ff2b34f69 Mon Sep 17 00:00:00 2001 From: Aditya Kotalwar Date: Sun, 25 Jun 2023 19:28:29 -0700 Subject: [PATCH 6/7] Removed unused Usings --- Microsoft.Azure.Cosmos/src/CosmosElements/CosmosElement.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/CosmosElements/CosmosElement.cs b/Microsoft.Azure.Cosmos/src/CosmosElements/CosmosElement.cs index 283c15095a..24d1fa78d5 100644 --- a/Microsoft.Azure.Cosmos/src/CosmosElements/CosmosElement.cs +++ b/Microsoft.Azure.Cosmos/src/CosmosElements/CosmosElement.cs @@ -11,10 +11,7 @@ namespace Microsoft.Azure.Cosmos.CosmosElements using Microsoft.Azure.Cosmos.CosmosElements.Numbers; using Microsoft.Azure.Cosmos.Json; using Microsoft.Azure.Cosmos.Json.Interop; - using Microsoft.Azure.Cosmos.Query.Core.Exceptions; using Microsoft.Azure.Cosmos.Query.Core.Monads; - using Microsoft.Azure.Cosmos.Resource.CosmosExceptions; - using Microsoft.Azure.Documents; [Newtonsoft.Json.JsonConverter(typeof(CosmosElementJsonConverter))] #if INTERNAL From a75fcbdcd7d0927939bcf05df7c59f6a1298211c Mon Sep 17 00:00:00 2001 From: Aditya Kotalwar Date: Fri, 7 Jul 2023 16:13:33 -0700 Subject: [PATCH 7/7] Updated test code --- .../CosmosItemLinqTests.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemLinqTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemLinqTests.cs index 5b56e72d44..b3dc7afa41 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemLinqTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemLinqTests.cs @@ -214,12 +214,13 @@ public async Task ItemLINQQueryTest() [TestMethod] public void ItemLINQQueryWithInvalidContinuationTokenTest() { + string malformedString = "Malformed String"; FeedIterator feedIterator = this.Container.GetItemLinqQueryable().ToFeedIterator(); while (feedIterator.HasMoreResults) { IOrderedQueryable querable = this.Container.GetItemLinqQueryable( - continuationToken: "Malformed String"); + continuationToken: malformedString); try { FeedIterator iterator = querable.ToFeedIterator(); @@ -227,8 +228,8 @@ public void ItemLINQQueryWithInvalidContinuationTokenTest() catch (CosmosException exception) { Assert.IsTrue(exception.StatusCode == System.Net.HttpStatusCode.BadRequest); - Assert.IsTrue(exception.SubStatusCode == 20007); - Assert.IsTrue(exception.Message.Contains("Malformed String")); + Assert.IsTrue(exception.SubStatusCode == (int)Documents.SubStatusCodes.MalformedContinuationToken); + Assert.IsTrue(exception.Message.Contains(malformedString)); return; }