merge mozilla-inbound to mozilla-central on a CLOSED TREE

This commit is contained in:
Carsten "Tomcat" Book 2015-10-21 15:32:33 +02:00
Родитель fddab43f09 e1cd84d88d
Коммит 894a28d90b
98 изменённых файлов: 2200 добавлений и 1374 удалений

Просмотреть файл

@ -658,12 +658,15 @@ AccessibleWrap::get_accFocus(
if (IsDefunct())
return CO_E_OBJNOTCONNECTED;
// TODO make this work with proxies.
if (IsProxy())
return E_NOTIMPL;
// Return the current IAccessible child that has focus
Accessible* focusedAccessible = FocusedChild();
Accessible* focusedAccessible;
if (IsProxy()) {
ProxyAccessible* proxy = Proxy()->FocusedChild();
focusedAccessible = proxy ? WrapperFor(proxy) : nullptr;
} else {
focusedAccessible = FocusedChild();
}
if (focusedAccessible == this) {
pvarChild->vt = VT_I4;
pvarChild->lVal = CHILDID_SELF;
@ -830,7 +833,17 @@ AccessibleWrap::get_accSelection(VARIANT __RPC_FAR *pvarChildren)
if (IsSelect()) {
nsAutoTArray<Accessible*, 10> selectedItems;
SelectedItems(&selectedItems);
if (IsProxy()) {
nsTArray<ProxyAccessible*> proxies;
Proxy()->SelectedItems(&proxies);
uint32_t selectedCount = proxies.Length();
for (uint32_t i = 0; i < selectedCount; i++) {
selectedItems.AppendElement(WrapperFor(proxies[i]));
}
} else {
SelectedItems(&selectedItems);
}
// 1) Create and initialize the enumeration
RefPtr<AccessibleEnumerator> pEnum = new AccessibleEnumerator(selectedItems);
@ -864,12 +877,13 @@ AccessibleWrap::get_accDefaultAction(
if (xpAccessible->IsDefunct())
return CO_E_OBJNOTCONNECTED;
// TODO make this work with proxies.
if (xpAccessible->IsProxy())
return E_NOTIMPL;
nsAutoString defaultAction;
xpAccessible->ActionNameAt(0, defaultAction);
if (xpAccessible->IsProxy()) {
xpAccessible->Proxy()->ActionNameAt(0, defaultAction);
} else {
xpAccessible->ActionNameAt(0, defaultAction);
}
*pszDefaultAction = ::SysAllocStringLen(defaultAction.get(),
defaultAction.Length());
return *pszDefaultAction ? S_OK : E_OUTOFMEMORY;
@ -895,23 +909,42 @@ AccessibleWrap::accSelect(
if (xpAccessible->IsDefunct())
return CO_E_OBJNOTCONNECTED;
// TODO make this work with proxies.
if (xpAccessible->IsProxy())
return E_NOTIMPL;
if (flagsSelect & (SELFLAG_TAKEFOCUS|SELFLAG_TAKESELECTION|SELFLAG_REMOVESELECTION))
{
if (flagsSelect & SELFLAG_TAKEFOCUS)
if (flagsSelect & SELFLAG_TAKEFOCUS) {
if (xpAccessible->IsProxy()) {
xpAccessible->Proxy()->TakeFocus();
} else {
xpAccessible->TakeFocus();
}
if (flagsSelect & SELFLAG_TAKESELECTION)
return S_OK;
}
if (flagsSelect & SELFLAG_TAKESELECTION) {
if (xpAccessible->IsProxy()) {
xpAccessible->Proxy()->TakeSelection();
} else {
xpAccessible->TakeSelection();
}
if (flagsSelect & SELFLAG_ADDSELECTION)
return S_OK;
}
if (flagsSelect & SELFLAG_ADDSELECTION) {
if (xpAccessible->IsProxy()) {
xpAccessible->Proxy()->SetSelected(true);
} else {
xpAccessible->SetSelected(true);
}
if (flagsSelect & SELFLAG_REMOVESELECTION)
return S_OK;
}
if (flagsSelect & SELFLAG_REMOVESELECTION) {
if (xpAccessible->IsProxy()) {
xpAccessible->Proxy()->SetSelected(false);
} else {
xpAccessible->SetSelected(false);
}
return S_OK;
}
@ -1063,11 +1096,15 @@ AccessibleWrap::accHitTest(
if (IsDefunct())
return CO_E_OBJNOTCONNECTED;
// TODO make this work with proxies.
if (IsProxy())
return E_NOTIMPL;
Accessible* accessible = ChildAtPoint(xLeft, yTop, eDirectChild);
Accessible* accessible = nullptr;
if (IsProxy()) {
ProxyAccessible* proxy = Proxy()->ChildAtPoint(xLeft, yTop, eDirectChild);
if (proxy) {
accessible = WrapperFor(proxy);
}
} else {
accessible = ChildAtPoint(xLeft, yTop, eDirectChild);
}
// if we got a child
if (accessible) {
@ -1107,7 +1144,7 @@ AccessibleWrap::accDoDefaultAction(
// TODO make this work with proxies.
if (xpAccessible->IsProxy())
return E_NOTIMPL;
return xpAccessible->Proxy()->DoAction(0) ? S_OK : E_INVALIDARG;
return xpAccessible->DoAction(0) ? S_OK : E_INVALIDARG;

Просмотреть файл

@ -1446,11 +1446,19 @@ pref("plain_text.wrap_long_lines", true);
pref("dom.debug.propagate_gesture_events_through_content", false);
// The request URL of the GeoLocation backend.
#ifdef RELEASE_BUILD
pref("geo.wifi.uri", "https://www.googleapis.com/geolocation/v1/geolocate?key=%GOOGLE_API_KEY%");
#else
pref("geo.wifi.uri", "https://location.services.mozilla.com/v1/geolocate?key=%MOZILLA_API_KEY%");
#endif
#ifdef XP_MACOSX
#ifdef RELEASE_BUILD
pref("geo.provider.use_corelocation", false);
#else
pref("geo.provider.use_corelocation", true);
#endif
#endif
#ifdef XP_WIN
pref("geo.provider.ms-windows-location", false);

Просмотреть файл

@ -2062,492 +2062,6 @@ FragmentOrElement::IndexOf(const nsINode* aPossibleChild) const
return mAttrsAndChildren.IndexOfChild(aPossibleChild);
}
// Try to keep the size of StringBuilder close to a jemalloc bucket size.
#define STRING_BUFFER_UNITS 1020
namespace {
// We put StringBuilder in the anonymous namespace to prevent anything outside
// this file from accidentally being linked against it.
class StringBuilder
{
private:
class Unit
{
public:
Unit() : mAtom(nullptr), mType(eUnknown), mLength(0)
{
MOZ_COUNT_CTOR(StringBuilder::Unit);
}
~Unit()
{
if (mType == eString || mType == eStringWithEncode) {
delete mString;
}
MOZ_COUNT_DTOR(StringBuilder::Unit);
}
enum Type
{
eUnknown,
eAtom,
eString,
eStringWithEncode,
eLiteral,
eTextFragment,
eTextFragmentWithEncode,
};
union
{
nsIAtom* mAtom;
const char* mLiteral;
nsAutoString* mString;
const nsTextFragment* mTextFragment;
};
Type mType;
uint32_t mLength;
};
public:
StringBuilder() : mLast(this), mLength(0)
{
MOZ_COUNT_CTOR(StringBuilder);
}
~StringBuilder()
{
MOZ_COUNT_DTOR(StringBuilder);
}
void Append(nsIAtom* aAtom)
{
Unit* u = AddUnit();
u->mAtom = aAtom;
u->mType = Unit::eAtom;
uint32_t 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;
uint32_t 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;
uint32_t 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;
uint32_t len = aString.Length();
u->mLength = len;
mLength += len;
}
void Append(nsAutoString* aString)
{
Unit* u = AddUnit();
u->mString = aString;
u->mType = Unit::eString;
uint32_t len = aString->Length();
u->mLength = len;
mLength += len;
}
void AppendWithAttrEncode(nsAutoString* aString, uint32_t 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;
uint32_t len = aTextFragment->GetLength();
u->mLength = len;
mLength += len;
}
void AppendWithEncode(const nsTextFragment* aTextFragment, uint32_t 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)) {
return false;
}
for (StringBuilder* current = this; current; current = current->mNext) {
uint32_t len = current->mUnits.Length();
for (uint32_t 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_CRASH("Unknown unit type?");
}
}
}
return true;
}
private:
Unit* AddUnit()
{
if (mLast->mUnits.Length() == STRING_BUFFER_UNITS) {
new StringBuilder(this);
}
return mLast->mUnits.AppendElement();
}
explicit StringBuilder(StringBuilder* aFirst)
: mLast(nullptr), mLength(0)
{
MOZ_COUNT_CTOR(StringBuilder);
aFirst->mLast->mNext = this;
aFirst->mLast = this;
}
void EncodeAttrString(const nsAutoString& aValue, nsAString& aOut)
{
const char16_t* c = aValue.BeginReading();
const char16_t* 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)
{
uint32_t len = aValue->GetLength();
if (aValue->Is2b()) {
const char16_t* data = aValue->Get2b();
for (uint32_t i = 0; i < len; ++i) {
const char16_t 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 (uint32_t 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.
uint32_t mLength;
};
} // namespace
static void
AppendEncodedCharacters(const nsTextFragment* aText, StringBuilder& aBuilder)
{
uint32_t extraSpaceNeeded = 0;
uint32_t len = aText->GetLength();
if (aText->Is2b()) {
const char16_t* data = aText->Get2b();
for (uint32_t i = 0; i < len; ++i) {
const char16_t 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 (uint32_t 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 char16_t* c = aValue->BeginReading();
const char16_t* end = aValue->EndReading();
uint32_t 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->NodeInfo()->NameAtom();
int32_t tagNS = aContent->GetNameSpaceID();
aBuilder.Append("<");
if (aContent->IsHTMLElement() || aContent->IsSVGElement() ||
aContent->IsMathMLElement()) {
aBuilder.Append(localName);
} else {
aBuilder.Append(aContent->NodeName());
}
int32_t count = aContent->GetAttrCount();
for (int32_t i = count; i > 0;) {
--i;
const nsAttrName* name = aContent->GetAttrNameAt(i);
int32_t 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;
}
aBuilder.Append(" ");
if (MOZ_LIKELY(attNs == kNameSpaceID_None) ||
(attNs == kNameSpaceID_XMLNS &&
attName == nsGkAtoms::xmlns)) {
// Nothing else required
} 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(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->IsHTMLElement()) {
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) == char16_t('\n')) {
aBuilder.Append("\n");
}
}
}
}*/
}
static inline bool
ShouldEscape(nsIContent* aParent)
{
if (!aParent || !aParent->IsHTMLElement()) {
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 (uint32_t i = 0; i < ArrayLength(nonEscapingElements); ++i) {
sFilter.add(nonEscapingElements[i]);
}
}
nsIAtom* tag = aParent->NodeInfo()->NameAtom();
if (sFilter.mightContain(tag)) {
for (uint32_t i = 0; i < ArrayLength(nonEscapingElements); ++i) {
if (tag == nonEscapingElements[i]) {
return false;
}
}
}
return true;
}
static inline bool
IsVoidTag(nsIAtom* aTag)
{
@ -2580,15 +2094,6 @@ IsVoidTag(nsIAtom* aTag)
return false;
}
static inline bool
IsVoidTag(Element* aElement)
{
if (!aElement->IsHTMLElement()) {
return false;
}
return IsVoidTag(aElement->NodeInfo()->NameAtom());
}
/* static */
bool
FragmentOrElement::IsHTMLVoid(nsIAtom* aLocalName)
@ -2596,112 +2101,6 @@ FragmentOrElement::IsHTMLVoid(nsIAtom* aLocalName)
return aLocalName && IsVoidTag(aLocalName);
}
static bool
Serialize(FragmentOrElement* aRoot, bool aDescendentsOnly, nsAString& aOut)
{
nsINode* current = aDescendentsOnly ?
nsNodeUtils::GetFirstChildOfTemplateOrNode(aRoot) : 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 = nsNodeUtils::GetFirstChildOfTemplateOrNode(current))) {
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->IsHTMLElement() || elem->IsSVGElement() ||
elem->IsMathMLElement()) {
builder.Append(elem->NodeInfo()->NameAtom());
} 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->GetParentNode();
// Handle template element. If the parent is a template's content,
// then adjust the parent to be the template element.
if (current != aRoot &&
current->NodeType() == nsIDOMNode::DOCUMENT_FRAGMENT_NODE) {
DocumentFragment* frag = static_cast<DocumentFragment*>(current);
nsIContent* fragHost = frag->GetHost();
if (fragHost && nsNodeUtils::IsTemplateElement(fragHost)) {
current = fragHost;
}
}
if (aDescendentsOnly && current == aRoot) {
return builder.ToString(aOut);
}
}
}
}
void
FragmentOrElement::GetMarkup(bool aIncludeSelf, nsAString& aMarkup)
{
@ -2709,7 +2108,7 @@ FragmentOrElement::GetMarkup(bool aIncludeSelf, nsAString& aMarkup)
nsIDocument* doc = OwnerDoc();
if (IsInHTMLDocument()) {
Serialize(this, !aIncludeSelf, aMarkup);
nsContentUtils::SerializeNodeToMarkup(this, !aIncludeSelf, aMarkup);
return;
}

Просмотреть файл

@ -48,11 +48,21 @@ NodeIsInTraversalRange(nsINode* aNode, bool aIsPreMode,
return false;
}
// If a chardata node contains an end point of the traversal range, it is
// If a leaf node contains an end point of the traversal range, it is
// always in the traversal range.
if (aNode->IsNodeOfType(nsINode::eDATA_NODE) &&
(aNode == aStartNode || aNode == aEndNode)) {
return true;
if (aNode == aStartNode || aNode == aEndNode) {
if (aNode->IsNodeOfType(nsINode::eDATA_NODE)) {
return true; // text node or something
}
if (!aNode->HasChildren()) {
MOZ_ASSERT(aNode != aStartNode || !aStartOffset,
"aStartNode doesn't have children and not a data node, "
"aStartOffset should be 0");
MOZ_ASSERT(aNode != aEndNode || !aEndOffset,
"aStartNode doesn't have children and not a data node, "
"aStartOffset should be 0");
return true;
}
}
nsINode* parent = aNode->GetParentNode();
@ -341,12 +351,14 @@ nsContentIterator::Init(nsIDOMRange* aDOMRange)
// character in the cdata node, should we set mFirst to
// the next sibling?
if (!startIsData) {
// If the node has no child, the child may be <br> or something.
// So, we shouldn't skip the empty node if the start offset is 0.
// In other words, if the offset is 1, the node should be ignored.
if (!startIsData && startIndx) {
mFirst = GetNextSibling(startNode);
// Does mFirst node really intersect the range? The range could be
// 'degenerate', i.e., not collapsed but still contain no content.
if (mFirst && !NodeIsInTraversalRange(mFirst, mPre, startNode,
startIndx, endNode, endIndx)) {
mFirst = nullptr;

Просмотреть файл

@ -197,6 +197,7 @@
#include "mozIThirdPartyUtil.h"
#include "nsICookieService.h"
#include "mozilla/EnumSet.h"
#include "mozilla/BloomFilter.h"
#include "nsIBidiKeyboard.h"
@ -8259,3 +8260,609 @@ nsContentUtils::InternalStorageAllowedForPrincipal(nsIPrincipal* aPrincipal,
return access;
}
namespace {
// We put StringBuilder in the anonymous namespace to prevent anything outside
// this file from accidentally being linked against it.
class StringBuilder
{
private:
// Try to keep the size of StringBuilder close to a jemalloc bucket size.
static const uint32_t STRING_BUFFER_UNITS = 1020;
class Unit
{
public:
Unit() : mAtom(nullptr), mType(eUnknown), mLength(0)
{
MOZ_COUNT_CTOR(StringBuilder::Unit);
}
~Unit()
{
if (mType == eString || mType == eStringWithEncode) {
delete mString;
}
MOZ_COUNT_DTOR(StringBuilder::Unit);
}
enum Type
{
eUnknown,
eAtom,
eString,
eStringWithEncode,
eLiteral,
eTextFragment,
eTextFragmentWithEncode,
};
union
{
nsIAtom* mAtom;
const char* mLiteral;
nsAutoString* mString;
const nsTextFragment* mTextFragment;
};
Type mType;
uint32_t mLength;
};
public:
StringBuilder() : mLast(this), mLength(0)
{
MOZ_COUNT_CTOR(StringBuilder);
}
~StringBuilder()
{
MOZ_COUNT_DTOR(StringBuilder);
}
void Append(nsIAtom* aAtom)
{
Unit* u = AddUnit();
u->mAtom = aAtom;
u->mType = Unit::eAtom;
uint32_t 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;
uint32_t 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;
uint32_t 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;
uint32_t len = aString.Length();
u->mLength = len;
mLength += len;
}
void Append(nsAutoString* aString)
{
Unit* u = AddUnit();
u->mString = aString;
u->mType = Unit::eString;
uint32_t len = aString->Length();
u->mLength = len;
mLength += len;
}
void AppendWithAttrEncode(nsAutoString* aString, uint32_t 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;
uint32_t len = aTextFragment->GetLength();
u->mLength = len;
mLength += len;
}
void AppendWithEncode(const nsTextFragment* aTextFragment, uint32_t 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)) {
return false;
}
for (StringBuilder* current = this; current; current = current->mNext) {
uint32_t len = current->mUnits.Length();
for (uint32_t 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_CRASH("Unknown unit type?");
}
}
}
return true;
}
private:
Unit* AddUnit()
{
if (mLast->mUnits.Length() == STRING_BUFFER_UNITS) {
new StringBuilder(this);
}
return mLast->mUnits.AppendElement();
}
explicit StringBuilder(StringBuilder* aFirst)
: mLast(nullptr), mLength(0)
{
MOZ_COUNT_CTOR(StringBuilder);
aFirst->mLast->mNext = this;
aFirst->mLast = this;
}
void EncodeAttrString(const nsAutoString& aValue, nsAString& aOut)
{
const char16_t* c = aValue.BeginReading();
const char16_t* 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)
{
uint32_t len = aValue->GetLength();
if (aValue->Is2b()) {
const char16_t* data = aValue->Get2b();
for (uint32_t i = 0; i < len; ++i) {
const char16_t 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 (uint32_t 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.
uint32_t mLength;
};
} // namespace
static void
AppendEncodedCharacters(const nsTextFragment* aText, StringBuilder& aBuilder)
{
uint32_t extraSpaceNeeded = 0;
uint32_t len = aText->GetLength();
if (aText->Is2b()) {
const char16_t* data = aText->Get2b();
for (uint32_t i = 0; i < len; ++i) {
const char16_t 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 (uint32_t 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 char16_t* c = aValue->BeginReading();
const char16_t* end = aValue->EndReading();
uint32_t 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->NodeInfo()->NameAtom();
int32_t tagNS = aContent->GetNameSpaceID();
aBuilder.Append("<");
if (aContent->IsHTMLElement() || aContent->IsSVGElement() ||
aContent->IsMathMLElement()) {
aBuilder.Append(localName);
} else {
aBuilder.Append(aContent->NodeName());
}
int32_t count = aContent->GetAttrCount();
for (int32_t i = count; i > 0;) {
--i;
const nsAttrName* name = aContent->GetAttrNameAt(i);
int32_t 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;
}
aBuilder.Append(" ");
if (MOZ_LIKELY(attNs == kNameSpaceID_None) ||
(attNs == kNameSpaceID_XMLNS &&
attName == nsGkAtoms::xmlns)) {
// Nothing else required
} 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(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->IsHTMLElement()) {
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) == char16_t('\n')) {
aBuilder.Append("\n");
}
}
}
}*/
}
static inline bool
ShouldEscape(nsIContent* aParent)
{
if (!aParent || !aParent->IsHTMLElement()) {
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 (uint32_t i = 0; i < ArrayLength(nonEscapingElements); ++i) {
sFilter.add(nonEscapingElements[i]);
}
}
nsIAtom* tag = aParent->NodeInfo()->NameAtom();
if (sFilter.mightContain(tag)) {
for (uint32_t i = 0; i < ArrayLength(nonEscapingElements); ++i) {
if (tag == nonEscapingElements[i]) {
return false;
}
}
}
return true;
}
static inline bool
IsVoidTag(Element* aElement)
{
if (!aElement->IsHTMLElement()) {
return false;
}
return FragmentOrElement::IsHTMLVoid(aElement->NodeInfo()->NameAtom());
}
bool
nsContentUtils::SerializeNodeToMarkup(nsINode* aRoot,
bool aDescendentsOnly,
nsAString& aOut)
{
// If you pass in a DOCUMENT_NODE, you must pass aDescendentsOnly as true
MOZ_ASSERT(aDescendentsOnly ||
aRoot->NodeType() != nsIDOMNode::DOCUMENT_NODE);
nsINode* current = aDescendentsOnly ?
nsNodeUtils::GetFirstChildOfTemplateOrNode(aRoot) : 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 = nsNodeUtils::GetFirstChildOfTemplateOrNode(current))) {
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->IsHTMLElement() || elem->IsSVGElement() ||
elem->IsMathMLElement()) {
builder.Append(elem->NodeInfo()->NameAtom());
} 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->GetParentNode();
// Handle template element. If the parent is a template's content,
// then adjust the parent to be the template element.
if (current != aRoot &&
current->NodeType() == nsIDOMNode::DOCUMENT_FRAGMENT_NODE) {
DocumentFragment* frag = static_cast<DocumentFragment*>(current);
nsIContent* fragHost = frag->GetHost();
if (fragHost && nsNodeUtils::IsTemplateElement(fragHost)) {
current = fragHost;
}
}
if (aDescendentsOnly && current == aRoot) {
return builder.ToString(aOut);
}
}
}
}

Просмотреть файл

@ -2561,6 +2561,13 @@ public:
*/
static StorageAccess StorageAllowedForPrincipal(nsIPrincipal* aPrincipal);
/*
* Serializes a HTML nsINode into its markup representation.
*/
static bool SerializeNodeToMarkup(nsINode* aRoot,
bool aDescendentsOnly,
nsAString& aOut);
private:
static bool InitializeEventTable();

Просмотреть файл

@ -2311,16 +2311,11 @@ GetRequestBody(nsIDOMDocument* aDoc, nsIInputStream** aResult,
uint64_t* aContentLength, nsACString& aContentType,
nsACString& aCharset)
{
aContentType.AssignLiteral("application/xml");
nsCOMPtr<nsIDocument> doc(do_QueryInterface(aDoc));
NS_ENSURE_STATE(doc);
aCharset.AssignLiteral("UTF-8");
nsresult rv;
nsCOMPtr<nsIDOMSerializer> serializer =
do_CreateInstance(NS_XMLSERIALIZER_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIStorageStream> storStream;
rv = NS_NewStorageStream(4096, UINT32_MAX, getter_AddRefs(storStream));
NS_ENSURE_SUCCESS(rv, rv);
@ -2329,9 +2324,32 @@ GetRequestBody(nsIDOMDocument* aDoc, nsIInputStream** aResult,
rv = storStream->GetOutputStream(0, getter_AddRefs(output));
NS_ENSURE_SUCCESS(rv, rv);
// Make sure to use the encoding we'll send
rv = serializer->SerializeToStream(aDoc, output, aCharset);
NS_ENSURE_SUCCESS(rv, rv);
if (doc->IsHTMLDocument()) {
aContentType.AssignLiteral("text/html");
nsString serialized;
if (!nsContentUtils::SerializeNodeToMarkup(doc, true, serialized)) {
return NS_ERROR_OUT_OF_MEMORY;
}
NS_ConvertUTF16toUTF8 utf8Serialized(serialized);
uint32_t written;
rv = output->Write(utf8Serialized.get(), utf8Serialized.Length(), &written);
NS_ENSURE_SUCCESS(rv, rv);
MOZ_ASSERT(written == utf8Serialized.Length());
} else {
aContentType.AssignLiteral("application/xml");
nsCOMPtr<nsIDOMSerializer> serializer =
do_CreateInstance(NS_XMLSERIALIZER_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
// Make sure to use the encoding we'll send
rv = serializer->SerializeToStream(aDoc, output, aCharset);
NS_ENSURE_SUCCESS(rv, rv);
}
output->Close();

Просмотреть файл

@ -4848,6 +4848,9 @@ HTMLInputElement::ChooseDirectory(ErrorResult& aRv)
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return;
}
// Script can call this method directly, so even though we don't show the
// "Pick Folder..." button on platforms that don't have a directory picker
// we have to redirect to the file picker here.
InitFilePicker(
#if defined(ANDROID) || defined(MOZ_B2G)
// No native directory picker - redirect to plain file picker

Просмотреть файл

@ -113,8 +113,6 @@ public:
StaticRefPtr<MediaMemoryTracker> MediaMemoryTracker::sUniqueInstance;
#if defined(PR_LOGGING)
PRLogModuleInfo* gStateWatchingLog;
PRLogModuleInfo* gMozPromiseLog;
PRLogModuleInfo* gMediaTimerLog;
PRLogModuleInfo* gMediaSampleLog;
#endif

Просмотреть файл

@ -819,9 +819,8 @@ WebMTrackDemuxer::Seek(media::TimeUnit aTime)
// Check what time we actually seeked to.
if (mSamples.GetSize() > 0) {
RefPtr<MediaRawData> sample(mSamples.PopFront());
const RefPtr<MediaRawData>& sample = mSamples.First();
seekTime = media::TimeUnit::FromMicroseconds(sample->mTime);
mSamples.PushFront(sample);
}
SetNextKeyFrameTime();
@ -876,40 +875,40 @@ WebMTrackDemuxer::SetNextKeyFrameTime()
mNextKeyframeTime.reset();
MediaRawDataQueue skipSamplesQueue;
RefPtr<MediaRawData> sample;
bool foundKeyframe = false;
while (!foundKeyframe && mSamples.GetSize()) {
sample = mSamples.PopFront();
RefPtr<MediaRawData> sample = mSamples.PopFront();
if (sample->mKeyframe) {
frameTime = sample->mTime;
foundKeyframe = true;
}
skipSamplesQueue.Push(sample);
skipSamplesQueue.Push(sample.forget());
}
Maybe<int64_t> startTime;
if (skipSamplesQueue.GetSize()) {
sample = skipSamplesQueue.PopFront();
const RefPtr<MediaRawData>& sample = skipSamplesQueue.First();
startTime.emplace(sample->mTimecode);
skipSamplesQueue.PushFront(sample);
}
// Demux and buffer frames until we find a keyframe.
RefPtr<MediaRawData> sample;
while (!foundKeyframe && (sample = NextSample())) {
if (sample->mKeyframe) {
frameTime = sample->mTime;
foundKeyframe = true;
}
skipSamplesQueue.Push(sample);
int64_t sampleTimecode = sample->mTimecode;
skipSamplesQueue.Push(sample.forget());
if (!startTime) {
startTime.emplace(sample->mTimecode);
startTime.emplace(sampleTimecode);
} else if (!foundKeyframe &&
sample->mTimecode > startTime.ref() + MAX_LOOK_AHEAD) {
sampleTimecode > startTime.ref() + MAX_LOOK_AHEAD) {
WEBM_DEBUG("Couldn't find keyframe in a reasonable time, aborting");
break;
}
}
// We may have demuxed more than intended, so ensure that all frames are kept
// in the right order.
mSamples.PushFront(skipSamplesQueue);
mSamples.PushFront(Move(skipSamplesQueue));
if (frameTime != -1) {
mNextKeyframeTime.emplace(media::TimeUnit::FromMicroseconds(frameTime));
@ -972,7 +971,7 @@ WebMTrackDemuxer::SkipToNextRandomAccessPoint(media::TimeUnit aTimeThreshold)
if (sample->mKeyframe && sample->mTime >= aTimeThreshold.ToMicroseconds()) {
found = true;
mSamples.Reset();
mSamples.PushFront(sample);
mSamples.PushFront(sample.forget());
}
}
SetNextKeyFrameTime();

Просмотреть файл

@ -9,6 +9,7 @@
#include "nsTArray.h"
#include "MediaDataDemuxer.h"
#include "NesteggPacketHolder.h"
#include "mozilla/Move.h"
typedef struct nestegg nestegg;
@ -27,16 +28,22 @@ class MediaRawDataQueue {
mQueue.push_back(aItem);
}
void Push(const MediaRawDataQueue& aOther) {
mQueue.insert(mQueue.end(), aOther.mQueue.begin(), aOther.mQueue.end());
void Push(already_AddRefed<MediaRawData>&& aItem) {
mQueue.push_back(Move(aItem));
}
void PushFront(MediaRawData* aItem) {
mQueue.push_front(aItem);
}
void PushFront(const MediaRawDataQueue& aOther) {
mQueue.insert(mQueue.begin(), aOther.mQueue.begin(), aOther.mQueue.end());
void PushFront(already_AddRefed<MediaRawData>&& aItem) {
mQueue.push_front(Move(aItem));
}
void PushFront(MediaRawDataQueue&& aOther) {
while (!aOther.mQueue.empty()) {
Push(aOther.PopFront());
}
}
already_AddRefed<MediaRawData> PopFront() {

Просмотреть файл

@ -54,7 +54,7 @@ dictionary MozXMLHttpRequestParameters
// c = new(window.ActiveXObject || XMLHttpRequest)("Microsoft.XMLHTTP")
// To handle that, we need a constructor that takes a string.
Constructor(DOMString ignored),
Exposed=(Window,Worker)]
Exposed=(Window,DedicatedWorker,SharedWorker)]
interface XMLHttpRequest : XMLHttpRequestEventTarget {
// event handler
attribute EventHandler onreadystatechange;

Просмотреть файл

@ -10,7 +10,7 @@
* liability, trademark and document use rules apply.
*/
[Exposed=(Window,Worker)]
[Exposed=(Window,DedicatedWorker,SharedWorker)]
interface XMLHttpRequestEventTarget : EventTarget {
// event handlers
[SetterThrows=Workers, GetterThrows=Workers]

Просмотреть файл

@ -10,7 +10,7 @@
* liability, trademark and document use rules apply.
*/
[Exposed=(Window,Worker)]
[Exposed=(Window,DedicatedWorker,SharedWorker)]
interface XMLHttpRequestUpload : XMLHttpRequestEventTarget {
};

Просмотреть файл

@ -195,12 +195,6 @@ var interfaceNamesInGlobalScope =
"TextDecoder",
// IMPORTANT: Do not change this list without review from a DOM peer!
"TextEncoder",
// IMPORTANT: Do not change this list without review from a DOM peer!
"XMLHttpRequest",
// IMPORTANT: Do not change this list without review from a DOM peer!
"XMLHttpRequestEventTarget",
// IMPORTANT: Do not change this list without review from a DOM peer!
"XMLHttpRequestUpload",
// IMPORTANT: Do not change this list without review from a DOM peer!
"URL",
// IMPORTANT: Do not change this list without review from a DOM peer!

Просмотреть файл

@ -57,6 +57,21 @@ private:
bool mReneuter;
};
class MOZ_RAII SuppressedNeuteringRegion
{
public:
SuppressedNeuteringRegion(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM);
~SuppressedNeuteringRegion();
static inline bool IsNeuteringSuppressed() { return sSuppressNeutering; }
private:
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
bool mReenable;
static bool sSuppressNeutering;
};
} // namespace ipc
} // namespace mozilla

Просмотреть файл

@ -15,6 +15,7 @@
#include "nsServiceManagerUtils.h"
#include "nsString.h"
#include "nsIXULAppInfo.h"
#include "nsWindowsDllInterceptor.h"
#include "WinUtils.h"
#include "mozilla/ArrayUtils.h"
@ -436,6 +437,93 @@ ProcessOrDeferMessage(HWND hwnd,
return res;
}
/*
* It is bad to subclass a window when neutering is active because you'll end
* up subclassing the *neutered* window procedure instead of the real window
* procedure. Since CreateWindow* fires WM_CREATE (and could thus trigger
* neutering), we intercept these calls and suppress neutering for the duration
* of the call. This ensures that any subsequent subclassing replaces the
* correct window procedure.
*/
WindowsDllInterceptor sUser32Interceptor;
typedef HWND (WINAPI *CreateWindowExWPtr)(DWORD,LPCWSTR,LPCWSTR,DWORD,int,int,int,int,HWND,HMENU,HINSTANCE,LPVOID);
typedef HWND (WINAPI *CreateWindowExAPtr)(DWORD,LPCSTR,LPCSTR,DWORD,int,int,int,int,HWND,HMENU,HINSTANCE,LPVOID);
typedef HWND (WINAPI *CreateWindowWPtr)(LPCWSTR,LPCWSTR,DWORD,int,int,int,int,HWND,HMENU,HINSTANCE,LPVOID);
typedef HWND (WINAPI *CreateWindowAPtr)(LPCSTR,LPCSTR,DWORD,int,int,int,int,HWND,HMENU,HINSTANCE,LPVOID);
CreateWindowExWPtr sCreateWindowExWStub = nullptr;
CreateWindowExAPtr sCreateWindowExAStub = nullptr;
CreateWindowWPtr sCreateWindowWStub = nullptr;
CreateWindowAPtr sCreateWindowAStub = nullptr;
HWND WINAPI
CreateWindowExWHook(DWORD aExStyle, LPCWSTR aClassName, LPCWSTR aWindowName,
DWORD aStyle, int aX, int aY, int aWidth, int aHeight,
HWND aParent, HMENU aMenu, HINSTANCE aInstance,
LPVOID aParam)
{
SuppressedNeuteringRegion doNotNeuterThisWindowYet;
return sCreateWindowExWStub(aExStyle, aClassName, aWindowName, aStyle, aX, aY,
aWidth, aHeight, aParent, aMenu, aInstance, aParam);
}
HWND WINAPI
CreateWindowExAHook(DWORD aExStyle, LPCSTR aClassName, LPCSTR aWindowName,
DWORD aStyle, int aX, int aY, int aWidth, int aHeight,
HWND aParent, HMENU aMenu, HINSTANCE aInstance,
LPVOID aParam)
{
SuppressedNeuteringRegion doNotNeuterThisWindowYet;
return sCreateWindowExAStub(aExStyle, aClassName, aWindowName, aStyle, aX, aY,
aWidth, aHeight, aParent, aMenu, aInstance, aParam);
}
HWND WINAPI
CreateWindowWHook(LPCWSTR aClassName, LPCWSTR aWindowName, DWORD aStyle, int aX,
int aY, int aWidth, int aHeight, HWND aParent, HMENU aMenu,
HINSTANCE aInstance, LPVOID aParam)
{
SuppressedNeuteringRegion doNotNeuterThisWindowYet;
return sCreateWindowWStub(aClassName, aWindowName, aStyle, aX, aY, aWidth,
aHeight, aParent, aMenu, aInstance, aParam);
}
HWND WINAPI
CreateWindowAHook(LPCSTR aClassName, LPCSTR aWindowName, DWORD aStyle, int aX,
int aY, int aWidth, int aHeight, HWND aParent, HMENU aMenu,
HINSTANCE aInstance, LPVOID aParam)
{
SuppressedNeuteringRegion doNotNeuterThisWindowYet;
return sCreateWindowAStub(aClassName, aWindowName, aStyle, aX, aY, aWidth,
aHeight, aParent, aMenu, aInstance, aParam);
}
void
InitCreateWindowHook()
{
sUser32Interceptor.Init("user32.dll");
if (!sCreateWindowExWStub) {
sUser32Interceptor.AddHook("CreateWindowExW",
reinterpret_cast<intptr_t>(CreateWindowExWHook),
(void**) &sCreateWindowExWStub);
}
if (!sCreateWindowExAStub) {
sUser32Interceptor.AddHook("CreateWindowExA",
reinterpret_cast<intptr_t>(CreateWindowExAHook),
(void**) &sCreateWindowExAStub);
}
if (!sCreateWindowWStub) {
sUser32Interceptor.AddHook("CreateWindowW",
reinterpret_cast<intptr_t>(CreateWindowWHook),
(void**) &sCreateWindowWStub);
}
if (!sCreateWindowAStub) {
sUser32Interceptor.AddHook("CreateWindowA",
reinterpret_cast<intptr_t>(CreateWindowAHook),
(void**) &sCreateWindowAStub);
}
}
} // namespace
// We need the pointer value of this in PluginInstanceChild.
@ -610,7 +698,9 @@ CallWindowProcedureHook(int nCode,
HWND hWnd = reinterpret_cast<CWPSTRUCT*>(lParam)->hwnd;
if (!gNeuteredWindows->Contains(hWnd) && NeuterWindowProcedure(hWnd)) {
if (!gNeuteredWindows->Contains(hWnd) &&
!SuppressedNeuteringRegion::IsNeuteringSuppressed() &&
NeuterWindowProcedure(hWnd)) {
if (!gNeuteredWindows->AppendElement(hWnd)) {
NS_ERROR("Out of memory!");
RestoreWindowProcedure(hWnd);
@ -710,6 +800,8 @@ InitUIThread()
gCOMWindow = FindCOMWindow();
}
MOZ_ASSERT(gWinEventHook);
InitCreateWindowHook();
}
} // namespace windows
@ -943,6 +1035,26 @@ DeneuteredWindowRegion::~DeneuteredWindowRegion()
}
}
SuppressedNeuteringRegion::SuppressedNeuteringRegion(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL)
: mReenable(::gUIThreadId == ::GetCurrentThreadId() && ::gWindowHook)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
if (mReenable) {
MOZ_ASSERT(!sSuppressNeutering);
sSuppressNeutering = true;
}
}
SuppressedNeuteringRegion::~SuppressedNeuteringRegion()
{
if (mReenable) {
MOZ_ASSERT(sSuppressNeutering);
sSuppressNeutering = false;
}
}
bool SuppressedNeuteringRegion::sSuppressNeutering = false;
bool
MessageChannel::WaitForSyncNotify(bool aHandleWindowsMessages)
{
@ -997,6 +1109,8 @@ MessageChannel::WaitForSyncNotify(bool aHandleWindowsMessages)
NS_ASSERTION(timerId, "SetTimer failed!");
}
NeuteredWindowRegion neuteredRgn(true);
{
while (1) {
MSG msg = { 0 };

Просмотреть файл

@ -123,6 +123,11 @@ class ModuleCompiler
bool finishGeneratingFunction(AsmFunction& func, CodeGenerator& codegen,
const AsmJSFunctionLabels& labels)
{
// If we have hit OOM then invariants which we assert below may not
// hold, so abort now.
if (masm().oom())
return false;
// Code range
unsigned line = func.lineno();
unsigned column = func.column();

Просмотреть файл

@ -641,11 +641,8 @@ ArrayMetaTypeDescr::construct(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
if (!args.isConstructing()) {
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr,
JSMSG_NOT_FUNCTION, "ArrayType");
if (!ThrowIfNotConstructing(cx, args, "ArrayType"))
return false;
}
RootedObject arrayTypeGlobal(cx, &args.callee());
@ -998,11 +995,8 @@ StructMetaTypeDescr::construct(JSContext* cx, unsigned int argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
if (!args.isConstructing()) {
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr,
JSMSG_NOT_FUNCTION, "StructType");
if (!ThrowIfNotConstructing(cx, args, "StructType"))
return false;
}
if (args.length() >= 1 && args[0].isObject()) {
RootedObject metaTypeDescr(cx, &args.callee());

Просмотреть файл

@ -85,10 +85,8 @@ WeakSetObject::construct(JSContext* cx, unsigned argc, Value* vp)
// Based on our "Set" implementation instead of the more general ES6 steps.
CallArgs args = CallArgsFromVp(argc, vp);
if (!args.isConstructing()) {
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NOT_FUNCTION, "WeakSet");
if (!ThrowIfNotConstructing(cx, args, "WeakSet"))
return false;
}
if (!args.get(0).isNullOrUndefined()) {
RootedObject map(cx, &obj->getReservedSlot(WEAKSET_MAP_SLOT).toObject());

Просмотреть файл

@ -9,7 +9,7 @@ function evalWithCache(code, ctx) {
// We create a new global ...
if (!("global" in ctx))
ctx.global = newGlobal();
ctx.global = newGlobal({ cloneSingletons: true });
if (!("isRunOnce" in ctx))
ctx.isRunOnce = true;

Просмотреть файл

@ -8,6 +8,7 @@ test = (function () {
evalWithCache(test, {});
function evalWithCache(code, ctx) {
code = cacheEntry(code);
ctx.global = newGlobal({ cloneSingletons: true });
ctx.isRunOnce = true;
var res1 = evaluate(code, Object.create(ctx, {saveBytecode: { value: true } }));
var res2 = evaluate(code, Object.create(ctx, {loadBytecode: { value: true }, saveBytecode: { value: true } }));

Просмотреть файл

@ -6,6 +6,7 @@ test = (function () {
evalWithCache(test, {});
function evalWithCache(code, ctx) {
code = cacheEntry(code);
ctx.global = newGlobal({ cloneSingletons: true });
var res1 = evaluate(code, Object.create(ctx, {saveBytecode: { value: true } }));
}
if (typeof assertThrowsInstanceOf === 'undefined') {

Просмотреть файл

@ -5,7 +5,7 @@ gczeal(2);
(function() {
evaluate(cacheEntry((function() {
return "".toSource()
})()), Object.create({}, {
})()), Object.create({ global: newGlobal({ cloneSingletons: true }) }, {
saveBytecode: {
value: true
}

Просмотреть файл

@ -0,0 +1,9 @@
var caught = false;
try {
evaluate(cacheEntry(""), {saveBytecode: {value: true}, global: this});
[[0]];
} catch (err) {
caught = true;
assertEq(err.message, "compartment cannot save singleton anymore.");
}
assertEq(caught, true);

Просмотреть файл

@ -150,7 +150,7 @@ test = `
evalWithCache(test, { assertEqBytecode: true, assertEqResult: true });
// And more of the same, in a slightly different way
var g1 = newGlobal();
var g1 = newGlobal({ cloneSingletons: true });
var g2 = newGlobal();
var res = "function f(){}";
var code = cacheEntry(res + "; f();");

Просмотреть файл

@ -2179,7 +2179,7 @@ Assembler::as_BranchPool(uint32_t value, RepatchLabel* label, ARMBuffer::PoolEnt
if (label->bound()) {
BufferOffset dest(label);
as_b(dest.diffB<BOffImm>(ret), c, ret);
} else {
} else if (!oom()) {
label->use(ret.getOffset());
}
#ifdef JS_DISASM_ARM
@ -2379,14 +2379,12 @@ Assembler::as_b(BOffImm off, Condition c, Label* documentation)
BufferOffset
Assembler::as_b(Label* l, Condition c)
{
if (m_buffer.oom()) {
BufferOffset ret;
return ret;
}
if (l->bound()) {
// Note only one instruction is emitted here, the NOP is overwritten.
BufferOffset ret = allocBranchInst();
if (oom())
return BufferOffset();
as_b(BufferOffset(l).diffB<BOffImm>(ret), c, ret);
#ifdef JS_DISASM_ARM
spewBranch(m_buffer.getInstOrNull(ret), l);
@ -2394,6 +2392,9 @@ Assembler::as_b(Label* l, Condition c)
return ret;
}
if (oom())
return BufferOffset();
int32_t old;
BufferOffset ret;
if (l->used()) {
@ -2410,6 +2411,10 @@ Assembler::as_b(Label* l, Condition c)
BOffImm inv;
ret = as_b(inv, c, l);
}
if (oom())
return BufferOffset();
DebugOnly<int32_t> check = l->use(ret.getOffset());
MOZ_ASSERT(check == old);
return ret;
@ -2446,14 +2451,12 @@ Assembler::as_bl(BOffImm off, Condition c, Label* documentation)
BufferOffset
Assembler::as_bl(Label* l, Condition c)
{
if (m_buffer.oom()) {
BufferOffset ret;
return ret;
}
if (l->bound()) {
// Note only one instruction is emitted here, the NOP is overwritten.
BufferOffset ret = allocBranchInst();
if (oom())
return BufferOffset();
as_bl(BufferOffset(l).diffB<BOffImm>(ret), c, ret);
#ifdef JS_DISASM_ARM
spewBranch(m_buffer.getInstOrNull(ret), l);
@ -2461,6 +2464,9 @@ Assembler::as_bl(Label* l, Condition c)
return ret;
}
if (oom())
return BufferOffset();
int32_t old;
BufferOffset ret;
// See if the list was empty :(
@ -2478,6 +2484,10 @@ Assembler::as_bl(Label* l, Condition c)
BOffImm inv;
ret = as_bl(inv, c, l);
}
if (oom())
return BufferOffset();
DebugOnly<int32_t> check = l->use(ret.getOffset());
MOZ_ASSERT(check == old);
return ret;

Просмотреть файл

@ -152,8 +152,13 @@ class AssemblerBuffer
bool ensureSpace(int size) {
// Space can exist in the most recent Slice.
if (tail && tail->length() + size <= tail->Capacity())
if (tail && tail->length() + size <= tail->Capacity()) {
// Simulate allocation failure even when we don't need a new slice.
if (js::oom::ShouldFailWithOOM())
return fail_oom();
return true;
}
// Otherwise, a new Slice must be added.
Slice* slice = newSlice(lifoAlloc_);

Просмотреть файл

@ -704,6 +704,8 @@ struct AssemblerBufferWithConstantPools : public AssemblerBuffer<SliceSize, Inst
// Mark and emit the guard branch.
markNextAsBranch();
this->putBytes(guardSize_ * InstSize, nullptr);
if (this->oom())
return;
BufferOffset afterPool = this->nextOffset();
Asm::WritePoolGuard(branch, this->getInst(branch), afterPool);
@ -864,7 +866,7 @@ struct AssemblerBufferWithConstantPools : public AssemblerBuffer<SliceSize, Inst
}
inhibitNops_ = true;
while (sizeExcludingCurrentPool() & (alignment - 1))
while ((sizeExcludingCurrentPool() & (alignment - 1)) && !this->oom())
putInt(alignFillInst_);
inhibitNops_ = false;
}

Просмотреть файл

@ -77,8 +77,7 @@ MSG_DEF(JSMSG_BAD_SURROGATE_CHAR, 1, JSEXN_TYPEERR, "bad surrogate characte
MSG_DEF(JSMSG_UTF8_CHAR_TOO_LARGE, 1, JSEXN_TYPEERR, "UTF-8 character {0} too large")
MSG_DEF(JSMSG_MALFORMED_UTF8_CHAR, 1, JSEXN_TYPEERR, "malformed UTF-8 character sequence at offset {0}")
MSG_DEF(JSMSG_WRONG_CONSTRUCTOR, 1, JSEXN_TYPEERR, "wrong constructor called for {0}")
MSG_DEF(JSMSG_BUILTIN_CTOR_NO_NEW, 1, JSEXN_NONE, "calling a builtin {0} constructor without new is deprecated and will be forbidden in ES6")
MSG_DEF(JSMSG_BUILTIN_CTOR_NO_NEW_FATAL, 1, JSEXN_TYPEERR, "calling a builtin {0} constructor without new is forbidden")
MSG_DEF(JSMSG_BUILTIN_CTOR_NO_NEW, 1, JSEXN_TYPEERR, "calling a builtin {0} constructor without new is forbidden")
MSG_DEF(JSMSG_PROTO_SETTING_SLOW, 0, JSEXN_NONE, "mutating the [[Prototype]] of an object will cause your code to run very slowly; instead create the object with the correct initial [[Prototype]] value using Object.create")
MSG_DEF(JSMSG_BAD_GENERATOR_YIELD, 1, JSEXN_TYPEERR, "yield from closing generator {0}")
MSG_DEF(JSMSG_EMPTY_ARRAY_REDUCE, 0, JSEXN_TYPEERR, "reduce of empty array with no initial value")

Просмотреть файл

@ -1242,10 +1242,8 @@ js::proxy(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
if (!args.isConstructing()) {
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NOT_FUNCTION, "Proxy");
if (!ThrowIfNotConstructing(cx, args, "Proxy"))
return false;
}
return NewScriptedProxy(cx, args, "Proxy");
}

Просмотреть файл

@ -1245,12 +1245,14 @@ Evaluate(JSContext* cx, unsigned argc, Value* vp)
{
if (saveBytecode) {
if (!JS::CompartmentOptionsRef(cx).getSingletonsAsTemplates()) {
if (!JS::CompartmentOptionsRef(cx).cloneSingletons()) {
JS_ReportErrorNumber(cx, my_GetErrorMessage, nullptr,
JSSMSG_CACHE_SINGLETON_FAILED);
return false;
}
JS::CompartmentOptionsRef(cx).setCloneSingletons(true);
// cloneSingletons implies that singletons are used as template objects.
MOZ_ASSERT(JS::CompartmentOptionsRef(cx).getSingletonsAsTemplates());
}
if (loadBytecode) {
@ -3805,6 +3807,11 @@ NewGlobal(JSContext* cx, unsigned argc, Value* vp)
if (v.isBoolean())
options.setInvisibleToDebugger(v.toBoolean());
if (!JS_GetProperty(cx, opts, "cloneSingletons", &v))
return false;
if (v.isBoolean())
options.setCloneSingletons(v.toBoolean());
if (!JS_GetProperty(cx, opts, "principal", &v))
return false;
if (!v.isUndefined()) {

Просмотреть файл

@ -589,7 +589,7 @@ ThrowIfNotConstructing(JSContext *cx, const CallArgs &args, const char *builtinN
if (args.isConstructing())
return true;
return JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, GetErrorMessage, nullptr,
JSMSG_BUILTIN_CTOR_NO_NEW_FATAL, builtinName);
JSMSG_BUILTIN_CTOR_NO_NEW, builtinName);
}
} // namespace js

Просмотреть файл

@ -29,11 +29,11 @@ namespace js {
*
* https://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/Bytecode
*/
static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 313;
static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 314;
static const uint32_t XDR_BYTECODE_VERSION =
uint32_t(0xb973c0de - XDR_BYTECODE_VERSION_SUBTRAHEND);
static_assert(JSErr_Limit == 419,
static_assert(JSErr_Limit == 418,
"GREETINGS, POTENTIAL SUBTRAHEND INCREMENTER! If you added or "
"removed MSG_DEFs from js.msg, you should increment "
"XDR_BYTECODE_VERSION_SUBTRAHEND and update this assertion's "

Просмотреть файл

@ -1254,6 +1254,8 @@ XRE_XPCShellMain(int argc, char** argv, char** envp)
NS_LogInit();
mozilla::LogModule::Init();
// A initializer to initialize histogram collection
// used by telemetry.
UniquePtr<base::StatisticsRecorder> telStats =

Просмотреть файл

@ -127,9 +127,14 @@ nsFileControlFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
{
nsCOMPtr<nsIDocument> doc = mContent->GetComposedDoc();
#if defined(ANDROID) || defined(MOZ_B2G)
bool isDirPicker = false;
#else
nsIContent* content = GetContent();
bool isDirPicker = Preferences::GetBool("dom.input.dirpicker", false) &&
content && content->HasAttr(kNameSpaceID_None, nsGkAtoms::directory);
bool isDirPicker =
Preferences::GetBool("dom.input.dirpicker", false) &&
content && content->HasAttr(kNameSpaceID_None, nsGkAtoms::directory);
#endif
RefPtr<HTMLInputElement> fileContent = HTMLInputElement::FromContentOrNull(mContent);

Просмотреть файл

@ -72,7 +72,6 @@
'./src/mediapipeline',
'./src/peerconnection',
'./src/sdp/sipcc',
'../../../xpcom/base',
'../../../dom/base',
'../../../dom/media',
'../../../media/mtransport',

Просмотреть файл

@ -23,7 +23,7 @@
#include "nsIObserverService.h"
#include "nsIObserver.h"
#include "mozilla/Services.h"
#include "StaticPtr.h"
#include "mozilla/StaticPtr.h"
#include "gmp-video-decode.h" // GMP_API_VIDEO_DECODER
#include "gmp-video-encode.h" // GMP_API_VIDEO_ENCODER

Просмотреть файл

@ -12,7 +12,7 @@
#endif
#include "mozilla/Attributes.h"
#include "StaticPtr.h"
#include "mozilla/StaticPtr.h"
#include "PeerConnectionImpl.h"
#include "mozIGeckoMediaPluginService.h"
#include "nsIRunnable.h"

30
netwerk/base/ARefBase.h Normal file
Просмотреть файл

@ -0,0 +1,30 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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_ARefBase_h
#define mozilla_net_ARefBase_h
namespace mozilla { namespace net {
// This is an abstract class that can be pointed to by either
// nsCOMPtr or nsRefPtr. nsHttpConnectionMgr uses it for generic
// objects that need to be reference counted - similiar to nsISupports
// but it may or may not be xpcom.
class ARefBase
{
public:
ARefBase() {}
virtual ~ARefBase() {}
NS_IMETHOD_ (MozExternalRefCountType) AddRef() = 0;
NS_IMETHOD_ (MozExternalRefCountType) Release() = 0;
};
} // namespace net
} // namespace mozilla
#endif

Просмотреть файл

@ -90,7 +90,6 @@ EventTokenBucket::EventTokenBucket(uint32_t eventsPerSecond,
, mFineGrainResetTimerArmed(false)
#endif
{
MOZ_COUNT_CTOR(EventTokenBucket);
mLastUpdate = TimeStamp::Now();
MOZ_ASSERT(NS_IsMainThread());
@ -112,7 +111,6 @@ EventTokenBucket::~EventTokenBucket()
SOCKET_LOG(("EventTokenBucket::dtor %p events=%d\n",
this, mEvents.GetSize()));
MOZ_COUNT_DTOR(EventTokenBucket);
if (mTimer && mTimerArmed)
mTimer->Cancel();

Просмотреть файл

@ -7,6 +7,7 @@
#ifndef NetEventTokenBucket_h__
#define NetEventTokenBucket_h__
#include "ARefBase.h"
#include "nsCOMPtr.h"
#include "nsDeque.h"
#include "nsITimer.h"
@ -59,7 +60,7 @@ namespace net {
class EventTokenBucket;
class ATokenBucketEvent
class ATokenBucketEvent
{
public:
virtual void OnTokenBucketAdmitted() = 0;
@ -67,10 +68,8 @@ public:
class TokenBucketCancelable;
class EventTokenBucket : public nsITimerCallback
class EventTokenBucket : public nsITimerCallback, public ARefBase
{
virtual ~EventTokenBucket();
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSITIMERCALLBACK
@ -93,6 +92,8 @@ public:
nsresult SubmitEvent(ATokenBucketEvent *event, nsICancelable **cancelable);
private:
virtual ~EventTokenBucket();
friend class RunNotifyEvent;
friend class SetTimerEvent;

Просмотреть файл

@ -28,7 +28,7 @@ nsHttpConnectionMgr::PrintDiagnostics()
}
void
nsHttpConnectionMgr::OnMsgPrintDiagnostics(int32_t, void *)
nsHttpConnectionMgr::OnMsgPrintDiagnostics(int32_t, ARefBase *)
{
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);

Просмотреть файл

@ -14,6 +14,7 @@
#include "prinrval.h"
#include "TunnelUtils.h"
#include "mozilla/Mutex.h"
#include "ARefBase.h"
#include "nsIAsyncInputStream.h"
#include "nsIAsyncOutputStream.h"
@ -43,6 +44,7 @@ class nsHttpConnection final : public nsAHttpSegmentReader
, public nsITransportEventSink
, public nsIInterfaceRequestor
, public NudgeTunnelCallback
, public ARefBase
{
virtual ~nsHttpConnection();

Просмотреть файл

@ -12,6 +12,7 @@
#include "nsCOMPtr.h"
#include "nsStringFwd.h"
#include "mozilla/Logging.h"
#include "ARefBase.h"
extern PRLogModuleInfo *gHttpLog;
@ -30,7 +31,7 @@ extern PRLogModuleInfo *gHttpLog;
namespace mozilla { namespace net {
class nsHttpConnectionInfo
class nsHttpConnectionInfo: public ARefBase
{
public:
nsHttpConnectionInfo(const nsACString &originHost,
@ -162,7 +163,7 @@ private:
bool mUsingConnect; // if will use CONNECT with http proxy
nsCString mNPNToken;
// for nsRefPtr
// for RefPtr
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(nsHttpConnectionInfo)
};

Просмотреть файл

@ -147,12 +147,25 @@ nsHttpConnectionMgr::Init(uint16_t maxConns,
return EnsureSocketThreadTarget();
}
class BoolWrapper : public ARefBase
{
public:
BoolWrapper() : mBool(false) {}
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(BoolWrapper)
public: // intentional!
bool mBool;
private:
virtual ~BoolWrapper() {}
};
nsresult
nsHttpConnectionMgr::Shutdown()
{
LOG(("nsHttpConnectionMgr::Shutdown\n"));
bool shutdown = false;
RefPtr<BoolWrapper> shutdownWrapper = new BoolWrapper();
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
@ -161,7 +174,7 @@ nsHttpConnectionMgr::Shutdown()
return NS_OK;
nsresult rv = PostEvent(&nsHttpConnectionMgr::OnMsgShutdown,
0, &shutdown);
0, shutdownWrapper);
// release our reference to the STS to prevent further events
// from being posted. this is how we indicate that we are
@ -176,14 +189,41 @@ nsHttpConnectionMgr::Shutdown()
}
// wait for shutdown event to complete
while (!shutdown)
while (!shutdownWrapper->mBool) {
NS_ProcessNextEvent(NS_GetCurrentThread());
}
return NS_OK;
}
class ConnEvent : public nsRunnable
{
public:
ConnEvent(nsHttpConnectionMgr *mgr,
nsConnEventHandler handler, int32_t iparam, ARefBase *vparam)
: mMgr(mgr)
, mHandler(handler)
, mIParam(iparam)
, mVParam(vparam) {}
NS_IMETHOD Run()
{
(mMgr->*mHandler)(mIParam, mVParam);
return NS_OK;
}
private:
virtual ~ConnEvent() {}
RefPtr<nsHttpConnectionMgr> mMgr;
nsConnEventHandler mHandler;
int32_t mIParam;
RefPtr<ARefBase> mVParam;
};
nsresult
nsHttpConnectionMgr::PostEvent(nsConnEventHandler handler, int32_t iparam, void *vparam)
nsHttpConnectionMgr::PostEvent(nsConnEventHandler handler,
int32_t iparam, ARefBase *vparam)
{
EnsureSocketThreadTarget();
@ -195,7 +235,7 @@ nsHttpConnectionMgr::PostEvent(nsConnEventHandler handler, int32_t iparam, void
rv = NS_ERROR_NOT_INITIALIZED;
}
else {
nsCOMPtr<nsIRunnable> event = new nsConnEvent(this, handler, iparam, vparam);
nsCOMPtr<nsIRunnable> event = new ConnEvent(this, handler, iparam, vparam);
rv = mSocketThreadTarget->Dispatch(event, NS_DISPATCH_NORMAL);
}
return rv;
@ -293,37 +333,22 @@ nsresult
nsHttpConnectionMgr::AddTransaction(nsHttpTransaction *trans, int32_t priority)
{
LOG(("nsHttpConnectionMgr::AddTransaction [trans=%p %d]\n", trans, priority));
NS_ADDREF(trans);
nsresult rv = PostEvent(&nsHttpConnectionMgr::OnMsgNewTransaction, priority, trans);
if (NS_FAILED(rv))
NS_RELEASE(trans);
return rv;
return PostEvent(&nsHttpConnectionMgr::OnMsgNewTransaction, priority, trans);
}
nsresult
nsHttpConnectionMgr::RescheduleTransaction(nsHttpTransaction *trans, int32_t priority)
{
LOG(("nsHttpConnectionMgr::RescheduleTransaction [trans=%p %d]\n", trans, priority));
NS_ADDREF(trans);
nsresult rv = PostEvent(&nsHttpConnectionMgr::OnMsgReschedTransaction, priority, trans);
if (NS_FAILED(rv))
NS_RELEASE(trans);
return rv;
return PostEvent(&nsHttpConnectionMgr::OnMsgReschedTransaction, priority, trans);
}
nsresult
nsHttpConnectionMgr::CancelTransaction(nsHttpTransaction *trans, nsresult reason)
{
LOG(("nsHttpConnectionMgr::CancelTransaction [trans=%p reason=%x]\n", trans, reason));
NS_ADDREF(trans);
nsresult rv = PostEvent(&nsHttpConnectionMgr::OnMsgCancelTransaction,
static_cast<int32_t>(reason), trans);
if (NS_FAILED(rv))
NS_RELEASE(trans);
return rv;
return PostEvent(&nsHttpConnectionMgr::OnMsgCancelTransaction,
static_cast<int32_t>(reason), trans);
}
nsresult
@ -350,30 +375,18 @@ nsHttpConnectionMgr::VerifyTraffic()
return PostEvent(&nsHttpConnectionMgr::OnMsgVerifyTraffic);
}
nsresult
nsHttpConnectionMgr::DoShiftReloadConnectionCleanup(nsHttpConnectionInfo *aCI)
{
RefPtr<nsHttpConnectionInfo> connInfo(aCI);
nsresult rv = PostEvent(&nsHttpConnectionMgr::OnMsgDoShiftReloadConnectionCleanup,
0, connInfo);
if (NS_SUCCEEDED(rv))
unused << connInfo.forget();
return rv;
return PostEvent(&nsHttpConnectionMgr::OnMsgDoShiftReloadConnectionCleanup,
0, aCI);
}
class SpeculativeConnectArgs
class SpeculativeConnectArgs : public ARefBase
{
virtual ~SpeculativeConnectArgs() {}
public:
SpeculativeConnectArgs() { mOverridesOK = false; }
// Added manually so we can use nsRefPtr without inheriting from
// nsISupports
NS_IMETHOD_(MozExternalRefCountType) AddRef(void);
NS_IMETHOD_(MozExternalRefCountType) Release(void);
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SpeculativeConnectArgs)
public: // intentional!
RefPtr<NullHttpTransaction> mTrans;
@ -385,16 +398,11 @@ public: // intentional!
bool mIsFromPredictor;
bool mAllow1918;
// As above, added manually so we can use nsRefPtr without inheriting from
// nsISupports
protected:
ThreadSafeAutoRefCnt mRefCnt;
private:
virtual ~SpeculativeConnectArgs() {}
NS_DECL_OWNINGTHREAD
};
NS_IMPL_ADDREF(SpeculativeConnectArgs)
NS_IMPL_RELEASE(SpeculativeConnectArgs)
nsresult
nsHttpConnectionMgr::SpeculativeConnect(nsHttpConnectionInfo *ci,
nsIInterfaceRequestor *callbacks,
@ -444,11 +452,7 @@ nsHttpConnectionMgr::SpeculativeConnect(nsHttpConnectionInfo *ci,
overrider->GetAllow1918(&args->mAllow1918);
}
nsresult rv =
PostEvent(&nsHttpConnectionMgr::OnMsgSpeculativeConnect, 0, args);
if (NS_SUCCEEDED(rv))
unused << args.forget();
return rv;
return PostEvent(&nsHttpConnectionMgr::OnMsgSpeculativeConnect, 0, args);
}
nsresult
@ -465,58 +469,49 @@ nsresult
nsHttpConnectionMgr::ReclaimConnection(nsHttpConnection *conn)
{
LOG(("nsHttpConnectionMgr::ReclaimConnection [conn=%p]\n", conn));
NS_ADDREF(conn);
nsresult rv = PostEvent(&nsHttpConnectionMgr::OnMsgReclaimConnection, 0, conn);
if (NS_FAILED(rv))
NS_RELEASE(conn);
return rv;
return PostEvent(&nsHttpConnectionMgr::OnMsgReclaimConnection, 0, conn);
}
// A structure used to marshall 2 pointers across the various necessary
// threads to complete an HTTP upgrade.
class nsCompleteUpgradeData
class nsCompleteUpgradeData : public ARefBase
{
public:
nsCompleteUpgradeData(nsAHttpConnection *aConn,
nsIHttpUpgradeListener *aListener)
: mConn(aConn), mUpgradeListener(aListener) {}
nsCompleteUpgradeData(nsAHttpConnection *aConn,
nsIHttpUpgradeListener *aListener)
: mConn(aConn)
, mUpgradeListener(aListener) { }
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(nsCompleteUpgradeData)
RefPtr<nsAHttpConnection> mConn;
nsCOMPtr<nsIHttpUpgradeListener> mUpgradeListener;
private:
virtual ~nsCompleteUpgradeData() { }
};
nsresult
nsHttpConnectionMgr::CompleteUpgrade(nsAHttpConnection *aConn,
nsIHttpUpgradeListener *aUpgradeListener)
{
nsCompleteUpgradeData *data =
RefPtr<nsCompleteUpgradeData> data =
new nsCompleteUpgradeData(aConn, aUpgradeListener);
nsresult rv;
rv = PostEvent(&nsHttpConnectionMgr::OnMsgCompleteUpgrade, 0, data);
if (NS_FAILED(rv))
delete data;
return rv;
return PostEvent(&nsHttpConnectionMgr::OnMsgCompleteUpgrade, 0, data);
}
nsresult
nsHttpConnectionMgr::UpdateParam(nsParamName name, uint16_t value)
{
uint32_t param = (uint32_t(name) << 16) | uint32_t(value);
return PostEvent(&nsHttpConnectionMgr::OnMsgUpdateParam, 0,
(void *)(uintptr_t) param);
return PostEvent(&nsHttpConnectionMgr::OnMsgUpdateParam,
static_cast<int32_t>(param), nullptr);
}
nsresult
nsHttpConnectionMgr::ProcessPendingQ(nsHttpConnectionInfo *ci)
{
LOG(("nsHttpConnectionMgr::ProcessPendingQ [ci=%s]\n", ci->HashKey().get()));
NS_ADDREF(ci);
nsresult rv = PostEvent(&nsHttpConnectionMgr::OnMsgProcessPendingQ, 0, ci);
if (NS_FAILED(rv))
NS_RELEASE(ci);
return rv;
return PostEvent(&nsHttpConnectionMgr::OnMsgProcessPendingQ, 0, ci);
}
nsresult
@ -527,25 +522,19 @@ nsHttpConnectionMgr::ProcessPendingQ()
}
void
nsHttpConnectionMgr::OnMsgUpdateRequestTokenBucket(int32_t, void *param)
nsHttpConnectionMgr::OnMsgUpdateRequestTokenBucket(int32_t, ARefBase *param)
{
RefPtr<EventTokenBucket> tokenBucket =
dont_AddRef(static_cast<EventTokenBucket *>(param));
EventTokenBucket *tokenBucket = static_cast<EventTokenBucket *>(param);
gHttpHandler->SetRequestTokenBucket(tokenBucket);
}
nsresult
nsHttpConnectionMgr::UpdateRequestTokenBucket(EventTokenBucket *aBucket)
{
RefPtr<EventTokenBucket> bucket(aBucket);
// Call From main thread when a new EventTokenBucket has been made in order
// to post the new value to the socket thread.
nsresult rv = PostEvent(&nsHttpConnectionMgr::OnMsgUpdateRequestTokenBucket,
0, bucket);
if (NS_SUCCEEDED(rv))
unused << bucket.forget();
return rv;
return PostEvent(&nsHttpConnectionMgr::OnMsgUpdateRequestTokenBucket,
0, aBucket);
}
PLDHashOperator
@ -1196,7 +1185,7 @@ nsHttpConnectionMgr::SupportsPipelining(nsHttpConnectionInfo *ci)
// nsHttpPipelineFeedback used to hold references across events
class nsHttpPipelineFeedback
class nsHttpPipelineFeedback : public ARefBase
{
public:
nsHttpPipelineFeedback(nsHttpConnectionInfo *ci,
@ -1209,14 +1198,14 @@ public:
{
}
~nsHttpPipelineFeedback()
{
}
RefPtr<nsHttpConnectionInfo> mConnInfo;
RefPtr<nsHttpConnection> mConn;
nsHttpConnectionMgr::PipelineFeedbackInfoType mInfo;
uint32_t mData;
private:
~nsHttpPipelineFeedback() {}
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(nsHttpPipelineFeedback)
};
void
@ -1230,18 +1219,13 @@ nsHttpConnectionMgr::PipelineFeedbackInfo(nsHttpConnectionInfo *ci,
// Post this to the socket thread if we are not running there already
if (PR_GetCurrentThread() != gSocketThread) {
nsHttpPipelineFeedback *fb = new nsHttpPipelineFeedback(ci, info,
conn, data);
nsresult rv = PostEvent(&nsHttpConnectionMgr::OnMsgProcessFeedback,
0, fb);
if (NS_FAILED(rv))
delete fb;
RefPtr<nsHttpPipelineFeedback> fb =
new nsHttpPipelineFeedback(ci, info, conn, data);
PostEvent(&nsHttpConnectionMgr::OnMsgProcessFeedback, 0, fb);
return;
}
nsConnectionEntry *ent = mCT.Get(ci->HashKey());
if (ent)
ent->OnPipelineFeedbackInfo(info, conn, data);
}
@ -1924,6 +1908,44 @@ nsHttpConnectionMgr::DispatchTransaction(nsConnectionEntry *ent,
return rv;
}
//-----------------------------------------------------------------------------
// ConnectionHandle
//
// thin wrapper around a real connection, used to keep track of references
// to the connection to determine when the connection may be reused. the
// transaction (or pipeline) owns a reference to this handle. this extra
// layer of indirection greatly simplifies consumer code, avoiding the
// need for consumer code to know when to give the connection back to the
// connection manager.
//
class ConnectionHandle : public nsAHttpConnection
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSAHTTPCONNECTION(mConn)
explicit ConnectionHandle(nsHttpConnection *conn) { NS_ADDREF(mConn = conn); }
nsHttpConnection *mConn;
private:
virtual ~ConnectionHandle();
};
nsAHttpConnection *
nsHttpConnectionMgr::MakeConnectionHandle(nsHttpConnection *aWrapped)
{
return new ConnectionHandle(aWrapped);
}
ConnectionHandle::~ConnectionHandle()
{
if (mConn) {
gHttpHandler->ReclaimConnection(mConn);
NS_RELEASE(mConn);
}
}
NS_IMPL_ISUPPORTS0(ConnectionHandle)
// Use this method for dispatching nsAHttpTransction's. It can only safely be
// used upon first use of a connection when NPN has not negotiated SPDY vs
@ -1963,7 +1985,7 @@ nsHttpConnectionMgr::DispatchAbstractTransaction(nsConnectionEntry *ent,
transaction = aTrans;
}
RefPtr<nsConnectionHandle> handle = new nsConnectionHandle(conn);
RefPtr<ConnectionHandle> handle = new ConnectionHandle(conn);
// give the transaction the indirect reference to the connection.
transaction->SetConnection(handle);
@ -2253,7 +2275,7 @@ nsHttpConnectionMgr::ProcessSpdyPendingQCB(const nsACString &key,
}
void
nsHttpConnectionMgr::OnMsgProcessAllSpdyPendingQ(int32_t, void *)
nsHttpConnectionMgr::OnMsgProcessAllSpdyPendingQ(int32_t, ARefBase *)
{
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
LOG(("nsHttpConnectionMgr::OnMsgProcessAllSpdyPendingQ\n"));
@ -2294,7 +2316,7 @@ nsHttpConnectionMgr::GetSpdyPreferredConn(nsConnectionEntry *ent)
//-----------------------------------------------------------------------------
void
nsHttpConnectionMgr::OnMsgShutdown(int32_t, void *param)
nsHttpConnectionMgr::OnMsgShutdown(int32_t, ARefBase *param)
{
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
LOG(("nsHttpConnectionMgr::OnMsgShutdown\n"));
@ -2317,41 +2339,40 @@ nsHttpConnectionMgr::OnMsgShutdown(int32_t, void *param)
// signal shutdown complete
nsCOMPtr<nsIRunnable> runnable =
new nsConnEvent(this, &nsHttpConnectionMgr::OnMsgShutdownConfirm,
0, param);
new ConnEvent(this, &nsHttpConnectionMgr::OnMsgShutdownConfirm,
0, param);
NS_DispatchToMainThread(runnable);
}
void
nsHttpConnectionMgr::OnMsgShutdownConfirm(int32_t priority, void *param)
nsHttpConnectionMgr::OnMsgShutdownConfirm(int32_t priority, ARefBase *param)
{
MOZ_ASSERT(NS_IsMainThread());
LOG(("nsHttpConnectionMgr::OnMsgShutdownConfirm\n"));
bool *shutdown = static_cast<bool*>(param);
*shutdown = true;
BoolWrapper *shutdown = static_cast<BoolWrapper *>(param);
shutdown->mBool = true;
}
void
nsHttpConnectionMgr::OnMsgNewTransaction(int32_t priority, void *param)
nsHttpConnectionMgr::OnMsgNewTransaction(int32_t priority, ARefBase *param)
{
LOG(("nsHttpConnectionMgr::OnMsgNewTransaction [trans=%p]\n", param));
nsHttpTransaction *trans = (nsHttpTransaction *) param;
nsHttpTransaction *trans = static_cast<nsHttpTransaction *>(param);
trans->SetPriority(priority);
nsresult rv = ProcessNewTransaction(trans);
if (NS_FAILED(rv))
trans->Close(rv); // for whatever its worth
NS_RELEASE(trans);
}
void
nsHttpConnectionMgr::OnMsgReschedTransaction(int32_t priority, void *param)
nsHttpConnectionMgr::OnMsgReschedTransaction(int32_t priority, ARefBase *param)
{
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
LOG(("nsHttpConnectionMgr::OnMsgReschedTransaction [trans=%p]\n", param));
nsHttpTransaction *trans = (nsHttpTransaction *) param;
nsHttpTransaction *trans = static_cast<nsHttpTransaction *>(param);
trans->SetPriority(priority);
nsConnectionEntry *ent = LookupConnectionEntry(trans->ConnectionInfo(),
@ -2364,19 +2385,16 @@ nsHttpConnectionMgr::OnMsgReschedTransaction(int32_t priority, void *param)
InsertTransactionSorted(ent->mPendingQ, trans);
}
}
NS_RELEASE(trans);
}
void
nsHttpConnectionMgr::OnMsgCancelTransaction(int32_t reason, void *param)
nsHttpConnectionMgr::OnMsgCancelTransaction(int32_t reason, ARefBase *param)
{
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
LOG(("nsHttpConnectionMgr::OnMsgCancelTransaction [trans=%p]\n", param));
nsresult closeCode = static_cast<nsresult>(reason);
RefPtr<nsHttpTransaction> trans =
dont_AddRef(static_cast<nsHttpTransaction *>(param));
nsHttpTransaction *trans = static_cast<nsHttpTransaction *>(param);
//
// if the transaction owns a connection and the transaction is not done,
@ -2394,7 +2412,7 @@ nsHttpConnectionMgr::OnMsgCancelTransaction(int32_t reason, void *param)
int32_t index = ent->mPendingQ.IndexOf(trans);
if (index >= 0) {
LOG(("nsHttpConnectionMgr::OnMsgCancelTransaction [trans=%p]"
" found in pending queue\n", trans.get()));
" found in pending queue\n", trans));
ent->mPendingQ.RemoveElementAt(index);
nsHttpTransaction *temp = trans;
NS_RELEASE(temp); // b/c NS_RELEASE nulls its argument!
@ -2429,7 +2447,7 @@ nsHttpConnectionMgr::OnMsgCancelTransaction(int32_t reason, void *param)
if (liveTransaction && liveTransaction->IsNullTransaction()) {
LOG(("nsHttpConnectionMgr::OnMsgCancelTransaction [trans=%p] "
"also canceling Null Transaction %p on conn %p\n",
trans.get(), liveTransaction, activeConn));
trans, liveTransaction, activeConn));
activeConn->CloseTransaction(liveTransaction, closeCode);
}
}
@ -2437,10 +2455,10 @@ nsHttpConnectionMgr::OnMsgCancelTransaction(int32_t reason, void *param)
}
void
nsHttpConnectionMgr::OnMsgProcessPendingQ(int32_t, void *param)
nsHttpConnectionMgr::OnMsgProcessPendingQ(int32_t, ARefBase *param)
{
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
nsHttpConnectionInfo *ci = (nsHttpConnectionInfo *) param;
nsHttpConnectionInfo *ci = static_cast<nsHttpConnectionInfo *>(param);
if (!ci) {
LOG(("nsHttpConnectionMgr::OnMsgProcessPendingQ [ci=nullptr]\n"));
@ -2459,30 +2477,22 @@ nsHttpConnectionMgr::OnMsgProcessPendingQ(int32_t, void *param)
// for the specified connection info. walk the connection table...
mCT.Enumerate(ProcessOneTransactionCB, this);
}
NS_RELEASE(ci);
}
nsresult
nsHttpConnectionMgr::CancelTransactions(nsHttpConnectionInfo *aCI, nsresult code)
nsHttpConnectionMgr::CancelTransactions(nsHttpConnectionInfo *ci, nsresult code)
{
RefPtr<nsHttpConnectionInfo> ci(aCI);
LOG(("nsHttpConnectionMgr::CancelTransactions %s\n",ci->HashKey().get()));
int32_t intReason = static_cast<int32_t>(code);
nsresult rv = PostEvent(&nsHttpConnectionMgr::OnMsgCancelTransactions, intReason, ci);
if (NS_SUCCEEDED(rv)) {
unused << ci.forget();
}
return rv;
return PostEvent(&nsHttpConnectionMgr::OnMsgCancelTransactions, intReason, ci);
}
void
nsHttpConnectionMgr::OnMsgCancelTransactions(int32_t code, void *param)
nsHttpConnectionMgr::OnMsgCancelTransactions(int32_t code, ARefBase *param)
{
nsresult reason = static_cast<nsresult>(code);
RefPtr<nsHttpConnectionInfo> ci =
dont_AddRef(static_cast<nsHttpConnectionInfo *>(param));
nsHttpConnectionInfo *ci = static_cast<nsHttpConnectionInfo *>(param);
nsConnectionEntry *ent = mCT.Get(ci->HashKey());
LOG(("nsHttpConnectionMgr::OnMsgCancelTransactions %s %p\n",
ci->HashKey().get(), ent));
@ -2502,7 +2512,7 @@ nsHttpConnectionMgr::OnMsgCancelTransactions(int32_t code, void *param)
}
void
nsHttpConnectionMgr::OnMsgPruneDeadConnections(int32_t, void *)
nsHttpConnectionMgr::OnMsgPruneDeadConnections(int32_t, ARefBase *)
{
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
LOG(("nsHttpConnectionMgr::OnMsgPruneDeadConnections\n"));
@ -2517,7 +2527,7 @@ nsHttpConnectionMgr::OnMsgPruneDeadConnections(int32_t, void *)
}
void
nsHttpConnectionMgr::OnMsgPruneNoTraffic(int32_t, void *)
nsHttpConnectionMgr::OnMsgPruneNoTraffic(int32_t, ARefBase *)
{
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
LOG(("nsHttpConnectionMgr::OnMsgPruneNoTraffic\n"));
@ -2529,7 +2539,7 @@ nsHttpConnectionMgr::OnMsgPruneNoTraffic(int32_t, void *)
}
void
nsHttpConnectionMgr::OnMsgVerifyTraffic(int32_t, void *)
nsHttpConnectionMgr::OnMsgVerifyTraffic(int32_t, ARefBase *)
{
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
LOG(("nsHttpConnectionMgr::OnMsgVerifyTraffic\n"));
@ -2561,13 +2571,12 @@ nsHttpConnectionMgr::OnMsgVerifyTraffic(int32_t, void *)
}
void
nsHttpConnectionMgr::OnMsgDoShiftReloadConnectionCleanup(int32_t, void *param)
nsHttpConnectionMgr::OnMsgDoShiftReloadConnectionCleanup(int32_t, ARefBase *param)
{
LOG(("nsHttpConnectionMgr::OnMsgDoShiftReloadConnectionCleanup\n"));
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
RefPtr<nsHttpConnectionInfo> ci =
dont_AddRef(static_cast<nsHttpConnectionInfo *>(param));
nsHttpConnectionInfo *ci = static_cast<nsHttpConnectionInfo *>(param);
mCT.Enumerate(ClosePersistentConnectionsCB, this);
if (ci)
@ -2575,12 +2584,12 @@ nsHttpConnectionMgr::OnMsgDoShiftReloadConnectionCleanup(int32_t, void *param)
}
void
nsHttpConnectionMgr::OnMsgReclaimConnection(int32_t, void *param)
nsHttpConnectionMgr::OnMsgReclaimConnection(int32_t, ARefBase *param)
{
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
LOG(("nsHttpConnectionMgr::OnMsgReclaimConnection [conn=%p]\n", param));
nsHttpConnection *conn = (nsHttpConnection *) param;
nsHttpConnection *conn = static_cast<nsHttpConnection *>(param);
//
// 1) remove the connection from the active list
@ -2601,8 +2610,7 @@ nsHttpConnectionMgr::OnMsgReclaimConnection(int32_t, void *param)
}
MOZ_ASSERT(ent);
nsHttpConnectionInfo *ci = nullptr;
NS_ADDREF(ci = ent->mConnInfo);
RefPtr<nsHttpConnectionInfo> ci(ent->mConnInfo);
// If the connection is in the active list, remove that entry
// and the reference held by the mActiveConns list.
@ -2668,15 +2676,14 @@ nsHttpConnectionMgr::OnMsgReclaimConnection(int32_t, void *param)
conn->Close(NS_ERROR_ABORT);
}
OnMsgProcessPendingQ(0, ci); // releases |ci|
NS_RELEASE(conn);
OnMsgProcessPendingQ(0, ci);
}
void
nsHttpConnectionMgr::OnMsgCompleteUpgrade(int32_t, void *param)
nsHttpConnectionMgr::OnMsgCompleteUpgrade(int32_t, ARefBase *param)
{
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
nsCompleteUpgradeData *data = (nsCompleteUpgradeData *) param;
nsCompleteUpgradeData *data = static_cast<nsCompleteUpgradeData *>(param);
LOG(("nsHttpConnectionMgr::OnMsgCompleteUpgrade "
"this=%p conn=%p listener=%p\n", this, data->mConn.get(),
data->mUpgradeListener.get()));
@ -2694,14 +2701,14 @@ nsHttpConnectionMgr::OnMsgCompleteUpgrade(int32_t, void *param)
data->mUpgradeListener->OnTransportAvailable(socketTransport,
socketIn,
socketOut);
delete data;
}
void
nsHttpConnectionMgr::OnMsgUpdateParam(int32_t, void *param)
nsHttpConnectionMgr::OnMsgUpdateParam(int32_t inParam, ARefBase *)
{
uint16_t name = (NS_PTR_TO_INT32(param) & 0xFFFF0000) >> 16;
uint16_t value = NS_PTR_TO_INT32(param) & 0x0000FFFF;
uint32_t param = static_cast<uint32_t>(inParam);
uint16_t name = ((param) & 0xFFFF0000) >> 16;
uint16_t value = param & 0x0000FFFF;
switch (name) {
case MAX_CONNECTIONS:
@ -2735,13 +2742,11 @@ nsHttpConnectionMgr::nsConnectionEntry::~nsConnectionEntry()
}
void
nsHttpConnectionMgr::OnMsgProcessFeedback(int32_t, void *param)
nsHttpConnectionMgr::OnMsgProcessFeedback(int32_t, ARefBase *param)
{
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
nsHttpPipelineFeedback *fb = (nsHttpPipelineFeedback *)param;
nsHttpPipelineFeedback *fb = static_cast<nsHttpPipelineFeedback *>(param);
PipelineFeedbackInfo(fb->mConnInfo, fb->mInfo, fb->mConn, fb->mData);
delete fb;
}
// Read Timeout Tick handlers
@ -2854,19 +2859,6 @@ nsHttpConnectionMgr::TimeoutTickCB(const nsACString &key,
return PL_DHASH_NEXT;
}
//-----------------------------------------------------------------------------
// nsHttpConnectionMgr::nsConnectionHandle
nsHttpConnectionMgr::nsConnectionHandle::~nsConnectionHandle()
{
if (mConn) {
gHttpHandler->ReclaimConnection(mConn);
NS_RELEASE(mConn);
}
}
NS_IMPL_ISUPPORTS0(nsHttpConnectionMgr::nsConnectionHandle)
// GetOrCreateConnectionEntry finds a ent for a particular CI for use in
// dispatching a transaction according to these rules
// 1] use an ent that matches the ci that can be dispatched immediately
@ -2907,36 +2899,34 @@ nsHttpConnectionMgr::GetOrCreateConnectionEntry(nsHttpConnectionInfo *specificCI
}
nsresult
nsHttpConnectionMgr::nsConnectionHandle::OnHeadersAvailable(nsAHttpTransaction *trans,
nsHttpRequestHead *req,
nsHttpResponseHead *resp,
bool *reset)
ConnectionHandle::OnHeadersAvailable(nsAHttpTransaction *trans,
nsHttpRequestHead *req,
nsHttpResponseHead *resp,
bool *reset)
{
return mConn->OnHeadersAvailable(trans, req, resp, reset);
}
void
nsHttpConnectionMgr::nsConnectionHandle::CloseTransaction(nsAHttpTransaction *trans, nsresult reason)
ConnectionHandle::CloseTransaction(nsAHttpTransaction *trans, nsresult reason)
{
mConn->CloseTransaction(trans, reason);
}
nsresult
nsHttpConnectionMgr::
nsConnectionHandle::TakeTransport(nsISocketTransport **aTransport,
nsIAsyncInputStream **aInputStream,
nsIAsyncOutputStream **aOutputStream)
ConnectionHandle::TakeTransport(nsISocketTransport **aTransport,
nsIAsyncInputStream **aInputStream,
nsIAsyncOutputStream **aOutputStream)
{
return mConn->TakeTransport(aTransport, aInputStream, aOutputStream);
}
void
nsHttpConnectionMgr::OnMsgSpeculativeConnect(int32_t, void *param)
nsHttpConnectionMgr::OnMsgSpeculativeConnect(int32_t, ARefBase *param)
{
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
RefPtr<SpeculativeConnectArgs> args =
dont_AddRef(static_cast<SpeculativeConnectArgs *>(param));
SpeculativeConnectArgs *args = static_cast<SpeculativeConnectArgs *>(param);
LOG(("nsHttpConnectionMgr::OnMsgSpeculativeConnect [ci=%s]\n",
args->mTrans->ConnectionInfo()->HashKey().get()));
@ -2980,25 +2970,25 @@ nsHttpConnectionMgr::OnMsgSpeculativeConnect(int32_t, void *param)
}
bool
nsHttpConnectionMgr::nsConnectionHandle::IsPersistent()
ConnectionHandle::IsPersistent()
{
return mConn->IsPersistent();
}
bool
nsHttpConnectionMgr::nsConnectionHandle::IsReused()
ConnectionHandle::IsReused()
{
return mConn->IsReused();
}
void
nsHttpConnectionMgr::nsConnectionHandle::DontReuse()
ConnectionHandle::DontReuse()
{
mConn->DontReuse();
}
nsresult
nsHttpConnectionMgr::nsConnectionHandle::PushBack(const char *buf, uint32_t bufLen)
ConnectionHandle::PushBack(const char *buf, uint32_t bufLen)
{
return mConn->PushBack(buf, bufLen);
}
@ -3451,10 +3441,7 @@ nsHalfOpenSocket::OnOutputStreamReady(nsIAsyncOutputStream *out)
// otherwise just put this in the persistent connection pool
LOG(("nsHalfOpenSocket::OnOutputStreamReady no transaction match "
"returning conn %p to pool\n", conn.get()));
RefPtr<nsHttpConnection> copy(conn);
// forget() to effectively addref because onmsg*() will drop a ref
gHttpHandler->ConnMgr()->OnMsgReclaimConnection(
0, conn.forget().take());
gHttpHandler->ConnMgr()->OnMsgReclaimConnection(0, conn);
}
}
@ -3569,7 +3556,7 @@ nsHttpConnectionMgr::nsHalfOpenSocket::GetInterface(const nsIID &iid,
nsHttpConnection *
nsHttpConnectionMgr::nsConnectionHandle::TakeHttpConnection()
ConnectionHandle::TakeHttpConnection()
{
// return our connection object to the caller and clear it internally
// do not drop our reference - the caller now owns it.
@ -3581,19 +3568,19 @@ nsHttpConnectionMgr::nsConnectionHandle::TakeHttpConnection()
}
uint32_t
nsHttpConnectionMgr::nsConnectionHandle::CancelPipeline(nsresult reason)
ConnectionHandle::CancelPipeline(nsresult reason)
{
// no pipeline to cancel
return 0;
}
nsAHttpTransaction::Classifier
nsHttpConnectionMgr::nsConnectionHandle::Classification()
ConnectionHandle::Classification()
{
if (mConn)
return mConn->Classification();
LOG(("nsConnectionHandle::Classification this=%p "
LOG(("ConnectionHandle::Classification this=%p "
"has null mConn using CLASS_SOLO default", this));
return nsAHttpTransaction::CLASS_SOLO;
}

Просмотреть файл

@ -17,6 +17,7 @@
#include "mozilla/TimeStamp.h"
#include "mozilla/Attributes.h"
#include "AlternateServices.h"
#include "ARefBase.h"
#include "nsIObserver.h"
#include "nsITimer.h"
@ -31,6 +32,10 @@ struct HttpRetParams;
//-----------------------------------------------------------------------------
// message handlers have this signature
class nsHttpConnectionMgr;
typedef void (nsHttpConnectionMgr:: *nsConnEventHandler)(int32_t, ARefBase *);
class nsHttpConnectionMgr final : public nsIObserver
, public AltSvcCache
{
@ -389,32 +394,9 @@ private:
void ResetIPFamilyPreference();
};
// nsConnectionHandle
//
// thin wrapper around a real connection, used to keep track of references
// to the connection to determine when the connection may be reused. the
// transaction (or pipeline) owns a reference to this handle. this extra
// layer of indirection greatly simplifies consumer code, avoiding the
// need for consumer code to know when to give the connection back to the
// connection manager.
//
class nsConnectionHandle : public nsAHttpConnection
{
virtual ~nsConnectionHandle();
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSAHTTPCONNECTION(mConn)
explicit nsConnectionHandle(nsHttpConnection *conn) { NS_ADDREF(mConn = conn); }
nsHttpConnection *mConn;
};
public:
static nsAHttpConnection *MakeConnectionHandle(nsHttpConnection *aWrapped)
{
return new nsConnectionHandle(aWrapped);
}
static nsAHttpConnection *MakeConnectionHandle(nsHttpConnection *aWrapped);
private:
// nsHalfOpenSocket is used to hold the state of an opening TCP socket
@ -522,7 +504,7 @@ private:
uint16_t mMaxRequestDelay; // in seconds
uint16_t mMaxPipelinedRequests;
uint16_t mMaxOptimisticPipelinedRequests;
bool mIsShuttingDown;
Atomic<bool, mozilla::Relaxed> mIsShuttingDown;
//-------------------------------------------------------------------------
// NOTE: these members are only accessed on the socket transport thread
@ -594,72 +576,30 @@ private:
const nsACString &key, nsAutoPtr<nsConnectionEntry> &ent,
void *closure);
// message handlers have this signature
typedef void (nsHttpConnectionMgr:: *nsConnEventHandler)(int32_t, void *);
// nsConnEvent
//
// subclass of nsRunnable used to marshall events to the socket transport
// thread. this class is used to implement PostEvent.
//
class nsConnEvent;
friend class nsConnEvent;
class nsConnEvent : public nsRunnable
{
public:
nsConnEvent(nsHttpConnectionMgr *mgr,
nsConnEventHandler handler,
int32_t iparam,
void *vparam)
: mMgr(mgr)
, mHandler(handler)
, mIParam(iparam)
, mVParam(vparam)
{
NS_ADDREF(mMgr);
}
NS_IMETHOD Run()
{
(mMgr->*mHandler)(mIParam, mVParam);
return NS_OK;
}
private:
virtual ~nsConnEvent()
{
NS_RELEASE(mMgr);
}
nsHttpConnectionMgr *mMgr;
nsConnEventHandler mHandler;
int32_t mIParam;
void *mVParam;
};
// used to marshall events to the socket transport thread.
nsresult PostEvent(nsConnEventHandler handler,
int32_t iparam = 0,
void *vparam = nullptr);
ARefBase *vparam = nullptr);
// message handlers
void OnMsgShutdown (int32_t, void *);
void OnMsgShutdownConfirm (int32_t, void *);
void OnMsgNewTransaction (int32_t, void *);
void OnMsgReschedTransaction (int32_t, void *);
void OnMsgCancelTransaction (int32_t, void *);
void OnMsgCancelTransactions (int32_t, void *);
void OnMsgProcessPendingQ (int32_t, void *);
void OnMsgPruneDeadConnections (int32_t, void *);
void OnMsgSpeculativeConnect (int32_t, void *);
void OnMsgReclaimConnection (int32_t, void *);
void OnMsgCompleteUpgrade (int32_t, void *);
void OnMsgUpdateParam (int32_t, void *);
void OnMsgDoShiftReloadConnectionCleanup (int32_t, void *);
void OnMsgProcessFeedback (int32_t, void *);
void OnMsgProcessAllSpdyPendingQ (int32_t, void *);
void OnMsgUpdateRequestTokenBucket (int32_t, void *);
void OnMsgVerifyTraffic (int32_t, void *);
void OnMsgPruneNoTraffic (int32_t, void *);
void OnMsgShutdown (int32_t, ARefBase *);
void OnMsgShutdownConfirm (int32_t, ARefBase *);
void OnMsgNewTransaction (int32_t, ARefBase *);
void OnMsgReschedTransaction (int32_t, ARefBase *);
void OnMsgCancelTransaction (int32_t, ARefBase *);
void OnMsgCancelTransactions (int32_t, ARefBase *);
void OnMsgProcessPendingQ (int32_t, ARefBase *);
void OnMsgPruneDeadConnections (int32_t, ARefBase *);
void OnMsgSpeculativeConnect (int32_t, ARefBase *);
void OnMsgReclaimConnection (int32_t, ARefBase *);
void OnMsgCompleteUpgrade (int32_t, ARefBase *);
void OnMsgUpdateParam (int32_t, ARefBase *);
void OnMsgDoShiftReloadConnectionCleanup (int32_t, ARefBase *);
void OnMsgProcessFeedback (int32_t, ARefBase *);
void OnMsgProcessAllSpdyPendingQ (int32_t, ARefBase *);
void OnMsgUpdateRequestTokenBucket (int32_t, ARefBase *);
void OnMsgVerifyTraffic (int32_t, ARefBase *);
void OnMsgPruneNoTraffic (int32_t, ARefBase *);
// Total number of active connections in all of the ConnectionEntry objects
// that are accessed from mCT connection table.
@ -711,7 +651,7 @@ private:
void *closure);
// For diagnostics
void OnMsgPrintDiagnostics(int32_t, void *);
void OnMsgPrintDiagnostics(int32_t, ARefBase *);
static PLDHashOperator PrintDiagnosticsCB(const nsACString &key,
nsAutoPtr<nsConnectionEntry> &ent,
void *closure);

Просмотреть файл

@ -16,6 +16,7 @@
#include "TimingStruct.h"
#include "Http2Push.h"
#include "mozilla/net/DNS.h"
#include "ARefBase.h"
#ifdef MOZ_WIDGET_GONK
#include "nsINetworkInterface.h"
@ -45,6 +46,7 @@ class nsHttpTransaction final : public nsAHttpTransaction
, public ATokenBucketEvent
, public nsIInputStreamCallback
, public nsIOutputStreamCallback
, public ARefBase
{
public:
NS_DECL_THREADSAFE_ISUPPORTS

Просмотреть файл

@ -5,24 +5,32 @@
__version__ = '1.0.0'
from .marionette_test import MarionetteTestCase, MarionetteJSTestCase, CommonTestCase, expectedFailure, skip, SkipTest
from .runner import (
B2GTestCaseMixin,
B2GTestResultMixin,
BaseMarionetteArguments,
BaseMarionetteTestRunner,
BrowserMobProxyTestCaseMixin,
EnduranceArguments,
EnduranceTestCaseMixin,
HTMLReportingArguments,
HTMLReportingTestResultMixin,
HTMLReportingTestRunnerMixin,
Marionette,
MarionetteTest,
MarionetteTestResult,
MarionetteTextTestRunner,
MemoryEnduranceTestCaseMixin,
TestManifest,
TestResult,
TestResultCollection
from .marionette_test import (
CommonTestCase,
expectedFailure,
MarionetteJSTestCase,
MarionetteTestCase,
skip,
SkipTest,
skip_unless_protocol,
)
from .runner import (
B2GTestCaseMixin,
B2GTestResultMixin,
BaseMarionetteArguments,
BaseMarionetteTestRunner,
BrowserMobProxyTestCaseMixin,
EnduranceArguments,
EnduranceTestCaseMixin,
HTMLReportingArguments,
HTMLReportingTestResultMixin,
HTMLReportingTestRunnerMixin,
Marionette,
MarionetteTest,
MarionetteTestResult,
MarionetteTextTestRunner,
MemoryEnduranceTestCaseMixin,
TestManifest,
TestResult,
TestResultCollection,
)

Просмотреть файл

@ -56,9 +56,7 @@ class _UnexpectedSuccess(Exception):
pass
def skip(reason):
"""
Unconditionally skip a test.
"""
"""Unconditionally skip a test."""
def decorator(test_item):
if not isinstance(test_item, (type, types.ClassType)):
@functools.wraps(test_item)
@ -81,12 +79,18 @@ def expectedFailure(func):
raise _UnexpectedSuccess
return wrapper
def skip_if_desktop(target):
def wrapper(self, *args, **kwargs):
if self.marionette.session_capabilities.get('b2g') is None:
raise SkipTest('skipping due to desktop')
return target(self, *args, **kwargs)
return wrapper
def skip_if_b2g(target):
def wrapper(self, *args, **kwargs):
if self.marionette.session_capabilities.get('b2g') == True:
raise SkipTest('skipping due to b2g')
return target(self, *args, **kwargs)
return wrapper
def skip_if_e10s(target):
@ -104,6 +108,19 @@ def skip_if_e10s(target):
return target(self, *args, **kwargs)
return wrapper
def skip_unless_protocol(predicate):
"""Given a predicate passed the current protocol level, skip the
test if the predicate does not match."""
def decorator(test_item):
@functools.wraps(test_item)
def skip_wrapper(self):
level = self.marionette.client.protocol
if not predicate(level):
raise SkipTest('skipping because protocol level is %s' % level)
return self
return skip_wrapper
return decorator
def parameterized(func_suffix, *args, **kwargs):
"""
A decorator that can generate methods given a base method and some data.

Просмотреть файл

@ -2,12 +2,14 @@
# 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/.
from marionette import MarionetteTestCase
from marionette_driver.errors import MarionetteException
from unittest import skip
from marionette.marionette_test import MarionetteTestCase, skip_if_desktop, skip_unless_protocol
from marionette_driver.errors import MarionetteException, JavascriptException
class TestEmulatorContent(MarionetteTestCase):
@skip_if_desktop
def test_emulator_cmd(self):
self.marionette.set_script_timeout(10000)
expected = ["<build>",
@ -17,6 +19,7 @@ class TestEmulatorContent(MarionetteTestCase):
""");
self.assertEqual(result, expected)
@skip_if_desktop
def test_emulator_shell(self):
self.marionette.set_script_timeout(10000)
expected = ["Hello World!"]
@ -25,6 +28,7 @@ class TestEmulatorContent(MarionetteTestCase):
""");
self.assertEqual(result, expected)
@skip_if_desktop
def test_emulator_order(self):
self.marionette.set_script_timeout(10000)
self.assertRaises(MarionetteException,
@ -35,21 +39,17 @@ class TestEmulatorContent(MarionetteTestCase):
class TestEmulatorChrome(TestEmulatorContent):
def setUp(self):
super(TestEmulatorChrome, self).setUp()
self.marionette.set_context("chrome")
class TestEmulatorScreen(MarionetteTestCase):
def setUp(self):
MarionetteTestCase.setUp(self)
@skip_if_desktop
def test_emulator_orientation(self):
self.screen = self.marionette.emulator.screen
self.screen.initialize()
def test_emulator_orientation(self):
self.assertEqual(self.screen.orientation, self.screen.SO_PORTRAIT_PRIMARY,
'Orientation has been correctly initialized.')
@ -68,3 +68,70 @@ class TestEmulatorScreen(MarionetteTestCase):
self.screen.orientation = self.screen.SO_PORTRAIT_PRIMARY
self.assertEqual(self.screen.orientation, self.screen.SO_PORTRAIT_PRIMARY,
'Orientation has been set to portrait-primary')
class TestEmulatorCallbacks(MarionetteTestCase):
def setUp(self):
MarionetteTestCase.setUp(self)
self.original_emulator_cmd = self.marionette._emulator_cmd
self.original_emulator_shell = self.marionette._emulator_shell
self.marionette._emulator_cmd = self.mock_emulator_cmd
self.marionette._emulator_shell = self.mock_emulator_shell
def tearDown(self):
self.marionette._emulator_cmd = self.original_emulator_cmd
self.marionette._emulator_shell = self.original_emulator_shell
def mock_emulator_cmd(self, *args):
return self.marionette._send_emulator_result("cmd response")
def mock_emulator_shell(self, *args):
return self.marionette._send_emulator_result("shell response")
def _execute_emulator(self, action, args):
script = "%s(%s, function(res) { marionetteScriptFinished(res); })" % (action, args)
return self.marionette.execute_async_script(script)
def emulator_cmd(self, cmd):
return self._execute_emulator("runEmulatorCmd", escape(cmd))
def emulator_shell(self, *args):
js_args = ", ".join(map(escape, args))
js_args = "[%s]" % js_args
return self._execute_emulator("runEmulatorShell", js_args)
def test_emulator_cmd_content(self):
with self.marionette.using_context("content"):
res = self.emulator_cmd("yo")
self.assertEqual("cmd response", res)
def test_emulator_shell_content(self):
with self.marionette.using_context("content"):
res = self.emulator_shell("first", "second")
self.assertEqual("shell response", res)
@skip_unless_protocol(lambda level: level >= 3)
def test_emulator_result_error_content(self):
with self.marionette.using_context("content"):
with self.assertRaisesRegexp(JavascriptException, "TypeError"):
self.marionette.execute_async_script("runEmulatorCmd()")
def test_emulator_cmd_chrome(self):
with self.marionette.using_context("chrome"):
res = self.emulator_cmd("yo")
self.assertEqual("cmd response", res)
def test_emulator_shell_chrome(self):
with self.marionette.using_context("chrome"):
res = self.emulator_shell("first", "second")
self.assertEqual("shell response", res)
@skip_unless_protocol(lambda level: level >= 3)
def test_emulator_result_error_chrome(self):
with self.marionette.using_context("chrome"):
with self.assertRaisesRegexp(JavascriptException, "TypeError"):
self.marionette.execute_async_script("runEmulatorCmd()")
def escape(word):
return "'%s'" % word

Просмотреть файл

@ -3,6 +3,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from marionette import MarionetteTestCase
from marionette_driver.by import By
from marionette_driver.errors import (JavascriptException,
NoSuchFrameException)
@ -134,3 +135,56 @@ class TestSwitchFrame(MarionetteTestCase):
test_html = self.marionette.absolute_url("test.html")
self.marionette.navigate(test_html)
self.assertEqual("Marionette Test", self.marionette.title)
def test_switch_to_parent_frame(self):
frame_html = self.marionette.absolute_url("frameset.html")
self.marionette.navigate(frame_html)
frame = self.marionette.find_element("name", "third")
self.marionette.switch_to_frame(frame)
# If we don't find the following element we aren't on the right page
self.marionette.find_element(By.ID, "checky")
form_page_title = self.marionette.execute_script("return document.title")
self.assertEqual("We Leave From Here", form_page_title)
self.marionette.switch_to_parent_frame()
current_page_title = self.marionette.execute_script("return document.title")
self.assertEqual("Unique title", current_page_title)
def test_switch_to_parent_frame_from_default_context_is_a_noop(self):
formpage = self.marionette.absolute_url("formPage.html")
self.marionette.navigate(formpage)
self.marionette.switch_to_parent_frame()
form_page_title = self.marionette.execute_script("return document.title")
self.assertEqual("We Leave From Here", form_page_title)
def test_should_be_able_to_switch_to_parent_from_second_level(self):
frame_html = self.marionette.absolute_url("frameset.html")
self.marionette.navigate(frame_html)
frame = self.marionette.find_element(By.NAME, "fourth")
self.marionette.switch_to_frame(frame)
second_level = self.marionette.find_element(By.NAME, "child1")
self.marionette.switch_to_frame(second_level)
self.marionette.find_element(By.NAME, "myCheckBox")
self.marionette.switch_to_parent_frame()
second_level = self.marionette.find_element(By.NAME, "child1")
def test_should_be_able_to_switch_to_parent_from_iframe(self):
frame_html = self.marionette.absolute_url("test_iframe.html")
self.marionette.navigate(frame_html)
frame = self.marionette.find_element(By.ID, "test_iframe")
self.marionette.switch_to_frame(frame)
current_page_title = self.marionette.execute_script("return document.title")
self.assertEqual("Marionette Test", current_page_title)
self.marionette.switch_to_parent_frame()
parent_page_title = self.marionette.execute_script("return document.title")
self.assertEqual("Marionette IFrame Test", parent_page_title)

Просмотреть файл

@ -0,0 +1,181 @@
# 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/.
import json
from marionette import MarionetteTestCase, skip_unless_protocol
from marionette_transport import (
Command,
Proto2Command,
Proto2Response,
Response
)
get_current_url = ("getCurrentUrl", None)
execute_script = ("executeScript", {"script": "return 42"})
class TestMessageSequencing(MarionetteTestCase):
@property
def last_id(self):
return self.marionette.client.last_id
@last_id.setter
def last_id(self, new_id):
self.marionette.client.last_id = new_id
def send(self, name, params):
self.last_id = self.last_id + 1
cmd = Command(self.last_id, name, params)
self.marionette.client.send(cmd)
return self.last_id
@skip_unless_protocol(lambda level: level >= 3)
def test_discard_older_messages(self):
first = self.send(*get_current_url)
second = self.send(*execute_script)
resp = self.marionette.client.receive()
self.assertEqual(second, resp.id)
@skip_unless_protocol(lambda level: level >= 3)
def test_last_id_incremented(self):
before = self.last_id
self.send(*get_current_url)
self.assertGreater(self.last_id, before)
class MessageTestCase(MarionetteTestCase):
def assert_attr(self, obj, attr):
self.assertTrue(hasattr(obj, attr),
"object does not have attribute %s" % attr)
class TestCommand(MessageTestCase):
def create(self, msgid="msgid", name="name", params="params"):
return Command(msgid, name, params)
def test_initialise(self):
cmd = self.create()
self.assert_attr(cmd, "id")
self.assert_attr(cmd, "name")
self.assert_attr(cmd, "params")
self.assertEqual("msgid", cmd.id)
self.assertEqual("name", cmd.name)
self.assertEqual("params", cmd.params)
def test_stringify(self):
cmd = self.create()
string = str(cmd)
self.assertIn("Command", string)
self.assertIn("id=msgid", string)
self.assertIn("name=name", string)
self.assertIn("params=params", string)
def test_to_msg(self):
cmd = self.create()
msg = json.loads(cmd.to_msg())
self.assertEquals(msg[0], Command.TYPE)
self.assertEquals(msg[1], "msgid")
self.assertEquals(msg[2], "name")
self.assertEquals(msg[3], "params")
def test_from_msg(self):
msg = [Command.TYPE, "msgid", "name", "params"]
payload = json.dumps(msg)
cmd = Command.from_msg(payload)
self.assertEquals(msg[1], cmd.id)
self.assertEquals(msg[2], cmd.name)
self.assertEquals(msg[3], cmd.params)
class TestResponse(MessageTestCase):
def create(self, msgid="msgid", error="error", result="result"):
return Response(msgid, error, result)
def test_initialise(self):
resp = self.create()
self.assert_attr(resp, "id")
self.assert_attr(resp, "error")
self.assert_attr(resp, "result")
self.assertEqual("msgid", resp.id)
self.assertEqual("error", resp.error)
self.assertEqual("result", resp.result)
def test_stringify(self):
resp = self.create()
string = str(resp)
self.assertIn("Response", string)
self.assertIn("id=msgid", string)
self.assertIn("error=error", string)
self.assertIn("result=result", string)
def test_to_msg(self):
resp = self.create()
msg = json.loads(resp.to_msg())
self.assertEquals(msg[0], Response.TYPE)
self.assertEquals(msg[1], "msgid")
self.assertEquals(msg[2], "error")
self.assertEquals(msg[3], "result")
def test_from_msg(self):
msg = [Response.TYPE, "msgid", "error", "result"]
payload = json.dumps(msg)
resp = Response.from_msg(payload)
self.assertEquals(msg[1], resp.id)
self.assertEquals(msg[2], resp.error)
self.assertEquals(msg[3], resp.result)
class TestProto2Command(MessageTestCase):
def create(self, name="name", params="params"):
return Proto2Command(name, params)
def test_initialise(self):
cmd = self.create()
self.assert_attr(cmd, "id")
self.assert_attr(cmd, "name")
self.assert_attr(cmd, "params")
self.assertEqual(None, cmd.id)
self.assertEqual("name", cmd.name)
self.assertEqual("params", cmd.params)
def test_from_data_emulator_cmd(self):
data = {"emulator_cmd": "emulator_cmd"}
cmd = Proto2Command.from_data(data)
self.assertEqual("runEmulatorCmd", cmd.name)
self.assertEqual(data, cmd.params)
def test_from_data_emulator_shell(self):
data = {"emulator_shell": "emulator_shell"}
cmd = Proto2Command.from_data(data)
self.assertEqual("runEmulatorShell", cmd.name)
self.assertEqual(data, cmd.params)
def test_from_data_unknown(self):
with self.assertRaises(ValueError):
cmd = Proto2Command.from_data({})
class TestProto2Response(MessageTestCase):
def create(self, error="error", result="result"):
return Proto2Response(error, result)
def test_initialise(self):
resp = self.create()
self.assert_attr(resp, "id")
self.assert_attr(resp, "error")
self.assert_attr(resp, "result")
self.assertEqual(None, resp.id)
self.assertEqual("error", resp.error)
self.assertEqual("result", resp.result)
def test_from_data_error(self):
data = {"error": "error"}
resp = Proto2Response.from_data(data)
self.assertEqual(data, resp.error)
self.assertEqual(None, resp.result)
def test_from_data_result(self):
resp = Proto2Response.from_data("result")
self.assertEqual(None, resp.error)
self.assertEqual("result", resp.result)

Просмотреть файл

@ -51,7 +51,6 @@ disabled = "Bug 896046"
[test_log.py]
[test_emulator.py]
browser = false
qemu = true
[test_about_pages.py]

Просмотреть файл

@ -1,7 +1,7 @@
<html>
<head></head>
<frameset cols="*, *">
<frame name="child1" src="page/10"/>
<frame name="child2" src="page/11"/>
<frame name="child1" src="test.html"/>
<frame name="child2" src="test.html"/>
</frameset>
</html>
</html>

Просмотреть файл

@ -1622,6 +1622,13 @@ GeckoDriver.prototype.getActiveFrame = function(cmd, resp) {
}
};
/**
*
*/
GeckoDriver.prototype.switchToParentFrame = function (cmd, resp) {
let res = yield this.listener.switchToParentFrame();
};
/**
* Switch to a given frame within the current window.
*
@ -2966,6 +2973,7 @@ GeckoDriver.prototype.commands = {
"setWindowPosition": GeckoDriver.prototype.setWindowPosition,
"getActiveFrame": GeckoDriver.prototype.getActiveFrame,
"switchToFrame": GeckoDriver.prototype.switchToFrame,
"switchToParentFrame": GeckoDriver.prototype.switchToParentFrame,
"switchToWindow": GeckoDriver.prototype.switchToWindow,
"switchToShadowRoot": GeckoDriver.prototype.switchToShadowRoot,
"deleteSession": GeckoDriver.prototype.deleteSession,

Просмотреть файл

@ -15,7 +15,7 @@ from contextlib import contextmanager
from decorators import do_crash_check
from keys import Keys
from marionette_transport import MarionetteTransport
import marionette_transport as transport
from mozrunner import B2GEmulatorRunner
@ -25,6 +25,7 @@ import errors
WEBELEMENT_KEY = "ELEMENT"
W3C_WEBELEMENT_KEY = "element-6066-11e4-a52e-4f735466cecf"
class HTMLElement(object):
"""
Represents a DOM Element.
@ -623,16 +624,15 @@ class Marionette(object):
self.port = self.emulator.setup_port_forwarding(remote_port=self.port)
assert(self.emulator.wait_for_port(self.port)), "Timed out waiting for port!"
self.client = MarionetteTransport(
self.host,
self.port,
self.socket_timeout)
if emulator:
if busybox:
self.emulator.install_busybox(busybox=busybox)
self.emulator.wait_for_system_message(self)
# for callbacks from a protocol level 2 or lower remote,
# we store the callback ID so it can be used by _send_emulator_result
self.emulator_callback_id = None
def cleanup(self):
if self.session:
try:
@ -667,23 +667,24 @@ class Marionette(object):
s.close()
def wait_for_port(self, timeout=60):
return MarionetteTransport.wait_for_port(self.host,
self.port,
timeout=timeout)
return transport.wait_for_port(self.host, self.port, timeout=timeout)
@do_crash_check
def _send_message(self, command, body=None, key=None):
if not self.session_id and command != "newSession":
def _send_message(self, name, params=None, key=None):
if not self.session_id and name != "newSession":
raise errors.MarionetteException("Please start a session")
message = {"name": command}
if body:
message["parameters"] = body
packet = json.dumps(message)
try:
resp = self.client.send(packet)
if self.protocol < 3:
data = {"name": name}
if params:
data["parameters"] = params
self.client.send(data)
msg = self.client.receive()
else:
msg = self.client.request(name, params)
except IOError:
if self.instance and not hasattr(self.instance, 'detached'):
# If we've launched the binary we've connected to, wait
@ -697,28 +698,24 @@ class Marionette(object):
self.client.close()
raise errors.TimeoutException("Connection timed out")
# Process any emulator commands that are sent from a script
# while it's executing
if isinstance(resp, dict) and any (k in resp for k in ("emulator_cmd", "emulator_shell")):
while True:
id = resp.get("id")
cmd = resp.get("emulator_cmd")
shell = resp.get("emulator_shell")
if cmd:
resp = self._emulator_cmd(id, cmd)
continue
if shell:
resp = self._emulator_shell(id, shell)
continue
break
if isinstance(msg, transport.Command):
if msg.name == "runEmulatorCmd":
self.emulator_callback_id = msg.params.get("id")
msg = self._emulator_cmd(msg.params["emulator_cmd"])
elif msg.name == "runEmulatorShell":
self.emulator_callback_id = msg.params.get("id")
msg = self._emulator_shell(msg.params["emulator_shell"])
else:
raise IOError("Unknown command: %s" % msg)
if "error" in resp:
self._handle_error(resp)
res, err = msg.result, msg.error
if err:
self._handle_error(err)
if key is not None:
return self._unwrap_response(resp.get(key))
return self._unwrap_response(res.get(key))
else:
return self._unwrap_response(resp)
return self._unwrap_response(res)
def _unwrap_response(self, value):
if isinstance(value, dict) and \
@ -732,15 +729,15 @@ class Marionette(object):
else:
return value
def _emulator_cmd(self, id, cmd):
def _emulator_cmd(self, cmd):
if not self.emulator:
raise errors.MarionetteException(
"No emulator in this test to run command against")
payload = cmd.encode("ascii")
result = self.emulator._run_telnet(payload)
return self._send_emulator_result(id, result)
return self._send_emulator_result(result)
def _emulator_shell(self, id, args):
def _emulator_shell(self, args):
if not isinstance(args, list) or not self.emulator:
raise errors.MarionetteException(
"No emulator in this test to run shell command against")
@ -748,25 +745,32 @@ class Marionette(object):
self.emulator.dm.shell(args, buf)
result = str(buf.getvalue()[0:-1]).rstrip().splitlines()
buf.close()
return self._send_emulator_result(id, result)
return self._send_emulator_result(result)
def _send_emulator_result(self, id, result):
return self.client.send(json.dumps({"name": "emulatorCmdResult",
"id": id,
"result": result}))
def _handle_error(self, resp):
if self.protocol == 1:
if "error" not in resp or not isinstance(resp["error"], dict):
raise errors.MarionetteException(
"Malformed packet, expected key 'error' to be a dict: %s" % resp)
error = resp["error"].get("status")
message = resp["error"].get("message")
stacktrace = resp["error"].get("stacktrace")
def _send_emulator_result(self, result):
if self.protocol < 3:
body = {"name": "emulatorCmdResult",
"id": self.emulator_callback_id,
"result": result}
self.client.send(body)
return self.client.receive()
else:
error = resp["error"]
message = resp["message"]
stacktrace = resp["stacktrace"]
return self.client.respond(result)
def _handle_error(self, obj):
if self.protocol == 1:
if "error" not in obj or not isinstance(obj["error"], dict):
raise errors.MarionetteException(
"Malformed packet, expected key 'error' to be a dict: %s" % obj)
error = obj["error"].get("status")
message = obj["error"].get("message")
stacktrace = obj["error"].get("stacktrace")
else:
error = obj["error"]
message = obj["message"]
stacktrace = obj["stacktrace"]
raise errors.lookup(error)(message, stacktrace=stacktrace)
def _reset_timeouts(self):
@ -1132,6 +1136,10 @@ class Marionette(object):
# We're managing a binary which has terminated, so restart it.
self.instance.restart()
self.client = transport.TcpTransport(
self.host,
self.port,
self.socket_timeout)
self.protocol, _ = self.client.connect()
self.wait_for_port(timeout=timeout)
@ -1308,7 +1316,6 @@ class Marionette(object):
marionette.set_context(marionette.CONTEXT_CHROME)
"""
assert(context == self.CONTEXT_CHROME or context == self.CONTEXT_CONTENT)
if context not in [self.CONTEXT_CHROME, self.CONTEXT_CONTENT]:
raise ValueError("Unknown context: %s" % context)
self._send_message("setContext", {"value": context})
@ -1368,6 +1375,12 @@ class Marionette(object):
"""Switch the current context to page's default content."""
return self.switch_to_frame()
def switch_to_parent_frame(self):
"""
Switch to the Parent Frame
"""
self._send_message("switchToParentFrame")
def switch_to_frame(self, frame=None, focus=True):
"""Switch the current context to the specified frame. Subsequent
commands will operate in the context of the specified frame,

Просмотреть файл

@ -255,6 +255,7 @@ function startListeners() {
addMessageListenerId("Marionette:sendKeysToElement", sendKeysToElement);
addMessageListenerId("Marionette:clearElement", clearElementFn);
addMessageListenerId("Marionette:switchToFrame", switchToFrame);
addMessageListenerId("Marionette:switchToParentFrame", switchToParentFrame);
addMessageListenerId("Marionette:switchToShadowRoot", switchToShadowRootFn);
addMessageListenerId("Marionette:deleteSession", deleteSession);
addMessageListenerId("Marionette:sleepSession", sleepSession);
@ -359,6 +360,7 @@ function deleteSession(msg) {
removeMessageListenerId("Marionette:sendKeysToElement", sendKeysToElement);
removeMessageListenerId("Marionette:clearElement", clearElementFn);
removeMessageListenerId("Marionette:switchToFrame", switchToFrame);
removeMessageListenerId("Marionette:switchToParentFrame", switchToParentFrame);
removeMessageListenerId("Marionette:switchToShadowRoot", switchToShadowRootFn);
removeMessageListenerId("Marionette:deleteSession", deleteSession);
removeMessageListenerId("Marionette:sleepSession", sleepSession);
@ -1679,6 +1681,20 @@ function switchToShadowRoot(id) {
curContainer.shadowRoot = foundShadowRoot;
}
/**
* Switch to the parent frame of the current Frame. If the frame is the top most
* is the current frame then no action will happen.
*/
function switchToParentFrame(msg) {
let command_id = msg.json.command_id;
curContainer.frame = curContainer.frame.parent;
let parentElement = elementManager.addToKnownElements(curContainer.frame);
sendSyncMessage("Marionette:switchedToFrame", { frameValue: parentElement });
sendOk(msg.json.command_id);
}
/**
* Switch to frame given either the server-assigned element id,
* its index in window.frames, or the iframe's name or id.

Просмотреть файл

@ -4,5 +4,4 @@
__version__ = '0.7.1'
from transport import MarionetteTransport
from transport import *

Просмотреть файл

@ -7,16 +7,111 @@ import errno
import json
import socket
import time
import types
class MarionetteTransport(object):
"""The Marionette socket client. This speaks the same protocol
as the remote debugger inside Gecko, in which messages are always
preceded by the message length and a colon, e.g.:
class Message(object):
def __init__(self, msgid):
self.id = msgid
20:{"command": "test"}
def __eq__(self, other):
return self.id == other.id
class Command(Message):
TYPE = 0
def __init__(self, msgid, name, params):
Message.__init__(self, msgid)
self.name = name
self.params = params
def __str__(self):
return "<Command id=%s, name=%s, params=%s>" % (self.id, self.name, self.params)
def to_msg(self):
msg = [Command.TYPE, self.id, self.name, self.params]
return json.dumps(msg)
@staticmethod
def from_msg(payload):
data = json.loads(payload)
assert data[0] == Command.TYPE
cmd = Command(data[1], data[2], data[3])
return cmd
class Response(Message):
TYPE = 1
def __init__(self, msgid, error, result):
Message.__init__(self, msgid)
self.error = error
self.result = result
def __str__(self):
return "<Response id=%s, error=%s, result=%s>" % (self.id, self.error, self.result)
def to_msg(self):
msg = [Response.TYPE, self.id, self.error, self.result]
return json.dumps(msg)
@staticmethod
def from_msg(payload):
data = json.loads(payload)
assert data[0] == Response.TYPE
return Response(data[1], data[2], data[3])
class Proto2Command(Command):
"""Compatibility shim that marshals messages from a protocol level
2 and below remote into ``Command`` objects.
"""
def __init__(self, name, params):
Command.__init__(self, None, name, params)
@staticmethod
def from_data(data):
if "emulator_cmd" in data:
name = "runEmulatorCmd"
elif "emulator_shell" in data:
name = "runEmulatorShell"
else:
raise ValueError
return Proto2Command(name, data)
class Proto2Response(Response):
"""Compatibility shim that marshals messages from a protocol level
2 and below remote into ``Response`` objects.
"""
def __init__(self, error, result):
Response.__init__(self, None, error, result)
@staticmethod
def from_data(data):
err, res = None, None
if "error" in data:
err = data
else:
res = data
return Proto2Response(err, res)
class TcpTransport(object):
"""Socket client that communciates with Marionette via TCP.
It speaks the protocol of the remote debugger in Gecko, in which
messages are always preceded by the message length and a colon, e.g.:
7:MESSAGE
On top of this protocol it uses a Marionette message format, that
depending on the protocol level offered by the remote server, varies.
Supported protocol levels are 1 and above.
"""
max_packet_length = 4096
connection_lost_msg = "Connection to Marionette server is lost. Check gecko.log (desktop firefox) or logcat (b2g) for errors."
@ -24,14 +119,16 @@ class MarionetteTransport(object):
self.addr = addr
self.port = port
self.socket_timeout = socket_timeout
self.sock = None
self.protocol = 1
self.application_type = None
self.last_id = 0
self.expected_responses = []
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.settimeout(self.socket_timeout)
def _recv_n_bytes(self, n):
"""Convenience method for receiving exactly n bytes from self.sock
(assuming it's open and connected).
"""
data = ""
while len(data) < n:
chunk = self.sock.recv(n - len(data))
@ -40,41 +137,82 @@ class MarionetteTransport(object):
data += chunk
return data
def receive(self):
"""Receive the next complete response from the server, and
return it as a JSON structure. Each response from the server
is prepended by len(message) + ":".
def _unmarshal(self, packet):
msg = None
# protocol 3 and above
if self.protocol >= 3:
typ = int(packet[1])
if typ == Command.TYPE:
msg = Command.from_msg(packet)
elif typ == Response.TYPE:
msg = Response.from_msg(packet)
# protocol 2 and below
else:
data = json.loads(packet)
# emulator callbacks
if isinstance(data, dict) and any(k in data for k in ("emulator_cmd", "emulator_shell")):
msg = Proto2Command.from_data(data)
# everything else
else:
msg = Proto2Response.from_data(data)
return msg
def receive(self, unmarshal=True):
"""Wait for the next complete response from the remote.
:param unmarshal: Default is to deserialise the packet and
return a ``Message`` type. Setting this to false will return
the raw packet.
"""
assert(self.sock)
now = time.time()
response = ''
data = ""
bytes_to_recv = 10
while time.time() - now < self.socket_timeout:
try:
data = self.sock.recv(bytes_to_recv)
response += data
chunk = self.sock.recv(bytes_to_recv)
data += chunk
except socket.timeout:
pass
else:
if not data:
if not chunk:
raise IOError(self.connection_lost_msg)
sep = response.find(':')
sep = data.find(":")
if sep > -1:
length = response[0:sep]
remaining = response[sep + 1:]
length = data[0:sep]
remaining = data[sep + 1:]
if len(remaining) == int(length):
return json.loads(remaining)
if unmarshal:
msg = self._unmarshal(remaining)
self.last_id = msg.id
if isinstance(msg, Response) and self.protocol >= 3:
if msg not in self.expected_responses:
raise Exception("Received unexpected response: %s" % msg)
else:
self.expected_responses.remove(msg)
return msg
else:
return remaining
bytes_to_recv = int(length) - len(remaining)
raise socket.timeout('connection timed out after %d s' % self.socket_timeout)
raise socket.timeout("connection timed out after %ds" % self.socket_timeout)
def connect(self):
"""Connect to the server and process the hello message we expect
to receive in response.
Return a tuple of the protocol level and the application type.
Returns a tuple of the protocol level and the application type.
"""
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.settimeout(self.socket_timeout)
try:
self.sock.connect((self.addr, self.port))
except:
@ -82,22 +220,34 @@ class MarionetteTransport(object):
# another connection attempt.
self.sock = None
raise
self.sock.settimeout(2.0)
hello = self.receive()
# first packet is always a JSON Object
# which we can use to tell which protocol level we are at
raw = self.receive(unmarshal=False)
hello = json.loads(raw)
self.protocol = hello.get("marionetteProtocol", 1)
self.application_type = hello.get("applicationType")
return (self.protocol, self.application_type)
def send(self, data):
"""Send a message on the socket, prepending it with len(msg) + ":"."""
def send(self, obj):
"""Send message to the remote server. Allowed input is a
``Message`` instance or a JSON serialisable object.
"""
if not self.sock:
self.connect()
data = "%s:%s" % (len(data), data)
for packet in [data[i:i + self.max_packet_length] for i in
range(0, len(data), self.max_packet_length)]:
if isinstance(obj, Message):
data = obj.to_msg()
self.expected_responses.append(obj)
else:
data = json.dumps(obj)
payload = "%s:%s" % (len(data), data)
for packet in [payload[i:i + self.max_packet_length] for i in
range(0, len(payload), self.max_packet_length)]:
try:
self.sock.send(packet)
except IOError as e:
@ -106,32 +256,55 @@ class MarionetteTransport(object):
else:
raise e
def respond(self, obj):
"""Send a response to a command. This can be an arbitrary JSON
serialisable object or an ``Exception``.
"""
res, err = None, None
if isinstance(obj, Exception):
err = obj
else:
res = obj
msg = Response(self.last_id, err, res)
self.send(msg)
return self.receive()
def request(self, name, params):
"""Sends a message to the remote server and waits for a response
to come back.
"""
self.last_id = self.last_id + 1
cmd = Command(self.last_id, name, params)
self.send(cmd)
return self.receive()
def close(self):
"""Close the socket."""
if self.sock:
self.sock.close()
def __del__(self):
self.close()
self.sock = None
@staticmethod
def wait_for_port(host, port, timeout=60):
""" Wait for the specified Marionette host/port to be available."""
starttime = datetime.datetime.now()
poll_interval = 0.1
while datetime.datetime.now() - starttime < datetime.timedelta(seconds=timeout):
sock = None
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((host, port))
data = sock.recv(16)
def wait_for_port(host, port, timeout=60):
""" Wait for the specified host/port to be available."""
starttime = datetime.datetime.now()
poll_interval = 0.1
while datetime.datetime.now() - starttime < datetime.timedelta(seconds=timeout):
sock = None
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((host, port))
data = sock.recv(16)
sock.close()
if ':' in data:
return True
except socket.error:
pass
finally:
if sock:
sock.close()
if ':' in data:
return True
except socket.error:
pass
finally:
if sock:
sock.close()
time.sleep(poll_interval)
return False
time.sleep(poll_interval)
return False

Просмотреть файл

@ -1,8 +0,0 @@
[send-content-type-string.htm]
type: testharness
[XMLHttpRequest: send() - Content-Type 1]
expected: FAIL
[XMLHttpRequest: send() - Content-Type 2]
expected: FAIL

Просмотреть файл

@ -1,17 +0,0 @@
[send-entity-body-document.htm]
type: testharness
[XMLHttpRequest: send() - Document]
expected: FAIL
[XMLHttpRequest: send() - Document 1]
expected: FAIL
[XMLHttpRequest: send() - Document 2]
expected: FAIL
[XMLHttpRequest: send() - Document 3]
expected: FAIL
[XMLHttpRequest: send() - Document 4]
expected: FAIL

Просмотреть файл

@ -469,12 +469,6 @@
"url": "/_mozilla/service-workers/service-worker/state.https.html"
}
],
"service-workers/service-worker/sync-xhr-doesnt-deadlock.https.html": [
{
"path": "service-workers/service-worker/sync-xhr-doesnt-deadlock.https.html",
"url": "/_mozilla/service-workers/service-worker/sync-xhr-doesnt-deadlock.https.html"
}
],
"service-workers/service-worker/synced-state.https.html": [
{
"path": "service-workers/service-worker/synced-state.https.html",
@ -528,6 +522,12 @@
"path": "service-workers/service-worker/worker-interception.https.html",
"url": "/_mozilla/service-workers/service-worker/worker-interception.https.html"
}
],
"service-workers/service-worker/xhr.https.html": [
{
"path": "service-workers/service-worker/xhr.https.html",
"url": "/_mozilla/service-workers/service-worker/xhr.https.html"
}
]
}
},
@ -537,4 +537,4 @@
"rev": null,
"url_base": "/_mozilla/",
"version": 2
}
}

Просмотреть файл

@ -1,5 +0,0 @@
[sync-xhr-doesnt-deadlock.https.html]
type: testharness
[Verify SyncXHR does not deadlock]
expected: FAIL

Просмотреть файл

@ -1,12 +0,0 @@
<!DOCTYPE html>
<title>Service Worker: SyncXHR doesn't deadlock iframe</title>
<script>
function performSyncXHR() {
var url = 'sync-xhr-doesnt-deadlock.data?bustcache=' + Date.now();
var syncXhr = new XMLHttpRequest();
syncXhr.open("GET", url, false);
syncXhr.send();
if (syncXhr.responseText != 'hello')
throw 'FAIL';
}
</script>

Просмотреть файл

@ -1,5 +0,0 @@
self.onfetch = function(event) {
if (event.request.url.indexOf('sync-xhr-doesnt-deadlock.data') == -1)
return;
event.respondWith(fetch('404resource?bustcache=' + Date.now()));
};

Просмотреть файл

@ -0,0 +1,6 @@
self.addEventListener('activate', function(event) {
event.waitUntil(clients.claim());
});
self.addEventListener('message', function(event) {
event.data.port.postMessage({xhr: !!("XMLHttpRequest" in self)});
});

Просмотреть файл

@ -1,23 +0,0 @@
<!DOCTYPE html>
<title>Service Worker: SyncXHR doesn't deadlock</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="resources/test-helpers.sub.js"></script>
<script>
async_test(function(t) {
var url = 'resources/sync-xhr-doesnt-deadlock.js';
var scope = 'resources/sync-xhr-doesnt-deadlock-iframe.html';
service_worker_unregister_and_register(t, url, scope)
.then(function(registration) {
return wait_for_state(t, registration.installing, 'activated');
})
.then(function() { return with_iframe(scope); })
.then(function(frame) {
frame.contentWindow.performSyncXHR();
service_worker_unregister_and_done(t, scope);
})
.catch(unreached_rejection(t));
}, 'Verify SyncXHR does not deadlock');
</script>

Просмотреть файл

@ -0,0 +1,34 @@
<!DOCTYPE html>
<title>Service Worker: XHR doesn't exist</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="resources/get-host-info.sub.js"></script>
<script src="resources/test-helpers.sub.js?pipe=sub"></script>
<script>
async_test(function(t) {
var path = new URL(".", window.location).pathname
var url = 'resources/xhr.js';
var scope = 'resources/blank.html?xhr';
var host_info = get_host_info();
var frameURL = host_info['HTTPS_ORIGIN'] + path + scope;
service_worker_unregister_and_register(t, url, scope)
.then(function(registration) {
return wait_for_state(t, registration.installing, 'activated');
})
.then(function() { return with_iframe(frameURL); })
.then(function(frame) {
return new Promise(function(resolve, reject) {
function onMessage(e) {
assert_false(e.data.xhr);
service_worker_unregister_and_done(t, scope);
}
var channel = new MessageChannel();
channel.port1.onmessage = t.step_func(onMessage);
frame.contentWindow.navigator.serviceWorker.controller.postMessage({port: channel.port2}, [channel.port2]);
})
})
.catch(unreached_rejection(t));
}, 'Verify XHR does not exist');
</script>

Просмотреть файл

@ -0,0 +1,5 @@
def main(request, response):
headers = [("Content-type", "text/html;charset=utf-8")]
content = "<!DOCTYPE html><div></div>"
return headers, content

Просмотреть файл

@ -0,0 +1,5 @@
def main(request, response):
headers = [("Content-type", "text/html;charset=utf-8")]
content = "<img>foo"
return headers, content

Просмотреть файл

@ -20,7 +20,7 @@
request("TEST", "text/plain;charset=UTF-8")
function init(fr) { request(fr.contentDocument, fr.getAttribute("data-t")) }
</script>
<iframe src='data:text/xml;charset=windows-1252,<%FF/>' onload="init(this)" data-t="application/xml;charset=windows-1252"></iframe>
<iframe src='data:text/html;charset=windows-1252,%FF' onload="init(this)" data-t="text/html;charset=windows-1252"></iframe>
<iframe src='data:text/xml;charset=windows-1252,<%FF/>' onload="init(this)" data-t="application/xml;charset=UTF-8"></iframe>
<iframe src='data:text/html;charset=windows-1252,%FF' onload="init(this)" data-t="text/html;charset=UTF-8"></iframe>
</body>
</html>

Просмотреть файл

@ -16,11 +16,13 @@
{ contentType: 'text/html;charset=UTF-8', responseText : '<body>\uFFFD<\/body>' }, /*invalid character code in document turns into FFFD*/
{ contentType: 'text/html;charset=UTF-8', responseText : '<body>\u30C6\u30b9\u30c8<\/body>' } /* correctly serialized Shift-JIS */,
{ contentType: 'text/html;charset=UTF-8', responseText: 'top' }, /* There's some markup included, but it's not really relevant for this test suite, so we do an indexOf() test */
{ contentType: 'text/html;charset=UTF-8' }
{ contentType: 'text/html;charset=UTF-8' },
{ contentType: 'text/html;charset=UTF-8', responseText: '<img>foo' },
{ contentType: 'text/html;charset=UTF-8', responseText: '<!DOCTYPE html><html><head></head><body><div></div></body></html>' }
]
function request(input, isHTML, title) {
function request(input, number, title) {
test(function() {
var client = new XMLHttpRequest()
client.open("POST", "resources/content.py?response_charset_label=UTF-8", false)
@ -30,12 +32,14 @@
// The indexOf() assertation will overlook some stuff, i.e. XML prologues that shouldn't be there (looking at you, Presto).
// However, arguably these things have little to do with the XHR functionality we're testing.
if(exp.responseText){ // This test does not want to assert anything about what markup a standalone IMG should be wrapped in. Hence the GIF test lacks a responseText expectation.
assert_true(client.responseText.indexOf(exp.responseText) != -1);
assert_true(client.responseText.indexOf(exp.responseText) != -1,
JSON.stringify(exp.responseText) + " not in " +
JSON.stringify(client.responseText));
}
assert_equals(client.responseXML, null)
}, title)
}
function init(fr, number, title) { request(fr.contentDocument, number) }
function init(fr, number, title) { request(fr.contentDocument, number, title) }
</script>
<!--
This test also tests how documents in various encodings are serialized.
@ -50,6 +54,8 @@
<iframe src='resources/shift-jis-html.py' onload="init(this, 2, 'HTML document, shift-jis')"></iframe>
<iframe src='folder.txt' onload="init(this, 3, 'plain text file')"></iframe>
<iframe src='resources/image.gif' onload="init(this, 4, 'image file')"></iframe>
<iframe src='resources/img-utf8-html.py' onload="init(this, 5, 'img tag')"></iframe>
<iframe src='resources/empty-div-utf8-html.py' onload="init(this, 6, 'empty div')"></iframe>
</body>
</html>

Просмотреть файл

@ -110,6 +110,7 @@ function buildOptionListForChildren(node) {
tagName: tagName,
textContent: textContent,
disabled: child.disabled,
display: child.style.display,
// We need to do this for every option element as each one can have
// an individual style set for direction
textDirection: getComputedDirection(child),

Просмотреть файл

@ -86,6 +86,7 @@ function populateChildren(menulist, options, selectedIndex, zoom, startIndex = 0
item.setAttribute("label", option.textContent);
item.style.direction = option.textDirection;
item.style.fontSize = adjustedTextSize;
item.style.display = option.display;
item.setAttribute("tooltiptext", option.tooltip);
element.appendChild(item);

Просмотреть файл

@ -350,6 +350,8 @@ XRE_InitChildProcess(int aArgc,
// NB: This must be called before profiler_init
NS_LogInit();
mozilla::LogModule::Init();
char aLocal;
profiler_init(&aLocal);

100
xpcom/base/Logging.cpp Normal file
Просмотреть файл

@ -0,0 +1,100 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=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/. */
#include "mozilla/Logging.h"
#include <algorithm>
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/Mutex.h"
#include "mozilla/StaticPtr.h"
#include "nsClassHashtable.h"
// NB: Initial amount determined by auditing the codebase for the total amount
// of unique module names and padding up to the next power of 2.
const uint32_t kInitialModuleCount = 256;
namespace mozilla {
/**
* Safely converts an integer into a valid LogLevel.
*/
LogLevel
Clamp(int32_t aLevel)
{
aLevel = std::min(aLevel, static_cast<int32_t>(LogLevel::Verbose));
aLevel = std::max(aLevel, static_cast<int32_t>(LogLevel::Disabled));
return static_cast<LogLevel>(aLevel);
}
class LogModuleManager
{
public:
LogModuleManager()
: mModulesLock("logmodules")
, mModules(kInitialModuleCount)
{
}
~LogModuleManager()
{
// NB: mModules owns all of the log modules, they will get destroyed by
// its destructor.
}
LogModule* CreateOrGetModule(const char* aName)
{
OffTheBooksMutexAutoLock guard(mModulesLock);
LogModule* module = nullptr;
if (!mModules.Get(aName, &module)) {
// Create the PRLogModule, this will read any env vars that set the log
// level ahead of time. The module is held internally by NSPR, so it's
// okay to drop the pointer when leaving this scope.
PRLogModuleInfo* prModule = PR_NewLogModule(aName);
// NSPR does not impose a restriction on the values that log levels can
// be. LogModule uses the LogLevel enum class so we must clamp the value
// to a max of Verbose.
LogLevel logLevel = Clamp(prModule->level);
module = new LogModule(logLevel);
mModules.Put(aName, module);
}
return module;
}
private:
OffTheBooksMutex mModulesLock;
nsClassHashtable<nsCharPtrHashKey, LogModule> mModules;
};
StaticAutoPtr<LogModuleManager> sLogModuleManager;
LogModule*
LogModule::Get(const char* aName)
{
// This is just a pass through to the LogModuleManager so
// that the LogModuleManager implementation can be kept internal.
MOZ_ASSERT(sLogModuleManager != nullptr);
return sLogModuleManager->CreateOrGetModule(aName);
}
void
LogModule::Init()
{
// NB: This method is not threadsafe; it is expected to be called very early
// in startup prior to any other threads being run.
if (sLogModuleManager) {
// Already initialized.
return;
}
// NB: We intentionally do not register for ClearOnShutdown as that happens
// before all logging is complete. And, yes, that means we leak, but
// we're doing that intentionally.
sLogModuleManager = new LogModuleManager();
}
} // namespace mozilla

Просмотреть файл

@ -10,6 +10,8 @@
#include "prlog.h"
#include "mozilla/Assertions.h"
#include "mozilla/Atomics.h"
#include "mozilla/Likely.h"
// This file is a placeholder for a replacement to the NSPR logging framework
// that is defined in prlog.h. Currently it is just a pass through, but as
@ -43,6 +45,87 @@ enum class LogLevel {
Verbose,
};
class LogModule
{
public:
/**
* Retrieves the module with the given name. If it does not already exist
* it will be created.
*
* @param aName The name of the module.
* @return A log module for the given name. This may be shared.
*/
#if !defined(MOZILLA_XPCOMRT_API)
static LogModule* Get(const char* aName);
#else
// For simplicity, libxpcomrt doesn't supoort logging.
static LogModule* Get(const char* aName) { return nullptr; }
#endif
static void Init();
/**
* Indicates whether or not the given log level is enabled.
*/
bool ShouldLog(LogLevel aLevel) const { return mLevel >= aLevel; }
/**
* Retrieves the log module's current level.
*/
LogLevel Level() const { return mLevel; }
private:
friend class LogModuleManager;
explicit LogModule(LogLevel aLevel) : mLevel(aLevel) {}
LogModule(LogModule&) = delete;
LogModule& operator=(const LogModule&) = delete;
Atomic<LogLevel, Relaxed> mLevel;
};
/**
* Helper class that lazy loads the given log module. This is safe to use for
* declaring static references to log modules and can be used as a replacement
* for accessing a LogModule directly.
*
* Example usage:
* static LazyLogModule sLayoutLog("layout");
*
* void Foo() {
* MOZ_LOG(sLayoutLog, LogLevel::Verbose, ("Entering foo"));
* }
*/
class LazyLogModule final
{
public:
explicit MOZ_CONSTEXPR LazyLogModule(const char* aLogName)
: mLogName(aLogName)
, mLog(nullptr)
{
}
operator LogModule*()
{
// NB: The use of an atomic makes the reading and assignment of mLog
// thread-safe. There is a small chance that mLog will be set more
// than once, but that's okay as it will be set to the same LogModule
// instance each time. Also note LogModule::Get is thread-safe.
LogModule* tmp = mLog;
if (MOZ_UNLIKELY(!tmp)) {
tmp = LogModule::Get(mLogName);
mLog = tmp;
}
return tmp;
}
private:
const char* const mLogName;
Atomic<LogModule*, ReleaseAcquire> mLog;
};
namespace detail {
inline bool log_test(const PRLogModuleInfo* module, LogLevel level) {
@ -50,6 +133,11 @@ inline bool log_test(const PRLogModuleInfo* module, LogLevel level) {
return module && module->level >= static_cast<int>(level);
}
inline bool log_test(const LogModule* module, LogLevel level) {
MOZ_ASSERT(level != LogLevel::Disabled);
return module && module->ShouldLog(level);
}
} // namespace detail
} // namespace mozilla

Просмотреть файл

@ -83,6 +83,7 @@ EXPORTS.mozilla += [
'HoldDropJSObjects.h',
'JSObjectHolder.h',
'LinuxUtils.h',
'Logging.h',
'nsMemoryInfoDumper.h',
'OwningNonNull.h',
'StaticMutex.h',
@ -107,6 +108,7 @@ UNIFIED_SOURCES += [
'ErrorNames.cpp',
'HoldDropJSObjects.cpp',
'JSObjectHolder.cpp',
'Logging.cpp',
'nsConsoleMessage.cpp',
'nsConsoleService.cpp',
'nsCycleCollector.cpp',

Просмотреть файл

@ -17,7 +17,6 @@
#include "nsString.h"
#include "nsXULAppAPI.h"
#include "prprf.h"
#include "mozilla/Logging.h"
#include "nsError.h"
#include "prerror.h"
#include "prerr.h"
@ -217,16 +216,6 @@ nsDebugImpl::SetMultiprocessMode(const char* aDesc)
* always compiled in, in case some other module that uses it is
* compiled with debugging even if this library is not.
*/
static PRLogModuleInfo* gDebugLog;
static void
InitLog()
{
if (0 == gDebugLog) {
gDebugLog = PR_NewLogModule("nsDebug");
}
}
enum nsAssertBehavior
{
NS_ASSERT_UNINITIALIZED,
@ -317,26 +306,20 @@ EXPORT_XPCOM_API(void)
NS_DebugBreak(uint32_t aSeverity, const char* aStr, const char* aExpr,
const char* aFile, int32_t aLine)
{
InitLog();
FixedBuffer buf;
mozilla::LogLevel ll = LogLevel::Warning;
const char* sevString = "WARNING";
switch (aSeverity) {
case NS_DEBUG_ASSERTION:
sevString = "###!!! ASSERTION";
ll = LogLevel::Error;
break;
case NS_DEBUG_BREAK:
sevString = "###!!! BREAK";
ll = LogLevel::Error;
break;
case NS_DEBUG_ABORT:
sevString = "###!!! ABORT";
ll = LogLevel::Error;
break;
default:
@ -371,13 +354,9 @@ NS_DebugBreak(uint32_t aSeverity, const char* aStr, const char* aExpr,
# undef PrintToBuffer
// Write out the message to the debug log
MOZ_LOG(gDebugLog, ll, ("%s", buf.buffer));
PR_LogFlush();
// errors on platforms without a debugdlg ring a bell on stderr
#if !defined(XP_WIN)
if (ll != LogLevel::Warning) {
if (aSeverity != NS_DEBUG_WARNING) {
fprintf(stderr, "\07");
}
#endif

Просмотреть файл

@ -498,6 +498,8 @@ NS_InitXPCOM2(nsIServiceManager** aResult,
NS_LogInit();
mozilla::LogModule::Init();
JS_SetCurrentEmbedderTimeFunction(TimeSinceProcessCreation);
char aLocal;

Просмотреть файл

@ -18,16 +18,8 @@ namespace mozilla {
namespace probes {
#if defined(MOZ_LOGGING)
static PRLogModuleInfo*
GetProbeLog()
{
static PRLogModuleInfo* sLog;
if (!sLog) {
sLog = PR_NewLogModule("SysProbe");
}
return sLog;
}
#define LOG(x) MOZ_LOG(GetProbeLog(), mozilla::LogLevel::Debug, x)
static LazyLogModule sProbeLog("SysProbe");
#define LOG(x) MOZ_LOG(sProbeLog, mozilla::LogLevel::Debug, x)
#else
#define LOG(x)
#endif

Просмотреть файл

@ -81,7 +81,7 @@
using namespace mozilla;
PRLogModuleInfo* nsComponentManagerLog = nullptr;
static LazyLogModule nsComponentManagerLog("nsComponentManager");
#if 0 || defined (DEBUG_timeless)
#define SHOW_DENIED_ON_SHUTDOWN
@ -369,10 +369,6 @@ nsComponentManagerImpl::Init()
{
PR_ASSERT(NOT_INITIALIZED == mStatus);
if (!nsComponentManagerLog) {
nsComponentManagerLog = PR_NewLogModule("nsComponentManager");
}
// Initialize our arena
PL_INIT_ARENA_POOL(&mArena, "ComponentManagerArena", NS_CM_BLOCK_SIZE);

Просмотреть файл

@ -49,17 +49,8 @@
using namespace mozilla;
static PRLogModuleInfo*
GetNativeModuleLoaderLog()
{
static PRLogModuleInfo* sLog;
if (!sLog) {
sLog = PR_NewLogModule("nsNativeModuleLoader");
}
return sLog;
}
#define LOG(level, args) MOZ_LOG(GetNativeModuleLoaderLog(), level, args)
static LazyLogModule sNativeModuleLoaderLog("nsNativeModuleLoader");
#define LOG(level, args) MOZ_LOG(sNativeModuleLoaderLog, level, args)
nsresult
nsNativeModuleLoader::Init()
@ -202,7 +193,7 @@ nsNativeModuleLoader::UnloadLibraries()
}
for (auto iter = mLibraries.Iter(); !iter.Done(); iter.Next()) {
if (MOZ_LOG_TEST(GetNativeModuleLoaderLog(), LogLevel::Debug)) {
if (MOZ_LOG_TEST(sNativeModuleLoaderLog, LogLevel::Debug)) {
nsIHashable* hashedFile = iter.Key();
nsCOMPtr<nsIFile> file(do_QueryInterface(hashedFile));

Просмотреть файл

@ -30,16 +30,8 @@
//
// this enables LogLevel::Debug level information and places all output in
// the file nspr.log
static PRLogModuleInfo*
GetObserverServiceLog()
{
static PRLogModuleInfo* sLog;
if (!sLog) {
sLog = PR_NewLogModule("ObserverService");
}
return sLog;
}
#define LOG(x) MOZ_LOG(GetObserverServiceLog(), mozilla::LogLevel::Debug, x)
static mozilla::LazyLogModule sObserverServiceLog("ObserverService");
#define LOG(x) MOZ_LOG(sObserverServiceLog, mozilla::LogLevel::Debug, x)
using namespace mozilla;

Просмотреть файл

@ -75,7 +75,6 @@ EXPORTS.mozilla += [
'FileUtils.h',
'GenericFactory.h',
'IntentionalCrash.h',
'Logging.h',
'Monitor.h',
'Mutex.h',
'Observer.h',

Просмотреть файл

@ -22,16 +22,9 @@ using namespace mozilla;
#ifdef LOG
#undef LOG
#endif
static PRLogModuleInfo*
GetTeeLog()
{
static PRLogModuleInfo* sLog;
if (!sLog) {
sLog = PR_NewLogModule("nsInputStreamTee");
}
return sLog;
}
#define LOG(args) MOZ_LOG(GetTeeLog(), mozilla::LogLevel::Debug, args)
static LazyLogModule sTeeLog("nsInputStreamTee");
#define LOG(args) MOZ_LOG(sTeeLog, mozilla::LogLevel::Debug, args)
class nsInputStreamTee final : public nsIInputStreamTee
{

Просмотреть файл

@ -31,16 +31,8 @@ using namespace mozilla;
//
// set NSPR_LOG_MODULES=nsPipe:5
//
static PRLogModuleInfo*
GetPipeLog()
{
static PRLogModuleInfo* sLog;
if (!sLog) {
sLog = PR_NewLogModule("nsPipe");
}
return sLog;
}
#define LOG(args) MOZ_LOG(GetPipeLog(), mozilla::LogLevel::Debug, args)
static LazyLogModule sPipeLog("nsPipe");
#define LOG(args) MOZ_LOG(sPipeLog, mozilla::LogLevel::Debug, args)
#define DEFAULT_SEGMENT_SIZE 4096
#define DEFAULT_SEGMENT_COUNT 16

Просмотреть файл

@ -41,19 +41,11 @@ using mozilla::ipc::StringInputStreamParams;
// this enables LogLevel::Debug level information and places all output in
// the file nspr.log
//
static PRLogModuleInfo*
GetStorageStreamLog()
{
static PRLogModuleInfo* sLog;
if (!sLog) {
sLog = PR_NewLogModule("nsStorageStream");
}
return sLog;
}
static LazyLogModule sStorageStreamLog("nsStorageStream");
#ifdef LOG
#undef LOG
#endif
#define LOG(args) MOZ_LOG(GetStorageStreamLog(), mozilla::LogLevel::Debug, args)
#define LOG(args) MOZ_LOG(sStorageStreamLog, mozilla::LogLevel::Debug, args)
nsStorageStream::nsStorageStream()
: mSegmentedBuffer(0), mSegmentSize(0), mWriteInProgress(false),

Просмотреть файл

@ -22,6 +22,9 @@
namespace mozilla {
LazyLogModule gMozPromiseLog("MozPromise");
LazyLogModule gStateWatchingLog("StateWatching");
StaticRefPtr<AbstractThread> sMainThread;
ThreadLocal<AbstractThread*> AbstractThread::sCurrentThreadTLS;
@ -117,9 +120,6 @@ AbstractThread::MainThread()
void
AbstractThread::InitStatics()
{
gMozPromiseLog = PR_NewLogModule("MozPromise");
gStateWatchingLog = PR_NewLogModule("StateWatching");
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!sMainThread);
nsCOMPtr<nsIThread> mainThread;

Просмотреть файл

@ -20,10 +20,9 @@
namespace mozilla {
extern PRLogModuleInfo* gMozPromiseLog;
extern LazyLogModule gMozPromiseLog;
#define PROMISE_LOG(x, ...) \
MOZ_ASSERT(gMozPromiseLog); \
MOZ_LOG(gMozPromiseLog, mozilla::LogLevel::Debug, (x, ##__VA_ARGS__))
namespace detail {

Просмотреть файл

@ -56,10 +56,9 @@
namespace mozilla {
extern PRLogModuleInfo* gStateWatchingLog;
extern LazyLogModule gStateWatchingLog;
#define WATCH_LOG(x, ...) \
MOZ_ASSERT(gStateWatchingLog); \
MOZ_LOG(gStateWatchingLog, LogLevel::Debug, (x, ##__VA_ARGS__))
/*

Просмотреть файл

@ -13,19 +13,11 @@
using namespace mozilla;
static PRLogModuleInfo*
GetLog()
{
static PRLogModuleInfo* sLog;
if (!sLog) {
sLog = PR_NewLogModule("nsEventQueue");
}
return sLog;
}
static LazyLogModule sEventQueueLog("nsEventQueue");
#ifdef LOG
#undef LOG
#endif
#define LOG(args) MOZ_LOG(GetLog(), mozilla::LogLevel::Debug, args)
#define LOG(args) MOZ_LOG(sEventQueueLog, mozilla::LogLevel::Debug, args)
nsEventQueue::nsEventQueue(Mutex& aLock)
: mHead(nullptr)

Просмотреть файл

@ -86,19 +86,11 @@ using namespace mozilla::tasktracer;
using namespace mozilla;
static PRLogModuleInfo*
GetThreadLog()
{
static PRLogModuleInfo* sLog;
if (!sLog) {
sLog = PR_NewLogModule("nsThread");
}
return sLog;
}
static LazyLogModule sThreadLog("nsThread");
#ifdef LOG
#undef LOG
#endif
#define LOG(args) MOZ_LOG(GetThreadLog(), mozilla::LogLevel::Debug, args)
#define LOG(args) MOZ_LOG(sThreadLog, mozilla::LogLevel::Debug, args)
NS_DECL_CI_INTERFACE_GETTER(nsThread)

Просмотреть файл

@ -16,19 +16,11 @@
using namespace mozilla;
static PRLogModuleInfo*
GetThreadPoolLog()
{
static PRLogModuleInfo* sLog;
if (!sLog) {
sLog = PR_NewLogModule("nsThreadPool");
}
return sLog;
}
static LazyLogModule sThreadPoolLog("nsThreadPool");
#ifdef LOG
#undef LOG
#endif
#define LOG(args) MOZ_LOG(GetThreadPoolLog(), mozilla::LogLevel::Debug, args)
#define LOG(args) MOZ_LOG(sThreadPoolLog, mozilla::LogLevel::Debug, args)
// DESIGN:
// o Allocate anonymous threads.

Просмотреть файл

@ -40,14 +40,12 @@ static Atomic<int32_t> gGenerator;
static TimerThread* gThread = nullptr;
// This module prints info about the precision of timers.
PRLogModuleInfo*
static mozilla::LazyLogModule sTimerLog("nsTimerImpl");
mozilla::LogModule*
GetTimerLog()
{
static PRLogModuleInfo* sLog;
if (!sLog) {
sLog = PR_NewLogModule("nsTimerImpl");
}
return sLog;
return sTimerLog;
}
// This module prints info about which timers are firing, which is useful for
@ -83,14 +81,12 @@ GetTimerLog()
// More detailed docs are here:
// https://developer.mozilla.org/en-US/docs/Mozilla/Performance/TimerFirings_logging
//
PRLogModuleInfo*
static mozilla::LazyLogModule sTimerFiringsLog("TimerFirings");
mozilla::LogModule*
GetTimerFiringsLog()
{
static PRLogModuleInfo* sLog;
if (!sLog) {
sLog = PR_NewLogModule("TimerFirings");
}
return sLog;
return sTimerFiringsLog;
}
#include <math.h>

Просмотреть файл

@ -22,7 +22,7 @@
#include "TracedTaskCommon.h"
#endif
extern PRLogModuleInfo* GetTimerLog();
extern mozilla::LogModule* GetTimerLog();
#define NS_TIMER_CID \
{ /* 5ff24248-1dd2-11b2-8427-fbab44f29bc8 */ \