Bug 995321 - nsIDocumentEncoder.encodeToString should offer a way to limit the size of the output, r=smaug.

This commit is contained in:
Florian Quèze 2014-04-17 00:01:55 +02:00
parent 1f817c0e95
commit 9b8efd4d75
6 changed files with 115 additions and 11 deletions

View File

@ -35,7 +35,7 @@ interface nsIDocumentEncoderNodeFixup : nsISupports
nsIDOMNode fixupNode(in nsIDOMNode aNode, out boolean aSerializeCloneKids);
};
[scriptable, uuid(7222bdf1-c2b9-41f1-a40a-a3d65283a95b)]
[scriptable, uuid(1158bd7e-a08b-4ff6-9417-6f99144cfccc)]
interface nsIDocumentEncoder : nsISupports
{
// Output methods flag bits. There are a frightening number of these,
@ -329,6 +329,21 @@ interface nsIDocumentEncoder : nsISupports
AString encodeToStringWithContext( out AString aContextString,
out AString aInfoString);
/**
* Encode the document into a string of limited size.
* @param aMaxLength After aMaxLength characters, the encoder will stop
* encoding new data.
* Only values > 0 will be considered.
* The returned string may be slightly larger than
* aMaxLength because some serializers (eg. HTML)
* may need to close some tags after they stop
* encoding new data, or finish a line (72 columns
* by default for the plain text serializer).
*
* @return The document encoded into a string.
*/
AString encodeToStringWithMaxLength(in unsigned long aMaxLength);
/**
* Set the fixup object associated with node persistence.
* @param aFixup The fixup object.

View File

@ -81,7 +81,8 @@ protected:
nsINode* aOriginalNode = nullptr);
nsresult SerializeToStringRecursive(nsINode* aNode,
nsAString& aStr,
bool aDontSerializeRoot);
bool aDontSerializeRoot,
uint32_t aMaxLength = 0);
nsresult SerializeNodeEnd(nsINode* aNode, nsAString& aStr);
// This serializes the content of aNode.
nsresult SerializeToStringIterative(nsINode* aNode,
@ -450,8 +451,13 @@ nsDocumentEncoder::SerializeNodeEnd(nsINode* aNode,
nsresult
nsDocumentEncoder::SerializeToStringRecursive(nsINode* aNode,
nsAString& aStr,
bool aDontSerializeRoot)
bool aDontSerializeRoot,
uint32_t aMaxLength)
{
if (aMaxLength > 0 && aStr.Length() >= aMaxLength) {
return NS_OK;
}
if (!IsVisibleNode(aNode))
return NS_OK;
@ -487,7 +493,12 @@ nsDocumentEncoder::SerializeToStringRecursive(nsINode* aNode,
}
if (!aDontSerializeRoot) {
rv = SerializeNodeStart(maybeFixedNode, 0, -1, aStr, aNode);
int32_t endOffset = -1;
if (aMaxLength > 0) {
MOZ_ASSERT(aMaxLength >= aStr.Length());
endOffset = aMaxLength - aStr.Length();
}
rv = SerializeNodeStart(maybeFixedNode, 0, endOffset, aStr, aNode);
NS_ENSURE_SUCCESS(rv, rv);
}
@ -496,7 +507,7 @@ nsDocumentEncoder::SerializeToStringRecursive(nsINode* aNode,
for (nsINode* child = nsNodeUtils::GetFirstChildOfTemplateOrNode(node);
child;
child = child->GetNextSibling()) {
rv = SerializeToStringRecursive(child, aStr, false);
rv = SerializeToStringRecursive(child, aStr, false, aMaxLength);
NS_ENSURE_SUCCESS(rv, rv);
}
@ -1016,6 +1027,13 @@ nsDocumentEncoder::SerializeRangeToString(nsRange *aRange,
NS_IMETHODIMP
nsDocumentEncoder::EncodeToString(nsAString& aOutputString)
{
return EncodeToStringWithMaxLength(0, aOutputString);
}
NS_IMETHODIMP
nsDocumentEncoder::EncodeToStringWithMaxLength(uint32_t aMaxLength,
nsAString& aOutputString)
{
if (!mDocument)
return NS_ERROR_NOT_INITIALIZED;
@ -1146,7 +1164,7 @@ nsDocumentEncoder::EncodeToString(nsAString& aOutputString)
rv = mSerializer->AppendDocumentStart(mDocument, output);
if (NS_SUCCEEDED(rv)) {
rv = SerializeToStringRecursive(mDocument, output, false);
rv = SerializeToStringRecursive(mDocument, output, false, aMaxLength);
}
}

View File

@ -278,7 +278,8 @@ nsPlainTextSerializer::AppendText(nsIContent* aText,
return NS_ERROR_FAILURE;
}
int32_t endoffset = (aEndOffset == -1) ? frag->GetLength() : aEndOffset;
int32_t fragLength = frag->GetLength();
int32_t endoffset = (aEndOffset == -1) ? fragLength : std::min(aEndOffset, fragLength);
NS_ASSERTION(aStartOffset <= endoffset, "A start offset is beyond the end of the text fragment!");
int32_t length = endoffset - aStartOffset;

View File

@ -138,7 +138,8 @@ nsXMLContentSerializer::AppendTextData(nsIContent* aNode,
return NS_ERROR_FAILURE;
}
int32_t endoffset = (aEndOffset == -1) ? frag->GetLength() : aEndOffset;
int32_t fragLength = frag->GetLength();
int32_t endoffset = (aEndOffset == -1) ? fragLength : std::min(aEndOffset, fragLength);
int32_t length = endoffset - aStartOffset;
NS_ASSERTION(aStartOffset >= 0, "Negative start offset for text fragment!");
@ -300,12 +301,16 @@ nsXMLContentSerializer::AppendComment(nsIContent* aComment,
rv = comment->GetData(data);
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
if (aStartOffset || (aEndOffset != -1)) {
int32_t length = (aEndOffset == -1) ? data.Length() : aEndOffset;
int32_t dataLength = data.Length();
if (aStartOffset || (aEndOffset != -1 && aEndOffset < dataLength)) {
int32_t length =
(aEndOffset == -1) ? dataLength : std::min(aEndOffset, dataLength);
length -= aStartOffset;
nsAutoString frag;
data.Mid(frag, aStartOffset, length);
if (length > 0) {
data.Mid(frag, aStartOffset, length);
}
data.Assign(frag);
}

View File

@ -559,6 +559,7 @@ skip-if = buildapp == 'b2g' || toolkit == 'android' #bug 904183 # b2g(bug 904183
[test_domparser_null_char.html]
[test_domparsing.html]
[test_elementTraversal.html]
[test_encodeToStringWithMaxLength.html]
[test_fileapi.html]
skip-if = e10s
[test_fileapi_slice.html]

View File

@ -0,0 +1,64 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=995321
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 995321 - encodeToStringWithMaxLength</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript">
function getEncoder() {
const de = SpecialPowers.Ci.nsIDocumentEncoder;
const Cc = SpecialPowers.Cc;
// Create a plaintext encoder without flags.
var encoder = Cc["@mozilla.org/layout/documentEncoder;1?type=text/plain"]
.createInstance(de);
encoder.init(document, "text/plain", 0);
return encoder;
}
function testPlaintextSerializerWithMaxLength() {
var string = getEncoder().encodeToString();
var shorterString = getEncoder().encodeToStringWithMaxLength(1);
ok(shorterString.length < 1 + 72,
"test length is in the expected range after limiting the length to 1");
ok(string.startsWith(shorterString.trimRight()),
"the shorter string has the expected content");
shorterString = getEncoder().encodeToStringWithMaxLength(300);
ok(shorterString.length < 300 + 72,
"test length is in the expected range after limiting the length to 300");
ok(string.startsWith(shorterString.trimRight()),
"the shorter string has the expected content");
is(getEncoder().encodeToStringWithMaxLength(0), string,
"limiting the length to 0 should be ignored");
is(getEncoder().encodeToStringWithMaxLength(10000), string,
"limiting the length to a huge value should return the whole page");
SimpleTest.finish();
}
addLoadEvent(testPlaintextSerializerWithMaxLength);
SimpleTest.waitForExplicitFinish();
</script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=995321">Mozilla Bug 995321</a>
<p id="display"></p>
<div id="content" style="display: none">
The <em>Mozilla</em> project is a global community of <strong>people</strong> who believe that openness, innovation, and opportunity are key to the continued health of the Internet. We have worked together since 1998 to ensure that the Internet is developed in a way that benefits everyone. We are best known for creating the Mozilla Firefox web browser.
The Mozilla project uses a community-based approach to create world-class open source software and to develop new types of collaborative activities. We create communities of people involved in making the Internet experience better for all of us.
As a result of these efforts, we have distilled a set of principles that we believe are critical for the Internet to continue to benefit the public good as well as commercial aspects of life. We set out these principles below.
</div>
<pre id="test">
</pre>
</body>
</html>