diff --git a/commafeed-server/src/main/java/com/commafeed/backend/feed/parser/XMLCleaner.java b/commafeed-server/src/main/java/com/commafeed/backend/feed/parser/XMLCleaner.java index 03409528..3bcbd4b5 100644 --- a/commafeed-server/src/main/java/com/commafeed/backend/feed/parser/XMLCleaner.java +++ b/commafeed-server/src/main/java/com/commafeed/backend/feed/parser/XMLCleaner.java @@ -8,12 +8,13 @@ import org.apache.commons.lang3.StringUtils; import org.jdom2.Verifier; import java.util.Collection; +import java.util.regex.Matcher; import java.util.regex.Pattern; @Singleton public class XMLCleaner { - private static final Pattern DOCTYPE_PATTERN = Pattern.compile("]*>", Pattern.CASE_INSENSITIVE); + private static final Pattern DOCTYPE_START_PATTERN = Pattern.compile("]*>", without the quadratic cost of that regex when the + // input contains many "', matcher.end()); + if (end < 0) { + break; + } + + sb.append(xml, pos, matcher.start()); + pos = end + 1; + } + + return sb.append(xml, pos, xml.length()).toString(); } } diff --git a/commafeed-server/src/test/java/com/commafeed/backend/feed/parser/XMLCleanerTest.java b/commafeed-server/src/test/java/com/commafeed/backend/feed/parser/XMLCleanerTest.java index 0d4001f2..71d33088 100644 --- a/commafeed-server/src/test/java/com/commafeed/backend/feed/parser/XMLCleanerTest.java +++ b/commafeed-server/src/test/java/com/commafeed/backend/feed/parser/XMLCleanerTest.java @@ -4,6 +4,8 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import java.time.Duration; + class XMLCleanerTest { XMLCleaner xmlCleaner = new XMLCleaner(); @@ -279,5 +281,39 @@ class XMLCleanerTest { String source = ""; Assertions.assertEquals("", xmlCleaner.removeDoctypeDeclarations(source)); } + + @Test + void preservesUnterminatedDoctype() { + String source = ""; + Assertions.assertEquals("", xmlCleaner.removeDoctypeDeclarations(source)); + } + + @Test + void handlesManyUnterminatedDoctypesInLinearTime() { + String source = " Assertions.assertEquals(source, xmlCleaner.removeDoctypeDeclarations(source))); + } + + @Test + void handlesManyUnterminatedDoctypesAfterClosingBracketInLinearTime() { + String source = "" + " Assertions.assertEquals(source, xmlCleaner.removeDoctypeDeclarations(source))); + } } }