Skip to content

Commit a76cdfc

Browse files
committed
Fix Invalid Comment Edge Case
According to [the XML specification](https://www.w3.org/TR/xml11//#IDA5CES "W3 XML") XML comments can not end in `--->`. Prior to this commit creating a comment of the form `Comment("invalid-")` would yield no error though it should, since it is rendered as `<!--invalid--->`. This commit makes such `String` values yield an `IllegalArgumentException`. A companion object was also added with two helper methods, `validated` and `validatedOpt`, which allow for a user of the library to check if a `String` is valid without having to `catch` the `IllegalArgumentException`.
1 parent 0125cf6 commit a76cdfc

File tree

2 files changed

+102
-2
lines changed

2 files changed

+102
-2
lines changed

shared/src/main/scala/scala/xml/Comment.scala

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ package xml
1414
*
1515
* @author Burak Emir
1616
* @param commentText the text contained in this node, may not contain "--"
17+
* and the final character may not be `-` to prevent a closing span of `-->`
18+
* which is invalid. [[https://www.w3.org/TR/xml11//#IDA5CES]]
1719
*/
1820
case class Comment(commentText: String) extends SpecialNode {
1921

@@ -22,12 +24,79 @@ case class Comment(commentText: String) extends SpecialNode {
2224
final override def doCollectNamespaces = false
2325
final override def doTransform = false
2426

25-
if (commentText contains "--")
26-
throw new IllegalArgumentException("text contains \"--\"")
27+
// Validate the commentText. We call the `Comment.validate` method because
28+
// that shares code with the more safe constructs, e.g. `Comment.validated`
29+
// and `Comment.validatedOpt`.
30+
Comment.validate(commentText).fold(
31+
()
32+
)(e =>
33+
throw e
34+
)
2735

2836
/**
2937
* Appends &quot;<!-- text -->&quot; to this string buffer.
3038
*/
3139
override def buildString(sb: StringBuilder) =
3240
sb append "<!--" append commentText append "-->"
3341
}
42+
43+
// We have to extends `scala.runtime.AbstractFunction1[String, Comment]` and
44+
// override `apply` if we don't want to break binary compatibility.
45+
object Comment extends scala.runtime.AbstractFunction1[String, Comment]{
46+
47+
override final def apply(commentText: String): Comment =
48+
new Comment(commentText)
49+
50+
/** Validates if a given `String` can be a valid XML comment.
51+
*
52+
* There are two related cases where a `String` is invalid. The first is
53+
* when the `String` `"--"` occurs in the body of the text. The second is
54+
* when the final character in the comment is `'-'`. In the second case
55+
* this is invalid because it would yield a XML encoding of `-->` for the
56+
* final three characters of the rendered comment which invalidates the
57+
* first rule of not having `"--"` in the comment.
58+
*
59+
* @see [[https://www.w3.org/TR/xml11//#IDA5CES]]
60+
*/
61+
private def validate(commentText: String): Option[Throwable] =
62+
if (commentText.contains("--")) {
63+
Some(new IllegalArgumentException("text contains \"--\""))
64+
} else if (commentText.charAt(commentText.length - 1) == '-') {
65+
Some(new IllegalArgumentException("The final character of a XML comment may not be '-'. See https://www.w3.org/TR/xml11//#IDA5CES"))
66+
} else {
67+
None
68+
}
69+
70+
/** Validates if a given `String` can be a valid XML comment, yielding a
71+
* `Left` `Throwable` if it is invalid.
72+
*
73+
* There are two related cases where a `String` is invalid. The first is
74+
* when the `String` `"--"` occurs in the body of the text. The second is
75+
* when the final character in the comment is `'-'`. In the second case
76+
* this is invalid because it would yield a XML encoding of `-->` for the
77+
* final three characters of the rendered comment which invalidates the
78+
* first rule of not having `"--"` in the comment.
79+
*
80+
* @see [[https://www.w3.org/TR/xml11//#IDA5CES]]
81+
*/
82+
def validated(commentText: String): Either[Throwable, Comment] =
83+
validate(commentText).fold(
84+
Right(Comment(commentText)): Either[Throwable, Comment]
85+
)(t => Left(t))
86+
87+
88+
/** Validates if a given `String` can be a valid XML comment, `None` if it is
89+
* invalid.
90+
*
91+
* There are two related cases where a `String` is invalid. The first is
92+
* when the `String` `"--"` occurs in the body of the text. The second is
93+
* when the final character in the comment is `'-'`. In the second case
94+
* this is invalid because it would yield a XML encoding of `-->` for the
95+
* final three characters of the rendered comment which invalidates the
96+
* first rule of not having `"--"` in the comment.
97+
*
98+
* @see [[https://www.w3.org/TR/xml11//#IDA5CES]]
99+
*/
100+
def validatedOpt(commentText: String): Option[Comment] =
101+
validated(commentText).toOption
102+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package scala.xml
2+
3+
import org.junit.Assert.assertEquals
4+
import org.junit.Assert.assertTrue
5+
import org.junit.Test
6+
7+
final class CommentTest {
8+
9+
@Test(expected=classOf[IllegalArgumentException])
10+
def invalidCommentWithTwoDashes: Unit = {
11+
val invalid: String = "invalid--comment"
12+
assertTrue(Comment.validated(invalid).isLeft)
13+
assertTrue(Comment.validatedOpt(invalid).isEmpty)
14+
Comment(invalid)
15+
}
16+
17+
@Test(expected=classOf[IllegalArgumentException])
18+
def invalidCommentWithFinalDash: Unit = {
19+
val invalid: String = "invalid comment-"
20+
assertTrue(Comment.validated(invalid).isLeft)
21+
assertTrue(Comment.validatedOpt(invalid).isEmpty)
22+
Comment(invalid)
23+
}
24+
25+
@Test
26+
def validCommentWithDash: Unit = {
27+
val valid: String = "valid-comment"
28+
assertEquals(Right(Comment("valid-comment")), Comment.validated(valid))
29+
assertEquals(Some(Comment("valid-comment")), Comment.validatedOpt(valid))
30+
}
31+
}

0 commit comments

Comments
 (0)