From cbd99cc767085bf79f17682e2ffe2845330d39f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 22 Oct 2019 01:01:37 +0200 Subject: [PATCH] Resolve link-in-link edge case Testing with #6542 surfaced a crash scenario, caused by formatted links that had URLs in the display text, for example [mean example - https://osu.ppy.sh](https://osu.ppy.sh) In that case the outer Markdown link would get picked up once, and then reduced to the link text when looking for other links, leading to it being picked up again the second time when the raw link is found. Add a check in the raw link parsing path that ensures that the found URL is not a part of a bigger, pre-existing link. --- osu.Game.Tests/Chat/MessageFormatterTests.cs | 12 ++++++++++++ osu.Game/Online/Chat/MessageFormatter.cs | 18 +++++++++++++----- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Chat/MessageFormatterTests.cs b/osu.Game.Tests/Chat/MessageFormatterTests.cs index 1cbd083f0d..7988c6b96d 100644 --- a/osu.Game.Tests/Chat/MessageFormatterTests.cs +++ b/osu.Game.Tests/Chat/MessageFormatterTests.cs @@ -309,6 +309,18 @@ namespace osu.Game.Tests.Chat Assert.AreEqual(18, result.Links[0].Length); } + [Test] + public void TestMarkdownFormatLinkWithUrlAndTextInTitle() + { + Message result = MessageFormatter.FormatMessage(new Message { Content = "I haven't seen [oh no, text here! https://osu.ppy.sh](https://osu.ppy.sh) before..." }); + + Assert.AreEqual("I haven't seen oh no, text here! https://osu.ppy.sh before...", result.DisplayContent); + Assert.AreEqual(1, result.Links.Count); + Assert.AreEqual("https://osu.ppy.sh", result.Links[0].Url); + Assert.AreEqual(15, result.Links[0].Index); + Assert.AreEqual(36, result.Links[0].Length); + } + [Test] public void TestMarkdownFormatLinkWithMisleadingUrlInText() { diff --git a/osu.Game/Online/Chat/MessageFormatter.cs b/osu.Game/Online/Chat/MessageFormatter.cs index 749d24ee75..d77920c97d 100644 --- a/osu.Game/Online/Chat/MessageFormatter.cs +++ b/osu.Game/Online/Chat/MessageFormatter.cs @@ -1,4 +1,4 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. using System; @@ -95,11 +95,17 @@ namespace osu.Game.Online.Chat foreach (Match m in regex.Matches(result.Text, startIndex)) { var index = m.Index; - var link = m.Groups["link"].Value; - var indexLength = link.Length; + var linkText = m.Groups["link"].Value; + var indexLength = linkText.Length; - var details = getLinkDetails(link); - result.Links.Add(new Link(link, index, indexLength, details.Action, details.Argument)); + var details = getLinkDetails(linkText); + var link = new Link(linkText, index, indexLength, details.Action, details.Argument); + + // sometimes an already-processed formatted link can reduce to a simple URL, too + // (example: [mean example - https://osu.ppy.sh](https://osu.ppy.sh)) + // therefore we need to check if any of the pre-existing links contains the raw one we found + if (result.Links.All(existingLink => !existingLink.Contains(link))) + result.Links.Add(link); } } @@ -292,6 +298,8 @@ namespace osu.Game.Online.Chat Argument = argument; } + public bool Contains(Link otherLink) => otherLink.Index >= Index && otherLink.Index + otherLink.Length <= Index + Length; + public int CompareTo(Link otherLink) => Index > otherLink.Index ? 1 : -1; } }