Properly handle style (and similar) tags in HTML snippets
Bug: 3285281 Change-Id: Ia45dbe39b47f1bcb647efbf1860ed4b933976df8
This commit is contained in:
parent
ac7194b4a9
commit
5a8be8e7ed
@ -41,6 +41,10 @@ public class Snippet {
|
|||||||
// For some reason, isWhitespace() returns false with the following...
|
// For some reason, isWhitespace() returns false with the following...
|
||||||
/*package*/ static final char NON_BREAKING_SPACE_CHARACTER = (char)160;
|
/*package*/ static final char NON_BREAKING_SPACE_CHARACTER = (char)160;
|
||||||
|
|
||||||
|
// Tags whose content must be stripped as well
|
||||||
|
static final String[] STRIP_TAGS = new String[] {"title ", "script", "style ", "applet"};
|
||||||
|
static final int STRIP_TAG_LENGTH = 6;
|
||||||
|
|
||||||
// Note: ESCAPE_STRINGS is taken from the StringUtil class which is part of the
|
// Note: ESCAPE_STRINGS is taken from the StringUtil class which is part of the
|
||||||
// unbundled_google package
|
// unbundled_google package
|
||||||
static final Map<String, Character> ESCAPE_STRINGS;
|
static final Map<String, Character> ESCAPE_STRINGS;
|
||||||
@ -311,6 +315,33 @@ public class Snippet {
|
|||||||
return fromText(text, false);
|
return fromText(text, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the end of this tag; there are two alternatives: <tag .../> or <tag ...> ... </tag>
|
||||||
|
* @param htmlText some HTML text
|
||||||
|
* @param tag the HTML tag
|
||||||
|
* @param startPos the start position in the HTML text where the tag starts
|
||||||
|
* @return the position just before the end of the tag or -1 if not found
|
||||||
|
*/
|
||||||
|
/*package*/ static int findTagEnd(String htmlText, String tag, int startPos) {
|
||||||
|
if (tag.endsWith(" ")) {
|
||||||
|
tag = tag.substring(0, tag.length() - 1);
|
||||||
|
}
|
||||||
|
int length = htmlText.length();
|
||||||
|
char prevChar = 0;
|
||||||
|
for (int i = startPos; i < length; i++) {
|
||||||
|
char c = htmlText.charAt(i);
|
||||||
|
if (c == '>') {
|
||||||
|
if (prevChar == '/') {
|
||||||
|
return i - 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
prevChar = c;
|
||||||
|
}
|
||||||
|
// We didn't find /> at the end of the tag so find </tag>
|
||||||
|
return htmlText.indexOf("/" + tag, startPos);
|
||||||
|
}
|
||||||
|
|
||||||
public static String fromText(String text, boolean stripHtml) {
|
public static String fromText(String text, boolean stripHtml) {
|
||||||
// Handle null and empty string
|
// Handle null and empty string
|
||||||
if (TextUtils.isEmpty(text)) return "";
|
if (TextUtils.isEmpty(text)) return "";
|
||||||
@ -338,6 +369,26 @@ public class Snippet {
|
|||||||
char peek = text.charAt(i + 1);
|
char peek = text.charAt(i + 1);
|
||||||
if (peek == '!' || peek == '-' || peek == '/' || Character.isLetter(peek)) {
|
if (peek == '!' || peek == '-' || peek == '/' || Character.isLetter(peek)) {
|
||||||
inTag = true;
|
inTag = true;
|
||||||
|
// Strip content of title, script, style and applet tags
|
||||||
|
if (i < (length - (STRIP_TAG_LENGTH + 2))) {
|
||||||
|
String tag = text.substring(i + 1, i + STRIP_TAG_LENGTH + 1);
|
||||||
|
boolean stripContent = false;
|
||||||
|
for (String stripTag: STRIP_TAGS) {
|
||||||
|
if (stripTag.equals(tag)) {
|
||||||
|
stripContent = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (stripContent) {
|
||||||
|
// Look for the end of this tag
|
||||||
|
int endTagPosition = findTagEnd(text, tag, i);
|
||||||
|
if (endTagPosition < 0) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
i = endTagPosition;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (stripHtml && inTag && (c == '>')) {
|
} else if (stripHtml && inTag && (c == '>')) {
|
||||||
|
@ -24,6 +24,12 @@ package com.android.email;
|
|||||||
|
|
||||||
import android.test.AndroidTestCase;
|
import android.test.AndroidTestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests of Snippet
|
||||||
|
*
|
||||||
|
* You can run this entire test case with:
|
||||||
|
* runtest -c com.android.email.SnippetTests email
|
||||||
|
*/
|
||||||
public class SnippetTests extends AndroidTestCase {
|
public class SnippetTests extends AndroidTestCase {
|
||||||
|
|
||||||
public void testPlainSnippet() {
|
public void testPlainSnippet() {
|
||||||
@ -108,4 +114,46 @@ public class SnippetTests extends AndroidTestCase {
|
|||||||
assertEquals(c, '&');
|
assertEquals(c, '&');
|
||||||
assertEquals(0, skipCount[0]);
|
assertEquals(0, skipCount[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testStripContent() {
|
||||||
|
assertEquals("Visible", Snippet.fromHtmlText(
|
||||||
|
"<html><style foo=\"bar\">Not</style>Visible</html>"));
|
||||||
|
assertEquals("IsVisible", Snippet.fromHtmlText(
|
||||||
|
"<html><nostrip foo=\"bar\">Is</nostrip>Visible</html>"));
|
||||||
|
assertEquals("Visible", Snippet.fromHtmlText(
|
||||||
|
"<html>Visible<style foo=\"bar\">Not"));
|
||||||
|
assertEquals("VisibleAgainVisible", Snippet.fromHtmlText(
|
||||||
|
"<html>Visible<style foo=\"bar\">Not</style>AgainVisible"));
|
||||||
|
assertEquals("VisibleAgainVisible", Snippet.fromHtmlText(
|
||||||
|
"<html>Visible<style foo=\"bar\"/>AgainVisible"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We pass in HTML text in which an ampersand (@) is two chars ahead of the correct end position
|
||||||
|
* for the tag named 'tag' and then check whether the calculated end position matches the known
|
||||||
|
* correct position. HTML text not containing an ampersand should generate a calculated end of
|
||||||
|
* -1
|
||||||
|
* @param text the HTML text to test
|
||||||
|
*/
|
||||||
|
private void findTagEnd(String text, String tag) {
|
||||||
|
int calculatedEnd = Snippet.findTagEnd(text , tag, 0);
|
||||||
|
int knownEnd = text.indexOf('@') + 2;
|
||||||
|
if (knownEnd == 1) {
|
||||||
|
// indexOf will return -1, so we'll get 1 as knownEnd
|
||||||
|
assertEquals(-1, calculatedEnd);
|
||||||
|
} else {
|
||||||
|
assertEquals(calculatedEnd, knownEnd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testFindTagEnd() {
|
||||||
|
// Test with <tag ... />
|
||||||
|
findTagEnd("<tag foo=\"bar\"@ /> <blah blah>", "tag");
|
||||||
|
// Test with <tag ...> ... </tag>
|
||||||
|
findTagEnd("<tag foo=\"bar\">some text@</tag>some more text", "tag");
|
||||||
|
// Test with incomplete tag
|
||||||
|
findTagEnd("<tag foo=\"bar\">some more text but no end tag", "tag");
|
||||||
|
// Test with space at end of tag
|
||||||
|
findTagEnd("<tag foo=\"bar\">some more text but no end tag", "tag ");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user