Skip to content

Commit

Permalink
Escaping CDATA end tags
Browse files Browse the repository at this point in the history
Fixes javaee#4392

Signed-off-by: Tomas Hofman <thofman@redhat.com>
  • Loading branch information
TomasHofman committed Jul 22, 2019
1 parent 6ce2c4c commit 0bf29e5
Show file tree
Hide file tree
Showing 2 changed files with 120 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -867,7 +867,12 @@ public void writeText(char text) throws IOException {

closeStartIfNecessary();
if (dontEscape) {
writer.write(text);
if (writingCdata) {
charHolder[0] = text;
writeUnescapedCData(charHolder, 0, 1);
} else {
writer.write(text);
}
} else if (isPartial || !writingCdata) {
charHolder[0] = text;
HtmlUtils.writeText(writer, escapeUnicode, escapeIso, buffer, charHolder);
Expand Down Expand Up @@ -906,7 +911,11 @@ public void writeText(char text[]) throws IOException {
closeStartIfNecessary();

if (dontEscape) {
writer.write(text);
if (writingCdata) {
writeUnescapedCData(text, 0, text.length);
} else {
writer.write(text);
}
} else if (isPartial || !writingCdata) {
HtmlUtils.writeText(writer, escapeUnicode, escapeIso, buffer, text);
} else { // if writingCdata
Expand Down Expand Up @@ -943,7 +952,11 @@ public void writeText(Object text, String componentPropertyName)
String textStr = text.toString();

if (dontEscape) {
writer.write(textStr);
if (writingCdata) {
writeUnescapedCData(textStr.toCharArray(), 0, textStr.length());
} else {
writer.write(textStr);
}
} else if (isPartial || !writingCdata) {
ensureTextBufferCapacity(textStr);
HtmlUtils.writeText(writer,
Expand Down Expand Up @@ -1006,7 +1019,11 @@ public void writeText(char text[], int off, int len)
if (len == 0) return;

if (dontEscape) {
writer.write(text, off, len);
if (writingCdata) {
writeUnescapedCData(text, off, len);
} else {
writer.write(text, off, len);
}
} else if (isPartial || !writingCdata) {
HtmlUtils.writeText(writer, escapeUnicode, escapeIso, buffer, text, off, len);
} else { // if (writingCdata)
Expand Down Expand Up @@ -1405,4 +1422,61 @@ private void flushBuffer() throws IOException {
writer.write(cdataBuffer, 0, cdataBufferLength);
cdataBufferLength = 0;
}

/**
* When writing un-escaped CDATA, "]]>" sequence still has to be escaped by breaking CDATA block.
*/
private void writeUnescapedCData(char[] cbuf, int offset, int length) throws IOException {
// single char case
if (length == 1) {
if (cbuf[offset] == ']') {
appendBuffer(ESCAPEDSINGLEBRACKET);
} else {
appendBuffer(cbuf[offset]);
}
flushBuffer();
return;
}

// two char case
if (length == 2) {
if (cbuf[offset] == ']' && cbuf[offset + 1] == ']') {
appendBuffer(ESCAPEDSINGLEBRACKET);
appendBuffer(ESCAPEDSINGLEBRACKET);
} else {
appendBuffer(cbuf[offset]);
appendBuffer(cbuf[offset + 1]);
}
flushBuffer();
return;
}

// > 2 char case
boolean last = false;
for (int i = offset; i < length - 2; i++) {
if (cbuf[i] == ']' && cbuf[i + 1] == ']' && cbuf[i + 2] == '>') {
appendBuffer(ESCAPEDEND);
i += 2;
} else {
appendBuffer(cbuf[i]);
}
if (i == (offset + length - 1)) {
last = true;
}
}
// if we didn't look at the last characters, look at them now
if (!last) {
if (cbuf[offset + length - 2] == ']') {
appendBuffer(ESCAPEDSINGLEBRACKET);
} else {
appendBuffer(cbuf[offset + length - 2]);
}
if (cbuf[offset + length - 1] == ']') {
appendBuffer(ESCAPEDSINGLEBRACKET);
} else {
appendBuffer(cbuf[offset + length - 1]);
}
}
flushBuffer();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -141,4 +141,46 @@ public void testCDATAWithXHTML() throws Exception {
responseWriter.flush();
assertEquals(expected, stringWriter.toString());
}

/**
* Test CDATA escaping.
*/
@Test
public void testUnescapedCDATA() throws Exception {
String expectedStart = "<style>\n<![CDATA[\n";
String expectedEnd = "\n]]>\n</style>";

// single char
StringWriter stringWriter = new StringWriter();
HtmlResponseWriter responseWriter = new HtmlResponseWriter(stringWriter, "application/xhtml+xml", "UTF-8");
responseWriter.startElement("style", null);
responseWriter.startCDATA();
responseWriter.writeText(']', null);
responseWriter.endCDATA();
responseWriter.endElement("style");
responseWriter.flush();
assertEquals(expectedStart + "]]]><![CDATA[" + expectedEnd, stringWriter.toString());

// two chars
stringWriter = new StringWriter();
responseWriter = new HtmlResponseWriter(stringWriter, "application/xhtml+xml", "UTF-8");
responseWriter.startElement("style", null);
responseWriter.startCDATA();
responseWriter.writeText("]]".toCharArray());
responseWriter.endCDATA();
responseWriter.endElement("style");
responseWriter.flush();
assertEquals(expectedStart + "]]]><![CDATA[]]]><![CDATA[" + expectedEnd, stringWriter.toString());

// long string
stringWriter = new StringWriter();
responseWriter = new HtmlResponseWriter(stringWriter, "application/xhtml+xml", "UTF-8");
responseWriter.startElement("style", null);
responseWriter.startCDATA();
responseWriter.writeText("abc]]>abc", null);
responseWriter.endCDATA();
responseWriter.endElement("style");
responseWriter.flush();
assertEquals(expectedStart + "abc]]]><![CDATA[]>abc" + expectedEnd, stringWriter.toString());
}
}

0 comments on commit 0bf29e5

Please sign in to comment.