merge fx-team to m-c

This commit is contained in:
Rob Campbell 2012-06-01 09:48:58 -03:00
commit 57704f35e8
33 changed files with 2103 additions and 507 deletions

View File

@ -255,6 +255,7 @@ _TEST_FILES1 = \
test_DOMException.html \
test_mutationobservers.html \
mutationobserver_dialog.html \
test_bug744830.html \
$(NULL)
_TEST_FILES2 = \

View File

@ -27,7 +27,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=392511
/** Test for Bug 392511 **/
var results = [
"'\"&'",
"\""&\"",
"\""&\"",
"\"'&\"",
"\"'&\"",

View File

@ -0,0 +1,126 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=744830
-->
<head>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=166235">Mozilla Bug 166235</a>
<div id="testnodes"><span>hi</span> there <!-- mon ami --></div>
<pre id="test">
<script type="application/javascript">
var t = document.getElementById('testnodes');
is(t.innerHTML,
"<span>hi</span> there <!-- mon ami -->",
"comment nodes should be included");
var PI = document.createProcessingInstruction('foo', 'bar="1.0"');
t.appendChild(PI);
is(t.innerHTML, '<span>hi</span> there <!-- mon ami --><?foo bar="1.0">',
"pi nodes should be included");
t.innerHTML = null;
t.appendChild(document.createElement("textarea"));
t.firstChild.appendChild(document.createTextNode("\nhello"));
// This is the old behavior. Spec requires something else.
is(t.innerHTML, "<textarea>\nhello</textarea>",
"No extra newlines should be inserted to the textarea!");
t.innerHTML = null;
t.appendChild(document.createElementNS("http://www.w3.org/2000/svg", "svg:svg"));
t.firstChild.textContent = "<foo>";
is(t.innerHTML, "<svg>&lt;foo&gt;</svg>");
t.innerHTML = null;
t.appendChild(document.createElementNS("http://www.w3.org/1998/Math/MathML", "math:math"));
t.firstChild.textContent = "<foo>";
is(t.innerHTML, "<math>&lt;foo&gt;</math>");
// Prefix is serialized if element isn't HTML/SVG/MathML
t.innerHTML = null;
t.appendChild(document.createElementNS("http://www.example.org", "ex:example"));
t.firstChild.textContent = "<foo>";
is(t.innerHTML, "<ex:example>&lt;foo&gt;</ex:example>");
t.innerHTML = null;
t.appendChild(document.createElementNS("http://www.example.org", "example"));
t.firstChild.textContent = "<foo>";
is(t.innerHTML, "<example>&lt;foo&gt;</example>");
t.firstChild.setAttributeNS("http://www.w3.org/XML/1998/namespace", "xml:lang", "us-en");
is(t.innerHTML, '<example xml:lang="us-en">&lt;foo&gt;</example>');
t.firstChild.setAttributeNS("http://www.w3.org/1999/xlink", "href", "foo");
is(t.innerHTML, '<example xlink:href="foo" xml:lang="us-en">&lt;foo&gt;</example>');
t.firstChild.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns", "http://foo");
is(t.innerHTML, '<example xmlns="http://foo" xlink:href="foo" xml:lang="us-en">&lt;foo&gt;</example>');
t.firstChild.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:bar", "http://bar");
is(t.innerHTML, '<example xmlns:bar="http://bar" xmlns="http://foo" xlink:href="foo" xml:lang="us-en">&lt;foo&gt;</example>');
t.firstChild.setAttributeNS("http://www.helloworldns.org", "hello:world", "!");
is(t.innerHTML, '<example hello:world="!" xmlns:bar="http://bar" xmlns="http://foo" xlink:href="foo" xml:lang="us-en">&lt;foo&gt;</example>');
t.firstChild.setAttribute("foo", '-"&\xA0-');
is(t.innerHTML, '<example foo="-&quot;&amp;&nbsp;-" hello:world="!" xmlns:bar="http://bar" xmlns="http://foo" xlink:href="foo" xml:lang="us-en">&lt;foo&gt;</example>');
t.innerHTML = null;
t.appendChild(document.createElement("div"));
t.firstChild.appendChild(document.implementation
.createDocument(null, null, null)
.createCDATASection("foo"));
is(t.innerHTML, '<div>foo</div>');
t.firstChild.textContent = "1&2<3>4\xA0";
is(t.innerHTML, '<div>1&amp;2&lt;3&gt;4&nbsp;</div>');
t.innerHTML = null;
t.appendChild(document.createElement("script"));
t.firstChild.textContent = "1&2<3>4\xA0";
is(t.innerHTML, '<script>1&2<3>4\xA0\u003C/script>');
t.innerHTML = null;
t.appendChild(document.createElement("style"));
t.firstChild.textContent = "1&2<3>4\xA0";
is(t.innerHTML, '<style>1&2<3>4\xA0\u003C/style>');
t.innerHTML = null;
t.appendChild(document.createElementNS("http://www.w3.org/2000/svg", "svg"));
is(t.firstChild.namespaceURI, "http://www.w3.org/2000/svg");
t.firstChild.appendChild(document.createElementNS("http://www.w3.org/2000/svg", "script"));
is(t.firstChild.firstChild.namespaceURI, "http://www.w3.org/2000/svg");
t.firstChild.firstChild.textContent = "1&2<3>4\xA0";
is(t.innerHTML, '<svg><script>1&amp;2&lt;3&gt;4&nbsp;\u003C/script></svg>');
t.innerHTML = null;
t.appendChild(document.createElementNS("http://www.w3.org/2000/svg", "svg"));
is(t.firstChild.namespaceURI, "http://www.w3.org/2000/svg");
t.firstChild.appendChild(document.createElementNS("http://www.w3.org/2000/svg", "style"));
is(t.firstChild.firstChild.namespaceURI, "http://www.w3.org/2000/svg");
t.firstChild.firstChild.textContent = "1&2<3>4\xA0";
is(t.innerHTML, '<svg><style>1&amp;2&lt;3&gt;4&nbsp;\u003C/style></svg>');
t.innerHTML = null;
t.appendChild(document.createElementNS("http://www.w3.org/1998/Math/MathML", "math"));
is(t.firstChild.namespaceURI, "http://www.w3.org/1998/Math/MathML");
t.firstChild.appendChild(document.createElementNS("http://www.w3.org/1998/Math/MathML", "script"));
is(t.firstChild.firstChild.namespaceURI, "http://www.w3.org/1998/Math/MathML");
t.firstChild.firstChild.textContent = "1&2<3>4\xA0";
is(t.innerHTML, '<math><script>1&amp;2&lt;3&gt;4&nbsp;\u003C/script></math>');
t.innerHTML = null;
t.appendChild(document.createElementNS("http://www.w3.org/1998/Math/MathML", "math"));
is(t.firstChild.namespaceURI, "http://www.w3.org/1998/Math/MathML");
t.firstChild.appendChild(document.createElementNS("http://www.w3.org/1998/Math/MathML", "style"));
is(t.firstChild.firstChild.namespaceURI, "http://www.w3.org/1998/Math/MathML");
t.firstChild.firstChild.textContent = "1&2<3>4\xA0";
is(t.innerHTML, '<math><style>1&amp;2&lt;3&gt;4&nbsp;\u003C/style></math>');
</script>
</pre>
</body>
</html>

View File

@ -89,6 +89,7 @@
#include "nsDOMMutationObserver.h"
#include "mozilla/Preferences.h"
#include "mozilla/dom/FromParser.h"
#include "mozilla/BloomFilter.h"
using namespace mozilla;
using namespace mozilla::dom;
@ -632,19 +633,609 @@ nsGenericHTMLElement::GetOffsetParent(nsIDOMElement** aOffsetParent)
return NS_OK;
}
// Try to keep the size of StringBuilder close to a jemalloc bucket size.
#define STRING_BUFFER_UNITS 1020
class StringBuilder
{
private:
class Unit
{
public:
Unit() : mType(eUnknown), mLength(0) {}
~Unit()
{
if (mType == eString || mType == eStringWithEncode) {
delete mString;
}
}
enum Type
{
eUnknown,
eAtom,
eString,
eStringWithEncode,
eLiteral,
eTextFragment,
eTextFragmentWithEncode,
};
union
{
nsIAtom* mAtom;
const char* mLiteral;
nsAutoString* mString;
const nsTextFragment* mTextFragment;
};
Type mType;
PRUint32 mLength;
};
public:
StringBuilder() : mLast(this), mLength(0) {}
void Append(nsIAtom* aAtom)
{
Unit* u = AddUnit();
u->mAtom = aAtom;
u->mType = Unit::eAtom;
PRUint32 len = aAtom->GetLength();
u->mLength = len;
mLength += len;
}
template<int N>
void Append(const char (&aLiteral)[N])
{
Unit* u = AddUnit();
u->mLiteral = aLiteral;
u->mType = Unit::eLiteral;
PRUint32 len = N - 1;
u->mLength = len;
mLength += len;
}
template<int N>
void Append(char (&aLiteral)[N])
{
Unit* u = AddUnit();
u->mLiteral = aLiteral;
u->mType = Unit::eLiteral;
PRUint32 len = N - 1;
u->mLength = len;
mLength += len;
}
void Append(const nsAString& aString)
{
Unit* u = AddUnit();
u->mString = new nsAutoString(aString);
u->mType = Unit::eString;
PRUint32 len = aString.Length();
u->mLength = len;
mLength += len;
}
void Append(nsAutoString* aString)
{
Unit* u = AddUnit();
u->mString = aString;
u->mType = Unit::eString;
PRUint32 len = aString->Length();
u->mLength = len;
mLength += len;
}
void AppendWithAttrEncode(nsAutoString* aString, PRUint32 aLen)
{
Unit* u = AddUnit();
u->mString = aString;
u->mType = Unit::eStringWithEncode;
u->mLength = aLen;
mLength += aLen;
}
void Append(const nsTextFragment* aTextFragment)
{
Unit* u = AddUnit();
u->mTextFragment = aTextFragment;
u->mType = Unit::eTextFragment;
PRUint32 len = aTextFragment->GetLength();
u->mLength = len;
mLength += len;
}
void AppendWithEncode(const nsTextFragment* aTextFragment, PRUint32 aLen)
{
Unit* u = AddUnit();
u->mTextFragment = aTextFragment;
u->mType = Unit::eTextFragmentWithEncode;
u->mLength = aLen;
mLength += aLen;
}
bool ToString(nsAString& aOut)
{
if (!aOut.SetCapacity(mLength, fallible_t())) {
return false;
}
for (StringBuilder* current = this; current; current = current->mNext) {
PRUint32 len = current->mUnits.Length();
for (PRUint32 i = 0; i < len; ++i) {
Unit& u = current->mUnits[i];
switch (u.mType) {
case Unit::eAtom:
aOut.Append(nsDependentAtomString(u.mAtom));
break;
case Unit::eString:
aOut.Append(*(u.mString));
break;
case Unit::eStringWithEncode:
EncodeAttrString(*(u.mString), aOut);
break;
case Unit::eLiteral:
aOut.AppendASCII(u.mLiteral, u.mLength);
break;
case Unit::eTextFragment:
u.mTextFragment->AppendTo(aOut);
break;
case Unit::eTextFragmentWithEncode:
EncodeTextFragment(u.mTextFragment, aOut);
break;
default:
MOZ_NOT_REACHED("Unknown unit type?");
}
}
}
return true;
}
private:
Unit* AddUnit()
{
if (mLast->mUnits.Length() == STRING_BUFFER_UNITS) {
new StringBuilder(this);
}
return mLast->mUnits.AppendElement();
}
StringBuilder(StringBuilder* aFirst)
: mLast(nsnull), mLength(0)
{
aFirst->mLast->mNext = this;
aFirst->mLast = this;
}
void EncodeAttrString(const nsAutoString& aValue, nsAString& aOut)
{
const PRUnichar* c = aValue.BeginReading();
const PRUnichar* end = aValue.EndReading();
while (c < end) {
switch (*c) {
case '"':
aOut.AppendLiteral("&quot;");
break;
case '&':
aOut.AppendLiteral("&amp;");
break;
case 0x00A0:
aOut.AppendLiteral("&nbsp;");
break;
default:
aOut.Append(*c);
break;
}
++c;
}
}
void EncodeTextFragment(const nsTextFragment* aValue, nsAString& aOut)
{
PRUint32 len = aValue->GetLength();
if (aValue->Is2b()) {
const PRUnichar* data = aValue->Get2b();
for (PRUint32 i = 0; i < len; ++i) {
const PRUnichar c = data[i];
switch (c) {
case '<':
aOut.AppendLiteral("&lt;");
break;
case '>':
aOut.AppendLiteral("&gt;");
break;
case '&':
aOut.AppendLiteral("&amp;");
break;
case 0x00A0:
aOut.AppendLiteral("&nbsp;");
break;
default:
aOut.Append(c);
break;
}
}
} else {
const char* data = aValue->Get1b();
for (PRUint32 i = 0; i < len; ++i) {
const unsigned char c = data[i];
switch (c) {
case '<':
aOut.AppendLiteral("&lt;");
break;
case '>':
aOut.AppendLiteral("&gt;");
break;
case '&':
aOut.AppendLiteral("&amp;");
break;
case 0x00A0:
aOut.AppendLiteral("&nbsp;");
break;
default:
aOut.Append(c);
break;
}
}
}
}
nsAutoTArray<Unit, STRING_BUFFER_UNITS> mUnits;
nsAutoPtr<StringBuilder> mNext;
StringBuilder* mLast;
// mLength is used only in the first StringBuilder object in the linked list.
PRUint32 mLength;
};
static void
AppendEncodedCharacters(const nsTextFragment* aText, StringBuilder& aBuilder)
{
PRUint32 extraSpaceNeeded = 0;
PRUint32 len = aText->GetLength();
if (aText->Is2b()) {
const PRUnichar* data = aText->Get2b();
for (PRUint32 i = 0; i < len; ++i) {
const PRUnichar c = data[i];
switch (c) {
case '<':
extraSpaceNeeded += ArrayLength("&lt;") - 2;
break;
case '>':
extraSpaceNeeded += ArrayLength("&gt;") - 2;
break;
case '&':
extraSpaceNeeded += ArrayLength("&amp;") - 2;
break;
case 0x00A0:
extraSpaceNeeded += ArrayLength("&nbsp;") - 2;
break;
default:
break;
}
}
} else {
const char* data = aText->Get1b();
for (PRUint32 i = 0; i < len; ++i) {
const unsigned char c = data[i];
switch (c) {
case '<':
extraSpaceNeeded += ArrayLength("&lt;") - 2;
break;
case '>':
extraSpaceNeeded += ArrayLength("&gt;") - 2;
break;
case '&':
extraSpaceNeeded += ArrayLength("&amp;") - 2;
break;
case 0x00A0:
extraSpaceNeeded += ArrayLength("&nbsp;") - 2;
break;
default:
break;
}
}
}
if (extraSpaceNeeded) {
aBuilder.AppendWithEncode(aText, len + extraSpaceNeeded);
} else {
aBuilder.Append(aText);
}
}
static void
AppendEncodedAttributeValue(nsAutoString* aValue, StringBuilder& aBuilder)
{
const PRUnichar* c = aValue->BeginReading();
const PRUnichar* end = aValue->EndReading();
PRUint32 extraSpaceNeeded = 0;
while (c < end) {
switch (*c) {
case '"':
extraSpaceNeeded += ArrayLength("&quot;") - 2;
break;
case '&':
extraSpaceNeeded += ArrayLength("&amp;") - 2;
break;
case 0x00A0:
extraSpaceNeeded += ArrayLength("&nbsp;") - 2;
break;
default:
break;
}
++c;
}
if (extraSpaceNeeded) {
aBuilder.AppendWithAttrEncode(aValue, aValue->Length() + extraSpaceNeeded);
} else {
aBuilder.Append(aValue);
}
}
static void
StartElement(Element* aContent, StringBuilder& aBuilder)
{
nsIAtom* localName = aContent->Tag();
PRInt32 tagNS = aContent->GetNameSpaceID();
aBuilder.Append("<");
if (aContent->IsHTML() || aContent->IsSVG() || aContent->IsMathML()) {
aBuilder.Append(localName);
} else {
aBuilder.Append(aContent->NodeName());
}
PRInt32 count = aContent->GetAttrCount();
for (PRInt32 i = count; i > 0;) {
--i;
const nsAttrName* name = aContent->GetAttrNameAt(i);
PRInt32 attNs = name->NamespaceID();
nsIAtom* attName = name->LocalName();
// Filter out any attribute starting with [-|_]moz
nsDependentAtomString attrNameStr(attName);
if (StringBeginsWith(attrNameStr, NS_LITERAL_STRING("_moz")) ||
StringBeginsWith(attrNameStr, NS_LITERAL_STRING("-moz"))) {
continue;
}
nsAutoString* attValue = new nsAutoString();
aContent->GetAttr(attNs, attName, *attValue);
// Filter out special case of <br type="_moz*"> used by the editor.
// Bug 16988. Yuck.
if (localName == nsGkAtoms::br && tagNS == kNameSpaceID_XHTML &&
attName == nsGkAtoms::type && attNs == kNameSpaceID_None &&
StringBeginsWith(*attValue, NS_LITERAL_STRING("_moz"))) {
delete attValue;
continue;
}
if (NS_LIKELY(attNs == kNameSpaceID_None) ||
(attNs == kNameSpaceID_XMLNS &&
attName == nsGkAtoms::xmlns)) {
aBuilder.Append(" ");
} else if (attNs == kNameSpaceID_XML) {
aBuilder.Append(" xml:");
} else if (attNs == kNameSpaceID_XMLNS) {
aBuilder.Append(" xmlns:");
} else if (attNs == kNameSpaceID_XLink) {
aBuilder.Append(" xlink:");
} else {
nsIAtom* prefix = name->GetPrefix();
if (prefix) {
aBuilder.Append(" ");
aBuilder.Append(prefix);
aBuilder.Append(":");
}
}
aBuilder.Append(attName);
aBuilder.Append("=\"");
AppendEncodedAttributeValue(attValue, aBuilder);
aBuilder.Append("\"");
}
aBuilder.Append(">");
/*
// Per HTML spec we should append one \n if the first child of
// pre/textarea/listing is a textnode and starts with a \n.
// But because browsers haven't traditionally had that behavior,
// we're not changing our behavior either - yet.
if (aContent->IsHTML()) {
if (localName == nsGkAtoms::pre || localName == nsGkAtoms::textarea ||
localName == nsGkAtoms::listing) {
nsIContent* fc = aContent->GetFirstChild();
if (fc &&
(fc->NodeType() == nsIDOMNode::TEXT_NODE ||
fc->NodeType() == nsIDOMNode::CDATA_SECTION_NODE)) {
const nsTextFragment* text = fc->GetText();
if (text && text->GetLength() && text->CharAt(0) == PRUnichar('\n')) {
aBuilder.Append("\n");
}
}
}
}*/
}
static inline bool
ShouldEscape(nsIContent* aParent)
{
if (!aParent || !aParent->IsHTML()) {
return true;
}
static const nsIAtom* nonEscapingElements[] = {
nsGkAtoms::style, nsGkAtoms::script, nsGkAtoms::xmp,
nsGkAtoms::iframe, nsGkAtoms::noembed, nsGkAtoms::noframes,
nsGkAtoms::plaintext,
// Per the current spec noscript should be escaped in case
// scripts are disabled or if document doesn't have
// browsing context. However the latter seems to be a spec bug
// and Gecko hasn't traditionally done the former.
nsGkAtoms::noscript
};
static mozilla::BloomFilter<12, nsIAtom> sFilter;
static bool sInitialized = false;
if (!sInitialized) {
sInitialized = true;
for (PRUint32 i = 0; i < ArrayLength(nonEscapingElements); ++i) {
sFilter.add(nonEscapingElements[i]);
}
}
nsIAtom* tag = aParent->Tag();
if (sFilter.mightContain(tag)) {
for (PRUint32 i = 0; i < ArrayLength(nonEscapingElements); ++i) {
if (tag == nonEscapingElements[i]) {
return false;
}
}
}
return true;
}
static inline bool
IsVoidTag(Element* aElement)
{
if (!aElement->IsHTML()) {
return false;
}
static const nsIAtom* voidElements[] = {
nsGkAtoms::area, nsGkAtoms::base, nsGkAtoms::basefont,
nsGkAtoms::bgsound, nsGkAtoms::br, nsGkAtoms::col,
nsGkAtoms::command, nsGkAtoms::embed, nsGkAtoms::frame,
nsGkAtoms::hr, nsGkAtoms::img, nsGkAtoms::input,
nsGkAtoms::keygen, nsGkAtoms::link, nsGkAtoms::meta,
nsGkAtoms::param, nsGkAtoms::source, nsGkAtoms::track,
nsGkAtoms::wbr
};
static mozilla::BloomFilter<12, nsIAtom> sFilter;
static bool sInitialized = false;
if (!sInitialized) {
sInitialized = true;
for (PRUint32 i = 0; i < ArrayLength(voidElements); ++i) {
sFilter.add(voidElements[i]);
}
}
nsIAtom* tag = aElement->Tag();
if (sFilter.mightContain(tag)) {
for (PRUint32 i = 0; i < ArrayLength(voidElements); ++i) {
if (tag == voidElements[i]) {
return true;
}
}
}
return false;
}
static bool
Serialize(Element* aRoot, bool aDescendentsOnly, nsAString& aOut)
{
nsINode* current = aDescendentsOnly ? aRoot->GetFirstChild() : aRoot;
if (!current) {
return true;
}
StringBuilder builder;
nsIContent* next;
while (true) {
bool isVoid = false;
switch (current->NodeType()) {
case nsIDOMNode::ELEMENT_NODE: {
Element* elem = current->AsElement();
StartElement(elem, builder);
isVoid = IsVoidTag(elem);
if (!isVoid && (next = current->GetFirstChild())) {
current = next;
continue;
}
break;
}
case nsIDOMNode::TEXT_NODE:
case nsIDOMNode::CDATA_SECTION_NODE: {
const nsTextFragment* text = static_cast<nsIContent*>(current)->GetText();
nsIContent* parent = current->GetParent();
if (ShouldEscape(parent)) {
AppendEncodedCharacters(text, builder);
} else {
builder.Append(text);
}
break;
}
case nsIDOMNode::COMMENT_NODE: {
builder.Append("<!--");
builder.Append(static_cast<nsIContent*>(current)->GetText());
builder.Append("-->");
break;
}
case nsIDOMNode::DOCUMENT_TYPE_NODE: {
builder.Append("<!DOCTYPE ");
builder.Append(current->NodeName());
builder.Append(">");
break;
}
case nsIDOMNode::PROCESSING_INSTRUCTION_NODE: {
builder.Append("<?");
builder.Append(current->NodeName());
builder.Append(" ");
builder.Append(static_cast<nsIContent*>(current)->GetText());
builder.Append(">");
break;
}
}
while (true) {
if (!isVoid && current->NodeType() == nsIDOMNode::ELEMENT_NODE) {
builder.Append("</");
nsIContent* elem = static_cast<nsIContent*>(current);
if (elem->IsHTML() || elem->IsSVG() || elem->IsMathML()) {
builder.Append(elem->Tag());
} else {
builder.Append(current->NodeName());
}
builder.Append(">");
}
isVoid = false;
if (current == aRoot) {
return builder.ToString(aOut);
}
if ((next = current->GetNextSibling())) {
current = next;
break;
}
current = current->GetNodeParent();
if (aDescendentsOnly && current == aRoot) {
return builder.ToString(aOut);
}
}
}
}
nsresult
nsGenericHTMLElement::GetMarkup(bool aIncludeSelf, nsAString& aMarkup)
{
aMarkup.Truncate();
nsIDocument* doc = OwnerDoc();
if (IsInHTMLDocument()) {
return Serialize(this, !aIncludeSelf, aMarkup) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
}
nsAutoString contentType;
if (IsInHTMLDocument()) {
contentType.AssignLiteral("text/html");
} else {
doc->GetContentType(contentType);
}
doc->GetContentType(contentType);
nsCOMPtr<nsIDocumentEncoder> docEncoder = doc->GetCachedEncoder();
if (!docEncoder) {
@ -654,7 +1245,7 @@ nsGenericHTMLElement::GetMarkup(bool aIncludeSelf, nsAString& aMarkup)
NS_ConvertUTF16toUTF8(contentType)
).get());
}
if (!(docEncoder || doc->IsHTML())) {
if (!docEncoder) {
// This could be some type for which we create a synthetic document. Try
// again as XML
contentType.AssignLiteral("application/xml");

View File

@ -52,6 +52,7 @@
#include "nsSVGSVGElement.h"
#include "nsSVGTextContainerFrame.h"
#include "SVGAnimatedPreserveAspectRatio.h"
#include "mozilla/unused.h"
using namespace mozilla;
using namespace mozilla::dom;
@ -1669,9 +1670,9 @@ nsSVGUtils::WritePPM(const char *fname, gfxImageSurface *aSurface)
PRInt32 stride = aSurface->Stride();
for (int y=0; y<size.height; y++) {
for (int x=0; x<size.width; x++) {
fwrite(data + y * stride + 4 * x + GFX_ARGB32_OFFSET_R, 1, 1, f);
fwrite(data + y * stride + 4 * x + GFX_ARGB32_OFFSET_G, 1, 1, f);
fwrite(data + y * stride + 4 * x + GFX_ARGB32_OFFSET_B, 1, 1, f);
unused << fwrite(data + y * stride + 4 * x + GFX_ARGB32_OFFSET_R, 1, 1, f);
unused << fwrite(data + y * stride + 4 * x + GFX_ARGB32_OFFSET_G, 1, 1, f);
unused << fwrite(data + y * stride + 4 * x + GFX_ARGB32_OFFSET_B, 1, 1, f);
}
}
fclose(f);

View File

@ -7,41 +7,43 @@
#ifdef ANDROID
#define wrap(a) __wrap_ ## a
/* operator new wrapper implementation */
static void *
new(unsigned int size)
{
return malloc(size);
}
/* operator new(unsigned int) */
MOZ_EXPORT_API(void *)
wrap(_Znwj)(unsigned int) __attribute__((alias("new")));
/* operator new[](unsigned int) */
MOZ_EXPORT_API(void *)
wrap(_Znaj)(unsigned int) __attribute__((alias("new")));
/* operator delete wrapper implementation */
static void
delete(void *ptr)
{
free(ptr);
}
/* operator delete(void*) */
MOZ_EXPORT_API(void)
wrap(_ZdlPv)(void *ptr) __attribute__((alias("delete")));
/* operator delete[](void*) */
MOZ_EXPORT_API(void)
wrap(_ZdaPv)(void *ptr) __attribute__((alias("delete")));
#endif
#if defined(XP_WIN) || defined(XP_MACOSX)
#elif defined(XP_WIN) || defined(XP_MACOSX)
#define wrap(a) je_ ## a
#endif
#ifdef wrap
void *wrap(malloc)(size_t);
void wrap(free)(void *);
#endif
#ifdef ANDROID
/* operator new(unsigned int) */
MOZ_EXPORT_API(void *)
wrap(_Znwj)(unsigned int size)
{
return wrap(malloc)(size);
}
/* operator new[](unsigned int) */
MOZ_EXPORT_API(void *)
wrap(_Znaj)(unsigned int size)
{
return wrap(malloc)(size);
}
/* operator delete(void*) */
MOZ_EXPORT_API(void)
wrap(_ZdlPv)(void *ptr)
{
wrap(free)(ptr);
}
/* operator delete[](void*) */
MOZ_EXPORT_API(void)
wrap(_ZdaPv)(void *ptr)
{
wrap(free)(ptr);
}
#endif
#ifdef wrap
MOZ_EXPORT_API(char *)
wrap(strndup)(const char *src, size_t len)
{

View File

@ -0,0 +1,76 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_net_AutoClose_h
#define mozilla_net_AutoClose_h
#include "nsCOMPtr.h"
namespace mozilla { namespace net {
// Like an nsAutoPtr for XPCOM streams (e.g. nsIAsyncInputStream) and other
// refcounted classes that need to have the Close() method called explicitly
// before they are destroyed.
template <typename T>
class AutoClose
{
public:
AutoClose() { }
~AutoClose(){
Close();
}
operator bool() const
{
return mPtr;
}
already_AddRefed<T> forget()
{
return mPtr.forget();
}
void takeOver(AutoClose<T> & rhs)
{
Close();
mPtr = rhs.mPtr.forget();
}
// assign from |do_QueryInterface(expr, &rv)|
void operator=(const nsQueryInterfaceWithError rhs)
{
Close();
mPtr = rhs;
}
void CloseAndRelease()
{
Close();
mPtr = nsnull;
}
T* operator->() const
{
return mPtr.operator->();
}
private:
void Close()
{
if (mPtr) {
mPtr->Close();
}
}
void operator=(const AutoClose<T> &) MOZ_DELETE;
AutoClose(const AutoClose<T> &) MOZ_DELETE;
nsCOMPtr<T> mPtr;
};
} } // namespace mozilla::net
#endif // mozilla_net_AutoClose_h

View File

@ -540,6 +540,11 @@ nsInputStreamWrapper::LazyInit()
rv = nsCacheService::OpenInputStreamForEntry(cacheEntry, mode,
mStartOffset,
getter_AddRefs(mInput));
CACHE_LOG_DEBUG(("nsInputStreamWrapper::LazyInit "
"[entry=%p, wrapper=%p, mInput=%p, rv=%d]",
mDescriptor, this, mInput.get(), PRIntn(rv)));
if (NS_FAILED(rv)) return rv;
mInitialized = true;
@ -568,9 +573,14 @@ nsresult nsCacheEntryDescriptor::
nsInputStreamWrapper::Read(char *buf, PRUint32 count, PRUint32 *countRead)
{
nsresult rv = EnsureInit();
if (NS_FAILED(rv)) return rv;
if (NS_SUCCEEDED(rv))
rv = mInput->Read(buf, count, countRead);
return mInput->Read(buf, count, countRead);
CACHE_LOG_DEBUG(("nsInputStreamWrapper::Read "
"[entry=%p, wrapper=%p, mInput=%p, rv=%d]",
mDescriptor, this, mInput.get(), rv));
return rv;
}
nsresult nsCacheEntryDescriptor::

View File

@ -1759,7 +1759,7 @@ nsCacheService::ProcessRequest(nsCacheRequest * request,
if (request->mListener) { // Asynchronous
if (NS_FAILED(rv) && calledFromOpenCacheEntry)
if (NS_FAILED(rv) && calledFromOpenCacheEntry && request->IsBlocking())
return rv; // skip notifying listener, just return rv to caller
// call listener to report error or descriptor

View File

@ -4,6 +4,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsCache.h"
#include "nsDiskCache.h"
#include "nsDiskCacheBlockFile.h"
#include "mozilla/FileUtils.h"
@ -31,14 +32,15 @@ nsDiskCacheBlockFile::Open(nsILocalFile * blockFile,
// open the file - restricted to user, the data could be confidential
nsresult rv = blockFile->OpenNSPRFileDesc(PR_RDWR | PR_CREATE_FILE, 00600, &mFD);
if (NS_FAILED(rv)) return rv; // unable to open or create file
if (NS_FAILED(rv)) {
CACHE_LOG_DEBUG(("CACHE: nsDiskCacheBlockFile::Open "
"[this=%p] unable to open or create file: %d",
this, rv));
return rv; // unable to open or create file
}
// allocate bit map buffer
mBitMap = new PRUint32[mBitMapWords];
if (!mBitMap) {
rv = NS_ERROR_OUT_OF_MEMORY;
goto error_exit;
}
// check if we just creating the file
mFileSize = PR_Available(mFD);
@ -79,9 +81,13 @@ nsDiskCacheBlockFile::Open(nsILocalFile * blockFile,
goto error_exit;
}
}
CACHE_LOG_DEBUG(("CACHE: nsDiskCacheBlockFile::Open [this=%p] succeeded",
this));
return NS_OK;
error_exit:
CACHE_LOG_DEBUG(("CACHE: nsDiskCacheBlockFile::Open [this=%p] failed with "
"error %d", this, rv));
Close(false);
return rv;
}
@ -234,6 +240,9 @@ nsDiskCacheBlockFile::ReadBlocks( void * buffer,
}
*bytesRead = PR_Read(mFD, buffer, bytesToRead);
CACHE_LOG_DEBUG(("CACHE: nsDiskCacheBlockFile::Read [this=%p] "
"returned %d / %d bytes", this, *bytesRead, bytesToRead));
return NS_OK;
}

View File

@ -77,6 +77,8 @@ nsDiskCacheMap::Open(nsILocalFile * cacheDirectory)
if (!cacheFilesExist)
goto error_exit;
CACHE_LOG_DEBUG(("CACHE: nsDiskCacheMap::Open [this=%p] reading map", this));
// read the header
PRUint32 bytesRead = PR_Read(mMapFD, &mHeader, sizeof(nsDiskCacheHeader));
if (sizeof(nsDiskCacheHeader) != bytesRead) goto error_exit;
@ -686,7 +688,11 @@ nsDiskCacheMap::ReadDiskCacheEntry(nsDiskCacheRecord * record)
getter_AddRefs(file));
NS_ENSURE_SUCCESS(rv, nsnull);
CACHE_LOG_DEBUG(("CACHE: nsDiskCacheMap::ReadDiskCacheEntry"
"[this=%p] reading disk cache entry", this));
PRFileDesc * fd = nsnull;
// open the file - restricted to user, the data could be confidential
rv = file->OpenNSPRFileDesc(PR_RDONLY, 00600, &fd);
NS_ENSURE_SUCCESS(rv, nsnull);

View File

@ -108,11 +108,25 @@ nsDiskCacheInputStream::Read(char * buffer, PRUint32 count, PRUint32 * bytesRead
{
*bytesRead = 0;
if (mClosed)
if (mClosed) {
CACHE_LOG_DEBUG(("CACHE: nsDiskCacheInputStream::Read "
"[stream=%p] stream was closed",
this, buffer, count));
return NS_OK;
}
if (mPos == mStreamEnd) return NS_OK;
if (mPos > mStreamEnd) return NS_ERROR_UNEXPECTED;
if (mPos == mStreamEnd) {
CACHE_LOG_DEBUG(("CACHE: nsDiskCacheInputStream::Read "
"[stream=%p] stream at end of file",
this, buffer, count));
return NS_OK;
}
if (mPos > mStreamEnd) {
CACHE_LOG_DEBUG(("CACHE: nsDiskCacheInputStream::Read "
"[stream=%p] stream past end of file (!)",
this, buffer, count));
return NS_ERROR_UNEXPECTED;
}
if (count > mStreamEnd - mPos)
count = mStreamEnd - mPos;
@ -120,7 +134,14 @@ nsDiskCacheInputStream::Read(char * buffer, PRUint32 count, PRUint32 * bytesRead
if (mFD) {
// just read from file
PRInt32 result = PR_Read(mFD, buffer, count);
if (result < 0) return NS_ErrorAccordingToNSPR();
if (result < 0) {
PRErrorCode error = PR_GetError();
nsresult rv = NS_ErrorAccordingToNSPR();
CACHE_LOG_DEBUG(("CACHE: nsDiskCacheInputStream::Read PR_Read failed"
"[stream=%p, rv=%d, NSPR error %s",
this, PRIntn(rv), PR_ErrorToName(error)));
return rv;
}
mPos += (PRUint32)result;
*bytesRead = (PRUint32)result;
@ -134,6 +155,9 @@ nsDiskCacheInputStream::Read(char * buffer, PRUint32 count, PRUint32 * bytesRead
// no data source for input stream
}
CACHE_LOG_DEBUG(("CACHE: nsDiskCacheInputStream::Read "
"[stream=%p, count=%ud, byteRead=%ud] ",
this, PRUintn(count), PRUintn(*bytesRead)));
return NS_OK;
}
@ -679,6 +703,8 @@ nsDiskCacheStreamIO::OpenCacheFile(PRIntn flags, PRFileDesc ** fd)
{
NS_ENSURE_ARG_POINTER(fd);
CACHE_LOG_DEBUG(("nsDiskCacheStreamIO::OpenCacheFile"));
nsresult rv;
nsDiskCacheMap * cacheMap = mDevice->CacheMap();

View File

@ -50,7 +50,6 @@ HttpBaseChannel::HttpBaseChannel()
, mTimingEnabled(false)
, mAllowSpdy(true)
, mSuspendCount(0)
, mRedirectedCachekeys(nsnull)
{
LOG(("Creating HttpBaseChannel @%x\n", this));
@ -1626,8 +1625,7 @@ HttpBaseChannel::SetupReplacementChannel(nsIURI *newURI,
if (mRedirectedCachekeys) {
LOG(("HttpBaseChannel::SetupReplacementChannel "
"[this=%p] transferring chain of redirect cache-keys", this));
httpInternal->SetCacheKeysRedirectChain(mRedirectedCachekeys);
mRedirectedCachekeys = nsnull;
httpInternal->SetCacheKeysRedirectChain(mRedirectedCachekeys.forget());
}
}

View File

@ -140,10 +140,7 @@ public:
inline void CleanRedirectCacheChainIfNecessary()
{
if (mRedirectedCachekeys) {
delete mRedirectedCachekeys;
mRedirectedCachekeys = nsnull;
}
mRedirectedCachekeys = nsnull;
}
NS_IMETHOD HTTPUpgrade(const nsACString & aProtocolName,
nsIHttpUpgradeListener *aListener);
@ -272,7 +269,7 @@ protected:
// Current suspension depth for this channel object
PRUint32 mSuspendCount;
nsTArray<nsCString> *mRedirectedCachekeys;
nsAutoPtr<nsTArray<nsCString> > mRedirectedCachekeys;
};
// Share some code while working around C++'s absurd inability to handle casting

File diff suppressed because it is too large Load Diff

View File

@ -26,15 +26,17 @@
#include "nsIHttpAuthenticableChannel.h"
#include "nsIHttpChannelAuthProvider.h"
#include "nsIAsyncVerifyRedirectCallback.h"
#include "nsICryptoHash.h"
#include "nsITimedChannel.h"
#include "nsDNSPrefetch.h"
#include "TimingStruct.h"
#include "AutoClose.h"
#include "mozilla/Telemetry.h"
class nsAHttpConnection;
class AutoRedirectVetoNotifier;
using namespace mozilla::net;
namespace mozilla { namespace net {
class HttpCacheQuery;
//-----------------------------------------------------------------------------
// nsHttpChannel
@ -156,7 +158,8 @@ private:
typedef nsresult (nsHttpChannel::*nsContinueRedirectionFunc)(nsresult result);
bool RequestIsConditional();
nsresult Connect(bool firstTime = true);
nsresult Connect();
nsresult ContinueConnect();
void SpeculativeConnect();
nsresult SetupTransaction();
nsresult CallOnStartRequest();
@ -172,7 +175,6 @@ private:
nsresult ProcessFailedSSLConnect(PRUint32 httpStatus);
nsresult ProcessFallback(bool *waitingForRedirectCallback);
nsresult ContinueProcessFallback(nsresult);
bool ResponseWouldVary();
void HandleAsyncAbort();
nsresult EnsureAssocReq();
@ -200,11 +202,11 @@ private:
nsresult ResolveProxy();
// cache specific methods
nsresult OpenCacheEntry();
nsresult OpenCacheEntry(bool usingSSL);
nsresult OnOfflineCacheEntryAvailable(nsICacheEntryDescriptor *aEntry,
nsCacheAccessMode aAccess,
nsresult aResult);
nsresult OpenNormalCacheEntry();
nsresult OpenNormalCacheEntry(bool usingSSL);
nsresult OnNormalCacheEntryAvailable(nsICacheEntryDescriptor *aEntry,
nsCacheAccessMode aAccess,
nsresult aResult);
@ -219,8 +221,9 @@ private:
nsresult GenerateCacheKey(PRUint32 postID, nsACString &key);
nsresult UpdateExpirationTime();
nsresult CheckCache();
nsresult ShouldUpdateOfflineCacheEntry(bool *shouldCacheForOfflineUse);
nsresult ReadFromCache();
bool ShouldUpdateOfflineCacheEntry();
nsresult StartBufferingCachedEntity(bool usingSSL);
nsresult ReadFromCache(bool alreadyMarkedValid);
void CloseCacheEntry(bool doomOnFailure);
void CloseOfflineCacheEntry();
nsresult InitCacheEntry();
@ -232,7 +235,7 @@ private:
nsresult InstallCacheListener(PRUint32 offset = 0);
nsresult InstallOfflineCacheListener();
void MaybeInvalidateCacheEntryForSubsequentGet();
nsCacheStoragePolicy DetermineStoragePolicy();
nsCacheStoragePolicy DetermineStoragePolicy(bool isPrivate);
nsresult DetermineCacheAccess(nsCacheAccessMode *_retval);
void AsyncOnExamineCachedResponse();
@ -240,12 +243,10 @@ private:
void ClearBogusContentEncodingIfNeeded();
// byte range request specific methods
nsresult SetupByteRangeRequest(PRUint32 partialLen);
nsresult ProcessPartialContent();
nsresult OnDoneReadingPartialCacheEntry(bool *streamDone);
nsresult DoAuthRetry(nsAHttpConnection *);
bool MustValidateBasedOnQueryUrl();
void HandleAsyncRedirectChannelToHttps();
nsresult AsyncRedirectChannelToHttps();
@ -259,16 +260,10 @@ private:
*/
nsresult ProcessSTSHeader();
/**
* Computes and returns a 64 bit encoded string holding a hash of the
* input buffer. Input buffer must be a null-terminated string.
*/
nsresult Hash(const char *buf, nsACString &hash);
void InvalidateCacheEntryForLocation(const char *location);
void AssembleCacheKey(const char *spec, PRUint32 postID, nsACString &key);
nsresult CreateNewURI(const char *loc, nsIURI **newURI);
void DoInvalidateCacheEntry(nsACString &key);
void DoInvalidateCacheEntry(const nsCString &key);
// Ref RFC2616 13.10: "invalidation... MUST only be performed if
// the host part is the same as in the Request-URI"
@ -289,10 +284,15 @@ private:
PRUint64 mLogicalOffset;
// cache specific data
nsRefPtr<HttpCacheQuery> mCacheQuery;
nsCOMPtr<nsICacheEntryDescriptor> mCacheEntry;
// We must close mCacheAsyncInputStream explicitly to avoid leaks.
AutoClose<nsIAsyncInputStream> mCacheAsyncInputStream;
nsRefPtr<nsInputStreamPump> mCachePump;
nsAutoPtr<nsHttpResponseHead> mCachedResponseHead;
nsCOMPtr<nsISupports> mCachedSecurityInfo;
nsCacheAccessMode mCacheAccess;
mozilla::Telemetry::ID mCacheEntryDeviceTelemetryID;
PRUint32 mPostID;
PRUint32 mRequestTime;
@ -317,6 +317,8 @@ private:
friend class AutoRedirectVetoNotifier;
friend class HttpAsyncAborter<nsHttpChannel>;
friend class HttpCacheQuery;
nsCOMPtr<nsIURI> mRedirectURI;
nsCOMPtr<nsIChannel> mRedirectChannel;
PRUint32 mRedirectType;
@ -344,8 +346,6 @@ private:
nsTArray<nsContinueRedirectionFunc> mRedirectFuncStack;
nsCOMPtr<nsICryptoHash> mHasher;
PRTime mChannelCreationTime;
mozilla::TimeStamp mChannelCreationTimestamp;
mozilla::TimeStamp mAsyncOpenTime;
@ -374,4 +374,6 @@ private: // cache telemetry
bool mDidReval;
};
} } // namespace mozilla::net
#endif // nsHttpChannel_h__

View File

@ -406,52 +406,6 @@ nsHttpHandler::IsAcceptableEncoding(const char *enc)
return nsHttp::FindToken(mAcceptEncodings.get(), enc, HTTP_LWS ",") != nsnull;
}
nsresult
nsHttpHandler::GetCacheSession(nsCacheStoragePolicy storagePolicy,
bool isPrivate,
nsICacheSession **result)
{
nsresult rv;
// Skip cache if disabled in preferences
if (!mUseCache)
return NS_ERROR_NOT_AVAILABLE;
// We want to get the pointer to the cache service each time we're called,
// because it's possible for some add-ons (such as Google Gears) to swap
// in new cache services on the fly, and we want to pick them up as
// appropriate.
nsCOMPtr<nsICacheService> serv = do_GetService(NS_CACHESERVICE_CONTRACTID,
&rv);
if (NS_FAILED(rv)) return rv;
const char *sessionName = "HTTP";
switch (storagePolicy) {
case nsICache::STORE_IN_MEMORY:
sessionName = isPrivate ? "HTTP-memory-only-PB" : "HTTP-memory-only";
break;
case nsICache::STORE_OFFLINE:
sessionName = "HTTP-offline";
break;
default:
break;
}
nsCOMPtr<nsICacheSession> cacheSession;
rv = serv->CreateSession(sessionName,
storagePolicy,
nsICache::STREAM_BASED,
getter_AddRefs(cacheSession));
if (NS_FAILED(rv)) return rv;
rv = cacheSession->SetDoomEntriesIfExpired(false);
if (NS_FAILED(rv)) return rv;
NS_ADDREF(*result = cacheSession);
return NS_OK;
}
nsresult
nsHttpHandler::GetStreamConverterService(nsIStreamConverterService **result)
{

View File

@ -101,7 +101,7 @@ public:
nsHttpConnectionMgr *ConnMgr() { return mConnMgr; }
// cache support
nsresult GetCacheSession(nsCacheStoragePolicy, bool isPrivate, nsICacheSession **);
bool UseCache() const { return mUseCache; }
PRUint32 GenerateUniqueID() { return ++mLastUniqueID; }
PRUint32 SessionStartTime() { return mSessionStartTime; }

View File

@ -380,7 +380,11 @@ nsHttpResponseHead::IsResumable() const
{
// even though some HTTP/1.0 servers may support byte range requests, we're not
// going to bother with them, since those servers wouldn't understand If-Range.
return mVersion >= NS_HTTP_VERSION_1_1 &&
// Also, while in theory it may be possible to resume when the status code
// is not 200, it is unlikely to be worth the trouble, especially for
// non-2xx responses.
return mStatus == 200 &&
mVersion >= NS_HTTP_VERSION_1_1 &&
PeekHeader(nsHttp::Content_Length) &&
(PeekHeader(nsHttp::ETag) || PeekHeader(nsHttp::Last_Modified)) &&
HasHeaderValue(nsHttp::Accept_Ranges, "bytes");

View File

@ -270,6 +270,7 @@ package-tests: \
stage-peptest \
stage-mozbase \
stage-tps \
stage-modules \
$(NULL)
else
# This staging area has been built for us by universal/flight.mk
@ -336,6 +337,10 @@ stage-tps: make-stage-dir
@(cd $(topsrcdir)/services/sync/tps && tar $(TAR_CREATE_FLAGS) - *) | (cd $(PKG_STAGE)/tps && tar -xf -)
(cd $(topsrcdir)/services/sync/tests/tps && tar $(TAR_CREATE_FLAGS_QUIET) - *) | (cd $(PKG_STAGE)/tps/tests && tar -xf -)
# This will get replaced by actual logic in a subsequent patch.
stage-modules: make-stage-dir
$(TOUCH) $(PKG_STAGE)/modules/.dummy
stage-mozbase: make-stage-dir
$(MAKE) -C $(DEPTH)/testing/mozbase stage-package
.PHONY: \
@ -361,5 +366,6 @@ stage-mozbase: make-stage-dir
stage-peptest \
stage-mozbase \
stage-tps \
stage-modules \
$(NULL)

View File

@ -491,10 +491,7 @@ nsAutoCompleteController::HandleKeyNavigation(PRUint32 aKey, bool *_retval)
// The user wants explicitely to use that result, so this ensures
// association of the result with the autocompleted text.
nsAutoString value;
nsAutoString inputValue;
input->GetTextValue(inputValue);
if (NS_SUCCEEDED(GetDefaultCompleteValue(-1, false, value)) &&
value.Equals(inputValue, nsCaseInsensitiveStringComparator())) {
if (NS_SUCCEEDED(GetFinalDefaultCompleteValue(value))) {
input->SetTextValue(value);
input->SelectTextRange(value.Length(), value.Length());
}
@ -1184,10 +1181,7 @@ nsAutoCompleteController::EnterMatch(bool aIsPopupSelection)
// The user wants explicitely to use that result, so this ensures
// association of the result with the autocompleted text.
nsAutoString defaultIndexValue;
nsAutoString inputValue;
input->GetTextValue(inputValue);
if (NS_SUCCEEDED(GetDefaultCompleteValue(-1, false, defaultIndexValue)) &&
defaultIndexValue.Equals(inputValue, nsCaseInsensitiveStringComparator()))
if (NS_SUCCEEDED(GetFinalDefaultCompleteValue(defaultIndexValue)))
value = defaultIndexValue;
}
@ -1444,34 +1438,34 @@ nsAutoCompleteController::CompleteDefaultIndex(PRInt32 aResultIndex)
}
nsresult
nsAutoCompleteController::GetDefaultCompleteValue(PRInt32 aResultIndex,
bool aPreserveCasing,
nsAString &_retval)
nsAutoCompleteController::GetDefaultCompleteResult(PRInt32 aResultIndex,
nsIAutoCompleteResult** _result,
PRInt32* _defaultIndex)
{
PRInt32 defaultIndex = -1;
PRInt32 index = aResultIndex;
if (index < 0) {
PRUint32 count = mResults.Count();
for (PRUint32 i = 0; i < count; ++i) {
nsIAutoCompleteResult *result = mResults[i];
if (result && NS_SUCCEEDED(result->GetDefaultIndex(&defaultIndex)) &&
defaultIndex >= 0) {
index = i;
break;
}
*_defaultIndex = -1;
PRInt32 resultIndex = aResultIndex;
// If a result index was not provided, find the first defaultIndex result.
for (PRInt32 i = 0; resultIndex < 0 && i < mResults.Count(); ++i) {
nsIAutoCompleteResult *result = mResults[i];
if (result &&
NS_SUCCEEDED(result->GetDefaultIndex(_defaultIndex)) &&
*_defaultIndex >= 0) {
resultIndex = i;
}
}
NS_ENSURE_TRUE(index >= 0, NS_ERROR_FAILURE);
NS_ENSURE_TRUE(resultIndex >= 0, NS_ERROR_FAILURE);
nsIAutoCompleteResult *result = mResults.SafeObjectAt(index);
NS_ENSURE_TRUE(result != nsnull, NS_ERROR_FAILURE);
*_result = mResults.SafeObjectAt(resultIndex);
NS_ENSURE_TRUE(*_result, NS_ERROR_FAILURE);
if (defaultIndex < 0) {
if (*_defaultIndex < 0) {
// The search must explicitly provide a default index in order
// for us to be able to complete.
result->GetDefaultIndex(&defaultIndex);
(*_result)->GetDefaultIndex(_defaultIndex);
}
if (defaultIndex < 0) {
if (*_defaultIndex < 0) {
// We were given a result index, but that result doesn't want to
// be autocompleted.
return NS_ERROR_FAILURE;
@ -1481,10 +1475,24 @@ nsAutoCompleteController::GetDefaultCompleteValue(PRInt32 aResultIndex,
// provides a defaultIndex greater than its matchCount, avoid trying to
// complete to an empty value.
PRUint32 matchCount = 0;
result->GetMatchCount(&matchCount);
(*_result)->GetMatchCount(&matchCount);
// Here defaultIndex is surely non-negative, so can be cast to unsigned.
if ((PRUint32)defaultIndex >= matchCount)
if ((PRUint32)(*_defaultIndex) >= matchCount) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
nsresult
nsAutoCompleteController::GetDefaultCompleteValue(PRInt32 aResultIndex,
bool aPreserveCasing,
nsAString &_retval)
{
nsIAutoCompleteResult *result;
PRInt32 defaultIndex = -1;
nsresult rv = GetDefaultCompleteResult(aResultIndex, &result, &defaultIndex);
if (NS_FAILED(rv)) return rv;
nsAutoString resultValue;
result->GetValueAt(defaultIndex, resultValue);
@ -1512,6 +1520,37 @@ nsAutoCompleteController::GetDefaultCompleteValue(PRInt32 aResultIndex,
return NS_OK;
}
nsresult
nsAutoCompleteController::GetFinalDefaultCompleteValue(nsAString &_retval)
{
nsIAutoCompleteResult *result;
PRInt32 defaultIndex = -1;
nsresult rv = GetDefaultCompleteResult(-1, &result, &defaultIndex);
if (NS_FAILED(rv)) return rv;
// Hack: For typeAheadResults allow the comment to be used as the final
// defaultComplete value if provided, otherwise fall back to the usual
// value. This allows to provide a different complete text when the user
// confirms the match. Don't rely on this for production code, since it's a
// temporary solution that needs a dedicated API (bug 754265).
bool isTypeAheadResult = false;
if (NS_SUCCEEDED(result->GetTypeAheadResult(&isTypeAheadResult)) &&
isTypeAheadResult &&
NS_SUCCEEDED(result->GetCommentAt(defaultIndex, _retval)) &&
!_retval.IsEmpty()) {
return NS_OK;
}
result->GetValueAt(defaultIndex, _retval);
nsAutoString inputValue;
mInput->GetTextValue(inputValue);
if (!_retval.Equals(inputValue, nsCaseInsensitiveStringComparator())) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
nsresult
nsAutoCompleteController::CompleteValue(nsString &aValue)
/* mInput contains mSearchString, which we want to autocomplete to aValue. If

View File

@ -66,8 +66,50 @@ private:
nsresult GetResultValueLabelAt(PRInt32 aIndex, bool aValueOnly,
bool aGetValue, nsAString & _retval);
protected:
/**
* Gets and validates the defaultComplete result and the relative
* defaultIndex value.
*
* @param aResultIndex
* Index of the defaultComplete result to be used. Pass -1 to search
* for the first result providing a valid defaultIndex.
* @param _result
* The found result.
* @param _defaultIndex
* The defaultIndex relative to _result.
*/
nsresult GetDefaultCompleteResult(PRInt32 aResultIndex,
nsIAutoCompleteResult** _result,
PRInt32* _defaultIndex);
/**
* Gets the defaultComplete value to be suggested to the user.
*
* @param aResultIndex
* Index of the defaultComplete result to be used.
* @param aPreserveCasing
* Whether user casing should be preserved.
* @param _retval
* The value to be completed.
*/
nsresult GetDefaultCompleteValue(PRInt32 aResultIndex, bool aPreserveCasing,
nsAString &_retval);
/**
* Gets the defaultComplete value to be used when the user navigates or
* confirms the current match.
* The value is returned only if it case-insensitively matches the current
* input text, otherwise the method returns NS_ERROR_FAILURE.
* This happens because we don't want to override user casing in case of a
* navigation key (unless the text is the same), or to replace text if the
* user backspaces just before Enter.
*
* @param _retval
* The value to be completed.
*/
nsresult GetFinalDefaultCompleteValue(nsAString &_retval);
nsresult ClearResults();
nsresult RowIndexToSearch(PRInt32 aRowIndex,

View File

@ -718,7 +718,12 @@ Database::InitSchema(bool* aDatabaseMigrated)
NS_ENSURE_SUCCESS(rv, rv);
}
// Firefox 14 uses schema version 20.
if (currentSchemaVersion < 21) {
rv = MigrateV21Up();
NS_ENSURE_SUCCESS(rv, rv);
}
// Firefox 14 uses schema version 21.
// Schema Upgrades must add migration code here.
@ -1839,6 +1844,39 @@ Database::MigrateV20Up()
return NS_OK;
}
nsresult
Database::MigrateV21Up()
{
MOZ_ASSERT(NS_IsMainThread());
// Add a prefix column to moz_hosts.
nsCOMPtr<mozIStorageStatement> stmt;
nsresult rv = mMainConn->CreateStatement(NS_LITERAL_CSTRING(
"SELECT prefix FROM moz_hosts"
), getter_AddRefs(stmt));
if (NS_FAILED(rv)) {
rv = mMainConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"ALTER TABLE moz_hosts ADD COLUMN prefix"
));
NS_ENSURE_SUCCESS(rv, rv);
}
// Update prefixes.
nsCOMPtr<mozIStorageAsyncStatement> updatePrefixesStmt;
rv = mMainConn->CreateAsyncStatement(NS_LITERAL_CSTRING(
"UPDATE moz_hosts SET prefix = ( "
HOSTS_PREFIX_PRIORITY_FRAGMENT
") "
), getter_AddRefs(updatePrefixesStmt));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<mozIStoragePendingStatement> ps;
rv = updatePrefixesStmt->ExecuteAsync(nsnull, getter_AddRefs(ps));
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
void
Database::Shutdown()
{

View File

@ -14,7 +14,7 @@
// This is the schema version. Update it at any schema change and add a
// corresponding migrateVxx method below.
#define DATABASE_SCHEMA_VERSION 20
#define DATABASE_SCHEMA_VERSION 21
// Fired after Places inited.
#define TOPIC_PLACES_INIT_COMPLETE "places-init-complete"
@ -270,6 +270,7 @@ protected:
nsresult MigrateV18Up();
nsresult MigrateV19Up();
nsresult MigrateV20Up();
nsresult MigrateV21Up();
nsresult UpdateBookmarkRootTitles();
nsresult CheckAndUpdateGUIDs();

View File

@ -1287,7 +1287,7 @@ urlInlineComplete.prototype = {
// want to complete up to and including a URL separator.
this.__syncQuery = this._db.createStatement(
"/* do not warn (bug no): could index on (typed,frecency) but not worth it */ "
+ "SELECT host || '/' "
+ "SELECT host || '/', prefix || host || '/' "
+ "FROM moz_hosts "
+ "WHERE host BETWEEN :search_string AND :search_string || X'FFFF' "
+ "AND frecency <> 0 "
@ -1378,11 +1378,12 @@ urlInlineComplete.prototype = {
let lastSlashIndex = this._currentSearchString.lastIndexOf("/");
if (lastSlashIndex == -1) {
var hasDomainResult = false;
var domain;
var domain, untrimmedDomain;
try {
hasDomainResult = query.executeStep();
if (hasDomainResult) {
domain = query.getString(0);
untrimmedDomain = query.getString(1);
}
} finally {
query.reset();
@ -1390,7 +1391,9 @@ urlInlineComplete.prototype = {
if (hasDomainResult) {
// We got a match for a domain, we can add it immediately.
result.appendMatch(this._strippedPrefix + domain, "");
// TODO (bug 754265): this is a temporary solution introduced while
// waiting for a propert dedicated API.
result.appendMatch(this._strippedPrefix + domain, untrimmedDomain);
this._finishSearch();
return;
@ -1481,7 +1484,10 @@ urlInlineComplete.prototype = {
handleResult: function UIC_handleResult(aResultSet)
{
let row = aResultSet.getNextRow();
let url = fixupSearchText(row.getResultByIndex(0));
let value = row.getResultByIndex(0);
let url = fixupSearchText(value);
let prefix = value.slice(0, value.length - url.length);
// We must complete the URL up to the next separator (which is /, ? or #).
let separatorIndex = url.slice(this._currentSearchString.length)
@ -1494,8 +1500,10 @@ urlInlineComplete.prototype = {
url = url.slice(0, separatorIndex);
}
// Add the result
this._result.appendMatch(this._strippedPrefix + url, "");
// Add the result.
// TODO (bug 754265): this is a temporary solution introduced while
// waiting for a propert dedicated API.
this._result.appendMatch(this._strippedPrefix + url, prefix + url);
// handleCompletion() will cause the result listener to be called, and
// will display the result in the UI.

View File

@ -134,6 +134,7 @@
", host TEXT NOT NULL UNIQUE" \
", frecency INTEGER" \
", typed INTEGER NOT NULL DEFAULT 0" \
", prefix TEXT" \
")" \
)

View File

@ -46,6 +46,34 @@
"END" \
)
/**
* Select the best prefix for a host, based on existing pages registered for it.
* Prefixes have a priority, from the top to the bottom, so that secure pages
* have higher priority, and more generically "www." prefixed hosts come before
* unprefixed ones.
* Each condition just checks if a page exists for a specific prefixed host,
* and if so returns the relative prefix.
*/
#define HOSTS_PREFIX_PRIORITY_FRAGMENT \
"SELECT CASE " \
"WHEN EXISTS( " \
"SELECT 1 FROM moz_places WHERE url BETWEEN 'https://www.' || host || '/' " \
"AND 'https://www.' || host || '/' || X'FFFF' " \
") THEN 'https://www.' " \
"WHEN EXISTS( " \
"SELECT 1 FROM moz_places WHERE url BETWEEN 'https://' || host || '/' " \
"AND 'https://' || host || '/' || X'FFFF' " \
") THEN 'https://' " \
"WHEN EXISTS( " \
"SELECT 1 FROM moz_places WHERE url BETWEEN 'ftp://' || host || '/' " \
"AND 'ftp://' || host || '/' || X'FFFF' " \
") THEN 'ftp://' " \
"WHEN EXISTS( " \
"SELECT 1 FROM moz_places WHERE url BETWEEN 'http://www.' || host || '/' " \
"AND 'http://www.' || host || '/' || X'FFFF' " \
") THEN 'www.' " \
"END "
/**
* These triggers update the hostnames table whenever moz_places changes.
*/
@ -54,12 +82,17 @@
"AFTER INSERT ON moz_places FOR EACH ROW " \
"WHEN LENGTH(NEW.rev_host) > 1 " \
"BEGIN " \
"INSERT OR REPLACE INTO moz_hosts (id, host, frecency, typed) " \
"INSERT OR REPLACE INTO moz_hosts (id, host, frecency, typed, prefix) " \
"VALUES (" \
"(SELECT id FROM moz_hosts WHERE host = fixup_url(get_unreversed_host(NEW.rev_host))), " \
"fixup_url(get_unreversed_host(NEW.rev_host)), " \
"MAX(IFNULL((SELECT frecency FROM moz_hosts WHERE host = fixup_url(get_unreversed_host(NEW.rev_host))), -1), NEW.frecency), " \
"MAX(IFNULL((SELECT typed FROM moz_hosts WHERE host = fixup_url(get_unreversed_host(NEW.rev_host))), 0), NEW.typed) " \
"MAX(IFNULL((SELECT typed FROM moz_hosts WHERE host = fixup_url(get_unreversed_host(NEW.rev_host))), 0), NEW.typed), " \
"(" HOSTS_PREFIX_PRIORITY_FRAGMENT \
"FROM ( " \
"SELECT fixup_url(get_unreversed_host(NEW.rev_host)) AS host " \
") AS match " \
") " \
"); " \
"END" \
)
@ -75,6 +108,11 @@
"WHERE rev_host = get_unreversed_host(host || '.') || '.' " \
"OR rev_host = get_unreversed_host(host || '.') || '.www.' " \
"); " \
"UPDATE moz_hosts " \
"SET prefix = (" \
HOSTS_PREFIX_PRIORITY_FRAGMENT \
") " \
"WHERE host = fixup_url(get_unreversed_host(OLD.rev_host)); " \
"END" \
)

View File

@ -3,7 +3,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const CURRENT_SCHEMA_VERSION = 20;
const CURRENT_SCHEMA_VERSION = 21;
const NS_APP_USER_PROFILE_50_DIR = "ProfD";
const NS_APP_PROFILE_DIR_STARTUP = "ProfDS";

View File

@ -23,7 +23,7 @@ add_autocomplete_test([
add_autocomplete_test([
"Searching for cased entry 3",
"mozilla.org/T",
{ autoFilled: "mozilla.org/Test/", completed: "mozilla.org/Test/" },
{ autoFilled: "mozilla.org/Test/", completed: "http://mozilla.org/Test/" },
function () {
addBookmark({ url: "http://mozilla.org/Test/" });
}
@ -41,7 +41,7 @@ add_autocomplete_test([
add_autocomplete_test([
"Searching for cased entry 5",
"mOzilla.org/T",
{ autoFilled: "mOzilla.org/Test/", completed: "mozilla.org/Test/" },
{ autoFilled: "mOzilla.org/Test/", completed: "http://mozilla.org/Test/" },
function () {
addBookmark({ url: "http://mozilla.org/Test/" });
},
@ -59,7 +59,7 @@ add_autocomplete_test([
add_autocomplete_test([
"Searching for untrimmed cased entry with www",
"http://www.mOz",
{ autoFilled: "http://www.mOzilla.org/", completed: "http://www.mozilla.org/" },
{ autoFilled: "http://www.mOzilla.org/", completed: "www.mozilla.org/" },
function () {
addBookmark({ url: "http://www.mozilla.org/Test/" });
},

View File

@ -0,0 +1,134 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
add_autocomplete_test([
"Searching for untrimmed https://www entry",
"mo",
{ autoFilled: "mozilla.org/", completed: "https://www.mozilla.org/" },
function () {
addBookmark({ url: "https://www.mozilla.org/test/" });
},
]);
add_autocomplete_test([
"Searching for untrimmed https://www entry with path",
"mozilla.org/t",
{ autoFilled: "mozilla.org/test/", completed: "https://www.mozilla.org/test/" },
function () {
addBookmark({ url: "https://www.mozilla.org/test/" });
},
]);
add_autocomplete_test([
"Searching for untrimmed https:// entry",
"mo",
{ autoFilled: "mozilla.org/", completed: "https://mozilla.org/" },
function () {
addBookmark({ url: "https://mozilla.org/test/" });
},
]);
add_autocomplete_test([
"Searching for untrimmed https:// entry with path",
"mozilla.org/t",
{ autoFilled: "mozilla.org/test/", completed: "https://mozilla.org/test/" },
function () {
addBookmark({ url: "https://mozilla.org/test/" });
},
]);
add_autocomplete_test([
"Searching for untrimmed http://www entry",
"mo",
{ autoFilled: "mozilla.org/", completed: "www.mozilla.org/" },
function () {
addBookmark({ url: "http://www.mozilla.org/test/" });
},
]);
add_autocomplete_test([
"Searching for untrimmed http://www entry with path",
"mozilla.org/t",
{ autoFilled: "mozilla.org/test/", completed: "http://www.mozilla.org/test/" },
function () {
addBookmark({ url: "http://www.mozilla.org/test/" });
},
]);
add_autocomplete_test([
"Searching for untrimmed ftp:// entry",
"mo",
{ autoFilled: "mozilla.org/", completed: "ftp://mozilla.org/" },
function () {
addBookmark({ url: "ftp://mozilla.org/test/" });
},
]);
add_autocomplete_test([
"Searching for untrimmed ftp:// entry with path",
"mozilla.org/t",
{ autoFilled: "mozilla.org/test/", completed: "ftp://mozilla.org/test/" },
function () {
addBookmark({ url: "ftp://mozilla.org/test/" });
},
]);
add_autocomplete_test([
"Ensuring correct priority 1",
"mo",
{ autoFilled: "mozilla.org/", completed: "https://www.mozilla.org/" },
function () {
addBookmark({ url: "https://www.mozilla.org/test/" });
addBookmark({ url: "https://mozilla.org/test/" });
addBookmark({ url: "ftp://mozilla.org/test/" });
addBookmark({ url: "http://www.mozilla.org/test/" });
addBookmark({ url: "http://mozilla.org/test/" });
},
]);
add_autocomplete_test([
"Ensuring correct priority 2",
"mo",
{ autoFilled: "mozilla.org/", completed: "https://mozilla.org/" },
function () {
addBookmark({ url: "https://mozilla.org/test/" });
addBookmark({ url: "ftp://mozilla.org/test/" });
addBookmark({ url: "http://www.mozilla.org/test/" });
addBookmark({ url: "http://mozilla.org/test/" });
},
]);
add_autocomplete_test([
"Ensuring correct priority 3",
"mo",
{ autoFilled: "mozilla.org/", completed: "ftp://mozilla.org/" },
function () {
addBookmark({ url: "ftp://mozilla.org/test/" });
addBookmark({ url: "http://www.mozilla.org/test/" });
addBookmark({ url: "http://mozilla.org/test/" });
},
]);
add_autocomplete_test([
"Ensuring correct priority 4",
"mo",
{ autoFilled: "mozilla.org/", completed: "www.mozilla.org/" },
function () {
addBookmark({ url: "http://www.mozilla.org/test/" });
addBookmark({ url: "http://mozilla.org/test/" });
},
]);
add_autocomplete_test([
"Ensuring longer domain can't match",
"mo",
{ autoFilled: "mozilla.co/", completed: "mozilla.co/" },
function () {
// The .co should be preferred, but should not get the https from the .com.
// The .co domain must be added later to activate the trigger bug.
addBookmark({ url: "https://mozilla.com/" });
addBookmark({ url: "http://mozilla.co/" });
addBookmark({ url: "http://mozilla.co/" });
},
]);

View File

@ -6,5 +6,6 @@ tail =
[test_casing.js]
[test_do_not_trim.js]
[test_keywords.js]
[test_trimming.js]
[test_typed.js]
[test_zero_frecency.js]

View File

@ -282,7 +282,7 @@ function test_moz_hosts()
{
// This will throw if the column does not exist
let stmt = DBConn().createStatement(
"SELECT host, frecency, typed "
"SELECT host, frecency, typed, prefix "
+ "FROM moz_hosts "
);
stmt.finalize();

View File

@ -32,10 +32,10 @@ function isHostInMozPlaces(aURI)
return result;
}
function isHostInMozHosts(aURI, aTyped)
function isHostInMozHosts(aURI, aTyped, aPrefix)
{
let stmt = DBConn().createStatement(
"SELECT host, typed "
"SELECT host, typed, prefix "
+ "FROM moz_hosts "
+ "WHERE host = fixup_url(:host) "
+ "AND frecency NOTNULL "
@ -43,10 +43,7 @@ function isHostInMozHosts(aURI, aTyped)
let result = false;
stmt.params.host = aURI.host;
if (stmt.executeStep()) {
if (aTyped != null)
result = aTyped == stmt.row.typed;
else
result = true;
result = aTyped == stmt.row.typed && aPrefix == stmt.row.prefix;
}
stmt.finalize();
return result;
@ -54,15 +51,18 @@ function isHostInMozHosts(aURI, aTyped)
let urls = [{uri: NetUtil.newURI("http://visit1.mozilla.org"),
expected: "visit1.mozilla.org",
typed: 0
typed: 0,
prefix: null
},
{uri: NetUtil.newURI("http://visit2.mozilla.org"),
expected: "visit2.mozilla.org",
typed: 0
typed: 0,
prefix: null
},
{uri: NetUtil.newURI("http://www.foo.mozilla.org"),
expected: "foo.mozilla.org",
typed: 1
typed: 1,
prefix: "www."
},
];
@ -96,9 +96,9 @@ function test_moz_hosts_update()
do_throw("gHistory.updatePlaces() failed");
},
handleCompletion: function () {
do_check_true(isHostInMozHosts(urls[0].uri, urls[0].typed));
do_check_true(isHostInMozHosts(urls[1].uri, urls[1].typed));
do_check_true(isHostInMozHosts(urls[2].uri, urls[2].typed));
do_check_true(isHostInMozHosts(urls[0].uri, urls[0].typed, urls[0].prefix));
do_check_true(isHostInMozHosts(urls[1].uri, urls[1].typed, urls[1].prefix));
do_check_true(isHostInMozHosts(urls[2].uri, urls[2].typed, urls[2].prefix));
run_next_test();
}
});
@ -112,7 +112,7 @@ function test_remove_places()
waitForClearHistory(function (){
for (let idx in urls) {
do_check_false(isHostInMozHosts(urls[idx].uri));
do_check_false(isHostInMozHosts(urls[idx].uri, urls[idx].typed, urls[idx].prefix));
}
run_next_test();
});
@ -135,8 +135,8 @@ function test_bookmark_changes()
waitForClearHistory(function (){
let newUri = NetUtil.newURI(NEW_URL);
do_check_true(isHostInMozPlaces(newUri));
do_check_true(isHostInMozHosts(newUri));
do_check_false(isHostInMozHosts(NetUtil.newURI("http://test.mozilla.org")));
do_check_true(isHostInMozHosts(newUri, false, null));
do_check_false(isHostInMozHosts(NetUtil.newURI("http://test.mozilla.org"), false, null));
run_next_test();
});
}
@ -148,7 +148,7 @@ function test_bookmark_removal()
let newUri = NetUtil.newURI(NEW_URL);
PlacesUtils.bookmarks.removeItem(itemId);
waitForClearHistory(function (){
do_check_false(isHostInMozHosts(newUri));
do_check_false(isHostInMozHosts(newUri, false, null));
run_next_test();
});
}
@ -170,7 +170,7 @@ function test_moz_hosts_typed_update()
do_throw("gHistory.updatePlaces() failed");
},
handleCompletion: function () {
do_check_true(isHostInMozHosts(TEST_URI, true));
do_check_true(isHostInMozHosts(TEST_URI, true, null));
run_next_test();
}
});
@ -196,7 +196,8 @@ function test_moz_hosts_www_remove()
},
handleCompletion: function () {
PlacesUtils.history.removePage(aURIToRemove);
do_check_true(isHostInMozHosts(aURIToKeep));
let prefix = /www/.test(aURIToKeep.spec) ? "www." : null;
do_check_true(isHostInMozHosts(aURIToKeep, false, prefix));
waitForClearHistory(aCallback);
}
});