Skip to content

Commit

Permalink
Improve comment parsing in DTD/XSD detection algorithm
Browse files Browse the repository at this point in the history
Prior to this commit, XmlValidationModeDetector did not properly parse
all categories of comments (described below). When such categories of
comments were encountered XmlValidationModeDetector may have
incorrectly detected that an XML file used a DTD when it used an XSD,
or vice versa.

This commit revises the parsing algorithm in XmlValidationModeDetector
so that multi-line comments and multiple comments on a single line are
properly recognized.

Specifically, with this commit the following categories of comments are
now handled properly.

- Multiple comments on a single line
- Multi-line comment: beginning on one line and then ending on another
  line with an additional comment following on that same line.
- Multi-line comment: beginning at the end of XML content on one line
  and then spanning multiple lines.

Closes gh-27915
  • Loading branch information
sbrannen committed Jan 13, 2022
1 parent 9e8b6fe commit 4b1b254
Show file tree
Hide file tree
Showing 8 changed files with 75 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ public int detectValidationMode(InputStream inputStream) throws IOException {
String content;
while ((content = reader.readLine()) != null) {
content = consumeCommentTokens(content);
if (this.inComment || !StringUtils.hasText(content)) {
if (!StringUtils.hasText(content)) {
continue;
}
if (hasDoctype(content)) {
Expand Down Expand Up @@ -143,11 +143,10 @@ private boolean hasOpeningTag(String content) {
}

/**
* Consume all leading and trailing comments in the given String and return
* the remaining content, which may be empty since the supplied content might
* be all comment data.
* Consume all comments in the given String and return the remaining content,
* which may be empty since the supplied content might be all comment data.
* <p>This method takes the current "in comment" parsing state into account.
*/
@Nullable
private String consumeCommentTokens(String line) {
int indexOfStartComment = line.indexOf(START_COMMENT);
if (indexOfStartComment == -1 && !line.contains(END_COMMENT)) {
Expand All @@ -156,17 +155,15 @@ private String consumeCommentTokens(String line) {

String result = "";
String currLine = line;
if (indexOfStartComment >= 0) {
if (!this.inComment && (indexOfStartComment >= 0)) {
result = line.substring(0, indexOfStartComment);
currLine = line.substring(indexOfStartComment);
}

while ((currLine = consume(currLine)) != null) {
if (!this.inComment && !currLine.trim().startsWith(START_COMMENT)) {
return result + currLine;
}
if ((currLine = consume(currLine)) != null) {
result += consumeCommentTokens(currLine);
}
return null;
return result;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.util.xml.XmlValidationModeDetector.VALIDATION_DTD;
import static org.springframework.util.xml.XmlValidationModeDetector.VALIDATION_XSD;

/**
* Unit tests for {@link XmlValidationModeDetector}.
Expand All @@ -37,12 +38,29 @@ class XmlValidationModeDetectorTests {


@ParameterizedTest
@ValueSource(strings = { "dtdWithTrailingComment.xml", "dtdWithLeadingComment.xml", "dtdWithCommentOnNextLine.xml",
"dtdWithMultipleComments.xml" })
@ValueSource(strings = {
"dtdWithNoComments.xml",
"dtdWithLeadingComment.xml",
"dtdWithTrailingComment.xml",
"dtdWithTrailingCommentAcrossMultipleLines.xml",
"dtdWithCommentOnNextLine.xml",
"dtdWithMultipleComments.xml"
})
void dtdDetection(String fileName) throws Exception {
assertValidationMode(fileName, VALIDATION_DTD);
}

@ParameterizedTest
@ValueSource(strings = {
"xsdWithNoComments.xml",
"xsdWithMultipleComments.xml",
"xsdWithDoctypeInComment.xml",
"xsdWithDoctypeInOpenCommentWithAdditionalCommentOnSameLine.xml"
})
void xsdDetection(String fileName) throws Exception {
assertValidationMode(fileName, VALIDATION_XSD);
}


private void assertValidationMode(String fileName, int expectedValidationMode) throws IOException {
try (InputStream inputStream = getClass().getResourceAsStream(fileName)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "https://www.springframework.org/dtd/spring-beans-2.0.dtd">

<beans>

</beans>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "https://www.springframework.org/dtd/spring-beans-2.0.dtd"><!-- comment --><beans><!--
trailing comment across multiple lines -->


</beans>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "https://www.springframework.org/dtd/spring-beans-2.0.dtd"> -->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">

</beans>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "https://www.springframework.org/dtd/spring-beans-2.0.dtd"> --> <!-- additional comment on same line -->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">

</beans>
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- comment #1 --> <!-- comment #2 --> <beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd"><!--
trailing
comment
-->

</beans>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">

</beans>

0 comments on commit 4b1b254

Please sign in to comment.