mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 13:34:03 +00:00
import changes from `dev' branch of rmottola/Arctic-Fox:
- Bug 1140558 - Part 2 - Make the testing deepEqual implementation shared properly in ObjectUtils.jsm. r=yoric (f1a217e34a) - Bug 1154773 - Change undefined property a.prototype. r=Yoric (8a4dc37d6c) - Bug 1202971 (part 1) - Fix compile warnings in libmar. r=rstrong. (30cdf015c2) - bug 1200360 - fix $(DEFINES) usage in modules/libmar/tool/moz.build. r=mshal (26f1c5640b) - Bug 903135 - Updates to libmar needed to support B2G MAR signature verification. r=bbondy (81612e2200) - Bug 1228332 - Fix a potentially uninitialized pointer read, flagged by static analysis. r=spohl (9cac770c90) - Bug 1202971 (part 2) - Fix compile warnings in toolkit/mozapps/update/tests. r=rstrong. (814f2b3b8b) - Bug 973933 - Fix libmar warnings. r=rstrong. a=Callek (e0c2d3edcc) - Bug 1232219 (part 1) - Fix -Wunused warnings in libmar/. r=bbondy. (dc046504df) - Bug 1228281 - [GTK3] add padding to buttons. r=karlt (fe8ca55f58) - Bug 1232219 (part 2.5) - Fix -Wunused warnings in parser/expat/lib/. r=hsivonen. (e4d10c5d68) - Bug 1232219 (part 3) - Fix remaining -Wunused warnings. r=glandium. (35c5f3c38e) - Bug 1232219 (follow-up) - Fix nsinstall.c bustage in SM(e) builds. r=me. (d62c12cf35) - Bug 1186815 (part 1) - Replace nsBaseHashtable::Enumerate() calls in modules/libjar/ with iterators. r=mwu. (6959b19fab) - Bug 1186815 (part 2) - Replace nsBaseHashtable::Enumerate() calls in modules/libjar/ with iterators. r=mwu. (02c6f50482) - Bug 1181444 (part 1.5) - Remove dead PLDHashOperator declarations. r=froydnj. (c956e03dc0) - Bug 1225407 - Replace nsInterfaceHashtable::EnumerateRead() call in SubstitutingProtocolHandler with an iterator. r=michal (aa71f5499c) - Bug 1187781 (part 1) - Replace nsBaseHashtable::EnumerateRead() calls in dom/xbl/ with iterators. r=mrbkap. (68f51d05ba) - Bug 1187781 (part 2) - Replace nsBaseHashtable::EnumerateRead() calls in dom/xbl/ with iterators. r=mrbkap. (1dfc261267) - Bug 1187781 (part 3) - Replace nsBaseHashtable::EnumerateRead() calls in dom/xbl/ with iterators. r=mrbkap. (922fc4e4ef) - Bug 1187781 (part 4) - Replace nsBaseHashtable::EnumerateRead() calls in dom/xbl/ with iterators. r=mrbkap. (7b1915053f) - Bug 1187781 (part 5) - Replace nsBaseHashtable::EnumerateRead() calls in dom/xbl/ with iterators. r=mrbkap. (5df4cc1d09) - Bug 1181444 (part 2) - Remove nsBaseHashtable::Enumerate(). r=froydnj. (c606342f1d) - Bug 1243912 - Remove unused Loader::RemoveEntriesWithURI declaration. r=njn (e59b2ef892) - Bug 1187137 (part 4) - Replace nsBaseHashtable::Enumerate() calls in netwerk/protocol/ with iterators. r=valentin. (17fb17c48f) - Bug 1187137 (part 5) - Replace nsBaseHashtable::Enumerate() calls in netwerk/protocol/ with iterators. r=valentin. (89d430cf98) - Bug 1187137 (part 6) - Replace nsBaseHashtable::Enumerate() calls in netwerk/protocol/ with iterators. r=valentin. (37befe08c6) - Bug 1187137 (part 7) - Replace nsBaseHashtable::Enumerate() calls in netwerk/protocol/ with iterators. r=valentin (a8227c4b3e) - Bug 1187137 (part 1) - Replace nsBaseHashtable::Enumerate() calls in netwerk/protocol/ with iterators. r=michal. (05f71a4a94) - Bug 1187137 (part 2) - Replace nsBaseHashtable::Enumerate() calls in netwerk/protocol/ with iterators. r=michal. (5defa991b5) - Bug 1187137 (part 3) - Replace nsBaseHashtable::Enumerate() calls in netwerk/protocol/ with iterators. r=michal. (f2e0a4be0f) - Bug 1187137 (part 8) - Replace nsBaseHashtable::Enumerate() calls in netwerk/protocol/ with iterators. r=valentin. (11b77f3b67) - Bug 1187137 (part 9) - Replace nsBaseHashtable::Enumerate() calls in netwerk/protocol/ with iterators. r=valentin. (7a6bd9a17e) - Bug 1230743 - telemtry for nsConnectionEntry hit rate r=hurley (a75d6ec52c) - Bug 1218297 - eventtokenbucket shutdown leak r=valentin (1723059684) - Bug 1239961 - Minimize amount of PR_Poll and PR_Read calls during shutdown. r=mcmanus (127259afb6) - Bug 1187137 (part 10) - Replace nsBaseHashtable::Enumerate() calls in netwerk/protocol/ with iterators. r=valentin. (eee20459fb) - Bug 1187137 (part 11) - Replace nsBaseHashtable::Enumerate() calls in netwerk/protocol/ with iterators. r=valentin. (864bc96862) - Bug 1187137 (part 12) - Replace nsBaseHashtable::Enumerate() calls in netwerk/protocol/ with iterators. r=valentin. (4fd9540167) - Bug 1187137 (part 13) - Replace nsBaseHashtable::Enumerate() calls in netwerk/protocol/ with iterators. r=valentin. (65a01f4083) - Bug 1187151 (part 14) - Replace nsBaseHashtable::Enumerate() calls in dom/ with iterators. r=baku. (a71b4169a9) - Bug 1187141 - Replace nsBaseHashtable::Enumerate() calls in storage/ with iterators. r=mak. (d95fb168c9) - Bug 1187151 (part 11) - Replace nsBaseHashtable::Enumerate() calls in dom/ with iterators. r=khuey. (dda92d0455) - Bug 1187151 (part 10) - Replace nsBaseHashtable::Enumerate() calls in dom/ with iterators. r=khuey. (f59270049c) - Bug 1191460 Contextual Identity tests r=tanvi,r=ttaubert (03c079ede9) - Bug 1187151 (part 12) - Replace nsBaseHashtable::Enumerate() calls in dom/ with iterators. r=khuey. (0aa9356990) - Bug 1187151 (part 15) - Replace nsBaseHashtable::Enumerate() calls in dom/ with iterators. r=baku. (10e60a4b55) - Bug 1187151 (part 16) - Replace nsBaseHashtable::Enumerate() calls in dom/ with iterators. r=mccr8. (2ef1033aae) - Bug 1187151 (part 17) - Replace nsBaseHashtable::Enumerate() calls in dom/ with iterators. r=mccr8. (dc37dfc17b) - Bug 1241763: Don't fire dom-window-destroyed on outer windows. r=bz (ea30677af6) - Bug 1192128 - In DOM memory reporter, handle WindowID() being a uint64_t. r=mccr8. (b3f834b8f6) - Bug 1187151 (part 18) - Replace nsBaseHashtable::Enumerate() calls in dom/ with iterators. r=mccr8. (22d4fbe0f0) - Bug 1187138 (part 2) - Replace nsBaseHashtable::Enumerate() calls in toolkit/ with iterators. r=froydnj. (b4740ef44b) - Bug 1187138 (part 3) - Replace nsBaseHashtable::Enumerate() calls in toolkit/ with iterators. r=froydnj. (931eb9e813) - Bug 1187138 (part 4) - Replace nsBaseHashtable::Enumerate() calls in toolkit/ with iterators. r=froydnj. (a92fef3586) - Bug 1192189 - Fix assertion condition to use to-be-restyled element's composed document. r=dbaron (6c7733b7cc) - Bug 1187144 (part 10) - Replace nsBaseHashtable::Enumerate() calls in layout/ with iterators. r=heycam. (e93ad4330c) - Bug 1250525 - remove #IFDEF ENABLE_TESTS from dom/quota/ActorsParent.cpp. r=janv (22bc8fc0af) - Bug 1236632 - remove unused variable in FactoryOp::WaitForTransactions; r=janv (3c56b90fff) - Bug 1187116 (part 1) - Replace nsBaseHashtable::EnumerateRead() calls in dom/indexedDB/ with iterators. r=khuey. (f37ac71816) - Bug 1187116 (part 2) - Replace nsBaseHashtable::EnumerateRead() calls in dom/indexedDB/ with iterators. r=khuey. (6bf16c51fe) - Bug 1187116 (part 3) - Replace nsBaseHashtable::EnumerateRead() calls in dom/indexedDB/ with iterators. r=khuey. (351b7d5d34) - Bug 1187116 (part 4) - Replace nsBaseHashtable::EnumerateRead() calls in dom/indexedDB/ with iterators. r=khuey. (330678dde4) - Bug 1187116 (part 5) - Replace nsBaseHashtable::EnumerateRead() calls in dom/indexedDB/ with iterators. r=khuey. (43d20a7fa3) - Bug 1187116 (part 6) - Replace nsBaseHashtable::EnumerateRead() calls in dom/indexedDB/ with iterators. r=khuey. (d448d80726) - quick fix by revert of anticipated patch (00a093055d) - Bug 1186814 - Replace nsBaseHashtable::EnumerateRead() calls in extensions/spellcheck/ with iterators. r=ehsan. (ff78039ba0)
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += [
|
||||
'test/browser/browser.ini',
|
||||
]
|
||||
|
||||
with Files('**'):
|
||||
BUG_COMPONENT = ('Firefox', 'Contextual Identity')
|
||||
@@ -0,0 +1,7 @@
|
||||
[DEFAULT]
|
||||
skip-if = buildapp == "mulet"
|
||||
support-files =
|
||||
file_reflect_cookie_into_title.html
|
||||
|
||||
[browser_usercontext.js]
|
||||
skip-if = e10s
|
||||
@@ -0,0 +1,91 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
|
||||
const USER_CONTEXTS = [
|
||||
"default",
|
||||
"personal",
|
||||
"work",
|
||||
];
|
||||
|
||||
const BASE_URI = "http://mochi.test:8888/browser/browser/components/"
|
||||
+ "contextualidentity/test/browser/file_reflect_cookie_into_title.html";
|
||||
|
||||
|
||||
// opens `uri' in a new tab with the provided userContextId and focuses it.
|
||||
// returns the newly opened tab
|
||||
function openTabInUserContext(uri, userContextId) {
|
||||
// open the tab in the correct userContextId
|
||||
let tab = gBrowser.addTab(uri, {userContextId});
|
||||
|
||||
// select tab and make sure its browser is focused
|
||||
gBrowser.selectedTab = tab;
|
||||
tab.ownerDocument.defaultView.focus();
|
||||
|
||||
return tab;
|
||||
}
|
||||
|
||||
add_task(function* setup() {
|
||||
// make sure userContext is enabled.
|
||||
SpecialPowers.pushPrefEnv({"set": [
|
||||
["privacy.userContext.enabled", true]
|
||||
]});
|
||||
});
|
||||
|
||||
add_task(function* cleanup() {
|
||||
// make sure we don't leave any prefs set for the next tests
|
||||
registerCleanupFunction(function() {
|
||||
SpecialPowers.popPrefEnv();
|
||||
});
|
||||
});
|
||||
|
||||
add_task(function* test() {
|
||||
for (let userContextId of Object.keys(USER_CONTEXTS)) {
|
||||
// load the page in 3 different contexts and set a cookie
|
||||
// which should only be visible in that context
|
||||
let cookie = USER_CONTEXTS[userContextId];
|
||||
|
||||
// open our tab in the given user context
|
||||
let tab = openTabInUserContext(BASE_URI+"?"+cookie, userContextId);
|
||||
|
||||
// wait for tab load
|
||||
yield BrowserTestUtils.browserLoaded(gBrowser.getBrowserForTab(tab));
|
||||
|
||||
// remove the tab
|
||||
gBrowser.removeTab(tab);
|
||||
}
|
||||
|
||||
{
|
||||
// Set a cookie in a different context so we can detect if that affects
|
||||
// cross-context properly. If we don't do that, we get an UNEXPECTED-PASS
|
||||
// for the localStorage case for the last tab we set.
|
||||
let tab = openTabInUserContext(BASE_URI+"?foo", 9999);
|
||||
yield BrowserTestUtils.browserLoaded(gBrowser.getBrowserForTab(tab));
|
||||
gBrowser.removeTab(tab);
|
||||
}
|
||||
|
||||
for (let userContextId of Object.keys(USER_CONTEXTS)) {
|
||||
// Load the page without setting the cookie this time
|
||||
let expectedContext = USER_CONTEXTS[userContextId];
|
||||
|
||||
let tab = openTabInUserContext(BASE_URI, userContextId);
|
||||
|
||||
// wait for load
|
||||
let browser = gBrowser.getBrowserForTab(tab);
|
||||
yield BrowserTestUtils.browserLoaded(browser);
|
||||
|
||||
// get the title
|
||||
let title = browser.contentDocument.title.trim().split("|");
|
||||
|
||||
// check each item in the title and validate it meets expectatations
|
||||
for (let part of title) {
|
||||
let [storageMethodName, value] = part.split("=");
|
||||
let is_f = storageMethodName == "cookie" ? is : todo_is;
|
||||
is_f(value, expectedContext,
|
||||
"the title reflects the expected contextual identity of " +
|
||||
expectedContext + " for method " + storageMethodName + ": " + value);
|
||||
}
|
||||
|
||||
gBrowser.removeTab(tab);
|
||||
}
|
||||
});
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>title not set</title>
|
||||
<script>
|
||||
// if we have a query string, use it to set the cookie and localStorage
|
||||
if (window.location.search.length > 0) {
|
||||
let context_name = window.location.search.substr(1);
|
||||
document.cookie = "userContextId=" + context_name;
|
||||
localStorage.setItem("userContext", context_name);
|
||||
}
|
||||
|
||||
// get the cookie
|
||||
let [name, val] = document.cookie.split("=");
|
||||
|
||||
// set the title to reflect the cookie and local storage values we find
|
||||
document.title = "cookie=" + val + "|"
|
||||
+ "local=" + localStorage.getItem("userContext");
|
||||
</script>
|
||||
</head>
|
||||
<body></body>
|
||||
</html>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
DIRS += [
|
||||
'about',
|
||||
'contextualidentity',
|
||||
'certerror',
|
||||
'dirprovider',
|
||||
'downloads',
|
||||
|
||||
+2
-4
@@ -213,7 +213,6 @@ static void
|
||||
copydir( char *from, char *to, mode_t mode, char *group, char *owner,
|
||||
int dotimes, uid_t uid, gid_t gid)
|
||||
{
|
||||
int i;
|
||||
DIR *dir;
|
||||
struct dirent *ep;
|
||||
struct stat sb;
|
||||
@@ -262,13 +261,12 @@ copydir( char *from, char *to, mode_t mode, char *group, char *owner,
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int onlydir, dodir, dolink, dorelsymlink, dotimes, opt, len, lplen, tdlen, bnlen, exists, fromfd, tofd, cc, wc;
|
||||
int onlydir, dodir, dolink, dorelsymlink, dotimes, opt, len, lplen, tdlen, bnlen, exists;
|
||||
mode_t mode = 0755;
|
||||
char *linkprefix, *owner, *group, *cp, *cwd, *todir, *toname, *name, *base, *linkname, *bp, buf[BUFSIZ];
|
||||
char *linkprefix, *owner, *group, *cp, *cwd, *todir, *toname, *name, *base, *linkname, buf[BUFSIZ];
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
struct stat sb, tosb, fromsb;
|
||||
struct utimbuf utb;
|
||||
|
||||
program = argv[0];
|
||||
cwd = linkname = linkprefix = owner = group = 0;
|
||||
|
||||
@@ -467,37 +467,6 @@ nsCCUncollectableMarker::Observe(nsISupports* aSubject, const char* aTopic,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
struct TraceClosure
|
||||
{
|
||||
TraceClosure(JSTracer* aTrc, uint32_t aGCNumber)
|
||||
: mTrc(aTrc), mGCNumber(aGCNumber)
|
||||
{}
|
||||
JSTracer* mTrc;
|
||||
uint32_t mGCNumber;
|
||||
};
|
||||
|
||||
static PLDHashOperator
|
||||
TraceActiveWindowGlobal(const uint64_t& aId, nsGlobalWindow*& aWindow, void* aClosure)
|
||||
{
|
||||
if (aWindow->GetDocShell() && aWindow->IsOuterWindow()) {
|
||||
TraceClosure* closure = static_cast<TraceClosure*>(aClosure);
|
||||
aWindow->TraceGlobalJSObject(closure->mTrc);
|
||||
EventListenerManager* elm = aWindow->GetExistingListenerManager();
|
||||
if (elm) {
|
||||
elm->TraceListeners(closure->mTrc);
|
||||
}
|
||||
|
||||
#ifdef MOZ_XUL
|
||||
nsIDocument* doc = aWindow->GetExtantDoc();
|
||||
if (doc && doc->IsXULDocument()) {
|
||||
XULDocument* xulDoc = static_cast<XULDocument*>(doc);
|
||||
xulDoc->TraceProtos(closure->mTrc, closure->mGCNumber);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
void
|
||||
mozilla::dom::TraceBlackJS(JSTracer* aTrc, uint32_t aGCNumber, bool aIsShutdownGC)
|
||||
{
|
||||
@@ -518,12 +487,27 @@ mozilla::dom::TraceBlackJS(JSTracer* aTrc, uint32_t aGCNumber, bool aIsShutdownG
|
||||
return;
|
||||
}
|
||||
|
||||
TraceClosure closure(aTrc, aGCNumber);
|
||||
|
||||
// Mark globals of active windows black.
|
||||
nsGlobalWindow::WindowByIdTable* windowsById =
|
||||
nsGlobalWindow::GetWindowsTable();
|
||||
if (windowsById) {
|
||||
windowsById->Enumerate(TraceActiveWindowGlobal, &closure);
|
||||
for (auto iter = windowsById->Iter(); !iter.Done(); iter.Next()) {
|
||||
nsGlobalWindow* window = iter.Data();
|
||||
if (window->GetDocShell() && window->IsOuterWindow()) {
|
||||
window->TraceGlobalJSObject(aTrc);
|
||||
EventListenerManager* elm = window->GetExistingListenerManager();
|
||||
if (elm) {
|
||||
elm->TraceListeners(aTrc);
|
||||
}
|
||||
|
||||
#ifdef MOZ_XUL
|
||||
nsIDocument* doc = window->GetExtantDoc();
|
||||
if (doc && doc->IsXULDocument()) {
|
||||
XULDocument* xulDoc = static_cast<XULDocument*>(doc);
|
||||
xulDoc->TraceProtos(aTrc, aGCNumber);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,27 +37,18 @@ nsDOMAttributeMap::nsDOMAttributeMap(Element* aContent)
|
||||
// we'll be told to drop our reference
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear map pointer for attributes.
|
||||
*/
|
||||
PLDHashOperator
|
||||
RemoveMapRef(nsAttrHashKey::KeyType aKey, RefPtr<Attr>& aData,
|
||||
void* aUserArg)
|
||||
{
|
||||
aData->SetMap(nullptr);
|
||||
|
||||
return PL_DHASH_REMOVE;
|
||||
}
|
||||
|
||||
nsDOMAttributeMap::~nsDOMAttributeMap()
|
||||
{
|
||||
mAttributeCache.Enumerate(RemoveMapRef, nullptr);
|
||||
DropReference();
|
||||
}
|
||||
|
||||
void
|
||||
nsDOMAttributeMap::DropReference()
|
||||
{
|
||||
mAttributeCache.Enumerate(RemoveMapRef, nullptr);
|
||||
for (auto iter = mAttributeCache.Iter(); !iter.Done(); iter.Next()) {
|
||||
iter.Data()->SetMap(nullptr);
|
||||
iter.Remove();
|
||||
}
|
||||
mContent = nullptr;
|
||||
}
|
||||
|
||||
@@ -70,20 +61,10 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDOMAttributeMap)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
|
||||
PLDHashOperator
|
||||
TraverseMapEntry(nsAttrHashKey::KeyType aKey, RefPtr<Attr>& aData,
|
||||
void* aUserArg)
|
||||
{
|
||||
nsCycleCollectionTraversalCallback *cb =
|
||||
static_cast<nsCycleCollectionTraversalCallback*>(aUserArg);
|
||||
|
||||
cb->NoteXPCOMChild(static_cast<nsINode*>(aData.get()));
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMAttributeMap)
|
||||
tmp->mAttributeCache.Enumerate(TraverseMapEntry, &cb);
|
||||
for (auto iter = tmp->mAttributeCache.Iter(); !iter.Done(); iter.Next()) {
|
||||
cb.NoteXPCOMChild(static_cast<nsINode*>(iter.Data().get()));
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContent)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
@@ -1624,15 +1624,6 @@ nsMessageManagerScriptExecutor::DidCreateGlobal()
|
||||
}
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
RemoveCachedScriptEntry(const nsAString& aKey,
|
||||
nsMessageManagerScriptHolder*& aData,
|
||||
void* aUserArg)
|
||||
{
|
||||
delete aData;
|
||||
return PL_DHASH_REMOVE;
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
nsMessageManagerScriptExecutor::Shutdown()
|
||||
@@ -1640,7 +1631,10 @@ nsMessageManagerScriptExecutor::Shutdown()
|
||||
if (sCachedScripts) {
|
||||
AutoSafeJSContext cx;
|
||||
NS_ASSERTION(sCachedScripts != nullptr, "Need cached scripts");
|
||||
sCachedScripts->Enumerate(RemoveCachedScriptEntry, nullptr);
|
||||
for (auto iter = sCachedScripts->Iter(); !iter.Done(); iter.Next()) {
|
||||
delete iter.Data();
|
||||
iter.Remove();
|
||||
}
|
||||
|
||||
delete sCachedScripts;
|
||||
sCachedScripts = nullptr;
|
||||
|
||||
+17
-26
@@ -1622,6 +1622,9 @@ nsGlobalWindow::FreeInnerObjects(bool aForDocumentOpen)
|
||||
// other members that the window destroyed observers could
|
||||
// re-create.
|
||||
NotifyDOMWindowDestroyed(this);
|
||||
if (auto* reporter = nsWindowMemoryReporter::Get()) {
|
||||
reporter->ObserveDOMWindowDetached(this);
|
||||
}
|
||||
|
||||
mInnerObjectsFreed = true;
|
||||
|
||||
@@ -1737,13 +1740,6 @@ NS_INTERFACE_MAP_END
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsGlobalWindow)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsGlobalWindow)
|
||||
|
||||
static PLDHashOperator
|
||||
MarkXBLHandlers(nsXBLPrototypeHandler* aKey, JS::Heap<JSObject*>& aData, void* aClosure)
|
||||
{
|
||||
JS::ExposeObjectToActiveJS(aData);
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsGlobalWindow)
|
||||
if (tmp->IsBlackForCC(false)) {
|
||||
if (nsCCUncollectableMarker::InGeneration(tmp->mCanSkipCCGeneration)) {
|
||||
@@ -1751,7 +1747,11 @@ NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsGlobalWindow)
|
||||
}
|
||||
tmp->mCanSkipCCGeneration = nsCCUncollectableMarker::sGeneration;
|
||||
if (tmp->mCachedXBLPrototypeHandlers) {
|
||||
tmp->mCachedXBLPrototypeHandlers->Enumerate(MarkXBLHandlers, nullptr);
|
||||
for (auto iter = tmp->mCachedXBLPrototypeHandlers->Iter();
|
||||
!iter.Done();
|
||||
iter.Next()) {
|
||||
JS::ExposeObjectToActiveJS(iter.Data());
|
||||
}
|
||||
}
|
||||
if (EventListenerManager* elm = tmp->GetExistingListenerManager()) {
|
||||
elm->MarkForCC();
|
||||
@@ -1947,24 +1947,14 @@ nsGlobalWindow::RiskyUnlink()
|
||||
}
|
||||
#endif
|
||||
|
||||
struct TraceData
|
||||
{
|
||||
const TraceCallbacks& callbacks;
|
||||
void* closure;
|
||||
};
|
||||
|
||||
static PLDHashOperator
|
||||
TraceXBLHandlers(nsXBLPrototypeHandler* aKey, JS::Heap<JSObject*>& aData, void* aClosure)
|
||||
{
|
||||
TraceData* data = static_cast<TraceData*>(aClosure);
|
||||
data->callbacks.Trace(&aData, "Cached XBL prototype handler", data->closure);
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsGlobalWindow)
|
||||
if (tmp->mCachedXBLPrototypeHandlers) {
|
||||
TraceData data = { aCallbacks, aClosure };
|
||||
tmp->mCachedXBLPrototypeHandlers->Enumerate(TraceXBLHandlers, &data);
|
||||
for (auto iter = tmp->mCachedXBLPrototypeHandlers->Iter();
|
||||
!iter.Done();
|
||||
iter.Next()) {
|
||||
JS::Heap<JSObject*>& data = iter.Data();
|
||||
aCallbacks.Trace(&data, "Cached XBL prototype handler", aClosure);
|
||||
}
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||
@@ -2949,8 +2939,9 @@ nsGlobalWindow::DetachFromDocShell()
|
||||
inner->FreeInnerObjects();
|
||||
}
|
||||
|
||||
// Make sure that this is called before we null out the document.
|
||||
NotifyDOMWindowDestroyed(this);
|
||||
if (auto* reporter = nsWindowMemoryReporter::Get()) {
|
||||
reporter->ObserveDOMWindowDetached(this);
|
||||
}
|
||||
|
||||
NotifyWindowIDDestroyed("outer-window-destroyed");
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "js/TypeDecls.h"
|
||||
#include "nsRefPtrHashtable.h"
|
||||
|
||||
// Only fired for inner windows.
|
||||
#define DOM_WINDOW_DESTROYED_TOPIC "dom-window-destroyed"
|
||||
#define DOM_WINDOW_FROZEN_TOPIC "dom-window-frozen"
|
||||
#define DOM_WINDOW_THAWED_TOPIC "dom-window-thawed"
|
||||
|
||||
@@ -180,11 +180,6 @@ public:
|
||||
aConstructorEnabled);
|
||||
}
|
||||
|
||||
typedef PLDHashOperator
|
||||
(* NameEnumerator)(const nsAString& aGlobalName,
|
||||
const nsGlobalNameStruct& aGlobalNameStruct,
|
||||
void* aClosure);
|
||||
|
||||
class NameIterator : public PLDHashTable::Iterator
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -113,10 +113,6 @@ nsWindowMemoryReporter::Init()
|
||||
|
||||
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
|
||||
if (os) {
|
||||
// DOM_WINDOW_DESTROYED_TOPIC announces what we call window "detachment",
|
||||
// when a window's docshell is set to nullptr.
|
||||
os->AddObserver(sWindowReporter, DOM_WINDOW_DESTROYED_TOPIC,
|
||||
/* weakRef = */ true);
|
||||
os->AddObserver(sWindowReporter, "after-minimize-memory-usage",
|
||||
/* weakRef = */ true);
|
||||
os->AddObserver(sWindowReporter, "cycle-collector-begin",
|
||||
@@ -129,6 +125,12 @@ nsWindowMemoryReporter::Init()
|
||||
RegisterGhostWindowsDistinguishedAmount(GhostWindowsReporter::DistinguishedAmount);
|
||||
}
|
||||
|
||||
/* static */ nsWindowMemoryReporter*
|
||||
nsWindowMemoryReporter::Get()
|
||||
{
|
||||
return sWindowReporter;
|
||||
}
|
||||
|
||||
static already_AddRefed<nsIURI>
|
||||
GetWindowURI(nsIDOMWindow *aWindow)
|
||||
{
|
||||
@@ -169,7 +171,7 @@ AppendWindowURI(nsGlobalWindow *aWindow, nsACString& aStr, bool aAnonymize)
|
||||
|
||||
if (uri) {
|
||||
if (aAnonymize && !aWindow->IsChromeWindow()) {
|
||||
aStr.AppendPrintf("<anonymized-%d>", aWindow->WindowID());
|
||||
aStr.AppendPrintf("<anonymized-%llu>", aWindow->WindowID());
|
||||
} else {
|
||||
nsCString spec;
|
||||
uri->GetSpec(spec);
|
||||
@@ -278,9 +280,7 @@ CollectWindowReports(nsGlobalWindow *aWindow,
|
||||
if (top) {
|
||||
windowPath += NS_LITERAL_CSTRING("top(");
|
||||
AppendWindowURI(top, windowPath, aAnonymize);
|
||||
windowPath += NS_LITERAL_CSTRING(", id=");
|
||||
windowPath.AppendInt(top->WindowID());
|
||||
windowPath += NS_LITERAL_CSTRING(")");
|
||||
windowPath.AppendPrintf(", id=%llu)", top->WindowID());
|
||||
|
||||
aTopWindowPaths->Put(aWindow->WindowID(), windowPath);
|
||||
|
||||
@@ -448,15 +448,6 @@ CollectWindowReports(nsGlobalWindow *aWindow,
|
||||
|
||||
typedef nsTArray< RefPtr<nsGlobalWindow> > WindowArray;
|
||||
|
||||
static
|
||||
PLDHashOperator
|
||||
GetWindows(const uint64_t& aId, nsGlobalWindow*& aWindow, void* aClosure)
|
||||
{
|
||||
((WindowArray *)aClosure)->AppendElement(aWindow);
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindowMemoryReporter::CollectReports(nsIMemoryReporterCallback* aCb,
|
||||
nsISupports* aClosure, bool aAnonymize)
|
||||
@@ -468,7 +459,9 @@ nsWindowMemoryReporter::CollectReports(nsIMemoryReporterCallback* aCb,
|
||||
// Hold on to every window in memory so that window objects can't be
|
||||
// destroyed while we're calling the memory reporter callback.
|
||||
WindowArray windows;
|
||||
windowsById->Enumerate(GetWindows, &windows);
|
||||
for (auto iter = windowsById->Iter(); !iter.Done(); iter.Next()) {
|
||||
windows.AppendElement(iter.Data());
|
||||
}
|
||||
|
||||
// Get the IDs of all the "ghost" windows, and call aCb->Callback() for each
|
||||
// one.
|
||||
@@ -618,9 +611,7 @@ NS_IMETHODIMP
|
||||
nsWindowMemoryReporter::Observe(nsISupports *aSubject, const char *aTopic,
|
||||
const char16_t *aData)
|
||||
{
|
||||
if (!strcmp(aTopic, DOM_WINDOW_DESTROYED_TOPIC)) {
|
||||
ObserveDOMWindowDetached(aSubject);
|
||||
} else if (!strcmp(aTopic, "after-minimize-memory-usage")) {
|
||||
if (!strcmp(aTopic, "after-minimize-memory-usage")) {
|
||||
ObserveAfterMinimizeMemoryUsage();
|
||||
} else if (!strcmp(aTopic, "cycle-collector-begin")) {
|
||||
if (mCheckTimer) {
|
||||
@@ -642,9 +633,9 @@ nsWindowMemoryReporter::Observe(nsISupports *aSubject, const char *aTopic,
|
||||
}
|
||||
|
||||
void
|
||||
nsWindowMemoryReporter::ObserveDOMWindowDetached(nsISupports* aWindow)
|
||||
nsWindowMemoryReporter::ObserveDOMWindowDetached(nsGlobalWindow* aWindow)
|
||||
{
|
||||
nsWeakPtr weakWindow = do_GetWeakReference(aWindow);
|
||||
nsWeakPtr weakWindow = do_GetWeakReference(static_cast<nsIDOMEventTarget*>(aWindow));
|
||||
if (!weakWindow) {
|
||||
NS_WARNING("Couldn't take weak reference to a window?");
|
||||
return;
|
||||
@@ -693,19 +684,6 @@ nsWindowMemoryReporter::AsyncCheckForGhostWindows()
|
||||
}
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
BackdateTimeStampsEnumerator(nsISupports *aKey, TimeStamp &aTimeStamp,
|
||||
void* aClosure)
|
||||
{
|
||||
TimeStamp *minTimeStamp = static_cast<TimeStamp*>(aClosure);
|
||||
|
||||
if (!aTimeStamp.IsNull() && aTimeStamp > *minTimeStamp) {
|
||||
aTimeStamp = *minTimeStamp;
|
||||
}
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
void
|
||||
nsWindowMemoryReporter::ObserveAfterMinimizeMemoryUsage()
|
||||
{
|
||||
@@ -718,79 +696,12 @@ nsWindowMemoryReporter::ObserveAfterMinimizeMemoryUsage()
|
||||
TimeStamp minTimeStamp = TimeStamp::Now() -
|
||||
TimeDuration::FromSeconds(GetGhostTimeout());
|
||||
|
||||
mDetachedWindows.Enumerate(BackdateTimeStampsEnumerator,
|
||||
&minTimeStamp);
|
||||
}
|
||||
|
||||
struct CheckForGhostWindowsEnumeratorData
|
||||
{
|
||||
nsTHashtable<nsCStringHashKey> *nonDetachedDomains;
|
||||
nsTHashtable<nsUint64HashKey> *ghostWindowIDs;
|
||||
nsIEffectiveTLDService *tldService;
|
||||
uint32_t ghostTimeout;
|
||||
TimeStamp now;
|
||||
};
|
||||
|
||||
static PLDHashOperator
|
||||
CheckForGhostWindowsEnumerator(nsISupports *aKey, TimeStamp& aTimeStamp,
|
||||
void* aClosure)
|
||||
{
|
||||
CheckForGhostWindowsEnumeratorData *data =
|
||||
static_cast<CheckForGhostWindowsEnumeratorData*>(aClosure);
|
||||
|
||||
nsWeakPtr weakKey = do_QueryInterface(aKey);
|
||||
nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(weakKey);
|
||||
if (!window) {
|
||||
// The window object has been destroyed. Stop tracking its weak ref in our
|
||||
// hashtable.
|
||||
return PL_DHASH_REMOVE;
|
||||
}
|
||||
|
||||
// Avoid calling GetTop() if we have no outer window. Nothing will break if
|
||||
// we do, but it will spew debug output, which can cause our test logs to
|
||||
// overflow.
|
||||
nsCOMPtr<nsIDOMWindow> top;
|
||||
if (window->GetOuterWindow()) {
|
||||
top = window->GetOuterWindow()->GetTop();
|
||||
}
|
||||
|
||||
if (top) {
|
||||
// The window is no longer detached, so we no longer want to track it.
|
||||
return PL_DHASH_REMOVE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> uri = GetWindowURI(window);
|
||||
|
||||
nsAutoCString domain;
|
||||
if (uri) {
|
||||
// GetBaseDomain works fine if |uri| is null, but it outputs a warning
|
||||
// which ends up overrunning the mochitest logs.
|
||||
data->tldService->GetBaseDomain(uri, 0, domain);
|
||||
}
|
||||
|
||||
if (data->nonDetachedDomains->Contains(domain)) {
|
||||
// This window shares a domain with a non-detached window, so reset its
|
||||
// clock.
|
||||
aTimeStamp = TimeStamp();
|
||||
} else {
|
||||
// This window does not share a domain with a non-detached window, so it
|
||||
// meets ghost criterion (2).
|
||||
if (aTimeStamp.IsNull()) {
|
||||
// This may become a ghost window later; start its clock.
|
||||
aTimeStamp = data->now;
|
||||
} else if ((data->now - aTimeStamp).ToSeconds() > data->ghostTimeout) {
|
||||
// This definitely is a ghost window, so add it to ghostWindowIDs, if
|
||||
// that is not null.
|
||||
if (data->ghostWindowIDs) {
|
||||
nsCOMPtr<nsPIDOMWindow> pWindow = do_QueryInterface(window);
|
||||
if (pWindow) {
|
||||
data->ghostWindowIDs->PutEntry(pWindow->WindowID());
|
||||
}
|
||||
}
|
||||
for (auto iter = mDetachedWindows.Iter(); !iter.Done(); iter.Next()) {
|
||||
TimeStamp& timeStamp = iter.Data();
|
||||
if (!timeStamp.IsNull() && timeStamp > minTimeStamp) {
|
||||
timeStamp = minTimeStamp;
|
||||
}
|
||||
}
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -853,11 +764,62 @@ nsWindowMemoryReporter::CheckForGhostWindows(
|
||||
|
||||
// Update mDetachedWindows and write the ghost window IDs into aOutGhostIDs,
|
||||
// if it's not null.
|
||||
CheckForGhostWindowsEnumeratorData ghostEnumData =
|
||||
{ &nonDetachedWindowDomains, aOutGhostIDs, tldService,
|
||||
GetGhostTimeout(), mLastCheckForGhostWindows };
|
||||
mDetachedWindows.Enumerate(CheckForGhostWindowsEnumerator,
|
||||
&ghostEnumData);
|
||||
uint32_t ghostTimeout = GetGhostTimeout();
|
||||
TimeStamp now = mLastCheckForGhostWindows;
|
||||
for (auto iter = mDetachedWindows.Iter(); !iter.Done(); iter.Next()) {
|
||||
nsWeakPtr weakKey = do_QueryInterface(iter.Key());
|
||||
nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(weakKey);
|
||||
if (!window) {
|
||||
// The window object has been destroyed. Stop tracking its weak ref in
|
||||
// our hashtable.
|
||||
iter.Remove();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Avoid calling GetTop() if we have no outer window. Nothing will break if
|
||||
// we do, but it will spew debug output, which can cause our test logs to
|
||||
// overflow.
|
||||
nsCOMPtr<nsPIDOMWindow> top;
|
||||
if (window->GetOuterWindow()) {
|
||||
top = window->GetOuterWindow()->GetTop();
|
||||
}
|
||||
|
||||
if (top) {
|
||||
// The window is no longer detached, so we no longer want to track it.
|
||||
iter.Remove();
|
||||
continue;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> uri = GetWindowURI(nsGlobalWindow::Cast(window));
|
||||
|
||||
nsAutoCString domain;
|
||||
if (uri) {
|
||||
// GetBaseDomain works fine if |uri| is null, but it outputs a warning
|
||||
// which ends up overrunning the mochitest logs.
|
||||
tldService->GetBaseDomain(uri, 0, domain);
|
||||
}
|
||||
|
||||
TimeStamp& timeStamp = iter.Data();
|
||||
|
||||
if (nonDetachedWindowDomains.Contains(domain)) {
|
||||
// This window shares a domain with a non-detached window, so reset its
|
||||
// clock.
|
||||
timeStamp = TimeStamp();
|
||||
} else {
|
||||
// This window does not share a domain with a non-detached window, so it
|
||||
// meets ghost criterion (2).
|
||||
if (timeStamp.IsNull()) {
|
||||
// This may become a ghost window later; start its clock.
|
||||
timeStamp = now;
|
||||
} else if ((now - timeStamp).ToSeconds() > ghostTimeout) {
|
||||
// This definitely is a ghost window, so add it to aOutGhostIDs, if
|
||||
// that is not null.
|
||||
if (aOutGhostIDs && window) {
|
||||
aOutGhostIDs->PutEntry(window->WindowID());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsWindowMemoryReporter::GhostWindowsReporter,
|
||||
@@ -897,7 +859,9 @@ nsWindowMemoryReporter::UnlinkGhostWindows()
|
||||
// Hold on to every window in memory so that window objects can't be
|
||||
// destroyed while we're calling the UnlinkGhostWindows callback.
|
||||
WindowArray windows;
|
||||
windowsById->Enumerate(GetWindows, &windows);
|
||||
for (auto iter = windowsById->Iter(); !iter.Done(); iter.Next()) {
|
||||
windows.AppendElement(iter.Data());
|
||||
}
|
||||
|
||||
// Get the IDs of all the "ghost" windows, and unlink them all.
|
||||
nsTHashtable<nsUint64HashKey> ghostWindows;
|
||||
|
||||
@@ -158,6 +158,9 @@ public:
|
||||
static void UnlinkGhostWindows();
|
||||
#endif
|
||||
|
||||
static nsWindowMemoryReporter* Get();
|
||||
void ObserveDOMWindowDetached(nsGlobalWindow* aWindow);
|
||||
|
||||
private:
|
||||
~nsWindowMemoryReporter();
|
||||
|
||||
@@ -199,7 +202,6 @@ private:
|
||||
*/
|
||||
uint32_t GetGhostTimeout();
|
||||
|
||||
void ObserveDOMWindowDetached(nsISupports* aWindow);
|
||||
void ObserveAfterMinimizeMemoryUsage();
|
||||
|
||||
/**
|
||||
|
||||
@@ -294,28 +294,25 @@ BluetoothService::UnregisterBluetoothSignalHandler(
|
||||
}
|
||||
}
|
||||
|
||||
PLDHashOperator
|
||||
RemoveAllSignalHandlers(const nsAString& aKey,
|
||||
nsAutoPtr<BluetoothSignalObserverList>& aData,
|
||||
void* aUserArg)
|
||||
{
|
||||
BluetoothSignalObserver* handler =
|
||||
static_cast<BluetoothSignalObserver*>(aUserArg);
|
||||
aData->RemoveObserver(handler);
|
||||
// We shouldn't have duplicate instances in the ObserverList, but there's
|
||||
// no appropriate way to do duplication check while registering, so
|
||||
// assertions are added here.
|
||||
MOZ_ASSERT(!aData->RemoveObserver(handler));
|
||||
return aData->Length() ? PL_DHASH_NEXT : PL_DHASH_REMOVE;
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothService::UnregisterAllSignalHandlers(BluetoothSignalObserver* aHandler)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aHandler);
|
||||
|
||||
mBluetoothSignalObserverTable.Enumerate(RemoveAllSignalHandlers, aHandler);
|
||||
for (auto iter = mBluetoothSignalObserverTable.Iter();
|
||||
!iter.Done();
|
||||
iter.Next()) {
|
||||
nsAutoPtr<BluetoothSignalObserverList>& ol = iter.Data();
|
||||
ol->RemoveObserver(aHandler);
|
||||
// We shouldn't have duplicate instances in the ObserverList, but there's
|
||||
// no appropriate way to do duplication check while registering, so
|
||||
// assertions are added here.
|
||||
MOZ_ASSERT(!ol->RemoveObserver(aHandler));
|
||||
if (ol->Length() == 0) {
|
||||
iter.Remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -5024,19 +5024,17 @@ EventStateManager::SetContentState(nsIContent* aContent, EventStates aState)
|
||||
return true;
|
||||
}
|
||||
|
||||
PLDHashOperator
|
||||
void
|
||||
EventStateManager::ResetLastOverForContent(
|
||||
const uint32_t& aIdx,
|
||||
RefPtr<OverOutElementsWrapper>& aElemWrapper,
|
||||
void* aClosure)
|
||||
nsIContent* aContent)
|
||||
{
|
||||
nsIContent* content = static_cast<nsIContent*>(aClosure);
|
||||
if (aElemWrapper && aElemWrapper->mLastOverElement &&
|
||||
nsContentUtils::ContentIsDescendantOf(aElemWrapper->mLastOverElement, content)) {
|
||||
nsContentUtils::ContentIsDescendantOf(aElemWrapper->mLastOverElement,
|
||||
aContent)) {
|
||||
aElemWrapper->mLastOverElement = nullptr;
|
||||
}
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -5085,8 +5083,11 @@ EventStateManager::ContentRemoved(nsIDocument* aDocument, nsIContent* aContent)
|
||||
|
||||
// See bug 292146 for why we want to null this out
|
||||
ResetLastOverForContent(0, mMouseEnterLeaveHelper, aContent);
|
||||
mPointersEnterLeaveHelper.Enumerate(
|
||||
&EventStateManager::ResetLastOverForContent, aContent);
|
||||
for (auto iter = mPointersEnterLeaveHelper.Iter();
|
||||
!iter.Done();
|
||||
iter.Next()) {
|
||||
ResetLastOverForContent(iter.Key(), iter.Data(), aContent);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
|
||||
@@ -882,9 +882,9 @@ private:
|
||||
nsIContent* aStopBefore,
|
||||
EventStates aState,
|
||||
bool aAddState);
|
||||
static PLDHashOperator ResetLastOverForContent(const uint32_t& aIdx,
|
||||
RefPtr<OverOutElementsWrapper>& aChunk,
|
||||
void* aClosure);
|
||||
static void ResetLastOverForContent(const uint32_t& aIdx,
|
||||
RefPtr<OverOutElementsWrapper>& aChunk,
|
||||
nsIContent* aClosure);
|
||||
void PostHandleKeyboardEvent(WidgetKeyboardEvent* aKeyboardEvent,
|
||||
nsEventStatus& aStatus,
|
||||
bool dispatchedToContentProcess);
|
||||
|
||||
@@ -1197,11 +1197,6 @@ protected:
|
||||
// Current audio volume
|
||||
double mVolume;
|
||||
|
||||
// Helper function to iterate over a hash table
|
||||
// and convert it to a JSObject.
|
||||
static PLDHashOperator BuildObjectFromTags(nsCStringHashKey::KeyType aKey,
|
||||
nsCString aValue,
|
||||
void* aUserArg);
|
||||
nsAutoPtr<const MetadataTags> mTags;
|
||||
|
||||
// URI of the resource we're attempting to load. This stores the value we
|
||||
|
||||
+195
-469
@@ -398,7 +398,7 @@ public:
|
||||
MOZ_ASSERT(aId);
|
||||
|
||||
SelfType closure(aId, aName);
|
||||
aEnumerable.EnumerateRead(Enumerate, &closure);
|
||||
MatchHelper(aEnumerable, &closure);
|
||||
|
||||
return closure.mMetadata;
|
||||
}
|
||||
@@ -411,7 +411,7 @@ public:
|
||||
MOZ_ASSERT(aId);
|
||||
|
||||
SelfType closure(aId);
|
||||
aEnumerable.EnumerateRead(Enumerate, &closure);
|
||||
MatchHelper(aEnumerable, &closure);
|
||||
|
||||
return closure.mMetadata;
|
||||
}
|
||||
@@ -436,25 +436,29 @@ private:
|
||||
MOZ_ASSERT(aId);
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
Enumerate(const uint64_t& aKey, MetadataType* aValue, void* aClosure)
|
||||
template <class Enumerable>
|
||||
static void
|
||||
MatchHelper(const Enumerable& aEnumerable, SelfType* aClosure)
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(aKey);
|
||||
MOZ_ASSERT(aValue);
|
||||
MOZ_ASSERT(aClosure);
|
||||
|
||||
auto* closure = static_cast<SelfType*>(aClosure);
|
||||
for (auto iter = aEnumerable.ConstIter(); !iter.Done(); iter.Next()) {
|
||||
#ifdef DEBUG
|
||||
const uint64_t key = iter.Key();
|
||||
#endif
|
||||
MetadataType* value = iter.UserData();
|
||||
MOZ_ASSERT(key != 0);
|
||||
MOZ_ASSERT(value);
|
||||
|
||||
if (!aValue->mDeleted &&
|
||||
(closure->mId == aValue->mCommonMetadata.id() ||
|
||||
(closure->mCheckName &&
|
||||
closure->mName == aValue->mCommonMetadata.name()))) {
|
||||
closure->mMetadata = aValue;
|
||||
return PL_DHASH_STOP;
|
||||
if (!value->mDeleted &&
|
||||
(aClosure->mId == value->mCommonMetadata.id() ||
|
||||
(aClosure->mCheckName &&
|
||||
aClosure->mName == value->mCommonMetadata.name()))) {
|
||||
aClosure->mMetadata = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -8702,7 +8706,6 @@ class QuotaClient final
|
||||
// then we will attempt a full vacuum.
|
||||
static const int32_t kPercentUnusedThreshold = 20;
|
||||
|
||||
class AbortOperationsRunnable;
|
||||
class AutoProgressHandler;
|
||||
class GetDirectoryLockListener;
|
||||
struct MaintenanceInfoBase;
|
||||
@@ -9096,48 +9099,6 @@ private:
|
||||
NS_DECL_NSIRUNNABLE
|
||||
};
|
||||
|
||||
class QuotaClient::AbortOperationsRunnable final
|
||||
: public nsRunnable
|
||||
{
|
||||
const ContentParentId mContentParentId;
|
||||
const nsCString mOrigin;
|
||||
|
||||
nsTArray<RefPtr<Database>> mDatabases;
|
||||
|
||||
public:
|
||||
explicit AbortOperationsRunnable(const nsACString& aOrigin)
|
||||
: mOrigin(aOrigin)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!mOrigin.IsEmpty());
|
||||
}
|
||||
|
||||
explicit AbortOperationsRunnable(ContentParentId aContentParentId)
|
||||
: mContentParentId(aContentParentId)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mOrigin.IsEmpty());
|
||||
}
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
private:
|
||||
~AbortOperationsRunnable()
|
||||
{ }
|
||||
|
||||
static PLDHashOperator
|
||||
MatchOrigin(const nsACString& aKey,
|
||||
DatabaseActorInfo* aValue,
|
||||
void* aClosure);
|
||||
|
||||
static PLDHashOperator
|
||||
MatchContentParentId(const nsACString& aKey,
|
||||
DatabaseActorInfo* aValue,
|
||||
void* aClosure);
|
||||
|
||||
NS_DECL_NSIRUNNABLE
|
||||
};
|
||||
|
||||
class QuotaClient::GetDirectoryLockListener final
|
||||
: public OpenDirectoryListener
|
||||
{
|
||||
@@ -15135,56 +15096,6 @@ VersionChangeTransaction::RecvDeleteObjectStore(const int64_t& aObjectStoreId)
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
class MOZ_STACK_CLASS Helper final
|
||||
{
|
||||
const int64_t mObjectStoreId;
|
||||
bool mIsLastObjectStore;
|
||||
DebugOnly<bool> mFoundTargetId;
|
||||
|
||||
public:
|
||||
static bool
|
||||
IsLastObjectStore(const FullDatabaseMetadata* aDatabaseMetadata,
|
||||
const int64_t aObjectStoreId)
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(aDatabaseMetadata);
|
||||
MOZ_ASSERT(aObjectStoreId);
|
||||
|
||||
Helper helper(aObjectStoreId);
|
||||
aDatabaseMetadata->mObjectStores.EnumerateRead(&Enumerate, &helper);
|
||||
|
||||
MOZ_ASSERT_IF(helper.mIsLastObjectStore, helper.mFoundTargetId);
|
||||
|
||||
return helper.mIsLastObjectStore;
|
||||
}
|
||||
|
||||
private:
|
||||
explicit
|
||||
Helper(const int64_t aObjectStoreId)
|
||||
: mObjectStoreId(aObjectStoreId)
|
||||
, mIsLastObjectStore(true)
|
||||
, mFoundTargetId(false)
|
||||
{ }
|
||||
|
||||
static PLDHashOperator
|
||||
Enumerate(const uint64_t& aKey,
|
||||
FullObjectStoreMetadata* aValue,
|
||||
void* aClosure)
|
||||
{
|
||||
auto* helper = static_cast<Helper*>(aClosure);
|
||||
MOZ_ASSERT(helper);
|
||||
|
||||
if (uint64_t(helper->mObjectStoreId) == aKey) {
|
||||
helper->mFoundTargetId = true;
|
||||
} else if(!aValue->mDeleted) {
|
||||
helper->mIsLastObjectStore = false;
|
||||
return PL_DHASH_STOP;
|
||||
}
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
};
|
||||
|
||||
if (NS_WARN_IF(!aObjectStoreId)) {
|
||||
ASSERT_UNLESS_FUZZING();
|
||||
return false;
|
||||
@@ -15214,11 +15125,22 @@ VersionChangeTransaction::RecvDeleteObjectStore(const int64_t& aObjectStoreId)
|
||||
|
||||
foundMetadata->mDeleted = true;
|
||||
|
||||
bool isLastObjectStore = true;
|
||||
DebugOnly<bool> foundTargetId = false;
|
||||
for (auto iter = dbMetadata->mObjectStores.Iter();
|
||||
!iter.Done();
|
||||
iter.Next()) {
|
||||
if (uint64_t(aObjectStoreId) == iter.Key()) {
|
||||
foundTargetId = true;
|
||||
} else if (!iter.UserData()->mDeleted) {
|
||||
isLastObjectStore = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
MOZ_ASSERT_IF(isLastObjectStore, foundTargetId);
|
||||
|
||||
RefPtr<DeleteObjectStoreOp> op =
|
||||
new DeleteObjectStoreOp(this,
|
||||
foundMetadata,
|
||||
Helper::IsLastObjectStore(dbMetadata,
|
||||
aObjectStoreId));
|
||||
new DeleteObjectStoreOp(this, foundMetadata, isLastObjectStore);
|
||||
|
||||
if (NS_WARN_IF(!op->Init(this))) {
|
||||
op->Cleanup();
|
||||
@@ -15306,54 +15228,6 @@ VersionChangeTransaction::RecvDeleteIndex(const int64_t& aObjectStoreId,
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
class MOZ_STACK_CLASS Helper final
|
||||
{
|
||||
const int64_t mIndexId;
|
||||
bool mIsLastIndex;
|
||||
DebugOnly<bool> mFoundTargetId;
|
||||
|
||||
public:
|
||||
static bool
|
||||
IsLastIndex(const FullObjectStoreMetadata* aObjectStoreMetadata,
|
||||
const int64_t aIndexId)
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(aObjectStoreMetadata);
|
||||
MOZ_ASSERT(aIndexId);
|
||||
|
||||
Helper helper(aIndexId);
|
||||
aObjectStoreMetadata->mIndexes.EnumerateRead(&Enumerate, &helper);
|
||||
|
||||
MOZ_ASSERT_IF(helper.mIsLastIndex, helper.mFoundTargetId);
|
||||
|
||||
return helper.mIsLastIndex;
|
||||
}
|
||||
|
||||
private:
|
||||
explicit
|
||||
Helper(const int64_t aIndexId)
|
||||
: mIndexId(aIndexId)
|
||||
, mIsLastIndex(true)
|
||||
, mFoundTargetId(false)
|
||||
{ }
|
||||
|
||||
static PLDHashOperator
|
||||
Enumerate(const uint64_t& aKey, FullIndexMetadata* aValue, void* aClosure)
|
||||
{
|
||||
auto* helper = static_cast<Helper*>(aClosure);
|
||||
MOZ_ASSERT(helper);
|
||||
|
||||
if (uint64_t(helper->mIndexId) == aKey) {
|
||||
helper->mFoundTargetId = true;
|
||||
} else if (!aValue->mDeleted) {
|
||||
helper->mIsLastIndex = false;
|
||||
return PL_DHASH_STOP;
|
||||
}
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
};
|
||||
|
||||
if (NS_WARN_IF(!aObjectStoreId)) {
|
||||
ASSERT_UNLESS_FUZZING();
|
||||
return false;
|
||||
@@ -15402,12 +15276,26 @@ VersionChangeTransaction::RecvDeleteIndex(const int64_t& aObjectStoreId,
|
||||
|
||||
foundIndexMetadata->mDeleted = true;
|
||||
|
||||
bool isLastIndex = true;
|
||||
DebugOnly<bool> foundTargetId = false;
|
||||
for (auto iter = foundObjectStoreMetadata->mIndexes.ConstIter();
|
||||
!iter.Done();
|
||||
iter.Next()) {
|
||||
if (uint64_t(aIndexId) == iter.Key()) {
|
||||
foundTargetId = true;
|
||||
} else if (!iter.UserData()->mDeleted) {
|
||||
isLastIndex = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
MOZ_ASSERT_IF(isLastIndex, foundTargetId);
|
||||
|
||||
RefPtr<DeleteIndexOp> op =
|
||||
new DeleteIndexOp(this,
|
||||
aObjectStoreId,
|
||||
aIndexId,
|
||||
foundIndexMetadata->mCommonMetadata.unique(),
|
||||
Helper::IsLastIndex(foundObjectStoreMetadata, aIndexId));
|
||||
isLastIndex);
|
||||
|
||||
if (NS_WARN_IF(!op->Init(this))) {
|
||||
op->Cleanup();
|
||||
@@ -16744,29 +16632,55 @@ QuotaClient::ReleaseIOThreadObjects()
|
||||
void
|
||||
QuotaClient::AbortOperations(const nsACString& aOrigin)
|
||||
{
|
||||
if (mBackgroundThread) {
|
||||
RefPtr<AbortOperationsRunnable> runnable =
|
||||
new AbortOperationsRunnable(aOrigin);
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
if (NS_FAILED(mBackgroundThread->Dispatch(runnable, NS_DISPATCH_NORMAL))) {
|
||||
// This can happen if the thread has shut down already.
|
||||
return;
|
||||
if (!gLiveDatabaseHashtable) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsTArray<RefPtr<Database>> databases;
|
||||
|
||||
for (auto iter = gLiveDatabaseHashtable->ConstIter();
|
||||
!iter.Done(); iter.Next()) {
|
||||
for (Database* database : iter.Data()->mLiveDatabases) {
|
||||
if (aOrigin.IsVoid() || database->Origin() == aOrigin) {
|
||||
databases.AppendElement(database);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (Database* database : databases) {
|
||||
database->Invalidate();
|
||||
}
|
||||
|
||||
databases.Clear();
|
||||
}
|
||||
|
||||
void
|
||||
QuotaClient::AbortOperationsForProcess(ContentParentId aContentParentId)
|
||||
{
|
||||
if (mBackgroundThread) {
|
||||
RefPtr<AbortOperationsRunnable> runnable =
|
||||
new AbortOperationsRunnable(aContentParentId);
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
if (NS_FAILED(mBackgroundThread->Dispatch(runnable, NS_DISPATCH_NORMAL))) {
|
||||
// This can happen if the thread has shut down already.
|
||||
return;
|
||||
if (!gLiveDatabaseHashtable) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsTArray<RefPtr<Database>> databases;
|
||||
|
||||
for (auto iter = gLiveDatabaseHashtable->ConstIter();
|
||||
!iter.Done(); iter.Next()) {
|
||||
for (Database* database : iter.Data()->mLiveDatabases) {
|
||||
if (database->IsOwnedByProcess(aContentParentId)) {
|
||||
databases.AppendElement(database);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (Database* database : databases) {
|
||||
database->Invalidate();
|
||||
}
|
||||
|
||||
databases.Clear();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -18036,79 +17950,6 @@ ShutdownWorkThreadsRunnable::Run()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
PLDHashOperator
|
||||
QuotaClient::
|
||||
AbortOperationsRunnable::MatchOrigin(const nsACString& aKey,
|
||||
DatabaseActorInfo* aValue,
|
||||
void* aClosure)
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(!aKey.IsEmpty());
|
||||
MOZ_ASSERT(aValue);
|
||||
MOZ_ASSERT(aClosure);
|
||||
|
||||
auto* closure = static_cast<AbortOperationsRunnable*>(aClosure);
|
||||
|
||||
for (Database* database : aValue->mLiveDatabases) {
|
||||
if (closure->mOrigin.IsVoid() || closure->mOrigin == database->Origin()) {
|
||||
closure->mDatabases.AppendElement(database);
|
||||
}
|
||||
}
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
// static
|
||||
PLDHashOperator
|
||||
QuotaClient::
|
||||
AbortOperationsRunnable::MatchContentParentId(const nsACString& aKey,
|
||||
DatabaseActorInfo* aValue,
|
||||
void* aClosure)
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(!aKey.IsEmpty());
|
||||
MOZ_ASSERT(aValue);
|
||||
MOZ_ASSERT(aClosure);
|
||||
|
||||
auto* closure = static_cast<AbortOperationsRunnable*>(aClosure);
|
||||
|
||||
for (Database* database : aValue->mLiveDatabases) {
|
||||
if (database->IsOwnedByProcess(closure->mContentParentId)) {
|
||||
closure->mDatabases.AppendElement(database);
|
||||
}
|
||||
}
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED0(QuotaClient::AbortOperationsRunnable, nsRunnable)
|
||||
|
||||
NS_IMETHODIMP
|
||||
QuotaClient::
|
||||
AbortOperationsRunnable::Run()
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
if (!gLiveDatabaseHashtable) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (mOrigin.IsEmpty()) {
|
||||
gLiveDatabaseHashtable->EnumerateRead(MatchContentParentId, this);
|
||||
} else {
|
||||
gLiveDatabaseHashtable->EnumerateRead(MatchOrigin, this);
|
||||
}
|
||||
|
||||
for (Database* database : mDatabases) {
|
||||
database->Invalidate();
|
||||
}
|
||||
|
||||
mDatabases.Clear();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
QuotaClient::
|
||||
GetDirectoryLockListener::DirectoryLockAcquired(DirectoryLock* aLock)
|
||||
@@ -18555,51 +18396,7 @@ DatabaseOperationBase::GetUniqueIndexTableForObjectStore(
|
||||
MOZ_ASSERT(aObjectStoreId);
|
||||
MOZ_ASSERT(aMaybeUniqueIndexTable.isNothing());
|
||||
|
||||
class MOZ_STACK_CLASS Helper final
|
||||
{
|
||||
public:
|
||||
static nsresult
|
||||
CopyUniqueValues(const IndexTable& aIndexes,
|
||||
Maybe<UniqueIndexTable>& aMaybeUniqueIndexTable)
|
||||
{
|
||||
const uint32_t indexCount = aIndexes.Count();
|
||||
MOZ_ASSERT(indexCount);
|
||||
|
||||
aMaybeUniqueIndexTable.emplace();
|
||||
|
||||
aIndexes.EnumerateRead(Enumerate, aMaybeUniqueIndexTable.ptr());
|
||||
|
||||
if (NS_WARN_IF(aMaybeUniqueIndexTable.ref().Count() != indexCount)) {
|
||||
IDB_REPORT_INTERNAL_ERR();
|
||||
aMaybeUniqueIndexTable.reset();
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
aMaybeUniqueIndexTable.ref().MarkImmutable();
|
||||
#endif
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
static PLDHashOperator
|
||||
Enumerate(const uint64_t& aKey, FullIndexMetadata* aValue, void* aClosure)
|
||||
{
|
||||
auto* uniqueIndexTable = static_cast<UniqueIndexTable*>(aClosure);
|
||||
MOZ_ASSERT(uniqueIndexTable);
|
||||
MOZ_ASSERT(!uniqueIndexTable->Get(aValue->mCommonMetadata.id()));
|
||||
|
||||
if (NS_WARN_IF(!uniqueIndexTable->Put(aValue->mCommonMetadata.id(),
|
||||
aValue->mCommonMetadata.unique(),
|
||||
fallible))) {
|
||||
return PL_DHASH_STOP;
|
||||
}
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
};
|
||||
|
||||
const RefPtr<FullObjectStoreMetadata> objectStoreMetadata =
|
||||
const RefPtr<FullObjectStoreMetadata> objectStoreMetadata =
|
||||
aTransaction->GetMetadataForObjectStoreId(aObjectStoreId);
|
||||
MOZ_ASSERT(objectStoreMetadata);
|
||||
|
||||
@@ -18607,12 +18404,35 @@ DatabaseOperationBase::GetUniqueIndexTableForObjectStore(
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult rv = Helper::CopyUniqueValues(objectStoreMetadata->mIndexes,
|
||||
aMaybeUniqueIndexTable);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
const uint32_t indexCount = objectStoreMetadata->mIndexes.Count();
|
||||
MOZ_ASSERT(indexCount > 0);
|
||||
|
||||
aMaybeUniqueIndexTable.emplace();
|
||||
UniqueIndexTable* uniqueIndexTable = aMaybeUniqueIndexTable.ptr();
|
||||
MOZ_ASSERT(uniqueIndexTable);
|
||||
|
||||
for (auto iter = objectStoreMetadata->mIndexes.Iter(); !iter.Done(); iter.Next()) {
|
||||
FullIndexMetadata* value = iter.UserData();
|
||||
MOZ_ASSERT(!uniqueIndexTable->Get(value->mCommonMetadata.id()));
|
||||
|
||||
if (NS_WARN_IF(!uniqueIndexTable->Put(value->mCommonMetadata.id(),
|
||||
value->mCommonMetadata.unique(),
|
||||
fallible))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(aMaybeUniqueIndexTable.ref().Count() != indexCount)) {
|
||||
IDB_REPORT_INTERNAL_ERR();
|
||||
aMaybeUniqueIndexTable.reset();
|
||||
NS_WARNING("out of memory");
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
aMaybeUniqueIndexTable.ref().MarkImmutable();
|
||||
#endif
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -19586,9 +19406,6 @@ FactoryOp::WaitForTransactions()
|
||||
MOZ_ASSERT(!mDatabaseId.IsEmpty());
|
||||
MOZ_ASSERT(!IsActorDestroyed());
|
||||
|
||||
nsTArray<nsCString> databaseIds;
|
||||
databaseIds.AppendElement(mDatabaseId);
|
||||
|
||||
mState = State::WaitingForTransactionsToComplete;
|
||||
|
||||
RefPtr<WaitForTransactionsHelper> helper =
|
||||
@@ -21177,80 +20994,33 @@ OpenDatabaseOp::MetadataToSpec(DatabaseSpec& aSpec)
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(mMetadata);
|
||||
|
||||
class MOZ_STACK_CLASS Helper final
|
||||
{
|
||||
DatabaseSpec& mSpec;
|
||||
ObjectStoreSpec* mCurrentObjectStoreSpec;
|
||||
aSpec.metadata() = mMetadata->mCommonMetadata;
|
||||
|
||||
public:
|
||||
static void
|
||||
CopyToSpec(const FullDatabaseMetadata* aMetadata, DatabaseSpec& aSpec)
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(aMetadata);
|
||||
for (auto objectStoreIter = mMetadata->mObjectStores.ConstIter();
|
||||
!objectStoreIter.Done();
|
||||
objectStoreIter.Next()) {
|
||||
FullObjectStoreMetadata* metadata = objectStoreIter.UserData();
|
||||
MOZ_ASSERT(objectStoreIter.Key());
|
||||
MOZ_ASSERT(metadata);
|
||||
|
||||
aSpec.metadata() = aMetadata->mCommonMetadata;
|
||||
// XXX This should really be fallible...
|
||||
ObjectStoreSpec* objectStoreSpec = aSpec.objectStores().AppendElement();
|
||||
objectStoreSpec->metadata() = metadata->mCommonMetadata;
|
||||
|
||||
Helper helper(aSpec);
|
||||
aMetadata->mObjectStores.EnumerateRead(Enumerate, &helper);
|
||||
}
|
||||
|
||||
private:
|
||||
explicit Helper(DatabaseSpec& aSpec)
|
||||
: mSpec(aSpec)
|
||||
, mCurrentObjectStoreSpec(nullptr)
|
||||
{ }
|
||||
|
||||
static PLDHashOperator
|
||||
Enumerate(const uint64_t& aKey,
|
||||
FullObjectStoreMetadata* aValue,
|
||||
void* aClosure)
|
||||
{
|
||||
MOZ_ASSERT(aKey);
|
||||
MOZ_ASSERT(aValue);
|
||||
MOZ_ASSERT(aClosure);
|
||||
|
||||
auto* helper = static_cast<Helper*>(aClosure);
|
||||
|
||||
MOZ_ASSERT(!helper->mCurrentObjectStoreSpec);
|
||||
for (auto indexIter = metadata->mIndexes.Iter();
|
||||
!indexIter.Done();
|
||||
indexIter.Next()) {
|
||||
FullIndexMetadata* indexMetadata = indexIter.UserData();
|
||||
MOZ_ASSERT(indexIter.Key());
|
||||
MOZ_ASSERT(indexMetadata);
|
||||
|
||||
// XXX This should really be fallible...
|
||||
ObjectStoreSpec* objectStoreSpec =
|
||||
helper->mSpec.objectStores().AppendElement();
|
||||
objectStoreSpec->metadata() = aValue->mCommonMetadata;
|
||||
|
||||
AutoRestore<ObjectStoreSpec*> ar(helper->mCurrentObjectStoreSpec);
|
||||
helper->mCurrentObjectStoreSpec = objectStoreSpec;
|
||||
|
||||
aValue->mIndexes.EnumerateRead(Enumerate, helper);
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
IndexMetadata* metadata = objectStoreSpec->indexes().AppendElement();
|
||||
*metadata = indexMetadata->mCommonMetadata;
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
Enumerate(const uint64_t& aKey, FullIndexMetadata* aValue, void* aClosure)
|
||||
{
|
||||
MOZ_ASSERT(aKey);
|
||||
MOZ_ASSERT(aValue);
|
||||
MOZ_ASSERT(aClosure);
|
||||
|
||||
auto* helper = static_cast<Helper*>(aClosure);
|
||||
|
||||
MOZ_ASSERT(helper->mCurrentObjectStoreSpec);
|
||||
|
||||
// XXX This should really be fallible...
|
||||
IndexMetadata* metadata =
|
||||
helper->mCurrentObjectStoreSpec->indexes().AppendElement();
|
||||
*metadata = aValue->mCommonMetadata;
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
};
|
||||
|
||||
Helper::CopyToSpec(mMetadata, aSpec);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
void
|
||||
@@ -21258,110 +21028,6 @@ OpenDatabaseOp::AssertMetadataConsistency(const FullDatabaseMetadata* aMetadata)
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
class MOZ_STACK_CLASS Helper final
|
||||
{
|
||||
const ObjectStoreTable& mOtherObjectStores;
|
||||
IndexTable* mCurrentOtherIndexTable;
|
||||
|
||||
public:
|
||||
static void
|
||||
AssertConsistent(const ObjectStoreTable& aThisObjectStores,
|
||||
const ObjectStoreTable& aOtherObjectStores)
|
||||
{
|
||||
Helper helper(aOtherObjectStores);
|
||||
aThisObjectStores.EnumerateRead(Enumerate, &helper);
|
||||
}
|
||||
|
||||
private:
|
||||
explicit Helper(const ObjectStoreTable& aOtherObjectStores)
|
||||
: mOtherObjectStores(aOtherObjectStores)
|
||||
, mCurrentOtherIndexTable(nullptr)
|
||||
{ }
|
||||
|
||||
static PLDHashOperator
|
||||
Enumerate(const uint64_t& /* aKey */,
|
||||
FullObjectStoreMetadata* aThisObjectStore,
|
||||
void* aClosure)
|
||||
{
|
||||
MOZ_ASSERT(aThisObjectStore);
|
||||
MOZ_ASSERT(!aThisObjectStore->mDeleted);
|
||||
MOZ_ASSERT(aClosure);
|
||||
|
||||
auto* helper = static_cast<Helper*>(aClosure);
|
||||
|
||||
MOZ_ASSERT(!helper->mCurrentOtherIndexTable);
|
||||
|
||||
auto* otherObjectStore =
|
||||
MetadataNameOrIdMatcher<FullObjectStoreMetadata>::Match(
|
||||
helper->mOtherObjectStores, aThisObjectStore->mCommonMetadata.id());
|
||||
MOZ_ASSERT(otherObjectStore);
|
||||
|
||||
MOZ_ASSERT(aThisObjectStore != otherObjectStore);
|
||||
|
||||
MOZ_ASSERT(aThisObjectStore->mCommonMetadata.id() ==
|
||||
otherObjectStore->mCommonMetadata.id());
|
||||
MOZ_ASSERT(aThisObjectStore->mCommonMetadata.name() ==
|
||||
otherObjectStore->mCommonMetadata.name());
|
||||
MOZ_ASSERT(aThisObjectStore->mCommonMetadata.autoIncrement() ==
|
||||
otherObjectStore->mCommonMetadata.autoIncrement());
|
||||
MOZ_ASSERT(aThisObjectStore->mCommonMetadata.keyPath() ==
|
||||
otherObjectStore->mCommonMetadata.keyPath());
|
||||
// mNextAutoIncrementId and mComittedAutoIncrementId may be modified
|
||||
// concurrently with this OpenOp, so it is not possible to assert equality
|
||||
// here.
|
||||
MOZ_ASSERT(aThisObjectStore->mNextAutoIncrementId <=
|
||||
otherObjectStore->mNextAutoIncrementId);
|
||||
MOZ_ASSERT(aThisObjectStore->mComittedAutoIncrementId <=
|
||||
otherObjectStore->mComittedAutoIncrementId);
|
||||
MOZ_ASSERT(!otherObjectStore->mDeleted);
|
||||
|
||||
MOZ_ASSERT(aThisObjectStore->mIndexes.Count() ==
|
||||
otherObjectStore->mIndexes.Count());
|
||||
|
||||
AutoRestore<IndexTable*> ar(helper->mCurrentOtherIndexTable);
|
||||
helper->mCurrentOtherIndexTable = &otherObjectStore->mIndexes;
|
||||
|
||||
aThisObjectStore->mIndexes.EnumerateRead(Enumerate, helper);
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
Enumerate(const uint64_t& /* aKey */,
|
||||
FullIndexMetadata* aThisIndex,
|
||||
void* aClosure)
|
||||
{
|
||||
MOZ_ASSERT(aThisIndex);
|
||||
MOZ_ASSERT(!aThisIndex->mDeleted);
|
||||
MOZ_ASSERT(aClosure);
|
||||
|
||||
auto* helper = static_cast<Helper*>(aClosure);
|
||||
|
||||
MOZ_ASSERT(helper->mCurrentOtherIndexTable);
|
||||
|
||||
auto* otherIndex =
|
||||
MetadataNameOrIdMatcher<FullIndexMetadata>::Match(
|
||||
*helper->mCurrentOtherIndexTable, aThisIndex->mCommonMetadata.id());
|
||||
MOZ_ASSERT(otherIndex);
|
||||
|
||||
MOZ_ASSERT(aThisIndex != otherIndex);
|
||||
|
||||
MOZ_ASSERT(aThisIndex->mCommonMetadata.id() ==
|
||||
otherIndex->mCommonMetadata.id());
|
||||
MOZ_ASSERT(aThisIndex->mCommonMetadata.name() ==
|
||||
otherIndex->mCommonMetadata.name());
|
||||
MOZ_ASSERT(aThisIndex->mCommonMetadata.keyPath() ==
|
||||
otherIndex->mCommonMetadata.keyPath());
|
||||
MOZ_ASSERT(aThisIndex->mCommonMetadata.unique() ==
|
||||
otherIndex->mCommonMetadata.unique());
|
||||
MOZ_ASSERT(aThisIndex->mCommonMetadata.multiEntry() ==
|
||||
otherIndex->mCommonMetadata.multiEntry());
|
||||
MOZ_ASSERT(!otherIndex->mDeleted);
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
};
|
||||
|
||||
const FullDatabaseMetadata* thisDB = mMetadata;
|
||||
const FullDatabaseMetadata* otherDB = aMetadata;
|
||||
|
||||
@@ -21386,7 +21052,67 @@ OpenDatabaseOp::AssertMetadataConsistency(const FullDatabaseMetadata* aMetadata)
|
||||
|
||||
MOZ_ASSERT(thisDB->mObjectStores.Count() == otherDB->mObjectStores.Count());
|
||||
|
||||
Helper::AssertConsistent(thisDB->mObjectStores, otherDB->mObjectStores);
|
||||
for (auto objectStoreIter = thisDB->mObjectStores.ConstIter();
|
||||
!objectStoreIter.Done();
|
||||
objectStoreIter.Next()) {
|
||||
FullObjectStoreMetadata* thisObjectStore = objectStoreIter.UserData();
|
||||
MOZ_ASSERT(thisObjectStore);
|
||||
MOZ_ASSERT(!thisObjectStore->mDeleted);
|
||||
|
||||
auto* otherObjectStore =
|
||||
MetadataNameOrIdMatcher<FullObjectStoreMetadata>::Match(
|
||||
otherDB->mObjectStores, thisObjectStore->mCommonMetadata.id());
|
||||
MOZ_ASSERT(otherObjectStore);
|
||||
|
||||
MOZ_ASSERT(thisObjectStore != otherObjectStore);
|
||||
|
||||
MOZ_ASSERT(thisObjectStore->mCommonMetadata.id() ==
|
||||
otherObjectStore->mCommonMetadata.id());
|
||||
MOZ_ASSERT(thisObjectStore->mCommonMetadata.name() ==
|
||||
otherObjectStore->mCommonMetadata.name());
|
||||
MOZ_ASSERT(thisObjectStore->mCommonMetadata.autoIncrement() ==
|
||||
otherObjectStore->mCommonMetadata.autoIncrement());
|
||||
MOZ_ASSERT(thisObjectStore->mCommonMetadata.keyPath() ==
|
||||
otherObjectStore->mCommonMetadata.keyPath());
|
||||
// mNextAutoIncrementId and mComittedAutoIncrementId may be modified
|
||||
// concurrently with this OpenOp, so it is not possible to assert equality
|
||||
// here.
|
||||
MOZ_ASSERT(thisObjectStore->mNextAutoIncrementId <=
|
||||
otherObjectStore->mNextAutoIncrementId);
|
||||
MOZ_ASSERT(thisObjectStore->mComittedAutoIncrementId <=
|
||||
otherObjectStore->mComittedAutoIncrementId);
|
||||
MOZ_ASSERT(!otherObjectStore->mDeleted);
|
||||
|
||||
MOZ_ASSERT(thisObjectStore->mIndexes.Count() ==
|
||||
otherObjectStore->mIndexes.Count());
|
||||
|
||||
for (auto indexIter = thisObjectStore->mIndexes.Iter();
|
||||
!indexIter.Done();
|
||||
indexIter.Next()) {
|
||||
FullIndexMetadata* thisIndex = indexIter.UserData();
|
||||
MOZ_ASSERT(thisIndex);
|
||||
MOZ_ASSERT(!thisIndex->mDeleted);
|
||||
|
||||
auto* otherIndex =
|
||||
MetadataNameOrIdMatcher<FullIndexMetadata>::
|
||||
Match(otherObjectStore->mIndexes, thisIndex->mCommonMetadata.id());
|
||||
MOZ_ASSERT(otherIndex);
|
||||
|
||||
MOZ_ASSERT(thisIndex != otherIndex);
|
||||
|
||||
MOZ_ASSERT(thisIndex->mCommonMetadata.id() ==
|
||||
otherIndex->mCommonMetadata.id());
|
||||
MOZ_ASSERT(thisIndex->mCommonMetadata.name() ==
|
||||
otherIndex->mCommonMetadata.name());
|
||||
MOZ_ASSERT(thisIndex->mCommonMetadata.keyPath() ==
|
||||
otherIndex->mCommonMetadata.keyPath());
|
||||
MOZ_ASSERT(thisIndex->mCommonMetadata.unique() ==
|
||||
otherIndex->mCommonMetadata.unique());
|
||||
MOZ_ASSERT(thisIndex->mCommonMetadata.multiEntry() ==
|
||||
otherIndex->mCommonMetadata.multiEntry());
|
||||
MOZ_ASSERT(!otherIndex->mDeleted);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // DEBUG
|
||||
|
||||
@@ -51,12 +51,6 @@ private:
|
||||
|
||||
class MessagePortServiceData;
|
||||
|
||||
#ifdef DEBUG
|
||||
static PLDHashOperator
|
||||
CloseAllDebugCheck(const nsID& aID, MessagePortServiceData* aData,
|
||||
void* aPtr);
|
||||
#endif
|
||||
|
||||
nsClassHashtable<nsIDHashKey, MessagePortServiceData> mPorts;
|
||||
};
|
||||
|
||||
|
||||
@@ -84,10 +84,6 @@ public:
|
||||
// method updates the cached value (and toggles the 'mForceCompositing' flag)
|
||||
void UpdateCachedBaseValue(const nsSMILValue& aBaseValue);
|
||||
|
||||
// Static callback methods
|
||||
static PLDHashOperator DoComposeAttribute(
|
||||
nsSMILCompositor* aCompositor, void *aData);
|
||||
|
||||
// The hash key (tuple of element/attributeName/attributeType)
|
||||
KeyType mKey;
|
||||
|
||||
|
||||
@@ -1065,26 +1065,6 @@ DOMStorageDBThread::PendingOperations::HasTasks()
|
||||
|
||||
namespace {
|
||||
|
||||
PLDHashOperator
|
||||
ForgetUpdatesForScope(const nsACString& aMapping,
|
||||
nsAutoPtr<DOMStorageDBThread::DBOperation>& aPendingTask,
|
||||
void* aArg)
|
||||
{
|
||||
DOMStorageDBThread::DBOperation* newOp = static_cast<DOMStorageDBThread::DBOperation*>(aArg);
|
||||
|
||||
if (newOp->Type() == DOMStorageDBThread::DBOperation::opClear &&
|
||||
aPendingTask->Scope() != newOp->Scope()) {
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
if (newOp->Type() == DOMStorageDBThread::DBOperation::opClearMatchingScope &&
|
||||
!StringBeginsWith(aPendingTask->Scope(), newOp->Scope())) {
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
return PL_DHASH_REMOVE;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool
|
||||
@@ -1155,7 +1135,22 @@ DOMStorageDBThread::PendingOperations::Add(DOMStorageDBThread::DBOperation* aOpe
|
||||
// We do this as an optimization as well as a must based on the logic,
|
||||
// if we would not delete the update tasks, changes would have been stored
|
||||
// to the database after clear operations have been executed.
|
||||
mUpdates.Enumerate(ForgetUpdatesForScope, aOperation);
|
||||
for (auto iter = mUpdates.Iter(); !iter.Done(); iter.Next()) {
|
||||
nsAutoPtr<DBOperation>& pendingTask = iter.Data();
|
||||
|
||||
if (aOperation->Type() == DBOperation::opClear &&
|
||||
pendingTask->Scope() != aOperation->Scope()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (aOperation->Type() == DBOperation::opClearMatchingScope &&
|
||||
!StringBeginsWith(pendingTask->Scope(), aOperation->Scope())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
iter.Remove();
|
||||
}
|
||||
|
||||
mClears.Put(aOperation->Target(), aOperation);
|
||||
break;
|
||||
|
||||
@@ -1172,20 +1167,6 @@ DOMStorageDBThread::PendingOperations::Add(DOMStorageDBThread::DBOperation* aOpe
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
PLDHashOperator
|
||||
CollectTasks(const nsACString& aMapping, nsAutoPtr<DOMStorageDBThread::DBOperation>& aOperation, void* aArg)
|
||||
{
|
||||
nsTArray<nsAutoPtr<DOMStorageDBThread::DBOperation> >* tasks =
|
||||
static_cast<nsTArray<nsAutoPtr<DOMStorageDBThread::DBOperation> >*>(aArg);
|
||||
|
||||
tasks->AppendElement(aOperation.forget());
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool
|
||||
DOMStorageDBThread::PendingOperations::Prepare()
|
||||
{
|
||||
@@ -1196,10 +1177,14 @@ DOMStorageDBThread::PendingOperations::Prepare()
|
||||
// scheduled, we drop all updates matching that scope. So,
|
||||
// all scope-related update operations we have here now were
|
||||
// scheduled after the clear operations.
|
||||
mClears.Enumerate(CollectTasks, &mExecList);
|
||||
for (auto iter = mClears.Iter(); !iter.Done(); iter.Next()) {
|
||||
mExecList.AppendElement(iter.Data().forget());
|
||||
}
|
||||
mClears.Clear();
|
||||
|
||||
mUpdates.Enumerate(CollectTasks, &mExecList);
|
||||
for (auto iter = mUpdates.Iter(); !iter.Done(); iter.Next()) {
|
||||
mExecList.AppendElement(iter.Data().forget());
|
||||
}
|
||||
mUpdates.Clear();
|
||||
|
||||
return !!mExecList.Length();
|
||||
|
||||
@@ -83,36 +83,20 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsBindingManager)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
|
||||
static PLDHashOperator
|
||||
DocumentInfoHashtableTraverser(nsIURI* key,
|
||||
nsXBLDocumentInfo* di,
|
||||
void* userArg)
|
||||
{
|
||||
nsCycleCollectionTraversalCallback *cb =
|
||||
static_cast<nsCycleCollectionTraversalCallback*>(userArg);
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, "mDocumentTable value");
|
||||
cb->NoteXPCOMChild(di);
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
LoadingDocHashtableTraverser(nsIURI* key,
|
||||
nsIStreamListener* sl,
|
||||
void* userArg)
|
||||
{
|
||||
nsCycleCollectionTraversalCallback *cb =
|
||||
static_cast<nsCycleCollectionTraversalCallback*>(userArg);
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, "mLoadingDocTable value");
|
||||
cb->NoteXPCOMChild(sl);
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsBindingManager)
|
||||
// The hashes keyed on nsIContent are traversed from the nsIContent itself.
|
||||
if (tmp->mDocumentTable)
|
||||
tmp->mDocumentTable->EnumerateRead(&DocumentInfoHashtableTraverser, &cb);
|
||||
if (tmp->mLoadingDocTable)
|
||||
tmp->mLoadingDocTable->EnumerateRead(&LoadingDocHashtableTraverser, &cb);
|
||||
if (tmp->mDocumentTable) {
|
||||
for (auto iter = tmp->mDocumentTable->Iter(); !iter.Done(); iter.Next()) {
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mDocumentTable value");
|
||||
cb.NoteXPCOMChild(iter.UserData());
|
||||
}
|
||||
}
|
||||
if (tmp->mLoadingDocTable) {
|
||||
for (auto iter = tmp->mLoadingDocTable->Iter(); !iter.Done(); iter.Next()) {
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mLoadingDocTable value");
|
||||
cb.NoteXPCOMChild(iter.UserData());
|
||||
}
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAttachedStack)
|
||||
// No need to traverse mProcessAttachedQueueEvent, since it'll just
|
||||
// fire at some point or become revoke and drop its ref to us.
|
||||
|
||||
@@ -80,13 +80,6 @@ UnmarkXBLJSObject(JS::GCCellPtr aPtr, const char* aName, void* aClosure)
|
||||
JS::ExposeObjectToActiveJS(&aPtr.as<JSObject>());
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
UnmarkProtos(const nsACString &aKey, nsXBLPrototypeBinding *aProto, void* aClosure)
|
||||
{
|
||||
aProto->Trace(TraceCallbackFunc(UnmarkXBLJSObject), nullptr);
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
void
|
||||
nsXBLDocumentInfo::MarkInCCGeneration(uint32_t aGeneration)
|
||||
{
|
||||
@@ -95,7 +88,9 @@ nsXBLDocumentInfo::MarkInCCGeneration(uint32_t aGeneration)
|
||||
}
|
||||
// Unmark any JS we hold
|
||||
if (mBindingTable) {
|
||||
mBindingTable->EnumerateRead(UnmarkProtos, nullptr);
|
||||
for (auto iter = mBindingTable->Iter(); !iter.Done(); iter.Next()) {
|
||||
iter.UserData()->Trace(TraceCallbackFunc(UnmarkXBLJSObject), nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,16 +185,6 @@ nsXBLDocumentInfo::RemovePrototypeBinding(const nsACString& aRef)
|
||||
}
|
||||
}
|
||||
|
||||
// Callback to enumerate over the bindings from this document and write them
|
||||
// out to the cache.
|
||||
static PLDHashOperator
|
||||
WriteBinding(const nsACString &aKey, nsXBLPrototypeBinding *aProto, void* aClosure)
|
||||
{
|
||||
aProto->Write((nsIObjectOutputStream*)aClosure);
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
nsXBLDocumentInfo::ReadPrototypeBindings(nsIURI* aURI, nsXBLDocumentInfo** aDocInfo)
|
||||
@@ -292,7 +277,9 @@ nsXBLDocumentInfo::WritePrototypeBindings()
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (mBindingTable) {
|
||||
mBindingTable->EnumerateRead(WriteBinding, stream);
|
||||
for (auto iter = mBindingTable->Iter(); !iter.Done(); iter.Next()) {
|
||||
iter.UserData()->Write(stream);
|
||||
}
|
||||
}
|
||||
|
||||
// write a end marker at the end
|
||||
@@ -316,18 +303,13 @@ nsXBLDocumentInfo::SetFirstPrototypeBinding(nsXBLPrototypeBinding* aBinding)
|
||||
mFirstBinding = aBinding;
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
FlushScopedSkinSheets(const nsACString &aKey, nsXBLPrototypeBinding *aProto, void* aClosure)
|
||||
{
|
||||
aProto->FlushSkinSheets();
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
void
|
||||
nsXBLDocumentInfo::FlushSkinStylesheets()
|
||||
{
|
||||
if (mBindingTable) {
|
||||
mBindingTable->EnumerateRead(FlushScopedSkinSheets, nullptr);
|
||||
for (auto iter = mBindingTable->Iter(); !iter.Done(); iter.Next()) {
|
||||
iter.UserData()->FlushSkinSheets();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -488,101 +488,74 @@ nsXBLPrototypeBinding::LocateInstance(nsIContent* aBoundElement,
|
||||
return copyParent->GetChildAt(templParent->IndexOf(aTemplChild));
|
||||
}
|
||||
|
||||
struct nsXBLAttrChangeData
|
||||
{
|
||||
nsXBLPrototypeBinding* mProto;
|
||||
nsIContent* mBoundElement;
|
||||
nsIContent* mContent;
|
||||
int32_t mSrcNamespace;
|
||||
|
||||
nsXBLAttrChangeData(nsXBLPrototypeBinding* aProto,
|
||||
nsIContent* aElt, nsIContent* aContent)
|
||||
:mProto(aProto), mBoundElement(aElt), mContent(aContent) {}
|
||||
};
|
||||
|
||||
// XXXbz this duplicates lots of AttributeChanged
|
||||
static PLDHashOperator
|
||||
SetAttrs(nsISupports* aKey, nsXBLAttributeEntry* aEntry, void* aClosure)
|
||||
{
|
||||
nsXBLAttrChangeData* changeData = static_cast<nsXBLAttrChangeData*>(aClosure);
|
||||
|
||||
nsIAtom* src = aEntry->GetSrcAttribute();
|
||||
int32_t srcNs = changeData->mSrcNamespace;
|
||||
nsAutoString value;
|
||||
bool attrPresent = true;
|
||||
|
||||
if (src == nsGkAtoms::text && srcNs == kNameSpaceID_XBL) {
|
||||
nsContentUtils::GetNodeTextContent(changeData->mBoundElement, false,
|
||||
value);
|
||||
value.StripChar(char16_t('\n'));
|
||||
value.StripChar(char16_t('\r'));
|
||||
nsAutoString stripVal(value);
|
||||
stripVal.StripWhitespace();
|
||||
|
||||
if (stripVal.IsEmpty())
|
||||
attrPresent = false;
|
||||
}
|
||||
else {
|
||||
attrPresent = changeData->mBoundElement->GetAttr(srcNs, src, value);
|
||||
}
|
||||
|
||||
if (attrPresent) {
|
||||
nsIContent* content =
|
||||
changeData->mProto->GetImmediateChild(nsGkAtoms::content);
|
||||
|
||||
nsXBLAttributeEntry* curr = aEntry;
|
||||
while (curr) {
|
||||
nsIAtom* dst = curr->GetDstAttribute();
|
||||
int32_t dstNs = curr->GetDstNameSpace();
|
||||
nsIContent* element = curr->GetElement();
|
||||
|
||||
nsIContent *realElement =
|
||||
changeData->mProto->LocateInstance(changeData->mBoundElement, content,
|
||||
changeData->mContent, element);
|
||||
|
||||
if (realElement) {
|
||||
realElement->SetAttr(dstNs, dst, value, false);
|
||||
|
||||
// XXXndeakin shouldn't this be done in lieu of SetAttr?
|
||||
if ((dst == nsGkAtoms::text && dstNs == kNameSpaceID_XBL) ||
|
||||
(realElement->NodeInfo()->Equals(nsGkAtoms::html,
|
||||
kNameSpaceID_XUL) &&
|
||||
dst == nsGkAtoms::value && !value.IsEmpty())) {
|
||||
|
||||
RefPtr<nsTextNode> textContent =
|
||||
new nsTextNode(realElement->NodeInfo()->NodeInfoManager());
|
||||
|
||||
textContent->SetText(value, false);
|
||||
realElement->AppendChildTo(textContent, false);
|
||||
}
|
||||
}
|
||||
|
||||
curr = curr->GetNext();
|
||||
}
|
||||
}
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
SetAttrsNS(const uint32_t &aNamespace,
|
||||
nsXBLPrototypeBinding::InnerAttributeTable* aXBLAttributes,
|
||||
void* aClosure)
|
||||
{
|
||||
if (aXBLAttributes && aClosure) {
|
||||
nsXBLAttrChangeData* changeData = static_cast<nsXBLAttrChangeData*>(aClosure);
|
||||
changeData->mSrcNamespace = aNamespace;
|
||||
aXBLAttributes->EnumerateRead(SetAttrs, aClosure);
|
||||
}
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
void
|
||||
nsXBLPrototypeBinding::SetInitialAttributes(nsIContent* aBoundElement, nsIContent* aAnonymousContent)
|
||||
{
|
||||
if (mAttributeTable) {
|
||||
nsXBLAttrChangeData data(this, aBoundElement, aAnonymousContent);
|
||||
mAttributeTable->EnumerateRead(SetAttrsNS, &data);
|
||||
if (!mAttributeTable) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto iter1 = mAttributeTable->Iter(); !iter1.Done(); iter1.Next()) {
|
||||
InnerAttributeTable* xblAttributes = iter1.UserData();
|
||||
if (xblAttributes) {
|
||||
int32_t srcNamespace = iter1.Key();
|
||||
|
||||
for (auto iter2 = xblAttributes->Iter(); !iter2.Done(); iter2.Next()) {
|
||||
// XXXbz this duplicates lots of AttributeChanged
|
||||
nsXBLAttributeEntry* entry = iter2.UserData();
|
||||
nsIAtom* src = entry->GetSrcAttribute();
|
||||
nsAutoString value;
|
||||
bool attrPresent = true;
|
||||
|
||||
if (src == nsGkAtoms::text && srcNamespace == kNameSpaceID_XBL) {
|
||||
nsContentUtils::GetNodeTextContent(aBoundElement, false, value);
|
||||
value.StripChar(char16_t('\n'));
|
||||
value.StripChar(char16_t('\r'));
|
||||
nsAutoString stripVal(value);
|
||||
stripVal.StripWhitespace();
|
||||
|
||||
if (stripVal.IsEmpty()) {
|
||||
attrPresent = false;
|
||||
}
|
||||
} else {
|
||||
attrPresent = aBoundElement->GetAttr(srcNamespace, src, value);
|
||||
}
|
||||
|
||||
if (attrPresent) {
|
||||
nsIContent* content = GetImmediateChild(nsGkAtoms::content);
|
||||
|
||||
nsXBLAttributeEntry* curr = entry;
|
||||
while (curr) {
|
||||
nsIAtom* dst = curr->GetDstAttribute();
|
||||
int32_t dstNs = curr->GetDstNameSpace();
|
||||
nsIContent* element = curr->GetElement();
|
||||
|
||||
nsIContent* realElement =
|
||||
LocateInstance(aBoundElement, content,
|
||||
aAnonymousContent, element);
|
||||
|
||||
if (realElement) {
|
||||
realElement->SetAttr(dstNs, dst, value, false);
|
||||
|
||||
// XXXndeakin shouldn't this be done in lieu of SetAttr?
|
||||
if ((dst == nsGkAtoms::text && dstNs == kNameSpaceID_XBL) ||
|
||||
(realElement->NodeInfo()->Equals(nsGkAtoms::html,
|
||||
kNameSpaceID_XUL) &&
|
||||
dst == nsGkAtoms::value && !value.IsEmpty())) {
|
||||
|
||||
RefPtr<nsTextNode> textContent =
|
||||
new nsTextNode(realElement->NodeInfo()->NodeInfoManager());
|
||||
|
||||
textContent->SetText(value, false);
|
||||
realElement->AppendChildTo(textContent, false);
|
||||
}
|
||||
}
|
||||
|
||||
curr = curr->GetNext();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1041,15 +1014,6 @@ nsXBLPrototypeBinding::ReadNewBinding(nsIObjectInputStream* aStream,
|
||||
return rv;
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
WriteInterfaceID(const nsIID& aKey, nsIContent* aData, void* aClosure)
|
||||
{
|
||||
// We can just write out the ids. The cache will be invalidated when a
|
||||
// different build is used, so we don't need to worry about ids changing.
|
||||
static_cast<nsIObjectOutputStream *>(aClosure)->WriteID(aKey);
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsXBLPrototypeBinding::Write(nsIObjectOutputStream* aStream)
|
||||
{
|
||||
@@ -1118,7 +1082,11 @@ nsXBLPrototypeBinding::Write(nsIObjectOutputStream* aStream)
|
||||
rv = aStream->Write32(mInterfaceTable.Count());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mInterfaceTable.EnumerateRead(WriteInterfaceID, aStream);
|
||||
for (auto iter = mInterfaceTable.Iter(); !iter.Done(); iter.Next()) {
|
||||
// We can just write out the ids. The cache will be invalidated when a
|
||||
// different build is used, so we don't need to worry about ids changing.
|
||||
aStream->WriteID(iter.Key());
|
||||
}
|
||||
|
||||
// Write out the implementation details.
|
||||
if (mImplementation) {
|
||||
@@ -1381,60 +1349,6 @@ nsXBLPrototypeBinding::ReadContentNode(nsIObjectInputStream* aStream,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// This structure holds information about a forwarded attribute that needs to be
|
||||
// written out. This is used because we need several fields passed within the
|
||||
// enumeration closure.
|
||||
struct WriteAttributeData
|
||||
{
|
||||
nsXBLPrototypeBinding* binding;
|
||||
nsIObjectOutputStream* stream;
|
||||
nsIContent* content;
|
||||
int32_t srcNamespace;
|
||||
|
||||
WriteAttributeData(nsXBLPrototypeBinding* aBinding,
|
||||
nsIObjectOutputStream* aStream,
|
||||
nsIContent* aContent)
|
||||
: binding(aBinding), stream(aStream), content(aContent)
|
||||
{ }
|
||||
};
|
||||
|
||||
static PLDHashOperator
|
||||
WriteAttribute(nsISupports* aKey, nsXBLAttributeEntry* aEntry, void* aClosure)
|
||||
{
|
||||
WriteAttributeData* data = static_cast<WriteAttributeData *>(aClosure);
|
||||
nsIObjectOutputStream* stream = data->stream;
|
||||
const int32_t srcNamespace = data->srcNamespace;
|
||||
|
||||
do {
|
||||
if (aEntry->GetElement() == data->content) {
|
||||
data->binding->WriteNamespace(stream, srcNamespace);
|
||||
stream->WriteWStringZ(nsDependentAtomString(aEntry->GetSrcAttribute()).get());
|
||||
data->binding->WriteNamespace(stream, aEntry->GetDstNameSpace());
|
||||
stream->WriteWStringZ(nsDependentAtomString(aEntry->GetDstAttribute()).get());
|
||||
}
|
||||
|
||||
aEntry = aEntry->GetNext();
|
||||
} while (aEntry);
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
// WriteAttributeNS is the callback to enumerate over the attribute
|
||||
// forwarding entries. Since these are stored in a hash of hashes,
|
||||
// we need to iterate over the inner hashes, calling WriteAttribute
|
||||
// to do the actual work.
|
||||
static PLDHashOperator
|
||||
WriteAttributeNS(const uint32_t &aNamespace,
|
||||
nsXBLPrototypeBinding::InnerAttributeTable* aXBLAttributes,
|
||||
void* aClosure)
|
||||
{
|
||||
WriteAttributeData* data = static_cast<WriteAttributeData *>(aClosure);
|
||||
data->srcNamespace = aNamespace;
|
||||
aXBLAttributes->EnumerateRead(WriteAttribute, data);
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsXBLPrototypeBinding::WriteContentNode(nsIObjectOutputStream* aStream,
|
||||
nsIContent* aNode)
|
||||
@@ -1515,8 +1429,27 @@ nsXBLPrototypeBinding::WriteContentNode(nsIObjectOutputStream* aStream,
|
||||
|
||||
// Write out the attribute fowarding information
|
||||
if (mAttributeTable) {
|
||||
WriteAttributeData data(this, aStream, aNode);
|
||||
mAttributeTable->EnumerateRead(WriteAttributeNS, &data);
|
||||
for (auto iter1 = mAttributeTable->Iter(); !iter1.Done(); iter1.Next()) {
|
||||
int32_t srcNamespace = iter1.Key();
|
||||
InnerAttributeTable* xblAttributes = iter1.UserData();
|
||||
|
||||
for (auto iter2 = xblAttributes->Iter(); !iter2.Done(); iter2.Next()) {
|
||||
nsXBLAttributeEntry* entry = iter2.UserData();
|
||||
|
||||
do {
|
||||
if (entry->GetElement() == aNode) {
|
||||
WriteNamespace(aStream, srcNamespace);
|
||||
aStream->WriteWStringZ(
|
||||
nsDependentAtomString(entry->GetSrcAttribute()).get());
|
||||
WriteNamespace(aStream, entry->GetDstNameSpace());
|
||||
aStream->WriteWStringZ(
|
||||
nsDependentAtomString(entry->GetDstAttribute()).get());
|
||||
}
|
||||
|
||||
entry = entry->GetNext();
|
||||
} while (entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
rv = aStream->Write8(XBLBinding_Serialize_NoMoreAttributes);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
@@ -579,41 +579,22 @@ nsXULPrototypeCache::BeginCaching(nsIURI* aURI)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
MarkXBLInCCGeneration(nsIURI* aKey, RefPtr<nsXBLDocumentInfo> &aDocInfo,
|
||||
void* aClosure)
|
||||
{
|
||||
uint32_t* gen = static_cast<uint32_t*>(aClosure);
|
||||
aDocInfo->MarkInCCGeneration(*gen);
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
MarkXULInCCGeneration(nsIURI* aKey, RefPtr<nsXULPrototypeDocument> &aDoc,
|
||||
void* aClosure)
|
||||
{
|
||||
uint32_t* gen = static_cast<uint32_t*>(aClosure);
|
||||
aDoc->MarkInCCGeneration(*gen);
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
void
|
||||
nsXULPrototypeCache::MarkInCCGeneration(uint32_t aGeneration)
|
||||
{
|
||||
mXBLDocTable.Enumerate(MarkXBLInCCGeneration, &aGeneration);
|
||||
mPrototypeTable.Enumerate(MarkXULInCCGeneration, &aGeneration);
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
MarkScriptsInGC(nsIURI* aKey, JS::Heap<JSScript*>& aScript, void* aClosure)
|
||||
{
|
||||
JSTracer* trc = static_cast<JSTracer*>(aClosure);
|
||||
JS::TraceEdge(trc, &aScript, "nsXULPrototypeCache script");
|
||||
return PL_DHASH_NEXT;
|
||||
for (auto iter = mXBLDocTable.Iter(); !iter.Done(); iter.Next()) {
|
||||
iter.Data()->MarkInCCGeneration(aGeneration);
|
||||
}
|
||||
for (auto iter = mPrototypeTable.Iter(); !iter.Done(); iter.Next()) {
|
||||
iter.Data()->MarkInCCGeneration(aGeneration);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsXULPrototypeCache::MarkInGC(JSTracer* aTrc)
|
||||
{
|
||||
mScriptTable.Enumerate(MarkScriptsInGC, aTrc);
|
||||
for (auto iter = mScriptTable.Iter(); !iter.Done(); iter.Next()) {
|
||||
JS::Heap<JSScript*>& script = iter.Data();
|
||||
JS::TraceEdge(aTrc, &script, "nsXULPrototypeCache script");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,17 +104,20 @@ nsXULTemplateBuilder::nsXULTemplateBuilder(void)
|
||||
MOZ_COUNT_CTOR(nsXULTemplateBuilder);
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
DestroyMatchList(nsISupports* aKey, nsTemplateMatch*& aMatch, void* aContext)
|
||||
void
|
||||
nsXULTemplateBuilder::DestroyMatchMap()
|
||||
{
|
||||
// delete all the matches in the list
|
||||
while (aMatch) {
|
||||
nsTemplateMatch* next = aMatch->mNext;
|
||||
nsTemplateMatch::Destroy(aMatch, true);
|
||||
aMatch = next;
|
||||
}
|
||||
for (auto iter = mMatchMap.Iter(); !iter.Done(); iter.Next()) {
|
||||
nsTemplateMatch*& match = iter.Data();
|
||||
// delete all the matches in the list
|
||||
while (match) {
|
||||
nsTemplateMatch* next = match->mNext;
|
||||
nsTemplateMatch::Destroy(match, true);
|
||||
match = next;
|
||||
}
|
||||
|
||||
return PL_DHASH_REMOVE;
|
||||
iter.Remove();
|
||||
}
|
||||
}
|
||||
|
||||
nsXULTemplateBuilder::~nsXULTemplateBuilder(void)
|
||||
@@ -195,7 +198,7 @@ nsXULTemplateBuilder::CleanUp(bool aIsFinal)
|
||||
|
||||
mQuerySets.Clear();
|
||||
|
||||
mMatchMap.Enumerate(DestroyMatchList, nullptr);
|
||||
DestroyMatchMap();
|
||||
|
||||
// Setting mQueryProcessor to null will close connections. This would be
|
||||
// handled by the cycle collector, but we want to close them earlier.
|
||||
@@ -232,7 +235,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsXULTemplateBuilder)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mRootResult)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mListeners)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mQueryProcessor)
|
||||
tmp->mMatchMap.Enumerate(DestroyMatchList, nullptr);
|
||||
tmp->DestroyMatchMap();
|
||||
for (uint32_t i = 0; i < tmp->mQuerySets.Length(); ++i) {
|
||||
nsTemplateQuerySet* qs = tmp->mQuerySets[i];
|
||||
delete qs;
|
||||
|
||||
@@ -41,6 +41,7 @@ class nsXULTemplateBuilder : public nsIXULTemplateBuilder,
|
||||
public nsStubDocumentObserver
|
||||
{
|
||||
void CleanUp(bool aIsFinal);
|
||||
void DestroyMatchMap();
|
||||
|
||||
public:
|
||||
nsXULTemplateBuilder();
|
||||
|
||||
@@ -273,53 +273,32 @@ NS_IMETHODIMP mozHunspell::SetPersonalDictionary(mozIPersonalDictionary * aPerso
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
struct AppendNewStruct
|
||||
{
|
||||
char16_t **dics;
|
||||
uint32_t count;
|
||||
bool failed;
|
||||
};
|
||||
|
||||
static PLDHashOperator
|
||||
AppendNewString(const nsAString& aString, nsIFile* aFile, void* aClosure)
|
||||
{
|
||||
AppendNewStruct *ans = (AppendNewStruct*) aClosure;
|
||||
ans->dics[ans->count] = ToNewUnicode(aString);
|
||||
if (!ans->dics[ans->count]) {
|
||||
ans->failed = true;
|
||||
return PL_DHASH_STOP;
|
||||
}
|
||||
|
||||
++ans->count;
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP mozHunspell::GetDictionaryList(char16_t ***aDictionaries,
|
||||
uint32_t *aCount)
|
||||
{
|
||||
if (!aDictionaries || !aCount)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
AppendNewStruct ans = {
|
||||
(char16_t**) NS_Alloc(sizeof(char16_t*) * mDictionaries.Count()),
|
||||
0,
|
||||
false
|
||||
};
|
||||
uint32_t count = 0;
|
||||
char16_t** dicts =
|
||||
(char16_t**) moz_xmalloc(sizeof(char16_t*) * mDictionaries.Count());
|
||||
|
||||
// This pointer is used during enumeration
|
||||
mDictionaries.EnumerateRead(AppendNewString, &ans);
|
||||
|
||||
if (ans.failed) {
|
||||
while (ans.count) {
|
||||
--ans.count;
|
||||
NS_Free(ans.dics[ans.count]);
|
||||
for (auto iter = mDictionaries.Iter(); !iter.Done(); iter.Next()) {
|
||||
dicts[count] = ToNewUnicode(iter.Key());
|
||||
if (!dicts[count]) {
|
||||
while (count) {
|
||||
--count;
|
||||
free(dicts[count]);
|
||||
}
|
||||
free(dicts);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
NS_Free(ans.dics);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
++count;
|
||||
}
|
||||
|
||||
*aDictionaries = ans.dics;
|
||||
*aCount = ans.count;
|
||||
*aDictionaries = dicts;
|
||||
*aCount = count;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -308,11 +308,6 @@ protected:
|
||||
|
||||
void GenerateFontListKey(const nsAString& aKeyName, nsAString& aResult);
|
||||
|
||||
static PLDHashOperator
|
||||
HashEnumFuncForFamilies(nsStringHashKey::KeyType aKey,
|
||||
RefPtr<gfxFontFamily>& aFamilyEntry,
|
||||
void* aUserArg);
|
||||
|
||||
virtual void GetFontFamilyNames(nsTArray<nsString>& aFontFamilyNames);
|
||||
|
||||
nsILanguageAtomService* GetLangService();
|
||||
|
||||
@@ -63,78 +63,6 @@ struct RestyleEnumerateData : RestyleTracker::Hints {
|
||||
#endif
|
||||
};
|
||||
|
||||
struct RestyleCollector {
|
||||
RestyleTracker* tracker;
|
||||
RestyleEnumerateData** restyleArrayPtr;
|
||||
#ifdef RESTYLE_LOGGING
|
||||
uint32_t count;
|
||||
#endif
|
||||
};
|
||||
|
||||
static PLDHashOperator
|
||||
CollectRestyles(nsISupports* aElement,
|
||||
nsAutoPtr<RestyleTracker::RestyleData>& aData,
|
||||
void* aRestyleCollector)
|
||||
{
|
||||
dom::Element* element =
|
||||
static_cast<dom::Element*>(aElement);
|
||||
RestyleCollector* collector =
|
||||
static_cast<RestyleCollector*>(aRestyleCollector);
|
||||
// Only collect the entries that actually need restyling by us (and
|
||||
// haven't, for example, already been restyled).
|
||||
// It's important to not mess with the flags on entries not in our
|
||||
// document.
|
||||
if (element->GetCrossShadowCurrentDoc() != collector->tracker->Document() ||
|
||||
!element->HasFlag(collector->tracker->RestyleBit())) {
|
||||
LOG_RESTYLE_IF(collector->tracker, true,
|
||||
"skipping pending restyle %s, already restyled or no longer "
|
||||
"in the document", FrameTagToString(element).get());
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
NS_ASSERTION(!element->HasFlag(collector->tracker->RootBit()) ||
|
||||
// Maybe we're just not reachable via the frame tree?
|
||||
(element->GetFlattenedTreeParent() &&
|
||||
(!element->GetFlattenedTreeParent()->GetPrimaryFrame() ||
|
||||
element->GetFlattenedTreeParent()->GetPrimaryFrame()->IsLeaf() ||
|
||||
element->GetCurrentDoc()->GetShell()->FrameManager()
|
||||
->GetDisplayContentsStyleFor(element))) ||
|
||||
// Or not reachable due to an async reinsert we have
|
||||
// pending? If so, we'll have a reframe hint around.
|
||||
// That incidentally makes it safe that we still have
|
||||
// the bit, since any descendants that didn't get added
|
||||
// to the roots list because we had the bits will be
|
||||
// completely restyled in a moment.
|
||||
(aData->mChangeHint & nsChangeHint_ReconstructFrame),
|
||||
"Why did this not get handled while processing mRestyleRoots?");
|
||||
|
||||
// Unset the restyle bits now, so if they get readded later as we
|
||||
// process we won't clobber that adding of the bit.
|
||||
element->UnsetFlags(collector->tracker->RestyleBit() |
|
||||
collector->tracker->RootBit() |
|
||||
collector->tracker->ConditionalDescendantsBit());
|
||||
|
||||
RestyleEnumerateData** restyleArrayPtr = collector->restyleArrayPtr;
|
||||
RestyleEnumerateData* currentRestyle = *restyleArrayPtr;
|
||||
currentRestyle->mElement = element;
|
||||
currentRestyle->mRestyleHint = aData->mRestyleHint;
|
||||
currentRestyle->mChangeHint = aData->mChangeHint;
|
||||
// We can move aData since we'll be clearing mPendingRestyles after
|
||||
// we finish enumerating it.
|
||||
currentRestyle->mRestyleHintData = Move(aData->mRestyleHintData);
|
||||
#if defined(MOZ_ENABLE_PROFILER_SPS) && !defined(MOZILLA_XPCOMRT_API)
|
||||
currentRestyle->mBacktrace = Move(aData->mBacktrace);
|
||||
#endif
|
||||
#ifdef RESTYLE_LOGGING
|
||||
collector->count++;
|
||||
#endif
|
||||
|
||||
// Increment to the next slot in the array
|
||||
*restyleArrayPtr = currentRestyle + 1;
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
inline void
|
||||
RestyleTracker::ProcessOneRestyle(Element* aElement,
|
||||
nsRestyleHint aRestyleHint,
|
||||
@@ -356,9 +284,68 @@ RestyleTracker::DoProcessRestyles()
|
||||
RestyleEnumerateData* restylesToProcess =
|
||||
restyleArr.AppendElements(mPendingRestyles.Count());
|
||||
if (restylesToProcess) {
|
||||
RestyleEnumerateData* lastRestyle = restylesToProcess;
|
||||
RestyleCollector collector = { this, &lastRestyle };
|
||||
mPendingRestyles.Enumerate(CollectRestyles, &collector);
|
||||
RestyleEnumerateData* restyle = restylesToProcess;
|
||||
#ifdef RESTYLE_LOGGING
|
||||
uint32_t count = 0;
|
||||
#endif
|
||||
for (auto iter = mPendingRestyles.Iter(); !iter.Done(); iter.Next()) {
|
||||
auto element = static_cast<dom::Element*>(iter.Key());
|
||||
RestyleTracker::RestyleData* data = iter.Data();
|
||||
|
||||
// Only collect the entries that actually need restyling by us (and
|
||||
// haven't, for example, already been restyled).
|
||||
// It's important to not mess with the flags on entries not in our
|
||||
// document.
|
||||
if (element->GetCrossShadowCurrentDoc() != Document() ||
|
||||
!element->HasFlag(RestyleBit())) {
|
||||
LOG_RESTYLE("skipping pending restyle %s, already restyled or no "
|
||||
"longer in the document",
|
||||
FrameTagToString(element).get());
|
||||
continue;
|
||||
}
|
||||
|
||||
NS_ASSERTION(
|
||||
!element->HasFlag(RootBit()) ||
|
||||
// Maybe we're just not reachable via the frame tree?
|
||||
(element->GetFlattenedTreeParent() &&
|
||||
(!element->GetFlattenedTreeParent()->GetPrimaryFrame() ||
|
||||
element->GetFlattenedTreeParent()->GetPrimaryFrame()->IsLeaf() ||
|
||||
element->GetCrossShadowCurrentDoc()->GetShell()->FrameManager()
|
||||
->GetDisplayContentsStyleFor(element))) ||
|
||||
// Or not reachable due to an async reinsert we have
|
||||
// pending? If so, we'll have a reframe hint around.
|
||||
// That incidentally makes it safe that we still have
|
||||
// the bit, since any descendants that didn't get added
|
||||
// to the roots list because we had the bits will be
|
||||
// completely restyled in a moment.
|
||||
(data->mChangeHint & nsChangeHint_ReconstructFrame),
|
||||
"Why did this not get handled while processing mRestyleRoots?");
|
||||
|
||||
// Unset the restyle bits now, so if they get readded later as we
|
||||
// process we won't clobber that adding of the bit.
|
||||
element->UnsetFlags(RestyleBit() |
|
||||
RootBit() |
|
||||
ConditionalDescendantsBit());
|
||||
|
||||
restyle->mElement = element;
|
||||
restyle->mRestyleHint = data->mRestyleHint;
|
||||
restyle->mChangeHint = data->mChangeHint;
|
||||
// We can move data since we'll be clearing mPendingRestyles after
|
||||
// we finish enumerating it.
|
||||
restyle->mRestyleHintData = Move(data->mRestyleHintData);
|
||||
#if defined(MOZ_ENABLE_PROFILER_SPS) && !defined(MOZILLA_XPCOMRT_API)
|
||||
restyle->mBacktrace = Move(data->mBacktrace);
|
||||
#endif
|
||||
|
||||
#ifdef RESTYLE_LOGGING
|
||||
count++;
|
||||
#endif
|
||||
|
||||
// Increment to the next slot in the array
|
||||
restyle++;
|
||||
}
|
||||
|
||||
RestyleEnumerateData* lastRestyle = restyle;
|
||||
|
||||
// Clear the hashtable now that we don't need it anymore
|
||||
mPendingRestyles.Clear();
|
||||
@@ -371,7 +358,7 @@ RestyleTracker::DoProcessRestyles()
|
||||
++currentRestyle) {
|
||||
LOG_RESTYLE("processing pending restyle %s at index %d/%d",
|
||||
FrameTagToString(currentRestyle->mElement).get(),
|
||||
index++, collector.count);
|
||||
index++, count);
|
||||
LOG_RESTYLE_INDENT();
|
||||
|
||||
#if defined(MOZ_ENABLE_PROFILER_SPS) && !defined(MOZILLA_XPCOMRT_API)
|
||||
|
||||
@@ -441,11 +441,6 @@ public:
|
||||
private:
|
||||
friend class SheetLoadData;
|
||||
|
||||
static PLDHashOperator
|
||||
RemoveEntriesWithURI(URIPrincipalReferrerPolicyAndCORSModeHashKey* aKey,
|
||||
RefPtr<CSSStyleSheet>& aSheet,
|
||||
void* aUserData);
|
||||
|
||||
// Note: null aSourcePrincipal indicates that the content policy and
|
||||
// CheckLoadURI checks should be skipped.
|
||||
// aIsPreload indicates whether the html parser preloads that
|
||||
|
||||
@@ -458,18 +458,11 @@ private:
|
||||
const PLDHashEntryHdr *aHdr,
|
||||
const void *aKey);
|
||||
|
||||
static PLDHashOperator
|
||||
SweepHashEntry(PLDHashTable *table, PLDHashEntryHdr *hdr,
|
||||
uint32_t number, void *arg);
|
||||
void SweepChildren(nsTArray<nsRuleNode*>& aSweepQueue);
|
||||
bool DestroyIfNotMarked();
|
||||
|
||||
static const PLDHashTableOps ChildrenHashOps;
|
||||
|
||||
static PLDHashOperator
|
||||
EnqueueRuleNodeChildren(PLDHashTable *table, PLDHashEntryHdr *hdr,
|
||||
uint32_t number, void *arg);
|
||||
|
||||
Key GetKey() const {
|
||||
return Key(mRule, GetLevel(), IsImportantRule());
|
||||
}
|
||||
|
||||
@@ -76,10 +76,6 @@ private:
|
||||
HashTableMatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr,
|
||||
const void *key);
|
||||
|
||||
static PLDHashOperator
|
||||
FillSortedArray(PLDHashTable *table, PLDHashEntryHdr *hdr,
|
||||
uint32_t number, void *arg);
|
||||
|
||||
static int SortArray(const void *a, const void *b, void *closure);
|
||||
|
||||
/* state used only during enumeration */
|
||||
|
||||
@@ -82,3 +82,6 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
|
||||
|
||||
CFLAGS += CONFIG['MOZ_ALSA_CFLAGS']
|
||||
CFLAGS += CONFIG['MOZ_PULSEAUDIO_CFLAGS']
|
||||
|
||||
# We allow warnings for third-party code that can be updated from upstream.
|
||||
ALLOW_COMPILER_WARNINGS = True
|
||||
|
||||
@@ -25,3 +25,6 @@ if CONFIG['GKMEDIAS_SHARED_LIBRARY']:
|
||||
NO_VISIBILITY_FLAGS = True
|
||||
|
||||
FINAL_LIBRARY = 'gkmedias'
|
||||
|
||||
# We allow warnings for third-party code that can be updated from upstream.
|
||||
ALLOW_COMPILER_WARNINGS = True
|
||||
|
||||
@@ -11,4 +11,4 @@ UNIFIED_SOURCES += [
|
||||
FINAL_LIBRARY = 'gkmedias'
|
||||
|
||||
# We allow warnings for third-party code that can be updated from upstream.
|
||||
#ALLOW_COMPILER_WARNINGS = True
|
||||
ALLOW_COMPILER_WARNINGS = True
|
||||
|
||||
@@ -51,3 +51,6 @@ if CONFIG['GKMEDIAS_SHARED_LIBRARY']:
|
||||
NO_VISIBILITY_FLAGS = True
|
||||
|
||||
FINAL_LIBRARY = 'gkmedias'
|
||||
|
||||
# We allow warnings for third-party code that can be updated from upstream.
|
||||
ALLOW_COMPILER_WARNINGS = True
|
||||
|
||||
@@ -142,7 +142,7 @@ jemalloc_stats_impl(jemalloc_stats_t *stats)
|
||||
// src/ctl.c
|
||||
uint64_t epoch = 0;
|
||||
size_t esz = sizeof(epoch);
|
||||
int ret = je_(mallctl)("epoch", &epoch, &esz, &epoch, esz);
|
||||
je_(mallctl)("epoch", &epoch, &esz, &epoch, esz);
|
||||
|
||||
CTL_GET("arenas.narenas", narenas);
|
||||
CTL_GET("arenas.page", page);
|
||||
|
||||
+28
-44
@@ -1,4 +1,5 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* -*- 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/. */
|
||||
@@ -1096,16 +1097,11 @@ nsZipReaderCache::Init(uint32_t cacheSize)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
DropZipReaderCache(const nsACString &aKey, nsJAR* aZip, void*)
|
||||
{
|
||||
aZip->SetZipReaderCache(nullptr);
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
nsZipReaderCache::~nsZipReaderCache()
|
||||
{
|
||||
mZips.EnumerateRead(DropZipReaderCache, nullptr);
|
||||
for (auto iter = mZips.Iter(); !iter.Done(); iter.Next()) {
|
||||
iter.UserData()->SetZipReaderCache(nullptr);
|
||||
}
|
||||
|
||||
#ifdef ZIP_CACHE_HIT_RATE
|
||||
printf("nsZipReaderCache size=%d hits=%d lookups=%d rate=%f%% flushes=%d missed %d\n",
|
||||
@@ -1256,36 +1252,6 @@ nsZipReaderCache::GetFd(nsIFile* zipFile, PRFileDesc** aRetVal)
|
||||
#endif /* XP_WIN */
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
FindOldestZip(const nsACString &aKey, nsJAR* aZip, void* aClosure)
|
||||
{
|
||||
nsJAR** oldestPtr = static_cast<nsJAR**>(aClosure);
|
||||
nsJAR* oldest = *oldestPtr;
|
||||
nsJAR* current = aZip;
|
||||
PRIntervalTime currentReleaseTime = current->GetReleaseTime();
|
||||
if (currentReleaseTime != PR_INTERVAL_NO_TIMEOUT) {
|
||||
if (oldest == nullptr ||
|
||||
currentReleaseTime < oldest->GetReleaseTime()) {
|
||||
*oldestPtr = current;
|
||||
}
|
||||
}
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
struct ZipFindData {nsJAR* zip; bool found;};
|
||||
|
||||
static PLDHashOperator
|
||||
FindZip(const nsACString &aKey, nsJAR* aZip, void* aClosure)
|
||||
{
|
||||
ZipFindData* find_data = static_cast<ZipFindData*>(aClosure);
|
||||
|
||||
if (find_data->zip == aZip) {
|
||||
find_data->found = true;
|
||||
return PL_DHASH_STOP;
|
||||
}
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsZipReaderCache::ReleaseZip(nsJAR* zip)
|
||||
{
|
||||
@@ -1307,9 +1273,15 @@ nsZipReaderCache::ReleaseZip(nsJAR* zip)
|
||||
// So, we are going to try safeguarding here by searching our hashtable while
|
||||
// locked here for the zip. We return fast if it is not found.
|
||||
|
||||
ZipFindData find_data = {zip, false};
|
||||
mZips.EnumerateRead(FindZip, &find_data);
|
||||
if (!find_data.found) {
|
||||
bool found = false;
|
||||
for (auto iter = mZips.Iter(); !iter.Done(); iter.Next()) {
|
||||
if (zip == iter.UserData()) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
#ifdef ZIP_CACHE_HIT_RATE
|
||||
mZipSyncMisses++;
|
||||
#endif
|
||||
@@ -1321,8 +1293,18 @@ nsZipReaderCache::ReleaseZip(nsJAR* zip)
|
||||
if (mZips.Count() <= mCacheSize)
|
||||
return NS_OK;
|
||||
|
||||
// Find the oldest zip.
|
||||
nsJAR* oldest = nullptr;
|
||||
mZips.EnumerateRead(FindOldestZip, &oldest);
|
||||
for (auto iter = mZips.Iter(); !iter.Done(); iter.Next()) {
|
||||
nsJAR* current = iter.UserData();
|
||||
PRIntervalTime currentReleaseTime = current->GetReleaseTime();
|
||||
if (currentReleaseTime != PR_INTERVAL_NO_TIMEOUT) {
|
||||
if (oldest == nullptr ||
|
||||
currentReleaseTime < oldest->GetReleaseTime()) {
|
||||
oldest = current;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Because of the craziness above it is possible that there is no zip that
|
||||
// needs removing.
|
||||
@@ -1378,7 +1360,9 @@ nsZipReaderCache::Observe(nsISupports *aSubject,
|
||||
}
|
||||
else if (strcmp(aTopic, "chrome-flush-caches") == 0) {
|
||||
MutexAutoLock lock(mLock);
|
||||
mZips.EnumerateRead(DropZipReaderCache, nullptr);
|
||||
for (auto iter = mZips.Iter(); !iter.Done(); iter.Next()) {
|
||||
iter.UserData()->SetZipReaderCache(nullptr);
|
||||
}
|
||||
mZips.Clear();
|
||||
}
|
||||
else if (strcmp(aTopic, "flush-cache-entry") == 0) {
|
||||
|
||||
@@ -263,7 +263,7 @@ strip_signature_block(const char *src, const char * dest)
|
||||
FILE *fpSrc = NULL, *fpDest = NULL;
|
||||
int rv = -1, hasSignatureBlock;
|
||||
char buf[BLOCKSIZE];
|
||||
char *indexBuf = NULL, *indexBufLoc;
|
||||
char *indexBuf = NULL;
|
||||
|
||||
if (!src || !dest) {
|
||||
fprintf(stderr, "ERROR: Invalid parameter passed in.\n");
|
||||
@@ -433,7 +433,6 @@ strip_signature_block(const char *src, const char * dest)
|
||||
|
||||
/* Consume the index and adjust each index by the difference */
|
||||
indexBuf = malloc(indexLength);
|
||||
indexBufLoc = indexBuf;
|
||||
if (fread(indexBuf, indexLength, 1, fpSrc) != 1) {
|
||||
fprintf(stderr, "ERROR: Could not read index\n");
|
||||
goto failure;
|
||||
@@ -533,6 +532,9 @@ extract_signature(const char *src, uint32_t sigIndex, const char * dest)
|
||||
|
||||
/* Skip to the correct signature */
|
||||
for (i = 0; i <= sigIndex; i++) {
|
||||
/* Avoid leaking while skipping signatures */
|
||||
free(extractedSignature);
|
||||
|
||||
/* skip past the signature algorithm ID */
|
||||
if (fseeko(fpSrc, sizeof(uint32_t), SEEK_CUR)) {
|
||||
fprintf(stderr, "ERROR: Could not seek past sig algorithm ID.\n");
|
||||
@@ -834,7 +836,7 @@ mar_repackage_and_sign(const char *NSSConfigDir,
|
||||
char buf[BLOCKSIZE];
|
||||
SECKEYPrivateKey *privKeys[MAX_SIGNATURES];
|
||||
CERTCertificate *certs[MAX_SIGNATURES];
|
||||
char *indexBuf = NULL, *indexBufLoc;
|
||||
char *indexBuf = NULL;
|
||||
uint32_t k;
|
||||
|
||||
memset(signatureLengths, 0, sizeof(signatureLengths));
|
||||
@@ -1056,7 +1058,6 @@ mar_repackage_and_sign(const char *NSSConfigDir,
|
||||
|
||||
/* Consume the index and adjust each index by signatureSectionLength */
|
||||
indexBuf = malloc(indexLength);
|
||||
indexBufLoc = indexBuf;
|
||||
if (fread(indexBuf, indexLength, 1, fpSrc) != 1) {
|
||||
fprintf(stderr, "ERROR: Could not read index\n");
|
||||
goto failure;
|
||||
|
||||
@@ -22,6 +22,3 @@ DEFINES['MAR_NSS'] = True
|
||||
|
||||
if CONFIG['OS_ARCH'] == 'WINNT':
|
||||
USE_STATIC_LIBS = True
|
||||
|
||||
# XXX: We should fix these warnings.
|
||||
ALLOW_COMPILER_WARNINGS = True
|
||||
|
||||
@@ -81,7 +81,10 @@ GetPasswordString(void *arg, char *prompt)
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
QUIET_FGETS (phrase, sizeof(phrase), input);
|
||||
if (!QUIET_FGETS(phrase, sizeof(phrase), input)) {
|
||||
fprintf(stderr, "QUIET_FGETS failed\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (isInputTerminal) {
|
||||
fprintf(stdout, "\n");
|
||||
|
||||
@@ -134,6 +134,26 @@ int mar_create(const char *dest,
|
||||
*/
|
||||
int mar_extract(const char *path);
|
||||
|
||||
#define MAR_MAX_CERT_SIZE (16*1024) // Way larger than necessary
|
||||
|
||||
/* Read the entire file (not a MAR file) into a newly-allocated buffer.
|
||||
* This function does not write to stderr. Instead, the caller should
|
||||
* write whatever error messages it sees fit. The caller must free the returned
|
||||
* buffer using free().
|
||||
*
|
||||
* @param filePath The path to the file that should be read.
|
||||
* @param maxSize The maximum valid file size.
|
||||
* @param data On success, *data will point to a newly-allocated buffer
|
||||
* with the file's contents in it.
|
||||
* @param size On success, *size will be the size of the created buffer.
|
||||
*
|
||||
* @return 0 on success, -1 on error
|
||||
*/
|
||||
int mar_read_entire_file(const char * filePath,
|
||||
uint32_t maxSize,
|
||||
/*out*/ const uint8_t * *data,
|
||||
/*out*/ uint32_t *size);
|
||||
|
||||
/**
|
||||
* Verifies a MAR file by verifying each signature with the corresponding
|
||||
* certificate. That is, the first signature will be verified using the first
|
||||
@@ -154,12 +174,10 @@ int mar_extract(const char *path);
|
||||
* a negative number if there was an error
|
||||
* a positive number if the signature does not verify
|
||||
*/
|
||||
#ifdef XP_WIN
|
||||
int mar_verify_signaturesW(MarFile *mar,
|
||||
const uint8_t * const *certData,
|
||||
const uint32_t *certDataSizes,
|
||||
uint32_t certCount);
|
||||
#endif
|
||||
int mar_verify_signatures(MarFile *mar,
|
||||
const uint8_t * const *certData,
|
||||
const uint32_t *certDataSizes,
|
||||
uint32_t certCount);
|
||||
|
||||
/**
|
||||
* Reads the product info block from the MAR file's additional block section.
|
||||
|
||||
@@ -38,38 +38,6 @@ int get_mar_file_info(const char *path,
|
||||
uint32_t *offsetAdditionalBlocks,
|
||||
uint32_t *numAdditionalBlocks);
|
||||
|
||||
/**
|
||||
* Verifies a MAR file by verifying each signature with the corresponding
|
||||
* certificate. That is, the first signature will be verified using the first
|
||||
* certificate given, the second signature will be verified using the second
|
||||
* certificate given, etc. The signature count must exactly match the number of
|
||||
* certificates given, and all signature verifications must succeed.
|
||||
* This is only used by the signmar program when used with arguments to verify
|
||||
* a MAR. This should not be used to verify a MAR that will be extracted in the
|
||||
* same operation by updater code. This function prints the error message if
|
||||
* verification fails.
|
||||
*
|
||||
* @param pathToMAR The path of the MAR file whose signature should be
|
||||
* checked
|
||||
* @param certData Pointer to the first element in an array of certificate
|
||||
* file data.
|
||||
* @param certDataSizes Pointer to the first element in an array for size of
|
||||
* the cert data.
|
||||
* @param certNames Pointer to the first element in an array of certificate
|
||||
* names.
|
||||
* Used only if compiled with NSS support
|
||||
* @param certCount The number of elements in certData, certDataSizes,
|
||||
* and certNames
|
||||
* @return 0 on success
|
||||
* a negative number if there was an error
|
||||
* a positive number if the signature does not verify
|
||||
*/
|
||||
int mar_verify_signatures(const char *pathToMAR,
|
||||
const uint8_t * const *certData,
|
||||
const uint32_t *certDataSizes,
|
||||
const char * const *certNames,
|
||||
uint32_t certCount);
|
||||
|
||||
/**
|
||||
* Reads the product info block from the MAR file's additional block section.
|
||||
* The caller is responsible for freeing the fields in infoBlock
|
||||
|
||||
@@ -337,7 +337,7 @@ int get_mar_file_info_fp(FILE *fp,
|
||||
}
|
||||
}
|
||||
|
||||
if (ftell(fp) == offsetToContent) {
|
||||
if ((int64_t)ftell(fp) == (int64_t)offsetToContent) {
|
||||
*hasAdditionalBlocks = 0;
|
||||
} else {
|
||||
if (numAdditionalBlocks) {
|
||||
@@ -405,10 +405,12 @@ mar_read_product_info_block(MarFile *mar,
|
||||
/* The buffer size is 97 bytes because the MAR channel name < 64 bytes, and
|
||||
product version < 32 bytes + 3 NULL terminator bytes. */
|
||||
char buf[97] = { '\0' };
|
||||
int ret = get_mar_file_info_fp(mar->fp, NULL, NULL,
|
||||
&hasAdditionalBlocks,
|
||||
&offsetAdditionalBlocks,
|
||||
&numAdditionalBlocks);
|
||||
if (get_mar_file_info_fp(mar->fp, NULL, NULL,
|
||||
&hasAdditionalBlocks,
|
||||
&offsetAdditionalBlocks,
|
||||
&numAdditionalBlocks) != 0) {
|
||||
return -1;
|
||||
}
|
||||
for (i = 0; i < numAdditionalBlocks; ++i) {
|
||||
/* Read the additional block size */
|
||||
if (fread(&additionalBlockSize,
|
||||
|
||||
@@ -28,6 +28,3 @@ FORCE_STATIC_LIB = True
|
||||
|
||||
if CONFIG['OS_ARCH'] == 'WINNT':
|
||||
USE_STATIC_LIBS = True
|
||||
|
||||
# XXX: We should fix these warnings.
|
||||
ALLOW_COMPILER_WARNINGS = True
|
||||
|
||||
+74
-59
@@ -19,6 +19,8 @@
|
||||
#endif
|
||||
|
||||
#if !defined(NO_SIGN_VERIFY) && (!defined(XP_WIN) || defined(MAR_NSS))
|
||||
#include "cert.h"
|
||||
#include "pk11pub.h"
|
||||
int NSSInitCryptoContext(const char *NSSConfigDir);
|
||||
#endif
|
||||
|
||||
@@ -115,25 +117,26 @@ int main(int argc, char **argv) {
|
||||
const char *certNames[MAX_SIGNATURES];
|
||||
char *MARChannelID = MAR_CHANNEL_ID;
|
||||
char *productVersion = MOZ_APP_VERSION;
|
||||
uint32_t i, k;
|
||||
uint32_t k;
|
||||
int rv = -1;
|
||||
uint32_t certCount = 0;
|
||||
int32_t sigIndex = -1;
|
||||
|
||||
#if defined(XP_WIN) && !defined(MAR_NSS) && !defined(NO_SIGN_VERIFY)
|
||||
HANDLE certFile;
|
||||
uint8_t *certBuffers[MAX_SIGNATURES];
|
||||
#endif
|
||||
#if !defined(NO_SIGN_VERIFY) && ((!defined(MAR_NSS) && defined(XP_WIN)) || \
|
||||
defined(XP_MACOSX))
|
||||
char* DERFilePaths[MAX_SIGNATURES];
|
||||
#if !defined(NO_SIGN_VERIFY)
|
||||
uint32_t fileSizes[MAX_SIGNATURES];
|
||||
uint32_t read;
|
||||
const uint8_t* certBuffers[MAX_SIGNATURES];
|
||||
#if ((!defined(MAR_NSS) && defined(XP_WIN)) || defined(XP_MACOSX)) || \
|
||||
((defined(XP_WIN) || defined(XP_MACOSX)) && !defined(MAR_NSS))
|
||||
char* DERFilePaths[MAX_SIGNATURES];
|
||||
#endif
|
||||
#if (!defined(XP_WIN) && !defined(XP_MACOSX)) || defined(MAR_NSS)
|
||||
CERTCertificate* certs[MAX_SIGNATURES];
|
||||
#endif
|
||||
#endif
|
||||
|
||||
memset(certNames, 0, sizeof(certNames));
|
||||
memset((void*)certNames, 0, sizeof(certNames));
|
||||
#if defined(XP_WIN) && !defined(MAR_NSS) && !defined(NO_SIGN_VERIFY)
|
||||
memset(certBuffers, 0, sizeof(certBuffers));
|
||||
memset((void*)certBuffers, 0, sizeof(certBuffers));
|
||||
#endif
|
||||
#if !defined(NO_SIGN_VERIFY) && ((!defined(MAR_NSS) && defined(XP_WIN)) || \
|
||||
defined(XP_MACOSX))
|
||||
@@ -161,7 +164,9 @@ int main(int argc, char **argv) {
|
||||
break;
|
||||
/* -C workingdirectory */
|
||||
} else if (argv[1][0] == '-' && argv[1][1] == 'C') {
|
||||
chdir(argv[2]);
|
||||
if (chdir(argv[2]) != 0) {
|
||||
return -1;
|
||||
}
|
||||
argv += 2;
|
||||
argc -= 2;
|
||||
}
|
||||
@@ -319,43 +324,71 @@ int main(int argc, char **argv) {
|
||||
return import_signature(argv[2], sigIndex, argv[3], argv[4]);
|
||||
|
||||
case 'v':
|
||||
|
||||
#if defined(XP_WIN) && !defined(MAR_NSS)
|
||||
if (certCount == 0) {
|
||||
print_usage();
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (k = 0; k < certCount; ++k) {
|
||||
/* If the mar program was built using CryptoAPI, then read in the buffer
|
||||
containing the cert from disk. */
|
||||
certFile = CreateFileA(DERFilePaths[k], GENERIC_READ,
|
||||
FILE_SHARE_READ |
|
||||
FILE_SHARE_WRITE |
|
||||
FILE_SHARE_DELETE,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
0, NULL);
|
||||
if (INVALID_HANDLE_VALUE == certFile) {
|
||||
return -1;
|
||||
}
|
||||
fileSizes[k] = GetFileSize(certFile, NULL);
|
||||
certBuffers[k] = malloc(fileSizes[k]);
|
||||
if (!ReadFile(certFile, certBuffers[k], fileSizes[k], &read, NULL) ||
|
||||
fileSizes[k] != read) {
|
||||
CloseHandle(certFile);
|
||||
for (i = 0; i <= k; i++) {
|
||||
free(certBuffers[i]);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
CloseHandle(certFile);
|
||||
#if (!defined(XP_WIN) && !defined(XP_MACOSX)) || defined(MAR_NSS)
|
||||
if (!NSSConfigDir || certCount == 0) {
|
||||
print_usage();
|
||||
return -1;
|
||||
}
|
||||
|
||||
rv = mar_verify_signatures(argv[2], certBuffers, fileSizes,
|
||||
NULL, certCount);
|
||||
if (NSSInitCryptoContext(NSSConfigDir)) {
|
||||
fprintf(stderr, "ERROR: Could not initialize crypto library.\n");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
rv = 0;
|
||||
for (k = 0; k < certCount; ++k) {
|
||||
free(certBuffers[k]);
|
||||
#if (defined(XP_WIN) || defined(XP_MACOSX)) && !defined(MAR_NSS)
|
||||
rv = mar_read_entire_file(DERFilePaths[k], MAR_MAX_CERT_SIZE,
|
||||
&certBuffers[k], &fileSizes[k]);
|
||||
|
||||
if (rv) {
|
||||
fprintf(stderr, "ERROR: could not read file %s", DERFilePaths[k]);
|
||||
break;
|
||||
}
|
||||
#else
|
||||
/* It is somewhat circuitous to look up a CERTCertificate and then pass
|
||||
* in its DER encoding just so we can later re-create that
|
||||
* CERTCertificate to extract the public key out of it. However, by doing
|
||||
* things this way, we maximize the reuse of the mar_verify_signatures
|
||||
* function and also we keep the control flow as similar as possible
|
||||
* between programs and operating systems, at least for the functions
|
||||
* that are critically important to security.
|
||||
*/
|
||||
certs[k] = PK11_FindCertFromNickname(certNames[k], NULL);
|
||||
if (certs[k]) {
|
||||
certBuffers[k] = certs[k]->derCert.data;
|
||||
fileSizes[k] = certs[k]->derCert.len;
|
||||
} else {
|
||||
rv = -1;
|
||||
fprintf(stderr, "ERROR: could not find cert from nickname %s", certNames[k]);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!rv) {
|
||||
MarFile *mar = mar_open(argv[2]);
|
||||
if (mar) {
|
||||
rv = mar_verify_signatures(mar, certBuffers, fileSizes, certCount);
|
||||
mar_close(mar);
|
||||
} else {
|
||||
fprintf(stderr, "ERROR: Could not open MAR file.\n");
|
||||
rv = -1;
|
||||
}
|
||||
}
|
||||
for (k = 0; k < certCount; ++k) {
|
||||
#if (defined(XP_WIN) || defined(XP_MACOSX)) && !defined(MAR_NSS)
|
||||
free((void*)certBuffers[k]);
|
||||
#else
|
||||
/* certBuffers[k] is owned by certs[k] so don't free it */
|
||||
CERT_DestroyCertificate(certs[k]);
|
||||
#endif
|
||||
}
|
||||
if (rv) {
|
||||
/* Determine if the source MAR file has the new fields for signing */
|
||||
@@ -369,26 +402,8 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
#elif defined(XP_MACOSX)
|
||||
return mar_verify_signatures(argv[2], (const uint8_t* const*)DERFilePaths,
|
||||
0, NULL, certCount);
|
||||
#else
|
||||
if (!NSSConfigDir || certCount == 0) {
|
||||
print_usage();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (NSSInitCryptoContext(NSSConfigDir)) {
|
||||
fprintf(stderr, "ERROR: Could not initialize crypto library.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return mar_verify_signatures(argv[2], NULL, 0, certNames, certCount);
|
||||
|
||||
#endif /* defined(XP_WIN) && !defined(MAR_NSS) */
|
||||
case 's':
|
||||
if (!NSSConfigDir || certCount == 0 || argc < 4) {
|
||||
print_usage();
|
||||
|
||||
@@ -27,6 +27,7 @@ if CONFIG['MOZ_ENABLE_SIGNMAR']:
|
||||
|
||||
for var in ('MAR_CHANNEL_ID', 'MOZ_APP_VERSION'):
|
||||
DEFINES[var] = '"%s"' % CONFIG[var]
|
||||
HOST_DEFINES[var] = DEFINES[var]
|
||||
|
||||
if CONFIG['MOZ_ENABLE_SIGNMAR']:
|
||||
USE_LIBS += [
|
||||
@@ -57,14 +58,6 @@ if CONFIG['HOST_OS_ARCH'] == 'WINNT':
|
||||
'ws2_32',
|
||||
]
|
||||
|
||||
# XXX: We should fix these warnings.
|
||||
ALLOW_COMPILER_WARNINGS = True
|
||||
|
||||
HOST_CFLAGS += [
|
||||
#TODO: bug 1200360 - don't pass make variables here
|
||||
'$(DEFINES)',
|
||||
]
|
||||
|
||||
HOST_DEFINES['NO_SIGN_VERIFY'] = True
|
||||
|
||||
if CONFIG['CROSS_COMPILE'] and CONFIG['HOST_NSPR_MDCPUCFG']:
|
||||
|
||||
@@ -16,29 +16,32 @@
|
||||
/**
|
||||
* Loads the public key for the specified cert name from the NSS store.
|
||||
*
|
||||
* @param certName The cert name to find.
|
||||
* @param certData The DER-encoded X509 certificate to extract the key from.
|
||||
* @param certDataSize The size of certData.
|
||||
* @param publicKey Out parameter for the public key to use.
|
||||
* @param cert Out parameter for the certificate to use.
|
||||
* @return CryptoX_Success on success, CryptoX_Error on error.
|
||||
*/
|
||||
CryptoX_Result
|
||||
NSS_LoadPublicKey(const char *certNickname,
|
||||
SECKEYPublicKey **publicKey,
|
||||
CERTCertificate **cert)
|
||||
NSS_LoadPublicKey(const unsigned char *certData, unsigned int certDataSize,
|
||||
SECKEYPublicKey **publicKey)
|
||||
{
|
||||
secuPWData pwdata = { PW_NONE, 0 };
|
||||
if (!cert || !publicKey || !cert) {
|
||||
CERTCertificate * cert;
|
||||
SECItem certDataItem = { siBuffer, (unsigned char*) certData, certDataSize };
|
||||
|
||||
if (!certData || !publicKey) {
|
||||
return CryptoX_Error;
|
||||
}
|
||||
|
||||
cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &certDataItem, NULL,
|
||||
PR_FALSE, PR_TRUE);
|
||||
/* Get the cert and embedded public key out of the database */
|
||||
*cert = PK11_FindCertFromNickname(certNickname, &pwdata);
|
||||
if (!*cert) {
|
||||
if (!cert) {
|
||||
return CryptoX_Error;
|
||||
}
|
||||
*publicKey = CERT_ExtractPublicKey(*cert);
|
||||
*publicKey = CERT_ExtractPublicKey(cert);
|
||||
CERT_DestroyCertificate(cert);
|
||||
|
||||
if (!*publicKey) {
|
||||
CERT_DestroyCertificate(*cert);
|
||||
return CryptoX_Error;
|
||||
}
|
||||
return CryptoX_Success;
|
||||
@@ -150,12 +153,11 @@ CryptoX_Result
|
||||
CryptoAPI_LoadPublicKey(HCRYPTPROV provider,
|
||||
BYTE *certData,
|
||||
DWORD sizeOfCertData,
|
||||
HCRYPTKEY *publicKey,
|
||||
HCERTSTORE *certStore)
|
||||
HCRYPTKEY *publicKey)
|
||||
{
|
||||
CRYPT_DATA_BLOB blob;
|
||||
CERT_CONTEXT *context;
|
||||
if (!provider || !certData || !publicKey || !certStore) {
|
||||
if (!provider || !certData || !publicKey) {
|
||||
return CryptoX_Error;
|
||||
}
|
||||
|
||||
@@ -165,7 +167,7 @@ CryptoAPI_LoadPublicKey(HCRYPTPROV provider,
|
||||
CERT_QUERY_CONTENT_FLAG_CERT,
|
||||
CERT_QUERY_FORMAT_FLAG_BINARY,
|
||||
0, NULL, NULL, NULL,
|
||||
certStore, NULL, (const void **)&context)) {
|
||||
NULL, NULL, (const void **)&context)) {
|
||||
return CryptoX_Error;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,9 @@
|
||||
|
||||
#if defined(MAR_NSS)
|
||||
|
||||
#include "nss_secutil.h"
|
||||
#include "cert.h"
|
||||
#include "keyhi.h"
|
||||
#include "cryptohi.h"
|
||||
|
||||
#define CryptoX_InvalidHandleValue NULL
|
||||
#define CryptoX_ProviderHandle void*
|
||||
@@ -26,9 +28,9 @@
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
CryptoX_Result NSS_LoadPublicKey(const char *certNickname,
|
||||
SECKEYPublicKey **publicKey,
|
||||
CERTCertificate **cert);
|
||||
CryptoX_Result NSS_LoadPublicKey(const unsigned char* certData,
|
||||
unsigned int certDataSize,
|
||||
SECKEYPublicKey** publicKey);
|
||||
CryptoX_Result NSS_VerifyBegin(VFYContext **ctx,
|
||||
SECKEYPublicKey * const *publicKey);
|
||||
CryptoX_Result NSS_VerifySignature(VFYContext * const *ctx ,
|
||||
@@ -46,9 +48,8 @@ CryptoX_Result NSS_VerifySignature(VFYContext * const *ctx ,
|
||||
VFY_DestroyContext(*SignatureHandle, PR_TRUE)
|
||||
#define CryptoX_VerifyUpdate(SignatureHandle, buf, len) \
|
||||
VFY_Update(*SignatureHandle, (const unsigned char*)(buf), len)
|
||||
#define CryptoX_LoadPublicKey(CryptoHandle, certData, dataSize, \
|
||||
publicKey, certName, cert) \
|
||||
NSS_LoadPublicKey(certName, publicKey, cert)
|
||||
#define CryptoX_LoadPublicKey(CryptoHandle, certData, dataSize, publicKey) \
|
||||
NSS_LoadPublicKey(certData, dataSize, publicKey)
|
||||
#define CryptoX_VerifySignature(hash, publicKey, signedData, len) \
|
||||
NSS_VerifySignature(hash, (const unsigned char *)(signedData), len)
|
||||
#define CryptoX_FreePublicKey(key) \
|
||||
@@ -92,7 +93,7 @@ void CryptoMac_FreePublicKey(CryptoX_PublicKey* aPublicKey);
|
||||
#define CryptoX_VerifyUpdate(aInputData, aBuf, aLen) \
|
||||
CryptoMac_VerifyUpdate(aInputData, aBuf, aLen)
|
||||
#define CryptoX_LoadPublicKey(aProviderHandle, aCertData, aDataSize, \
|
||||
aPublicKey, aCertName, aCert) \
|
||||
aPublicKey) \
|
||||
CryptoMac_LoadPublicKey(aCertData, aDataSize, aPublicKey)
|
||||
#define CryptoX_VerifySignature(aInputData, aPublicKey, aSignature, \
|
||||
aSignatureLen) \
|
||||
@@ -112,8 +113,7 @@ CryptoX_Result CryptoAPI_InitCryptoContext(HCRYPTPROV *provider);
|
||||
CryptoX_Result CryptoAPI_LoadPublicKey(HCRYPTPROV hProv,
|
||||
BYTE *certData,
|
||||
DWORD sizeOfCertData,
|
||||
HCRYPTKEY *publicKey,
|
||||
HCERTSTORE *cert);
|
||||
HCRYPTKEY *publicKey);
|
||||
CryptoX_Result CryptoAPI_VerifyBegin(HCRYPTPROV provider, HCRYPTHASH* hash);
|
||||
CryptoX_Result CryptoAPI_VerifyUpdate(HCRYPTHASH* hash,
|
||||
BYTE *buf, DWORD len);
|
||||
@@ -134,10 +134,8 @@ CryptoX_Result CyprtoAPI_VerifySignature(HCRYPTHASH *hash,
|
||||
#define CryptoX_FreeSignatureHandle(SignatureHandle)
|
||||
#define CryptoX_VerifyUpdate(SignatureHandle, buf, len) \
|
||||
CryptoAPI_VerifyUpdate(SignatureHandle, (BYTE *)(buf), len)
|
||||
#define CryptoX_LoadPublicKey(CryptoHandle, certData, dataSize, \
|
||||
publicKey, certName, cert) \
|
||||
CryptoAPI_LoadPublicKey(CryptoHandle, (BYTE*)(certData), \
|
||||
dataSize, publicKey, cert)
|
||||
#define CryptoX_LoadPublicKey(CryptoHandle, certData, dataSize, publicKey) \
|
||||
CryptoAPI_LoadPublicKey(CryptoHandle, (BYTE*)(certData), dataSize, publicKey)
|
||||
#define CryptoX_VerifySignature(hash, publicKey, signedData, len) \
|
||||
CyprtoAPI_VerifySignature(hash, publicKey, signedData, len)
|
||||
#define CryptoX_FreePublicKey(key) \
|
||||
@@ -164,8 +162,7 @@ CryptoX_Result CyprtoAPI_VerifySignature(HCRYPTHASH *hash,
|
||||
CryptoX_Error
|
||||
#define CryptoX_FreeSignatureHandle(SignatureHandle)
|
||||
#define CryptoX_VerifyUpdate(SignatureHandle, buf, len) CryptoX_Error
|
||||
#define CryptoX_LoadPublicKey(CryptoHandle, certData, dataSize, \
|
||||
publicKey, certName, cert) \
|
||||
#define CryptoX_LoadPublicKey(CryptoHandle, certData, dataSize, publicKey) \
|
||||
CryptoX_Error
|
||||
#define CryptoX_VerifySignature(hash, publicKey, signedData, len) CryptoX_Error
|
||||
#define CryptoX_FreePublicKey(key) CryptoX_Error
|
||||
|
||||
@@ -17,6 +17,46 @@
|
||||
#include "mar.h"
|
||||
#include "cryptox.h"
|
||||
|
||||
int
|
||||
mar_read_entire_file(const char * filePath, uint32_t maxSize,
|
||||
/*out*/ const uint8_t * *data,
|
||||
/*out*/ uint32_t *size)
|
||||
{
|
||||
int result;
|
||||
FILE * f;
|
||||
|
||||
if (!filePath || !data || !size) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
f = fopen(filePath, "rb");
|
||||
if (!f) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
result = -1;
|
||||
if (!fseeko(f, 0, SEEK_END)) {
|
||||
int64_t fileSize = ftello(f);
|
||||
if (fileSize > 0 && fileSize <= maxSize && !fseeko(f, 0, SEEK_SET)) {
|
||||
unsigned char * fileData;
|
||||
|
||||
*size = (unsigned int) fileSize;
|
||||
fileData = malloc(*size);
|
||||
if (fileData) {
|
||||
if (fread(fileData, *size, 1, f) == 1) {
|
||||
*data = fileData;
|
||||
result = 0;
|
||||
} else {
|
||||
free(fileData);
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int mar_extract_and_verify_signatures_fp(FILE *fp,
|
||||
CryptoX_ProviderHandle provider,
|
||||
CryptoX_PublicKey *keys,
|
||||
@@ -81,92 +121,8 @@ ReadAndUpdateVerifyContext(FILE *fp,
|
||||
* certificate given, the second signature will be verified using the second
|
||||
* certificate given, etc. The signature count must exactly match the number of
|
||||
* certificates given, and all signature verifications must succeed.
|
||||
* This is only used by the signmar program when used with arguments to verify
|
||||
* a MAR. This should not be used to verify a MAR that will be extracted in the
|
||||
* same operation by updater code. This function prints the error message if
|
||||
* verification fails.
|
||||
*
|
||||
* @param pathToMARFile The path of the MAR file to verify.
|
||||
* @param certData Pointer to the first element in an array of certificate
|
||||
* file data.
|
||||
* @param certDataSizes Pointer to the first element in an array for size of the
|
||||
* cert data.
|
||||
* @param certNames Pointer to the first element in an array of certificate names.
|
||||
* Used only if compiled as NSS, specifies the certificate names
|
||||
* @param certCount The number of elements in certData, certDataSizes, and certNames
|
||||
* @return 0 on success
|
||||
* a negative number if there was an error
|
||||
* a positive number if the signature does not verify
|
||||
*/
|
||||
int
|
||||
mar_verify_signatures(const char *pathToMARFile,
|
||||
const uint8_t * const *certData,
|
||||
const uint32_t *certDataSizes,
|
||||
const char * const *certNames,
|
||||
uint32_t certCount) {
|
||||
int rv;
|
||||
CryptoX_ProviderHandle provider = CryptoX_InvalidHandleValue;
|
||||
CryptoX_Certificate certs[MAX_SIGNATURES];
|
||||
CryptoX_PublicKey keys[MAX_SIGNATURES];
|
||||
FILE *fp;
|
||||
uint32_t k;
|
||||
|
||||
memset(certs, 0, sizeof(certs));
|
||||
memset(keys, 0, sizeof(keys));
|
||||
|
||||
if (!pathToMARFile || certCount == 0) {
|
||||
fprintf(stderr, "ERROR: Invalid parameter specified.\n");
|
||||
return CryptoX_Error;
|
||||
}
|
||||
|
||||
fp = fopen(pathToMARFile, "rb");
|
||||
if (!fp) {
|
||||
fprintf(stderr, "ERROR: Could not open MAR file.\n");
|
||||
return CryptoX_Error;
|
||||
}
|
||||
|
||||
if (CryptoX_Failed(CryptoX_InitCryptoProvider(&provider))) {
|
||||
fclose(fp);
|
||||
fprintf(stderr, "ERROR: Could not init crytpo library.\n");
|
||||
return CryptoX_Error;
|
||||
}
|
||||
|
||||
/* Load the certs and keys */
|
||||
for (k = 0; k < certCount; k++) {
|
||||
if (CryptoX_Failed(CryptoX_LoadPublicKey(provider, certData[k], certDataSizes[k],
|
||||
&keys[k], certNames[k], &certs[k]))) {
|
||||
fclose(fp);
|
||||
fprintf(stderr, "ERROR: Could not load public key.\n");
|
||||
return CryptoX_Error;
|
||||
}
|
||||
}
|
||||
|
||||
rv = mar_extract_and_verify_signatures_fp(fp, provider, keys, certCount);
|
||||
fclose(fp);
|
||||
|
||||
/* Cleanup the allocated keys and certs */
|
||||
for (k = 0; k < certCount; k++) {
|
||||
if (keys[k]) {
|
||||
CryptoX_FreePublicKey(&keys[k]);
|
||||
}
|
||||
|
||||
if (certs[k]) {
|
||||
CryptoX_FreeCertificate(&certs[k]);
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
#ifdef XP_WIN
|
||||
/**
|
||||
* Verifies a MAR file by verifying each signature with the corresponding
|
||||
* certificate. That is, the first signature will be verified using the first
|
||||
* certificate given, the second signature will be verified using the second
|
||||
* certificate given, etc. The signature count must exactly match the number of
|
||||
* certificates given, and all signature verifications must succeed.
|
||||
*
|
||||
* @param pathToMARFile The path of the MAR file who's signature
|
||||
* should be calculated
|
||||
* @param mar The file who's signature should be calculated
|
||||
* @param certData Pointer to the first element in an array of
|
||||
* certificate data
|
||||
* @param certDataSizes Pointer to the first element in an array for size of
|
||||
@@ -175,17 +131,15 @@ mar_verify_signatures(const char *pathToMARFile,
|
||||
* @return 0 on success
|
||||
*/
|
||||
int
|
||||
mar_verify_signaturesW(MarFile *mar,
|
||||
const uint8_t * const *certData,
|
||||
const uint32_t *certDataSizes,
|
||||
uint32_t certCount) {
|
||||
mar_verify_signatures(MarFile *mar,
|
||||
const uint8_t * const *certData,
|
||||
const uint32_t *certDataSizes,
|
||||
uint32_t certCount) {
|
||||
int rv = -1;
|
||||
CryptoX_ProviderHandle provider = CryptoX_InvalidHandleValue;
|
||||
CryptoX_Certificate certs[MAX_SIGNATURES];
|
||||
CryptoX_PublicKey keys[MAX_SIGNATURES];
|
||||
uint32_t k;
|
||||
|
||||
memset(certs, 0, sizeof(certs));
|
||||
memset(keys, 0, sizeof(keys));
|
||||
|
||||
if (!mar || !certData || !certDataSizes || certCount == 0) {
|
||||
@@ -205,7 +159,7 @@ mar_verify_signaturesW(MarFile *mar,
|
||||
|
||||
for (k = 0; k < certCount; ++k) {
|
||||
if (CryptoX_Failed(CryptoX_LoadPublicKey(provider, certData[k], certDataSizes[k],
|
||||
&keys[k], "", &certs[k]))) {
|
||||
&keys[k]))) {
|
||||
fprintf(stderr, "ERROR: Could not load public key.\n");
|
||||
goto failure;
|
||||
}
|
||||
@@ -219,15 +173,10 @@ failure:
|
||||
if (keys[k]) {
|
||||
CryptoX_FreePublicKey(&keys[k]);
|
||||
}
|
||||
|
||||
if (certs[k]) {
|
||||
CryptoX_FreeCertificate(&certs[k]);
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Extracts each signature from the specified MAR file,
|
||||
@@ -244,11 +193,8 @@ mar_extract_and_verify_signatures_fp(FILE *fp,
|
||||
CryptoX_ProviderHandle provider,
|
||||
CryptoX_PublicKey *keys,
|
||||
uint32_t keyCount) {
|
||||
char buf[5] = {0};
|
||||
uint32_t signatureCount, signatureLen, numVerified = 0;
|
||||
uint32_t signatureAlgorithmIDs[MAX_SIGNATURES];
|
||||
int rv = -1;
|
||||
int64_t curPos;
|
||||
uint8_t *extractedSignatures[MAX_SIGNATURES];
|
||||
uint32_t i;
|
||||
|
||||
@@ -336,13 +282,17 @@ mar_extract_and_verify_signatures_fp(FILE *fp,
|
||||
}
|
||||
}
|
||||
|
||||
curPos = ftello(fp);
|
||||
rv = mar_verify_signatures_for_fp(fp,
|
||||
provider,
|
||||
keys,
|
||||
(const uint8_t * const *)extractedSignatures,
|
||||
signatureCount,
|
||||
&numVerified);
|
||||
if (ftello(fp) == -1) {
|
||||
return CryptoX_Error;
|
||||
}
|
||||
if (mar_verify_signatures_for_fp(fp,
|
||||
provider,
|
||||
keys,
|
||||
(const uint8_t * const *)extractedSignatures,
|
||||
signatureCount,
|
||||
&numVerified) == CryptoX_Error) {
|
||||
return CryptoX_Error;
|
||||
}
|
||||
for (i = 0; i < signatureCount; ++i) {
|
||||
free(extractedSignatures[i]);
|
||||
}
|
||||
|
||||
@@ -216,11 +216,6 @@ protected:
|
||||
const char *getPrefName(const char *aPrefName);
|
||||
void freeObserverList(void);
|
||||
|
||||
friend PLDHashOperator
|
||||
FreeObserverFunc(PrefCallback *aKey,
|
||||
nsAutoPtr<PrefCallback> &aCallback,
|
||||
void *aArgs);
|
||||
|
||||
private:
|
||||
int32_t mPrefRootLength;
|
||||
nsCString mPrefRoot;
|
||||
|
||||
@@ -207,6 +207,18 @@ EventTokenBucket::UnPause()
|
||||
UpdateTimer();
|
||||
}
|
||||
|
||||
void
|
||||
EventTokenBucket::Stop()
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
SOCKET_LOG(("EventTokenBucket::Stop %p armed=%d\n", this, mTimerArmed));
|
||||
mStopped = true;
|
||||
if (mTimerArmed) {
|
||||
mTimer->Cancel();
|
||||
mTimerArmed = false;
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
EventTokenBucket::SubmitEvent(ATokenBucketEvent *event, nsICancelable **cancelable)
|
||||
{
|
||||
|
||||
@@ -86,7 +86,7 @@ public:
|
||||
// credits. ClearCredits can be used before unpausing if desired.
|
||||
void Pause();
|
||||
void UnPause();
|
||||
void Stop() { mStopped = true; }
|
||||
void Stop();
|
||||
|
||||
// The returned cancelable event can only be canceled from the socket thread
|
||||
nsresult SubmitEvent(ATokenBucketEvent *event, nsICancelable **cancelable);
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "nsSocketTransport2.h"
|
||||
#include "NetworkActivityMonitor.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "nsIOService.h"
|
||||
#endif // !defined(MOZILLA_XPCOMRT_API)
|
||||
#include "nsASocketHandler.h"
|
||||
#include "nsError.h"
|
||||
@@ -1002,7 +1003,16 @@ nsSocketTransportService::DoPollIteration(bool wait, TimeDuration *pollDuration)
|
||||
// Measures seconds spent while blocked on PR_Poll
|
||||
uint32_t pollInterval;
|
||||
|
||||
int32_t n = Poll(wait, &pollInterval, pollDuration);
|
||||
int32_t n = 0;
|
||||
#if !defined(MOZILLA_XPCOMRT_API)
|
||||
if (!gIOService->IsNetTearingDown()) {
|
||||
// Let's not do polling during shutdown.
|
||||
n = Poll(wait, &pollInterval, pollDuration);
|
||||
}
|
||||
#else
|
||||
n = Poll(wait, &pollInterval, pollDuration);
|
||||
#endif // defined(MOZILLA_XPCOMRT_API)
|
||||
|
||||
if (n < 0) {
|
||||
SOCKET_LOG((" PR_Poll error [%d] os error [%d]\n", PR_GetError(),
|
||||
PR_GetOSError()));
|
||||
|
||||
@@ -42,67 +42,61 @@ nsHttpConnectionMgr::OnMsgPrintDiagnostics(int32_t, ARefBase *)
|
||||
mLogData.AppendPrintf("mNumActiveConns = %d\n", mNumActiveConns);
|
||||
mLogData.AppendPrintf("mNumIdleConns = %d\n", mNumIdleConns);
|
||||
|
||||
mCT.Enumerate(PrintDiagnosticsCB, this);
|
||||
for (auto iter = mCT.Iter(); !iter.Done(); iter.Next()) {
|
||||
nsAutoPtr<nsConnectionEntry>& ent = iter.Data();
|
||||
|
||||
mLogData.AppendPrintf(" ent host = %s hashkey = %s\n",
|
||||
ent->mConnInfo->Origin(), ent->mConnInfo->HashKey().get());
|
||||
mLogData.AppendPrintf(" AtActiveConnectionLimit = %d\n",
|
||||
AtActiveConnectionLimit(ent, NS_HTTP_ALLOW_KEEPALIVE));
|
||||
mLogData.AppendPrintf(" RestrictConnections = %d\n",
|
||||
RestrictConnections(ent));
|
||||
mLogData.AppendPrintf(" Pending Q Length = %u\n",
|
||||
ent->mPendingQ.Length());
|
||||
mLogData.AppendPrintf(" Active Conns Length = %u\n",
|
||||
ent->mActiveConns.Length());
|
||||
mLogData.AppendPrintf(" Idle Conns Length = %u\n",
|
||||
ent->mIdleConns.Length());
|
||||
mLogData.AppendPrintf(" Half Opens Length = %u\n",
|
||||
ent->mHalfOpens.Length());
|
||||
mLogData.AppendPrintf(" Coalescing Keys Length = %u\n",
|
||||
ent->mCoalescingKeys.Length());
|
||||
mLogData.AppendPrintf(" Spdy using = %d, tested = %d, preferred = %d\n",
|
||||
ent->mUsingSpdy, ent->mTestedSpdy, ent->mInPreferredHash);
|
||||
mLogData.AppendPrintf(" pipelinestate = %d penalty = %d\n",
|
||||
ent->mPipelineState, ent->mPipeliningPenalty);
|
||||
|
||||
uint32_t i;
|
||||
for (i = 0; i < nsAHttpTransaction::CLASS_MAX; ++i) {
|
||||
mLogData.AppendPrintf(" pipeline per class penalty 0x%x %d\n",
|
||||
i, ent->mPipeliningClassPenalty[i]);
|
||||
}
|
||||
for (i = 0; i < ent->mActiveConns.Length(); ++i) {
|
||||
mLogData.AppendPrintf(" :: Active Connection #%u\n", i);
|
||||
ent->mActiveConns[i]->PrintDiagnostics(mLogData);
|
||||
}
|
||||
for (i = 0; i < ent->mIdleConns.Length(); ++i) {
|
||||
mLogData.AppendPrintf(" :: Idle Connection #%u\n", i);
|
||||
ent->mIdleConns[i]->PrintDiagnostics(mLogData);
|
||||
}
|
||||
for (i = 0; i < ent->mHalfOpens.Length(); ++i) {
|
||||
mLogData.AppendPrintf(" :: Half Open #%u\n", i);
|
||||
ent->mHalfOpens[i]->PrintDiagnostics(mLogData);
|
||||
}
|
||||
for (i = 0; i < ent->mPendingQ.Length(); ++i) {
|
||||
mLogData.AppendPrintf(" :: Pending Transaction #%u\n", i);
|
||||
ent->mPendingQ[i]->PrintDiagnostics(mLogData);
|
||||
}
|
||||
for (i = 0; i < ent->mCoalescingKeys.Length(); ++i) {
|
||||
mLogData.AppendPrintf(" :: Coalescing Key #%u %s\n",
|
||||
i, ent->mCoalescingKeys[i].get());
|
||||
}
|
||||
}
|
||||
|
||||
consoleService->LogStringMessage(NS_ConvertUTF8toUTF16(mLogData).Data());
|
||||
mLogData.Truncate();
|
||||
}
|
||||
|
||||
PLDHashOperator
|
||||
nsHttpConnectionMgr::PrintDiagnosticsCB(const nsACString &key,
|
||||
nsAutoPtr<nsConnectionEntry> &ent,
|
||||
void *closure)
|
||||
{
|
||||
nsHttpConnectionMgr *self = static_cast<nsHttpConnectionMgr *>(closure);
|
||||
uint32_t i;
|
||||
|
||||
self->mLogData.AppendPrintf(" ent host = %s hashkey = %s\n",
|
||||
ent->mConnInfo->Origin(), ent->mConnInfo->HashKey().get());
|
||||
self->mLogData.AppendPrintf(" AtActiveConnectionLimit = %d\n",
|
||||
self->AtActiveConnectionLimit(ent, NS_HTTP_ALLOW_KEEPALIVE));
|
||||
self->mLogData.AppendPrintf(" RestrictConnections = %d\n",
|
||||
self->RestrictConnections(ent));
|
||||
self->mLogData.AppendPrintf(" Pending Q Length = %u\n",
|
||||
ent->mPendingQ.Length());
|
||||
self->mLogData.AppendPrintf(" Active Conns Length = %u\n",
|
||||
ent->mActiveConns.Length());
|
||||
self->mLogData.AppendPrintf(" Idle Conns Length = %u\n",
|
||||
ent->mIdleConns.Length());
|
||||
self->mLogData.AppendPrintf(" Half Opens Length = %u\n",
|
||||
ent->mHalfOpens.Length());
|
||||
self->mLogData.AppendPrintf(" Coalescing Keys Length = %u\n",
|
||||
ent->mCoalescingKeys.Length());
|
||||
self->mLogData.AppendPrintf(" Spdy using = %d, tested = %d, preferred = %d\n",
|
||||
ent->mUsingSpdy, ent->mTestedSpdy, ent->mInPreferredHash);
|
||||
self->mLogData.AppendPrintf(" pipelinestate = %d penalty = %d\n",
|
||||
ent->mPipelineState, ent->mPipeliningPenalty);
|
||||
for (i = 0; i < nsAHttpTransaction::CLASS_MAX; ++i) {
|
||||
self->mLogData.AppendPrintf(" pipeline per class penalty 0x%x %d\n",
|
||||
i, ent->mPipeliningClassPenalty[i]);
|
||||
}
|
||||
for (i = 0; i < ent->mActiveConns.Length(); ++i) {
|
||||
self->mLogData.AppendPrintf(" :: Active Connection #%u\n", i);
|
||||
ent->mActiveConns[i]->PrintDiagnostics(self->mLogData);
|
||||
}
|
||||
for (i = 0; i < ent->mIdleConns.Length(); ++i) {
|
||||
self->mLogData.AppendPrintf(" :: Idle Connection #%u\n", i);
|
||||
ent->mIdleConns[i]->PrintDiagnostics(self->mLogData);
|
||||
}
|
||||
for (i = 0; i < ent->mHalfOpens.Length(); ++i) {
|
||||
self->mLogData.AppendPrintf(" :: Half Open #%u\n", i);
|
||||
ent->mHalfOpens[i]->PrintDiagnostics(self->mLogData);
|
||||
}
|
||||
for (i = 0; i < ent->mPendingQ.Length(); ++i) {
|
||||
self->mLogData.AppendPrintf(" :: Pending Transaction #%u\n", i);
|
||||
ent->mPendingQ[i]->PrintDiagnostics(self->mLogData);
|
||||
}
|
||||
for (i = 0; i < ent->mCoalescingKeys.Length(); ++i) {
|
||||
self->mLogData.AppendPrintf(" :: Coalescing Key #%u %s\n",
|
||||
i, ent->mCoalescingKeys[i].get());
|
||||
}
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
void
|
||||
nsHttpConnectionMgr::nsHalfOpenSocket::PrintDiagnostics(nsCString &log)
|
||||
{
|
||||
|
||||
@@ -134,51 +134,27 @@ Http2Session::Http2Session(nsISocketTransport *aSocketTransport, uint32_t versio
|
||||
mPreviousPingThreshold = mPingThreshold;
|
||||
}
|
||||
|
||||
PLDHashOperator
|
||||
Http2Session::ShutdownEnumerator(nsAHttpTransaction *key,
|
||||
nsAutoPtr<Http2Stream> &stream,
|
||||
void *closure)
|
||||
void
|
||||
Http2Session::Shutdown()
|
||||
{
|
||||
Http2Session *self = static_cast<Http2Session *>(closure);
|
||||
nsresult result;
|
||||
for (auto iter = mStreamTransactionHash.Iter(); !iter.Done(); iter.Next()) {
|
||||
nsAutoPtr<Http2Stream> &stream = iter.Data();
|
||||
|
||||
// On a clean server hangup the server sets the GoAwayID to be the ID of
|
||||
// the last transaction it processed. If the ID of stream in the
|
||||
// local stream is greater than that it can safely be restarted because the
|
||||
// server guarantees it was not partially processed. Streams that have not
|
||||
// registered an ID haven't actually been sent yet so they can always be
|
||||
// restarted.
|
||||
if (self->mCleanShutdown &&
|
||||
(stream->StreamID() > self->mGoAwayID || !stream->HasRegisteredID())) {
|
||||
result = NS_ERROR_NET_RESET; // can be restarted
|
||||
} else if (stream->RecvdData()) {
|
||||
result = NS_ERROR_NET_PARTIAL_TRANSFER;
|
||||
} else {
|
||||
result = NS_ERROR_ABORT;
|
||||
// On a clean server hangup the server sets the GoAwayID to be the ID of
|
||||
// the last transaction it processed. If the ID of stream in the
|
||||
// local stream is greater than that it can safely be restarted because the
|
||||
// server guarantees it was not partially processed. Streams that have not
|
||||
// registered an ID haven't actually been sent yet so they can always be
|
||||
// restarted.
|
||||
if (mCleanShutdown &&
|
||||
(stream->StreamID() > mGoAwayID || !stream->HasRegisteredID())) {
|
||||
CloseStream(stream, NS_ERROR_NET_RESET); // can be restarted
|
||||
} else if (stream->RecvdData()) {
|
||||
CloseStream(stream, NS_ERROR_NET_PARTIAL_TRANSFER);
|
||||
} else {
|
||||
CloseStream(stream, NS_ERROR_ABORT);
|
||||
}
|
||||
}
|
||||
|
||||
self->CloseStream(stream, result);
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
PLDHashOperator
|
||||
Http2Session::GoAwayEnumerator(nsAHttpTransaction *key,
|
||||
nsAutoPtr<Http2Stream> &stream,
|
||||
void *closure)
|
||||
{
|
||||
Http2Session *self = static_cast<Http2Session *>(closure);
|
||||
|
||||
// these streams were not processed by the server and can be restarted.
|
||||
// Do that after the enumerator completes to avoid the risk of
|
||||
// a restart event re-entrantly modifying this hash. Be sure not to restart
|
||||
// a pushed (even numbered) stream
|
||||
if ((stream->StreamID() > self->mGoAwayID && (stream->StreamID() & 1)) ||
|
||||
!stream->HasRegisteredID()) {
|
||||
self->mGoAwayStreamsToRestart.Push(stream);
|
||||
}
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
Http2Session::~Http2Session()
|
||||
@@ -186,7 +162,7 @@ Http2Session::~Http2Session()
|
||||
LOG3(("Http2Session::~Http2Session %p mDownstreamState=%X",
|
||||
this, mDownstreamState));
|
||||
|
||||
mStreamTransactionHash.Enumerate(ShutdownEnumerator, this);
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1419,16 +1395,6 @@ Http2Session::RecvRstStream(Http2Session *self)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PLDHashOperator
|
||||
Http2Session::UpdateServerRwinEnumerator(nsAHttpTransaction *key,
|
||||
nsAutoPtr<Http2Stream> &stream,
|
||||
void *closure)
|
||||
{
|
||||
int32_t delta = *(static_cast<int32_t *>(closure));
|
||||
stream->UpdateServerReceiveWindow(delta);
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Http2Session::RecvSettings(Http2Session *self)
|
||||
{
|
||||
@@ -1488,10 +1454,13 @@ Http2Session::RecvSettings(Http2Session *self)
|
||||
int32_t delta = value - self->mServerInitialStreamWindow;
|
||||
self->mServerInitialStreamWindow = value;
|
||||
|
||||
// SETTINGS only adjusts stream windows. Leave the sesison window alone.
|
||||
// we need to add the delta to all open streams (delta can be negative)
|
||||
self->mStreamTransactionHash.Enumerate(UpdateServerRwinEnumerator,
|
||||
&delta);
|
||||
// SETTINGS only adjusts stream windows. Leave the session window alone.
|
||||
// We need to add the delta to all open streams (delta can be negative)
|
||||
for (auto iter = self->mStreamTransactionHash.Iter();
|
||||
!iter.Done();
|
||||
iter.Next()) {
|
||||
iter.Data()->UpdateServerReceiveWindow(delta);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1826,9 +1795,21 @@ Http2Session::RecvGoAway(Http2Session *self)
|
||||
self->mInputFrameBuffer.get() + kFrameHeaderBytes + 4);
|
||||
|
||||
// Find streams greater than the last-good ID and mark them for deletion
|
||||
// in the mGoAwayStreamsToRestart queue with the GoAwayEnumerator. The
|
||||
// underlying transaction can be restarted.
|
||||
self->mStreamTransactionHash.Enumerate(GoAwayEnumerator, self);
|
||||
// in the mGoAwayStreamsToRestart queue. The underlying transaction can be
|
||||
// restarted.
|
||||
for (auto iter = self->mStreamTransactionHash.Iter();
|
||||
!iter.Done();
|
||||
iter.Next()) {
|
||||
// these streams were not processed by the server and can be restarted.
|
||||
// Do that after the enumerator completes to avoid the risk of
|
||||
// a restart event re-entrantly modifying this hash. Be sure not to restart
|
||||
// a pushed (even numbered) stream
|
||||
nsAutoPtr<Http2Stream>& stream = iter.Data();
|
||||
if ((stream->StreamID() > self->mGoAwayID && (stream->StreamID() & 1)) ||
|
||||
!stream->HasRegisteredID()) {
|
||||
self->mGoAwayStreamsToRestart.Push(stream);
|
||||
}
|
||||
}
|
||||
|
||||
// Process the streams marked for deletion and restart.
|
||||
size_t size = self->mGoAwayStreamsToRestart.GetSize();
|
||||
@@ -1869,22 +1850,6 @@ Http2Session::RecvGoAway(Http2Session *self)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PLDHashOperator
|
||||
Http2Session::RestartBlockedOnRwinEnumerator(nsAHttpTransaction *key,
|
||||
nsAutoPtr<Http2Stream> &stream,
|
||||
void *closure)
|
||||
{
|
||||
Http2Session *self = static_cast<Http2Session *>(closure);
|
||||
MOZ_ASSERT(self->mServerSessionWindow > 0);
|
||||
|
||||
if (!stream->BlockedOnRwin() || stream->ServerReceiveWindow() <= 0)
|
||||
return PL_DHASH_NEXT;
|
||||
|
||||
self->mReadyForWrite.Push(stream);
|
||||
self->SetWriteCallbacks();
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Http2Session::RecvWindowUpdate(Http2Session *self)
|
||||
{
|
||||
@@ -1965,7 +1930,19 @@ Http2Session::RecvWindowUpdate(Http2Session *self)
|
||||
if ((oldRemoteWindow <= 0) && (self->mServerSessionWindow > 0)) {
|
||||
LOG3(("Http2Session::RecvWindowUpdate %p restart session window\n",
|
||||
self));
|
||||
self->mStreamTransactionHash.Enumerate(RestartBlockedOnRwinEnumerator, self);
|
||||
for (auto iter = self->mStreamTransactionHash.Iter();
|
||||
!iter.Done();
|
||||
iter.Next()) {
|
||||
MOZ_ASSERT(self->mServerSessionWindow > 0);
|
||||
|
||||
nsAutoPtr<Http2Stream>& stream = iter.Data();
|
||||
if (!stream->BlockedOnRwin() || stream->ServerReceiveWindow() <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
self->mReadyForWrite.Push(stream);
|
||||
self->SetWriteCallbacks();
|
||||
}
|
||||
}
|
||||
LOG3(("Http2Session::RecvWindowUpdate %p session window "
|
||||
"%d increased by %d now %d.\n", self,
|
||||
@@ -3027,7 +3004,8 @@ Http2Session::Close(nsresult aReason)
|
||||
|
||||
mClosed = true;
|
||||
|
||||
mStreamTransactionHash.Enumerate(ShutdownEnumerator, this);
|
||||
Shutdown();
|
||||
|
||||
mStreamIDHash.Clear();
|
||||
mStreamTransactionHash.Clear();
|
||||
|
||||
@@ -3708,22 +3686,6 @@ Http2Session::Http1xTransactionCount()
|
||||
return 0;
|
||||
}
|
||||
|
||||
// used as an enumerator by TakeSubTransactions()
|
||||
static PLDHashOperator
|
||||
TakeStream(nsAHttpTransaction *key,
|
||||
nsAutoPtr<Http2Stream> &stream,
|
||||
void *closure)
|
||||
{
|
||||
nsTArray<RefPtr<nsAHttpTransaction> > *list =
|
||||
static_cast<nsTArray<RefPtr<nsAHttpTransaction> > *>(closure);
|
||||
|
||||
list->AppendElement(key);
|
||||
|
||||
// removing the stream from the hash will delete the stream
|
||||
// and drop the transaction reference the hash held
|
||||
return PL_DHASH_REMOVE;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Http2Session::TakeSubTransactions(
|
||||
nsTArray<RefPtr<nsAHttpTransaction> > &outTransactions)
|
||||
@@ -3738,7 +3700,13 @@ Http2Session::TakeSubTransactions(
|
||||
|
||||
LOG3((" taking %d\n", mStreamTransactionHash.Count()));
|
||||
|
||||
mStreamTransactionHash.Enumerate(TakeStream, &outTransactions);
|
||||
for (auto iter = mStreamTransactionHash.Iter(); !iter.Done(); iter.Next()) {
|
||||
outTransactions.AppendElement(iter.Key());
|
||||
|
||||
// Removing the stream from the hash will delete the stream and drop the
|
||||
// transaction reference the hash held.
|
||||
iter.Remove();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -295,21 +295,7 @@ private:
|
||||
// to track network I/O for timeout purposes
|
||||
nsresult NetworkRead(nsAHttpSegmentWriter *, char *, uint32_t, uint32_t *);
|
||||
|
||||
static PLDHashOperator ShutdownEnumerator(nsAHttpTransaction *,
|
||||
nsAutoPtr<Http2Stream> &,
|
||||
void *);
|
||||
|
||||
static PLDHashOperator GoAwayEnumerator(nsAHttpTransaction *,
|
||||
nsAutoPtr<Http2Stream> &,
|
||||
void *);
|
||||
|
||||
static PLDHashOperator UpdateServerRwinEnumerator(nsAHttpTransaction *,
|
||||
nsAutoPtr<Http2Stream> &,
|
||||
void *);
|
||||
|
||||
static PLDHashOperator RestartBlockedOnRwinEnumerator(nsAHttpTransaction *,
|
||||
nsAutoPtr<Http2Stream> &,
|
||||
void *);
|
||||
void Shutdown();
|
||||
|
||||
// This is intended to be nsHttpConnectionMgr:nsConnectionHandle taken
|
||||
// from the first transaction on this session. That object contains the
|
||||
|
||||
@@ -91,45 +91,25 @@ SpdySession31::SpdySession31(nsISocketTransport *aSocketTransport)
|
||||
mPingThreshold = gHttpHandler->SpdyPingThreshold();
|
||||
}
|
||||
|
||||
PLDHashOperator
|
||||
SpdySession31::ShutdownEnumerator(nsAHttpTransaction *key,
|
||||
nsAutoPtr<SpdyStream31> &stream,
|
||||
void *closure)
|
||||
void
|
||||
SpdySession31::Shutdown()
|
||||
{
|
||||
SpdySession31 *self = static_cast<SpdySession31 *>(closure);
|
||||
for (auto iter = mStreamTransactionHash.Iter(); !iter.Done(); iter.Next()) {
|
||||
nsAutoPtr<SpdyStream31>& stream = iter.Data();
|
||||
|
||||
// On a clean server hangup the server sets the GoAwayID to be the ID of
|
||||
// the last transaction it processed. If the ID of stream in the
|
||||
// local stream is greater than that it can safely be restarted because the
|
||||
// server guarantees it was not partially processed. Streams that have not
|
||||
// registered an ID haven't actually been sent yet so they can always be
|
||||
// restarted.
|
||||
if (self->mCleanShutdown &&
|
||||
(stream->StreamID() > self->mGoAwayID || !stream->HasRegisteredID()))
|
||||
self->CloseStream(stream, NS_ERROR_NET_RESET); // can be restarted
|
||||
else
|
||||
self->CloseStream(stream, NS_ERROR_ABORT);
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
PLDHashOperator
|
||||
SpdySession31::GoAwayEnumerator(nsAHttpTransaction *key,
|
||||
nsAutoPtr<SpdyStream31> &stream,
|
||||
void *closure)
|
||||
{
|
||||
SpdySession31 *self = static_cast<SpdySession31 *>(closure);
|
||||
|
||||
// these streams were not processed by the server and can be restarted.
|
||||
// Do that after the enumerator completes to avoid the risk of
|
||||
// a restart event re-entrantly modifying this hash. Be sure not to restart
|
||||
// a pushed (even numbered) stream
|
||||
if ((stream->StreamID() > self->mGoAwayID && (stream->StreamID() & 1)) ||
|
||||
!stream->HasRegisteredID()) {
|
||||
self->mGoAwayStreamsToRestart.Push(stream);
|
||||
// On a clean server hangup the server sets the GoAwayID to be the ID of
|
||||
// the last transaction it processed. If the ID of stream in the
|
||||
// local stream is greater than that it can safely be restarted because the
|
||||
// server guarantees it was not partially processed. Streams that have not
|
||||
// registered an ID haven't actually been sent yet so they can always be
|
||||
// restarted.
|
||||
if (mCleanShutdown &&
|
||||
(stream->StreamID() > mGoAwayID || !stream->HasRegisteredID())) {
|
||||
CloseStream(stream, NS_ERROR_NET_RESET); // can be restarted
|
||||
} else {
|
||||
CloseStream(stream, NS_ERROR_ABORT);
|
||||
}
|
||||
}
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
SpdySession31::~SpdySession31()
|
||||
@@ -140,7 +120,7 @@ SpdySession31::~SpdySession31()
|
||||
inflateEnd(&mDownstreamZlib);
|
||||
deflateEnd(&mUpstreamZlib);
|
||||
|
||||
mStreamTransactionHash.Enumerate(ShutdownEnumerator, this);
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1370,16 +1350,6 @@ SpdySession31::HandleRstStream(SpdySession31 *self)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PLDHashOperator
|
||||
SpdySession31::UpdateServerRwinEnumerator(nsAHttpTransaction *key,
|
||||
nsAutoPtr<SpdyStream31> &stream,
|
||||
void *closure)
|
||||
{
|
||||
int32_t delta = *(static_cast<int32_t *>(closure));
|
||||
stream->UpdateRemoteWindow(delta);
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
nsresult
|
||||
SpdySession31::HandleSettings(SpdySession31 *self)
|
||||
{
|
||||
@@ -1431,8 +1401,11 @@ SpdySession31::HandleSettings(SpdySession31 *self)
|
||||
// do not use SETTINGS to adjust the session window.
|
||||
|
||||
// we need to add the delta to all open streams (delta can be negative)
|
||||
self->mStreamTransactionHash.Enumerate(UpdateServerRwinEnumerator,
|
||||
&delta);
|
||||
for (auto iter = self->mStreamTransactionHash.Iter();
|
||||
!iter.Done();
|
||||
iter.Next()) {
|
||||
iter.Data()->UpdateRemoteWindow(delta);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1506,9 +1479,22 @@ SpdySession31::HandleGoAway(SpdySession31 *self)
|
||||
self->mCleanShutdown = true;
|
||||
|
||||
// Find streams greater than the last-good ID and mark them for deletion
|
||||
// in the mGoAwayStreamsToRestart queue with the GoAwayEnumerator. The
|
||||
// underlying transaction can be restarted.
|
||||
self->mStreamTransactionHash.Enumerate(GoAwayEnumerator, self);
|
||||
// in the mGoAwayStreamsToRestart queue. The underlying transaction can be
|
||||
// restarted.
|
||||
for (auto iter = self->mStreamTransactionHash.Iter();
|
||||
!iter.Done();
|
||||
iter.Next()) {
|
||||
|
||||
// These streams were not processed by the server and can be restarted. Do
|
||||
// that after the enumerator completes to avoid the risk of a restart event
|
||||
// re-entrantly modifying this hash. Be sure not to restart a pushed (even
|
||||
// numbered) stream.
|
||||
nsAutoPtr<SpdyStream31>& stream = iter.Data();
|
||||
if ((stream->StreamID() > self->mGoAwayID && (stream->StreamID() & 1)) ||
|
||||
!stream->HasRegisteredID()) {
|
||||
self->mGoAwayStreamsToRestart.Push(stream);
|
||||
}
|
||||
}
|
||||
|
||||
// Process the streams marked for deletion and restart.
|
||||
size_t size = self->mGoAwayStreamsToRestart.GetSize();
|
||||
@@ -1622,22 +1608,6 @@ SpdySession31::HandleHeaders(SpdySession31 *self)
|
||||
return rv;
|
||||
}
|
||||
|
||||
PLDHashOperator
|
||||
SpdySession31::RestartBlockedOnRwinEnumerator(nsAHttpTransaction *key,
|
||||
nsAutoPtr<SpdyStream31> &stream,
|
||||
void *closure)
|
||||
{
|
||||
SpdySession31 *self = static_cast<SpdySession31 *>(closure);
|
||||
MOZ_ASSERT(self->mRemoteSessionWindow > 0);
|
||||
|
||||
if (!stream->BlockedOnRwin() || stream->RemoteWindow() <= 0)
|
||||
return PL_DHASH_NEXT;
|
||||
|
||||
self->mReadyForWrite.Push(stream);
|
||||
self->SetWriteCallbacks();
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
nsresult
|
||||
SpdySession31::HandleWindowUpdate(SpdySession31 *self)
|
||||
{
|
||||
@@ -1681,7 +1651,19 @@ SpdySession31::HandleWindowUpdate(SpdySession31 *self)
|
||||
if ((oldRemoteWindow <= 0) && (self->mRemoteSessionWindow > 0)) {
|
||||
LOG3(("SpdySession31::HandleWindowUpdate %p restart session window\n",
|
||||
self));
|
||||
self->mStreamTransactionHash.Enumerate(RestartBlockedOnRwinEnumerator, self);
|
||||
for (auto iter = self->mStreamTransactionHash.Iter();
|
||||
!iter.Done();
|
||||
iter.Next()) {
|
||||
MOZ_ASSERT(self->mRemoteSessionWindow > 0);
|
||||
|
||||
nsAutoPtr<SpdyStream31>& stream = iter.Data();
|
||||
if (!stream->BlockedOnRwin() || stream->RemoteWindow() <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
self->mReadyForWrite.Push(stream);
|
||||
self->SetWriteCallbacks();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2366,7 +2348,8 @@ SpdySession31::Close(nsresult aReason)
|
||||
|
||||
mClosed = true;
|
||||
|
||||
mStreamTransactionHash.Enumerate(ShutdownEnumerator, this);
|
||||
Shutdown();
|
||||
|
||||
mStreamIDHash.Clear();
|
||||
mStreamTransactionHash.Clear();
|
||||
|
||||
@@ -2908,22 +2891,6 @@ SpdySession31::Http1xTransactionCount()
|
||||
return 0;
|
||||
}
|
||||
|
||||
// used as an enumerator by TakeSubTransactions()
|
||||
static PLDHashOperator
|
||||
TakeStream(nsAHttpTransaction *key,
|
||||
nsAutoPtr<SpdyStream31> &stream,
|
||||
void *closure)
|
||||
{
|
||||
nsTArray<RefPtr<nsAHttpTransaction> > *list =
|
||||
static_cast<nsTArray<RefPtr<nsAHttpTransaction> > *>(closure);
|
||||
|
||||
list->AppendElement(key);
|
||||
|
||||
// removing the stream from the hash will delete the stream
|
||||
// and drop the transaction reference the hash held
|
||||
return PL_DHASH_REMOVE;
|
||||
}
|
||||
|
||||
nsresult
|
||||
SpdySession31::TakeSubTransactions(
|
||||
nsTArray<RefPtr<nsAHttpTransaction> > &outTransactions)
|
||||
@@ -2938,7 +2905,13 @@ SpdySession31::TakeSubTransactions(
|
||||
|
||||
LOG3((" taking %d\n", mStreamTransactionHash.Count()));
|
||||
|
||||
mStreamTransactionHash.Enumerate(TakeStream, &outTransactions);
|
||||
for (auto iter = mStreamTransactionHash.Iter(); !iter.Done(); iter.Next()) {
|
||||
outTransactions.AppendElement(iter.Key());
|
||||
|
||||
// Removing the stream from the hash will delete the stream and drop the
|
||||
// transaction reference the hash held.
|
||||
iter.Remove();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -243,21 +243,7 @@ private:
|
||||
// to track network I/O for timeout purposes
|
||||
nsresult NetworkRead(nsAHttpSegmentWriter *, char *, uint32_t, uint32_t *);
|
||||
|
||||
static PLDHashOperator ShutdownEnumerator(nsAHttpTransaction *,
|
||||
nsAutoPtr<SpdyStream31> &,
|
||||
void *);
|
||||
|
||||
static PLDHashOperator GoAwayEnumerator(nsAHttpTransaction *,
|
||||
nsAutoPtr<SpdyStream31> &,
|
||||
void *);
|
||||
|
||||
static PLDHashOperator UpdateServerRwinEnumerator(nsAHttpTransaction *,
|
||||
nsAutoPtr<SpdyStream31> &,
|
||||
void *);
|
||||
|
||||
static PLDHashOperator RestartBlockedOnRwinEnumerator(nsAHttpTransaction *,
|
||||
nsAutoPtr<SpdyStream31> &,
|
||||
void *);
|
||||
void Shutdown();
|
||||
|
||||
// This is intended to be nsHttpConnectionMgr:nsConnectionHandle taken
|
||||
// from the first transaction on this session. That object contains the
|
||||
|
||||
@@ -228,18 +228,6 @@ SpdyStream31::WriteSegments(nsAHttpSegmentWriter *writer,
|
||||
return rv;
|
||||
}
|
||||
|
||||
PLDHashOperator
|
||||
SpdyStream31::hdrHashEnumerate(const nsACString &key,
|
||||
nsAutoPtr<nsCString> &value,
|
||||
void *closure)
|
||||
{
|
||||
SpdyStream31 *self = static_cast<SpdyStream31 *>(closure);
|
||||
|
||||
self->CompressToFrame(key);
|
||||
self->CompressToFrame(value.get());
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
void
|
||||
SpdyStream31::CreatePushHashKey(const nsCString &scheme,
|
||||
const nsCString &hostHeader,
|
||||
@@ -535,7 +523,10 @@ SpdyStream31::GenerateSynFrame()
|
||||
CompressToFrame(nsDependentCString(mTransaction->RequestHead()->IsHTTPS() ? "https" : "http"));
|
||||
}
|
||||
|
||||
hdrHash.Enumerate(hdrHashEnumerate, this);
|
||||
for (auto iter = hdrHash.Iter(); !iter.Done(); iter.Next()) {
|
||||
CompressToFrame(iter.Key());
|
||||
CompressToFrame(iter.Data().get());
|
||||
}
|
||||
CompressFlushFrame();
|
||||
|
||||
// 4 to 7 are length and flags, which we can now fill in
|
||||
|
||||
@@ -144,10 +144,6 @@ protected:
|
||||
private:
|
||||
friend class nsAutoPtr<SpdyStream31>;
|
||||
|
||||
static PLDHashOperator hdrHashEnumerate(const nsACString &,
|
||||
nsAutoPtr<nsCString> &,
|
||||
void *);
|
||||
|
||||
nsresult ParseHttpRequestHeaders(const char *, uint32_t, uint32_t *);
|
||||
nsresult GenerateSynFrame();
|
||||
|
||||
|
||||
@@ -183,10 +183,6 @@ public:
|
||||
void Clear();
|
||||
|
||||
private:
|
||||
static PLDHashOperator
|
||||
RemoveExpiredEntries(const nsACString& aKey, nsAutoPtr<CacheEntry>& aValue,
|
||||
void* aUserData);
|
||||
|
||||
static bool GetCacheKey(nsIURI* aURI, nsIPrincipal* aPrincipal,
|
||||
bool aWithCredentials, nsACString& _retval);
|
||||
|
||||
@@ -304,7 +300,17 @@ nsPreflightCache::GetEntry(nsIURI* aURI,
|
||||
if (mTable.Count() == PREFLIGHT_CACHE_SIZE) {
|
||||
// Try to kick out all the expired entries.
|
||||
TimeStamp now = TimeStamp::NowLoRes();
|
||||
mTable.Enumerate(RemoveExpiredEntries, &now);
|
||||
for (auto iter = mTable.Iter(); !iter.Done(); iter.Next()) {
|
||||
nsAutoPtr<CacheEntry>& entry = iter.Data();
|
||||
entry->PurgeExpired(now);
|
||||
|
||||
if (entry->mHeaders.IsEmpty() &&
|
||||
entry->mMethods.IsEmpty()) {
|
||||
// Expired, remove from the list as well as the hash table.
|
||||
entry->removeFrom(sPreflightCache->mList);
|
||||
iter.Remove();
|
||||
}
|
||||
}
|
||||
|
||||
// If that didn't remove anything then kick out the least recently used
|
||||
// entry.
|
||||
@@ -351,25 +357,6 @@ nsPreflightCache::Clear()
|
||||
mTable.Clear();
|
||||
}
|
||||
|
||||
/* static */ PLDHashOperator
|
||||
nsPreflightCache::RemoveExpiredEntries(const nsACString& aKey,
|
||||
nsAutoPtr<CacheEntry>& aValue,
|
||||
void* aUserData)
|
||||
{
|
||||
TimeStamp* now = static_cast<TimeStamp*>(aUserData);
|
||||
|
||||
aValue->PurgeExpired(*now);
|
||||
|
||||
if (aValue->mHeaders.IsEmpty() &&
|
||||
aValue->mMethods.IsEmpty()) {
|
||||
// Expired, remove from the list as well as the hash table.
|
||||
aValue->removeFrom(sPreflightCache->mList);
|
||||
return PL_DHASH_REMOVE;
|
||||
}
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
nsPreflightCache::GetCacheKey(nsIURI* aURI,
|
||||
nsIPrincipal* aPrincipal,
|
||||
|
||||
@@ -651,7 +651,7 @@ nsHttpConnection::AddTransaction(nsAHttpTransaction *httpTransaction,
|
||||
}
|
||||
|
||||
void
|
||||
nsHttpConnection::Close(nsresult reason)
|
||||
nsHttpConnection::Close(nsresult reason, bool aIsShutdown)
|
||||
{
|
||||
LOG(("nsHttpConnection::Close [this=%p reason=%x]\n", this, reason));
|
||||
|
||||
@@ -685,7 +685,8 @@ nsHttpConnection::Close(nsresult reason)
|
||||
// socket with data pending. TLS is a classic case of this where
|
||||
// a Alert record might be superfulous to a clean HTTP/SPDY shutdown.
|
||||
// Never block to do this and limit it to a small amount of data.
|
||||
if (mSocketIn) {
|
||||
// During shutdown just be fast!
|
||||
if (mSocketIn && !aIsShutdown) {
|
||||
char buffer[4000];
|
||||
uint32_t count, total = 0;
|
||||
nsresult rv;
|
||||
|
||||
@@ -77,7 +77,7 @@ public:
|
||||
nsresult Activate(nsAHttpTransaction *, uint32_t caps, int32_t pri);
|
||||
|
||||
// Close the underlying socket transport.
|
||||
void Close(nsresult reason);
|
||||
void Close(nsresult reason, bool aIsShutdown = false);
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// XXX document when these are ok to call
|
||||
|
||||
@@ -532,25 +532,21 @@ nsHttpConnectionMgr::UpdateRequestTokenBucket(EventTokenBucket *aBucket)
|
||||
0, aBucket);
|
||||
}
|
||||
|
||||
PLDHashOperator
|
||||
nsHttpConnectionMgr::RemoveDeadConnections(const nsACString &key,
|
||||
nsAutoPtr<nsConnectionEntry> &ent,
|
||||
void *aArg)
|
||||
{
|
||||
if (ent->mIdleConns.Length() == 0 &&
|
||||
ent->mActiveConns.Length() == 0 &&
|
||||
ent->mHalfOpens.Length() == 0 &&
|
||||
ent->mPendingQ.Length() == 0) {
|
||||
return PL_DHASH_REMOVE;
|
||||
}
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpConnectionMgr::ClearConnectionHistory()
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
mCT.Enumerate(RemoveDeadConnections, nullptr);
|
||||
|
||||
for (auto iter = mCT.Iter(); !iter.Done(); iter.Next()) {
|
||||
nsAutoPtr<nsConnectionEntry>& ent = iter.Data();
|
||||
if (ent->mIdleConns.Length() == 0 &&
|
||||
ent->mActiveConns.Length() == 0 &&
|
||||
ent->mHalfOpens.Length() == 0 &&
|
||||
ent->mPendingQ.Length() == 0) {
|
||||
iter.Remove();
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -830,266 +826,6 @@ nsHttpConnectionMgr::GetSpdyPreferredEnt(nsConnectionEntry *aOriginalEntry)
|
||||
return preferred;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// enumeration callbacks
|
||||
|
||||
PLDHashOperator
|
||||
nsHttpConnectionMgr::ProcessOneTransactionCB(const nsACString &key,
|
||||
nsAutoPtr<nsConnectionEntry> &ent,
|
||||
void *closure)
|
||||
{
|
||||
nsHttpConnectionMgr *self = (nsHttpConnectionMgr *) closure;
|
||||
|
||||
if (self->ProcessPendingQForEntry(ent, false))
|
||||
return PL_DHASH_STOP;
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
PLDHashOperator
|
||||
nsHttpConnectionMgr::ProcessAllTransactionsCB(const nsACString &key,
|
||||
nsAutoPtr<nsConnectionEntry> &ent,
|
||||
void *closure)
|
||||
{
|
||||
nsHttpConnectionMgr *self = (nsHttpConnectionMgr *) closure;
|
||||
self->ProcessPendingQForEntry(ent, true);
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
// If the global number of connections is preventing the opening of
|
||||
// new connections to a host without idle connections, then
|
||||
// close them regardless of their TTL
|
||||
PLDHashOperator
|
||||
nsHttpConnectionMgr::PurgeExcessIdleConnectionsCB(const nsACString &key,
|
||||
nsAutoPtr<nsConnectionEntry> &ent,
|
||||
void *closure)
|
||||
{
|
||||
nsHttpConnectionMgr *self = (nsHttpConnectionMgr *) closure;
|
||||
|
||||
while (self->mNumIdleConns + self->mNumActiveConns + 1 >= self->mMaxConns) {
|
||||
if (!ent->mIdleConns.Length()) {
|
||||
// There are no idle conns left in this connection entry
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
nsHttpConnection *conn = ent->mIdleConns[0];
|
||||
ent->mIdleConns.RemoveElementAt(0);
|
||||
conn->Close(NS_ERROR_ABORT);
|
||||
NS_RELEASE(conn);
|
||||
self->mNumIdleConns--;
|
||||
self->ConditionallyStopPruneDeadConnectionsTimer();
|
||||
}
|
||||
return PL_DHASH_STOP;
|
||||
}
|
||||
|
||||
// If the global number of connections is preventing the opening of
|
||||
// new connections to a host without idle connections, then
|
||||
// close any spdy asap
|
||||
PLDHashOperator
|
||||
nsHttpConnectionMgr::PurgeExcessSpdyConnectionsCB(const nsACString &key,
|
||||
nsAutoPtr<nsConnectionEntry> &ent,
|
||||
void *closure)
|
||||
{
|
||||
if (!ent->mUsingSpdy)
|
||||
return PL_DHASH_NEXT;
|
||||
|
||||
nsHttpConnectionMgr *self = static_cast<nsHttpConnectionMgr *>(closure);
|
||||
for (uint32_t index = 0; index < ent->mActiveConns.Length(); ++index) {
|
||||
nsHttpConnection *conn = ent->mActiveConns[index];
|
||||
if (conn->UsingSpdy() && conn->CanReuse()) {
|
||||
conn->DontReuse();
|
||||
// stop on <= (particularly =) beacuse this dontreuse causes async close
|
||||
if (self->mNumIdleConns + self->mNumActiveConns + 1 <= self->mMaxConns)
|
||||
return PL_DHASH_STOP;
|
||||
}
|
||||
}
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
PLDHashOperator
|
||||
nsHttpConnectionMgr::PruneDeadConnectionsCB(const nsACString &key,
|
||||
nsAutoPtr<nsConnectionEntry> &ent,
|
||||
void *closure)
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
nsHttpConnectionMgr *self = (nsHttpConnectionMgr *) closure;
|
||||
|
||||
LOG((" pruning [ci=%s]\n", ent->mConnInfo->HashKey().get()));
|
||||
|
||||
// Find out how long it will take for next idle connection to not be reusable
|
||||
// anymore.
|
||||
uint32_t timeToNextExpire = UINT32_MAX;
|
||||
int32_t count = ent->mIdleConns.Length();
|
||||
if (count > 0) {
|
||||
for (int32_t i=count-1; i>=0; --i) {
|
||||
nsHttpConnection *conn = ent->mIdleConns[i];
|
||||
if (!conn->CanReuse()) {
|
||||
ent->mIdleConns.RemoveElementAt(i);
|
||||
conn->Close(NS_ERROR_ABORT);
|
||||
NS_RELEASE(conn);
|
||||
self->mNumIdleConns--;
|
||||
} else {
|
||||
timeToNextExpire = std::min(timeToNextExpire, conn->TimeToLive());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ent->mUsingSpdy) {
|
||||
for (uint32_t index = 0; index < ent->mActiveConns.Length(); ++index) {
|
||||
nsHttpConnection *conn = ent->mActiveConns[index];
|
||||
if (conn->UsingSpdy()) {
|
||||
if (!conn->CanReuse()) {
|
||||
// marking it dont reuse will create an active tear down if
|
||||
// the spdy session is idle.
|
||||
conn->DontReuse();
|
||||
}
|
||||
else {
|
||||
timeToNextExpire = std::min(timeToNextExpire,
|
||||
conn->TimeToLive());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If time to next expire found is shorter than time to next wake-up, we need to
|
||||
// change the time for next wake-up.
|
||||
if (timeToNextExpire != UINT32_MAX) {
|
||||
uint32_t now = NowInSeconds();
|
||||
uint64_t timeOfNextExpire = now + timeToNextExpire;
|
||||
// If pruning of dead connections is not already scheduled to happen
|
||||
// or time found for next connection to expire is is before
|
||||
// mTimeOfNextWakeUp, we need to schedule the pruning to happen
|
||||
// after timeToNextExpire.
|
||||
if (!self->mTimer || timeOfNextExpire < self->mTimeOfNextWakeUp) {
|
||||
self->PruneDeadConnectionsAfter(timeToNextExpire);
|
||||
}
|
||||
} else {
|
||||
self->ConditionallyStopPruneDeadConnectionsTimer();
|
||||
}
|
||||
|
||||
// if this entry is empty, we have too many entries,
|
||||
// and this doesn't represent some painfully determined
|
||||
// red condition, then we can clean it up and restart from
|
||||
// yellow
|
||||
if (ent->PipelineState() != PS_RED &&
|
||||
self->mCT.Count() > 125 &&
|
||||
ent->mIdleConns.Length() == 0 &&
|
||||
ent->mActiveConns.Length() == 0 &&
|
||||
ent->mHalfOpens.Length() == 0 &&
|
||||
ent->mPendingQ.Length() == 0 &&
|
||||
((!ent->mTestedSpdy && !ent->mUsingSpdy) ||
|
||||
!gHttpHandler->IsSpdyEnabled() ||
|
||||
self->mCT.Count() > 300)) {
|
||||
LOG((" removing empty connection entry\n"));
|
||||
return PL_DHASH_REMOVE;
|
||||
}
|
||||
|
||||
// otherwise use this opportunity to compact our arrays...
|
||||
ent->mIdleConns.Compact();
|
||||
ent->mActiveConns.Compact();
|
||||
ent->mPendingQ.Compact();
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
PLDHashOperator
|
||||
nsHttpConnectionMgr::VerifyTrafficCB(const nsACString &key,
|
||||
nsAutoPtr<nsConnectionEntry> &ent,
|
||||
void *closure)
|
||||
{
|
||||
// Iterate over all active connections and check them
|
||||
for (uint32_t index = 0; index < ent->mActiveConns.Length(); ++index) {
|
||||
nsHttpConnection *conn = ent->mActiveConns[index];
|
||||
conn->CheckForTraffic(true);
|
||||
}
|
||||
// Iterate the idle connections and unmark them for traffic checks
|
||||
for (uint32_t index = 0; index < ent->mIdleConns.Length(); ++index) {
|
||||
nsHttpConnection *conn = ent->mIdleConns[index];
|
||||
conn->CheckForTraffic(false);
|
||||
}
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
PLDHashOperator
|
||||
nsHttpConnectionMgr::PruneNoTrafficCB(const nsACString &key,
|
||||
nsAutoPtr<nsConnectionEntry> &ent,
|
||||
void *closure)
|
||||
{
|
||||
// Close the connections with no registered traffic
|
||||
nsHttpConnectionMgr *self = (nsHttpConnectionMgr *) closure;
|
||||
|
||||
LOG((" pruning no traffic [ci=%s]\n", ent->mConnInfo->HashKey().get()));
|
||||
|
||||
uint32_t numConns = ent->mActiveConns.Length();
|
||||
if (numConns) {
|
||||
// walk the list backwards to allow us to remove entries easily
|
||||
for (int index = numConns-1; index >= 0; index--) {
|
||||
if (ent->mActiveConns[index]->NoTraffic()) {
|
||||
RefPtr<nsHttpConnection> conn = dont_AddRef(ent->mActiveConns[index]);
|
||||
ent->mActiveConns.RemoveElementAt(index);
|
||||
self->DecrementActiveConnCount(conn);
|
||||
conn->Close(NS_ERROR_ABORT);
|
||||
LOG((" closed active connection due to no traffic [conn=%p]\n",
|
||||
conn.get()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
PLDHashOperator
|
||||
nsHttpConnectionMgr::ShutdownPassCB(const nsACString &key,
|
||||
nsAutoPtr<nsConnectionEntry> &ent,
|
||||
void *closure)
|
||||
{
|
||||
nsHttpConnectionMgr *self = (nsHttpConnectionMgr *) closure;
|
||||
|
||||
nsHttpTransaction *trans;
|
||||
nsHttpConnection *conn;
|
||||
|
||||
// close all active connections
|
||||
while (ent->mActiveConns.Length()) {
|
||||
conn = ent->mActiveConns[0];
|
||||
|
||||
ent->mActiveConns.RemoveElementAt(0);
|
||||
self->DecrementActiveConnCount(conn);
|
||||
|
||||
conn->Close(NS_ERROR_ABORT);
|
||||
NS_RELEASE(conn);
|
||||
}
|
||||
|
||||
// close all idle connections
|
||||
while (ent->mIdleConns.Length()) {
|
||||
conn = ent->mIdleConns[0];
|
||||
|
||||
ent->mIdleConns.RemoveElementAt(0);
|
||||
self->mNumIdleConns--;
|
||||
|
||||
conn->Close(NS_ERROR_ABORT);
|
||||
NS_RELEASE(conn);
|
||||
}
|
||||
// If all idle connections are removed,
|
||||
// we can stop pruning dead connections.
|
||||
self->ConditionallyStopPruneDeadConnectionsTimer();
|
||||
|
||||
// close all pending transactions
|
||||
while (ent->mPendingQ.Length()) {
|
||||
trans = ent->mPendingQ[0];
|
||||
|
||||
ent->mPendingQ.RemoveElementAt(0);
|
||||
|
||||
trans->Close(NS_ERROR_ABORT);
|
||||
NS_RELEASE(trans);
|
||||
}
|
||||
|
||||
// close all half open tcp connections
|
||||
for (int32_t i = ((int32_t) ent->mHalfOpens.Length()) - 1; i >= 0; i--)
|
||||
ent->mHalfOpens[i]->Abandon();
|
||||
|
||||
return PL_DHASH_REMOVE;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
bool
|
||||
@@ -1342,16 +1078,6 @@ nsHttpConnectionMgr::ClosePersistentConnections(nsConnectionEntry *ent)
|
||||
ent->mActiveConns[i]->DontReuse();
|
||||
}
|
||||
|
||||
PLDHashOperator
|
||||
nsHttpConnectionMgr::ClosePersistentConnectionsCB(const nsACString &key,
|
||||
nsAutoPtr<nsConnectionEntry> &ent,
|
||||
void *closure)
|
||||
{
|
||||
nsHttpConnectionMgr *self = static_cast<nsHttpConnectionMgr *>(closure);
|
||||
self->ClosePersistentConnections(ent);
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
bool
|
||||
nsHttpConnectionMgr::RestrictConnections(nsConnectionEntry *ent,
|
||||
bool ignorePossibleSpdyConnections)
|
||||
@@ -1470,12 +1196,56 @@ nsHttpConnectionMgr::MakeNewConnection(nsConnectionEntry *ent,
|
||||
// beacuse we have already determined there are no idle connections
|
||||
// to our destination
|
||||
|
||||
if ((mNumIdleConns + mNumActiveConns + 1 >= mMaxConns) && mNumIdleConns)
|
||||
mCT.Enumerate(PurgeExcessIdleConnectionsCB, this);
|
||||
if ((mNumIdleConns + mNumActiveConns + 1 >= mMaxConns) && mNumIdleConns) {
|
||||
// If the global number of connections is preventing the opening of new
|
||||
// connections to a host without idle connections, then close them
|
||||
// regardless of their TTL.
|
||||
auto iter = mCT.Iter();
|
||||
while (mNumIdleConns + mNumActiveConns + 1 >= mMaxConns &&
|
||||
!iter.Done()) {
|
||||
nsAutoPtr<nsConnectionEntry> &ent = iter.Data();
|
||||
if (!ent->mIdleConns.Length()) {
|
||||
iter.Next();
|
||||
continue;
|
||||
}
|
||||
nsHttpConnection *conn = ent->mIdleConns[0];
|
||||
ent->mIdleConns.RemoveElementAt(0);
|
||||
conn->Close(NS_ERROR_ABORT);
|
||||
NS_RELEASE(conn);
|
||||
mNumIdleConns--;
|
||||
ConditionallyStopPruneDeadConnectionsTimer();
|
||||
}
|
||||
}
|
||||
|
||||
if ((mNumIdleConns + mNumActiveConns + 1 >= mMaxConns) &&
|
||||
mNumActiveConns && gHttpHandler->IsSpdyEnabled())
|
||||
mCT.Enumerate(PurgeExcessSpdyConnectionsCB, this);
|
||||
{
|
||||
// If the global number of connections is preventing the opening of new
|
||||
// connections to a host without idle connections, then close any spdy
|
||||
// ASAP.
|
||||
for (auto iter = mCT.Iter(); !iter.Done(); iter.Next()) {
|
||||
nsAutoPtr<nsConnectionEntry> &ent = iter.Data();
|
||||
if (!ent->mUsingSpdy) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (uint32_t index = 0;
|
||||
index < ent->mActiveConns.Length();
|
||||
++index) {
|
||||
nsHttpConnection *conn = ent->mActiveConns[index];
|
||||
if (conn->UsingSpdy() && conn->CanReuse()) {
|
||||
conn->DontReuse();
|
||||
// Stop on <= (particularly =) because this dontreuse
|
||||
// causes async close.
|
||||
if (mNumIdleConns + mNumActiveConns + 1 <= mMaxConns) {
|
||||
goto outerLoopEnd;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
outerLoopEnd:
|
||||
;
|
||||
}
|
||||
|
||||
if (AtActiveConnectionLimit(ent, trans->Caps()))
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
@@ -2220,22 +1990,14 @@ nsHttpConnectionMgr::ProcessSpdyPendingQ(nsConnectionEntry *ent)
|
||||
leftovers.Clear();
|
||||
}
|
||||
|
||||
PLDHashOperator
|
||||
nsHttpConnectionMgr::ProcessSpdyPendingQCB(const nsACString &key,
|
||||
nsAutoPtr<nsConnectionEntry> &ent,
|
||||
void *closure)
|
||||
{
|
||||
nsHttpConnectionMgr *self = (nsHttpConnectionMgr *) closure;
|
||||
self->ProcessSpdyPendingQ(ent);
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
void
|
||||
nsHttpConnectionMgr::OnMsgProcessAllSpdyPendingQ(int32_t, ARefBase *)
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
LOG(("nsHttpConnectionMgr::OnMsgProcessAllSpdyPendingQ\n"));
|
||||
mCT.Enumerate(ProcessSpdyPendingQCB, this);
|
||||
for (auto iter = mCT.Iter(); !iter.Done(); iter.Next()) {
|
||||
ProcessSpdyPendingQ(iter.Data());
|
||||
}
|
||||
}
|
||||
|
||||
nsHttpConnection *
|
||||
@@ -2277,7 +2039,54 @@ nsHttpConnectionMgr::OnMsgShutdown(int32_t, ARefBase *param)
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
LOG(("nsHttpConnectionMgr::OnMsgShutdown\n"));
|
||||
|
||||
mCT.Enumerate(ShutdownPassCB, this);
|
||||
gHttpHandler->StopRequestTokenBucket();
|
||||
|
||||
for (auto iter = mCT.Iter(); !iter.Done(); iter.Next()) {
|
||||
nsAutoPtr<nsConnectionEntry>& ent = iter.Data();
|
||||
|
||||
// Close all active connections.
|
||||
while (ent->mActiveConns.Length()) {
|
||||
nsHttpConnection* conn = ent->mActiveConns[0];
|
||||
|
||||
ent->mActiveConns.RemoveElementAt(0);
|
||||
DecrementActiveConnCount(conn);
|
||||
|
||||
conn->Close(NS_ERROR_ABORT, true);
|
||||
NS_RELEASE(conn);
|
||||
}
|
||||
|
||||
// Close all idle connections.
|
||||
while (ent->mIdleConns.Length()) {
|
||||
nsHttpConnection* conn = ent->mIdleConns[0];
|
||||
|
||||
ent->mIdleConns.RemoveElementAt(0);
|
||||
mNumIdleConns--;
|
||||
|
||||
conn->Close(NS_ERROR_ABORT);
|
||||
NS_RELEASE(conn);
|
||||
}
|
||||
|
||||
// If all idle connections are removed we can stop pruning dead
|
||||
// connections.
|
||||
ConditionallyStopPruneDeadConnectionsTimer();
|
||||
|
||||
// Close all pending transactions.
|
||||
while (ent->mPendingQ.Length()) {
|
||||
nsHttpTransaction* trans = ent->mPendingQ[0];
|
||||
|
||||
ent->mPendingQ.RemoveElementAt(0);
|
||||
|
||||
trans->Close(NS_ERROR_ABORT);
|
||||
NS_RELEASE(trans);
|
||||
}
|
||||
|
||||
// Close all half open tcp connections.
|
||||
for (int32_t i = int32_t(ent->mHalfOpens.Length()) - 1; i >= 0; i--) {
|
||||
ent->mHalfOpens[i]->Abandon();
|
||||
}
|
||||
|
||||
iter.Remove();
|
||||
}
|
||||
|
||||
if (mTimeoutTick) {
|
||||
mTimeoutTick->Cancel();
|
||||
@@ -2419,7 +2228,9 @@ nsHttpConnectionMgr::OnMsgProcessPendingQ(int32_t, ARefBase *param)
|
||||
if (!ci) {
|
||||
LOG(("nsHttpConnectionMgr::OnMsgProcessPendingQ [ci=nullptr]\n"));
|
||||
// Try and dispatch everything
|
||||
mCT.Enumerate(ProcessAllTransactionsCB, this);
|
||||
for (auto iter = mCT.Iter(); !iter.Done(); iter.Next()) {
|
||||
ProcessPendingQForEntry(iter.Data(), true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2431,7 +2242,11 @@ nsHttpConnectionMgr::OnMsgProcessPendingQ(int32_t, ARefBase *param)
|
||||
if (!(ent && ProcessPendingQForEntry(ent, false))) {
|
||||
// if we reach here, it means that we couldn't dispatch a transaction
|
||||
// for the specified connection info. walk the connection table...
|
||||
mCT.Enumerate(ProcessOneTransactionCB, this);
|
||||
for (auto iter = mCT.Iter(); !iter.Done(); iter.Next()) {
|
||||
if (ProcessPendingQForEntry(iter.Data(), false)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2478,8 +2293,86 @@ nsHttpConnectionMgr::OnMsgPruneDeadConnections(int32_t, ARefBase *)
|
||||
|
||||
// check canreuse() for all idle connections plus any active connections on
|
||||
// connection entries that are using spdy.
|
||||
if (mNumIdleConns || (mNumActiveConns && gHttpHandler->IsSpdyEnabled()))
|
||||
mCT.Enumerate(PruneDeadConnectionsCB, this);
|
||||
if (mNumIdleConns || (mNumActiveConns && gHttpHandler->IsSpdyEnabled())) {
|
||||
for (auto iter = mCT.Iter(); !iter.Done(); iter.Next()) {
|
||||
nsAutoPtr<nsConnectionEntry>& ent = iter.Data();
|
||||
|
||||
LOG((" pruning [ci=%s]\n", ent->mConnInfo->HashKey().get()));
|
||||
|
||||
// Find out how long it will take for next idle connection to not
|
||||
// be reusable anymore.
|
||||
uint32_t timeToNextExpire = UINT32_MAX;
|
||||
int32_t count = ent->mIdleConns.Length();
|
||||
if (count > 0) {
|
||||
for (int32_t i = count - 1; i >= 0; --i) {
|
||||
nsHttpConnection* conn = ent->mIdleConns[i];
|
||||
if (!conn->CanReuse()) {
|
||||
ent->mIdleConns.RemoveElementAt(i);
|
||||
conn->Close(NS_ERROR_ABORT);
|
||||
NS_RELEASE(conn);
|
||||
mNumIdleConns--;
|
||||
} else {
|
||||
timeToNextExpire =
|
||||
std::min(timeToNextExpire, conn->TimeToLive());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ent->mUsingSpdy) {
|
||||
for (uint32_t i = 0; i < ent->mActiveConns.Length(); ++i) {
|
||||
nsHttpConnection* conn = ent->mActiveConns[i];
|
||||
if (conn->UsingSpdy()) {
|
||||
if (!conn->CanReuse()) {
|
||||
// Marking it don't-reuse will create an active
|
||||
// tear down if the spdy session is idle.
|
||||
conn->DontReuse();
|
||||
} else {
|
||||
timeToNextExpire =
|
||||
std::min(timeToNextExpire, conn->TimeToLive());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If time to next expire found is shorter than time to next
|
||||
// wake-up, we need to change the time for next wake-up.
|
||||
if (timeToNextExpire != UINT32_MAX) {
|
||||
uint32_t now = NowInSeconds();
|
||||
uint64_t timeOfNextExpire = now + timeToNextExpire;
|
||||
// If pruning of dead connections is not already scheduled to
|
||||
// happen or time found for next connection to expire is is
|
||||
// before mTimeOfNextWakeUp, we need to schedule the pruning to
|
||||
// happen after timeToNextExpire.
|
||||
if (!mTimer || timeOfNextExpire < mTimeOfNextWakeUp) {
|
||||
PruneDeadConnectionsAfter(timeToNextExpire);
|
||||
}
|
||||
} else {
|
||||
ConditionallyStopPruneDeadConnectionsTimer();
|
||||
}
|
||||
|
||||
// If this entry is empty, we have too many entries, and this
|
||||
// doesn't represent some painfully determined red condition, then
|
||||
// we can clean it up and restart from yellow.
|
||||
if (ent->PipelineState() != PS_RED &&
|
||||
mCT.Count() > 125 &&
|
||||
ent->mIdleConns.Length() == 0 &&
|
||||
ent->mActiveConns.Length() == 0 &&
|
||||
ent->mHalfOpens.Length() == 0 &&
|
||||
ent->mPendingQ.Length() == 0 &&
|
||||
((!ent->mTestedSpdy && !ent->mUsingSpdy) ||
|
||||
!gHttpHandler->IsSpdyEnabled() ||
|
||||
mCT.Count() > 300)) {
|
||||
LOG((" removing empty connection entry\n"));
|
||||
iter.Remove();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Otherwise use this opportunity to compact our arrays...
|
||||
ent->mIdleConns.Compact();
|
||||
ent->mActiveConns.Compact();
|
||||
ent->mPendingQ.Compact();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -2489,7 +2382,30 @@ nsHttpConnectionMgr::OnMsgPruneNoTraffic(int32_t, ARefBase *)
|
||||
LOG(("nsHttpConnectionMgr::OnMsgPruneNoTraffic\n"));
|
||||
|
||||
// Prune connections without traffic
|
||||
mCT.Enumerate(PruneNoTrafficCB, this);
|
||||
for (auto iter = mCT.Iter(); !iter.Done(); iter.Next()) {
|
||||
|
||||
// Close the connections with no registered traffic.
|
||||
nsAutoPtr<nsConnectionEntry>& ent = iter.Data();
|
||||
|
||||
LOG((" pruning no traffic [ci=%s]\n",
|
||||
ent->mConnInfo->HashKey().get()));
|
||||
|
||||
uint32_t numConns = ent->mActiveConns.Length();
|
||||
if (numConns) {
|
||||
// Walk the list backwards to allow us to remove entries easily.
|
||||
for (int index = numConns - 1; index >= 0; index--) {
|
||||
if (ent->mActiveConns[index]->NoTraffic()) {
|
||||
RefPtr<nsHttpConnection> conn =
|
||||
dont_AddRef(ent->mActiveConns[index]);
|
||||
ent->mActiveConns.RemoveElementAt(index);
|
||||
DecrementActiveConnCount(conn);
|
||||
conn->Close(NS_ERROR_ABORT);
|
||||
LOG((" closed active connection due to no traffic "
|
||||
"[conn=%p]\n", conn.get()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mPruningNoTraffic = false; // not pruning anymore
|
||||
}
|
||||
@@ -2507,7 +2423,18 @@ nsHttpConnectionMgr::OnMsgVerifyTraffic(int32_t, ARefBase *)
|
||||
}
|
||||
|
||||
// Mark connections for traffic verification
|
||||
mCT.Enumerate(VerifyTrafficCB, this);
|
||||
for (auto iter = mCT.Iter(); !iter.Done(); iter.Next()) {
|
||||
nsAutoPtr<nsConnectionEntry>& ent = iter.Data();
|
||||
|
||||
// Iterate over all active connections and check them.
|
||||
for (uint32_t index = 0; index < ent->mActiveConns.Length(); ++index) {
|
||||
ent->mActiveConns[index]->CheckForTraffic(true);
|
||||
}
|
||||
// Iterate the idle connections and unmark them for traffic checks.
|
||||
for (uint32_t index = 0; index < ent->mIdleConns.Length(); ++index) {
|
||||
ent->mIdleConns[index]->CheckForTraffic(false);
|
||||
}
|
||||
}
|
||||
|
||||
// If the timer is already there. we just re-init it
|
||||
if(!mTrafficTimer) {
|
||||
@@ -2534,7 +2461,10 @@ nsHttpConnectionMgr::OnMsgDoShiftReloadConnectionCleanup(int32_t, ARefBase *para
|
||||
|
||||
nsHttpConnectionInfo *ci = static_cast<nsHttpConnectionInfo *>(param);
|
||||
|
||||
mCT.Enumerate(ClosePersistentConnectionsCB, this);
|
||||
for (auto iter = mCT.Iter(); !iter.Done(); iter.Next()) {
|
||||
ClosePersistentConnections(iter.Data());
|
||||
}
|
||||
|
||||
if (ci)
|
||||
ResetIPFamilyPreference(ci);
|
||||
}
|
||||
@@ -2752,69 +2682,67 @@ nsHttpConnectionMgr::TimeoutTick()
|
||||
// Set it to the max value here, and the TimeoutTickCB()s can
|
||||
// reduce it to their local needs.
|
||||
mTimeoutTickNext = 3600; // 1hr
|
||||
mCT.Enumerate(TimeoutTickCB, this);
|
||||
|
||||
for (auto iter = mCT.Iter(); !iter.Done(); iter.Next()) {
|
||||
nsAutoPtr<nsConnectionEntry>& ent = iter.Data();
|
||||
|
||||
LOG(("nsHttpConnectionMgr::TimeoutTickCB() this=%p host=%s "
|
||||
"idle=%d active=%d half-len=%d pending=%d\n",
|
||||
this, ent->mConnInfo->Origin(), ent->mIdleConns.Length(),
|
||||
ent->mActiveConns.Length(), ent->mHalfOpens.Length(),
|
||||
ent->mPendingQ.Length()));
|
||||
|
||||
// First call the tick handler for each active connection.
|
||||
PRIntervalTime now = PR_IntervalNow();
|
||||
for (uint32_t index = 0; index < ent->mActiveConns.Length(); ++index) {
|
||||
uint32_t connNextTimeout =
|
||||
ent->mActiveConns[index]->ReadTimeoutTick(now);
|
||||
mTimeoutTickNext = std::min(mTimeoutTickNext, connNextTimeout);
|
||||
}
|
||||
|
||||
// Now check for any stalled half open sockets.
|
||||
if (ent->mHalfOpens.Length()) {
|
||||
TimeStamp now = TimeStamp::Now();
|
||||
double maxConnectTime_ms = gHttpHandler->ConnectTimeout();
|
||||
|
||||
for (uint32_t index = ent->mHalfOpens.Length(); index > 0; ) {
|
||||
index--;
|
||||
|
||||
nsHalfOpenSocket *half = ent->mHalfOpens[index];
|
||||
double delta = half->Duration(now);
|
||||
// If the socket has timed out, close it so the waiting
|
||||
// transaction will get the proper signal.
|
||||
if (delta > maxConnectTime_ms) {
|
||||
LOG(("Force timeout of half open to %s after %.2fms.\n",
|
||||
ent->mConnInfo->HashKey().get(), delta));
|
||||
if (half->SocketTransport()) {
|
||||
half->SocketTransport()->Close(NS_ERROR_ABORT);
|
||||
}
|
||||
if (half->BackupTransport()) {
|
||||
half->BackupTransport()->Close(NS_ERROR_ABORT);
|
||||
}
|
||||
}
|
||||
|
||||
// If this half open hangs around for 5 seconds after we've
|
||||
// closed() it then just abandon the socket.
|
||||
if (delta > maxConnectTime_ms + 5000) {
|
||||
LOG(("Abandon half open to %s after %.2fms.\n",
|
||||
ent->mConnInfo->HashKey().get(), delta));
|
||||
half->Abandon();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ent->mHalfOpens.Length()) {
|
||||
mTimeoutTickNext = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (mTimeoutTick) {
|
||||
mTimeoutTickNext = std::max(mTimeoutTickNext, 1U);
|
||||
mTimeoutTick->SetDelay(mTimeoutTickNext * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
PLDHashOperator
|
||||
nsHttpConnectionMgr::TimeoutTickCB(const nsACString &key,
|
||||
nsAutoPtr<nsConnectionEntry> &ent,
|
||||
void *closure)
|
||||
{
|
||||
nsHttpConnectionMgr *self = (nsHttpConnectionMgr *) closure;
|
||||
|
||||
LOG(("nsHttpConnectionMgr::TimeoutTickCB() this=%p host=%s "
|
||||
"idle=%d active=%d half-len=%d pending=%d\n",
|
||||
self, ent->mConnInfo->Origin(), ent->mIdleConns.Length(),
|
||||
ent->mActiveConns.Length(), ent->mHalfOpens.Length(),
|
||||
ent->mPendingQ.Length()));
|
||||
|
||||
// first call the tick handler for each active connection
|
||||
PRIntervalTime now = PR_IntervalNow();
|
||||
for (uint32_t index = 0; index < ent->mActiveConns.Length(); ++index) {
|
||||
uint32_t connNextTimeout = ent->mActiveConns[index]->ReadTimeoutTick(now);
|
||||
self->mTimeoutTickNext = std::min(self->mTimeoutTickNext, connNextTimeout);
|
||||
}
|
||||
|
||||
// now check for any stalled half open sockets
|
||||
if (ent->mHalfOpens.Length()) {
|
||||
TimeStamp now = TimeStamp::Now();
|
||||
double maxConnectTime = gHttpHandler->ConnectTimeout(); /* in milliseconds */
|
||||
|
||||
for (uint32_t index = ent->mHalfOpens.Length(); index > 0; ) {
|
||||
index--;
|
||||
|
||||
nsHalfOpenSocket *half = ent->mHalfOpens[index];
|
||||
double delta = half->Duration(now);
|
||||
// If the socket has timed out, close it so the waiting transaction
|
||||
// will get the proper signal
|
||||
if (delta > maxConnectTime) {
|
||||
LOG(("Force timeout of half open to %s after %.2fms.\n",
|
||||
ent->mConnInfo->HashKey().get(), delta));
|
||||
if (half->SocketTransport())
|
||||
half->SocketTransport()->Close(NS_ERROR_NET_TIMEOUT);
|
||||
if (half->BackupTransport())
|
||||
half->BackupTransport()->Close(NS_ERROR_NET_TIMEOUT);
|
||||
}
|
||||
|
||||
// If this half open hangs around for 5 seconds after we've closed() it
|
||||
// then just abandon the socket.
|
||||
if (delta > maxConnectTime + 5000) {
|
||||
LOG(("Abandon half open to %s after %.2fms.\n",
|
||||
ent->mConnInfo->HashKey().get(), delta));
|
||||
half->Abandon();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ent->mHalfOpens.Length()) {
|
||||
self->mTimeoutTickNext = 1;
|
||||
}
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
// 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
|
||||
@@ -2996,6 +2924,8 @@ nsHalfOpenSocket::SetupStreams(nsISocketTransport **transport,
|
||||
nsIAsyncOutputStream **outstream,
|
||||
bool isBackup)
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
|
||||
nsresult rv;
|
||||
const char *socketTypes[1];
|
||||
uint32_t typeCount = 0;
|
||||
@@ -3099,6 +3029,8 @@ nsHalfOpenSocket::SetupStreams(nsISocketTransport **transport,
|
||||
rv = socketTransport->SetSecurityCallbacks(this);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mEnt->mUsedForConnection = true;
|
||||
|
||||
nsCOMPtr<nsIOutputStream> sout;
|
||||
rv = socketTransport->OpenOutputStream(nsITransport::OPEN_UNBUFFERED,
|
||||
0, 0,
|
||||
@@ -3557,6 +3489,7 @@ nsConnectionEntry::nsConnectionEntry(nsHttpConnectionInfo *ci)
|
||||
, mInPreferredHash(false)
|
||||
, mPreferIPv4(false)
|
||||
, mPreferIPv6(false)
|
||||
, mUsedForConnection(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsConnectionEntry);
|
||||
if (gHttpHandler->GetPipelineAggressive()) {
|
||||
@@ -3810,51 +3743,50 @@ nsConnectionEntry::MaxPipelineDepth(nsAHttpTransaction::Classifier aClass)
|
||||
return mGreenDepth;
|
||||
}
|
||||
|
||||
PLDHashOperator
|
||||
nsHttpConnectionMgr::ReadConnectionEntry(const nsACString &key,
|
||||
nsAutoPtr<nsConnectionEntry> &ent,
|
||||
void *aArg)
|
||||
{
|
||||
if (ent->mConnInfo->GetPrivate())
|
||||
return PL_DHASH_NEXT;
|
||||
|
||||
nsTArray<HttpRetParams> *args = static_cast<nsTArray<HttpRetParams> *> (aArg);
|
||||
HttpRetParams data;
|
||||
data.host = ent->mConnInfo->Origin();
|
||||
data.port = ent->mConnInfo->OriginPort();
|
||||
for (uint32_t i = 0; i < ent->mActiveConns.Length(); i++) {
|
||||
HttpConnInfo info;
|
||||
info.ttl = ent->mActiveConns[i]->TimeToLive();
|
||||
info.rtt = ent->mActiveConns[i]->Rtt();
|
||||
if (ent->mActiveConns[i]->UsingSpdy())
|
||||
info.SetHTTP2ProtocolVersion(ent->mActiveConns[i]->GetSpdyVersion());
|
||||
else
|
||||
info.SetHTTP1ProtocolVersion(ent->mActiveConns[i]->GetLastHttpResponseVersion());
|
||||
|
||||
data.active.AppendElement(info);
|
||||
}
|
||||
for (uint32_t i = 0; i < ent->mIdleConns.Length(); i++) {
|
||||
HttpConnInfo info;
|
||||
info.ttl = ent->mIdleConns[i]->TimeToLive();
|
||||
info.rtt = ent->mIdleConns[i]->Rtt();
|
||||
info.SetHTTP1ProtocolVersion(ent->mIdleConns[i]->GetLastHttpResponseVersion());
|
||||
data.idle.AppendElement(info);
|
||||
}
|
||||
for(uint32_t i = 0; i < ent->mHalfOpens.Length(); i++) {
|
||||
HalfOpenSockets hSocket;
|
||||
hSocket.speculative = ent->mHalfOpens[i]->IsSpeculative();
|
||||
data.halfOpens.AppendElement(hSocket);
|
||||
}
|
||||
data.spdy = ent->mUsingSpdy;
|
||||
data.ssl = ent->mConnInfo->EndToEndSSL();
|
||||
args->AppendElement(data);
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
bool
|
||||
nsHttpConnectionMgr::GetConnectionData(nsTArray<HttpRetParams> *aArg)
|
||||
{
|
||||
mCT.Enumerate(ReadConnectionEntry, aArg);
|
||||
for (auto iter = mCT.Iter(); !iter.Done(); iter.Next()) {
|
||||
nsAutoPtr<nsConnectionEntry>& ent = iter.Data();
|
||||
|
||||
if (ent->mConnInfo->GetPrivate()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
HttpRetParams data;
|
||||
data.host = ent->mConnInfo->Origin();
|
||||
data.port = ent->mConnInfo->OriginPort();
|
||||
for (uint32_t i = 0; i < ent->mActiveConns.Length(); i++) {
|
||||
HttpConnInfo info;
|
||||
info.ttl = ent->mActiveConns[i]->TimeToLive();
|
||||
info.rtt = ent->mActiveConns[i]->Rtt();
|
||||
if (ent->mActiveConns[i]->UsingSpdy()) {
|
||||
info.SetHTTP2ProtocolVersion(
|
||||
ent->mActiveConns[i]->GetSpdyVersion());
|
||||
} else {
|
||||
info.SetHTTP1ProtocolVersion(
|
||||
ent->mActiveConns[i]->GetLastHttpResponseVersion());
|
||||
}
|
||||
data.active.AppendElement(info);
|
||||
}
|
||||
for (uint32_t i = 0; i < ent->mIdleConns.Length(); i++) {
|
||||
HttpConnInfo info;
|
||||
info.ttl = ent->mIdleConns[i]->TimeToLive();
|
||||
info.rtt = ent->mIdleConns[i]->Rtt();
|
||||
info.SetHTTP1ProtocolVersion(
|
||||
ent->mIdleConns[i]->GetLastHttpResponseVersion());
|
||||
data.idle.AppendElement(info);
|
||||
}
|
||||
for (uint32_t i = 0; i < ent->mHalfOpens.Length(); i++) {
|
||||
HalfOpenSockets hSocket;
|
||||
hSocket.speculative = ent->mHalfOpens[i]->IsSpeculative();
|
||||
data.halfOpens.AppendElement(hSocket);
|
||||
}
|
||||
data.spdy = ent->mUsingSpdy;
|
||||
data.ssl = ent->mConnInfo->EndToEndSSL();
|
||||
aArg->AppendElement(data);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -369,15 +369,15 @@ private:
|
||||
// To have the UsingSpdy flag means some host with the same connection
|
||||
// entry has done NPN=spdy/* at some point. It does not mean every
|
||||
// connection is currently using spdy.
|
||||
bool mUsingSpdy;
|
||||
bool mUsingSpdy : 1;
|
||||
|
||||
// mTestedSpdy is set after NPN negotiation has occurred and we know
|
||||
// with confidence whether a host speaks spdy or not (which is reflected
|
||||
// in mUsingSpdy). Before mTestedSpdy is set, handshake parallelism is
|
||||
// minimized so that we can multiplex on a single spdy connection.
|
||||
bool mTestedSpdy;
|
||||
bool mTestedSpdy : 1;
|
||||
|
||||
bool mInPreferredHash;
|
||||
bool mInPreferredHash : 1;
|
||||
|
||||
// Flags to remember our happy-eyeballs decision.
|
||||
// Reset only by Ctrl-F5 reload.
|
||||
@@ -388,6 +388,9 @@ private:
|
||||
// initially false.
|
||||
bool mPreferIPv6 : 1;
|
||||
|
||||
// True if this connection entry has initiated a socket
|
||||
bool mUsedForConnection : 1;
|
||||
|
||||
// Set the IP family preference flags according the connected family
|
||||
void RecordIPFamilyPreference(uint16_t family);
|
||||
// Resets all flags to their default values
|
||||
@@ -510,16 +513,6 @@ private:
|
||||
// NOTE: these members are only accessed on the socket transport thread
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
static PLDHashOperator ProcessOneTransactionCB(const nsACString &, nsAutoPtr<nsConnectionEntry> &, void *);
|
||||
static PLDHashOperator ProcessAllTransactionsCB(const nsACString &, nsAutoPtr<nsConnectionEntry> &, void *);
|
||||
|
||||
static PLDHashOperator PruneDeadConnectionsCB(const nsACString &, nsAutoPtr<nsConnectionEntry> &, void *);
|
||||
static PLDHashOperator ShutdownPassCB(const nsACString &, nsAutoPtr<nsConnectionEntry> &, void *);
|
||||
static PLDHashOperator PurgeExcessIdleConnectionsCB(const nsACString &, nsAutoPtr<nsConnectionEntry> &, void *);
|
||||
static PLDHashOperator PurgeExcessSpdyConnectionsCB(const nsACString &, nsAutoPtr<nsConnectionEntry> &, void *);
|
||||
static PLDHashOperator ClosePersistentConnectionsCB(const nsACString &, nsAutoPtr<nsConnectionEntry> &, void *);
|
||||
static PLDHashOperator VerifyTrafficCB(const nsACString &, nsAutoPtr<nsConnectionEntry> &, void *);
|
||||
static PLDHashOperator PruneNoTrafficCB(const nsACString &, nsAutoPtr<nsConnectionEntry> &, void *);
|
||||
bool ProcessPendingQForEntry(nsConnectionEntry *, bool considerAll);
|
||||
bool IsUnderPressure(nsConnectionEntry *ent,
|
||||
nsHttpTransaction::Classifier classification);
|
||||
@@ -571,9 +564,6 @@ private:
|
||||
nsHttpTransaction *trans);
|
||||
|
||||
void ProcessSpdyPendingQ(nsConnectionEntry *ent);
|
||||
static PLDHashOperator ProcessSpdyPendingQCB(
|
||||
const nsACString &key, nsAutoPtr<nsConnectionEntry> &ent,
|
||||
void *closure);
|
||||
|
||||
// used to marshall events to the socket transport thread.
|
||||
nsresult PostEvent(nsConnEventHandler handler,
|
||||
@@ -636,24 +626,12 @@ private:
|
||||
//
|
||||
nsClassHashtable<nsCStringHashKey, nsConnectionEntry> mCT;
|
||||
|
||||
static PLDHashOperator ReadConnectionEntry(const nsACString &key,
|
||||
nsAutoPtr<nsConnectionEntry> &ent,
|
||||
void *aArg);
|
||||
static PLDHashOperator RemoveDeadConnections(const nsACString &key,
|
||||
nsAutoPtr<nsConnectionEntry> &ent,
|
||||
void *aArg);
|
||||
|
||||
// Read Timeout Tick handlers
|
||||
void TimeoutTick();
|
||||
static PLDHashOperator TimeoutTickCB(const nsACString &key,
|
||||
nsAutoPtr<nsConnectionEntry> &ent,
|
||||
void *closure);
|
||||
|
||||
// For diagnostics
|
||||
void OnMsgPrintDiagnostics(int32_t, ARefBase *);
|
||||
static PLDHashOperator PrintDiagnosticsCB(const nsACString &key,
|
||||
nsAutoPtr<nsConnectionEntry> &ent,
|
||||
void *closure);
|
||||
|
||||
nsCString mLogData;
|
||||
};
|
||||
|
||||
|
||||
@@ -29,6 +29,8 @@ class nsISiteSecurityService;
|
||||
class nsIStreamConverterService;
|
||||
class nsITimer;
|
||||
|
||||
extern mozilla::Atomic<PRThread*, mozilla::Relaxed> gSocketThread;
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
class ATokenBucketEvent;
|
||||
@@ -559,6 +561,7 @@ public:
|
||||
nsresult SubmitPacedRequest(ATokenBucketEvent *event,
|
||||
nsICancelable **cancel)
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
if (!mRequestTokenBucket)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
return mRequestTokenBucket->SubmitEvent(event, cancel);
|
||||
@@ -567,9 +570,19 @@ public:
|
||||
// Socket thread only
|
||||
void SetRequestTokenBucket(EventTokenBucket *aTokenBucket)
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
mRequestTokenBucket = aTokenBucket;
|
||||
}
|
||||
|
||||
void StopRequestTokenBucket()
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
if (mRequestTokenBucket) {
|
||||
mRequestTokenBucket->Stop();
|
||||
mRequestTokenBucket = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
RefPtr<Tickler> mWifiTickler;
|
||||
void TickleWifi(nsIInterfaceRequestor *cb);
|
||||
|
||||
@@ -112,36 +112,19 @@ SubstitutingProtocolHandler::ConstructInternal()
|
||||
// IPC marshalling.
|
||||
//
|
||||
|
||||
struct EnumerateSubstitutionArg
|
||||
{
|
||||
EnumerateSubstitutionArg(nsCString& aScheme, nsTArray<SubstitutionMapping>& aMappings)
|
||||
: mScheme(aScheme), mMappings(aMappings) {}
|
||||
nsCString& mScheme;
|
||||
nsTArray<SubstitutionMapping>& mMappings;
|
||||
};
|
||||
|
||||
static PLDHashOperator
|
||||
EnumerateSubstitution(const nsACString& aKey,
|
||||
nsIURI* aURI,
|
||||
void* aArg)
|
||||
{
|
||||
auto arg = static_cast<EnumerateSubstitutionArg*>(aArg);
|
||||
SerializedURI uri;
|
||||
if (aURI) {
|
||||
aURI->GetSpec(uri.spec);
|
||||
aURI->GetOriginCharset(uri.charset);
|
||||
}
|
||||
|
||||
SubstitutionMapping substitution = { arg->mScheme, nsCString(aKey), uri };
|
||||
arg->mMappings.AppendElement(substitution);
|
||||
return (PLDHashOperator)PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
void
|
||||
SubstitutingProtocolHandler::CollectSubstitutions(InfallibleTArray<SubstitutionMapping>& aMappings)
|
||||
{
|
||||
EnumerateSubstitutionArg arg(mScheme, aMappings);
|
||||
mSubstitutions.EnumerateRead(&EnumerateSubstitution, &arg);
|
||||
for (auto iter = mSubstitutions.ConstIter(); !iter.Done(); iter.Next()) {
|
||||
nsCOMPtr<nsIURI> uri = iter.Data();
|
||||
SerializedURI serialized;
|
||||
if (uri) {
|
||||
uri->GetSpec(serialized.spec);
|
||||
uri->GetOriginCharset(serialized.charset);
|
||||
}
|
||||
SubstitutionMapping substitution = { mScheme, nsCString(iter.Key()), serialized };
|
||||
aMappings.AppendElement(substitution);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -390,8 +390,10 @@ setContext(XML_Parser parser, const XML_Char *context);
|
||||
static void FASTCALL normalizePublicId(XML_Char *s);
|
||||
|
||||
static DTD * dtdCreate(const XML_Memory_Handling_Suite *ms);
|
||||
/* BEGIN MOZILLA CHANGE (unused API) */
|
||||
/* do not call if parentParser != NULL */
|
||||
static void dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms);
|
||||
//static void dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms);
|
||||
/* END MOZILLA CHANGE */
|
||||
static void
|
||||
dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms);
|
||||
static int
|
||||
@@ -403,7 +405,9 @@ static NAMED *
|
||||
lookup(HASH_TABLE *table, KEY name, size_t createSize);
|
||||
static void FASTCALL
|
||||
hashTableInit(HASH_TABLE *, const XML_Memory_Handling_Suite *ms);
|
||||
static void FASTCALL hashTableClear(HASH_TABLE *);
|
||||
/* BEGIN MOZILLA CHANGE (unused API) */
|
||||
//static void FASTCALL hashTableClear(HASH_TABLE *);
|
||||
/* END MOZILLA CHANGE */
|
||||
static void FASTCALL hashTableDestroy(HASH_TABLE *);
|
||||
static void FASTCALL
|
||||
hashTableIterInit(HASH_TABLE_ITER *, const HASH_TABLE *);
|
||||
@@ -886,6 +890,8 @@ parserInit(XML_Parser parser, const XML_Char *encodingName)
|
||||
#endif
|
||||
}
|
||||
|
||||
/* BEGIN MOZILLA CHANGE (unused API) */
|
||||
#if 0
|
||||
/* moves list of bindings to freeBindingList */
|
||||
static void FASTCALL
|
||||
moveToFreeBindingList(XML_Parser parser, BINDING *bindings)
|
||||
@@ -898,8 +904,6 @@ moveToFreeBindingList(XML_Parser parser, BINDING *bindings)
|
||||
}
|
||||
}
|
||||
|
||||
/* BEGIN MOZILLA CHANGE (unused API) */
|
||||
#if 0
|
||||
XML_Bool XMLCALL
|
||||
XML_ParserReset(XML_Parser parser, const XML_Char *encodingName)
|
||||
{
|
||||
@@ -3075,7 +3079,6 @@ storeAtts(XML_Parser parser, const ENCODING *enc,
|
||||
static const XML_Char xmlnsPrefix[] = {
|
||||
'x', 'm', 'l', 'n', 's', '\0'
|
||||
};
|
||||
XML_Bool appendXMLNS = XML_TRUE;
|
||||
|
||||
((XML_Char *)s)[-1] = 0; /* clear flag */
|
||||
if (!poolAppendString(&tempPool, xmlnsNamespace)
|
||||
@@ -5909,6 +5912,8 @@ dtdCreate(const XML_Memory_Handling_Suite *ms)
|
||||
return p;
|
||||
}
|
||||
|
||||
/* BEGIN MOZILLA CHANGE (unused API) */
|
||||
#if 0
|
||||
static void
|
||||
dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms)
|
||||
{
|
||||
@@ -5950,6 +5955,8 @@ dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms)
|
||||
p->hasParamEntityRefs = XML_FALSE;
|
||||
p->standalone = XML_FALSE;
|
||||
}
|
||||
#endif
|
||||
/* END MOZILLA CHANGE */
|
||||
|
||||
static void
|
||||
dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms)
|
||||
@@ -6289,6 +6296,8 @@ lookup(HASH_TABLE *table, KEY name, size_t createSize)
|
||||
return table->v[i];
|
||||
}
|
||||
|
||||
/* BEGIN MOZILLA CHANGE (unused API) */
|
||||
#if 0
|
||||
static void FASTCALL
|
||||
hashTableClear(HASH_TABLE *table)
|
||||
{
|
||||
@@ -6299,6 +6308,8 @@ hashTableClear(HASH_TABLE *table)
|
||||
}
|
||||
table->used = 0;
|
||||
}
|
||||
#endif
|
||||
/* END MOZILLA CHANGE */
|
||||
|
||||
static void FASTCALL
|
||||
hashTableDestroy(HASH_TABLE *table)
|
||||
|
||||
@@ -79,7 +79,9 @@ public:
|
||||
void
|
||||
FinalizeStatements()
|
||||
{
|
||||
(void)mCachedStatements.Enumerate(FinalizeCachedStatements, nullptr);
|
||||
for (auto iter = mCachedStatements.Iter(); !iter.Done(); iter.Next()) {
|
||||
(void)iter.Data()->Finalize();
|
||||
}
|
||||
|
||||
// Clear the cache at this time too!
|
||||
(void)mCachedStatements.Clear();
|
||||
@@ -89,15 +91,6 @@ private:
|
||||
inline
|
||||
already_AddRefed<StatementType>
|
||||
CreateStatement(const nsACString& aQuery);
|
||||
static
|
||||
PLDHashOperator
|
||||
FinalizeCachedStatements(const nsACString& aKey,
|
||||
nsCOMPtr<StatementType>& aStatement,
|
||||
void*)
|
||||
{
|
||||
(void)aStatement->Finalize();
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
nsInterfaceHashtable<nsCStringHashKey, StatementType> mCachedStatements;
|
||||
nsCOMPtr<mozIStorageConnection>& mConnection;
|
||||
|
||||
@@ -118,12 +118,11 @@ static int id3_framesize(const uint8_t *p, long length)
|
||||
int mp3_sniff(const uint8_t *buf, long length)
|
||||
{
|
||||
mp3_header header;
|
||||
const uint8_t *p, *q;
|
||||
const uint8_t *p;
|
||||
long skip;
|
||||
long avail;
|
||||
|
||||
p = buf;
|
||||
q = p;
|
||||
avail = length;
|
||||
while (avail >= 4) {
|
||||
if (is_id3(p, avail)) {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/* -*- 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/. */
|
||||
@@ -415,18 +416,6 @@ nsFaviconService::GetFaviconLinkForIcon(nsIURI* aFaviconURI,
|
||||
}
|
||||
|
||||
|
||||
static PLDHashOperator
|
||||
ExpireFailedFaviconsCallback(nsCStringHashKey::KeyType aKey,
|
||||
uint32_t& aData,
|
||||
void* userArg)
|
||||
{
|
||||
uint32_t* threshold = reinterpret_cast<uint32_t*>(userArg);
|
||||
if (aData < *threshold)
|
||||
return PL_DHASH_REMOVE;
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFaviconService::AddFailedFavicon(nsIURI* aFaviconURI)
|
||||
{
|
||||
@@ -444,7 +433,11 @@ nsFaviconService::AddFailedFavicon(nsIURI* aFaviconURI)
|
||||
// of items that are the oldest
|
||||
uint32_t threshold = mFailedFaviconSerial -
|
||||
MAX_FAILED_FAVICONS + FAVICON_CACHE_REDUCE_COUNT;
|
||||
mFailedFavicons.Enumerate(ExpireFailedFaviconsCallback, &threshold);
|
||||
for (auto iter = mFailedFavicons.Iter(); !iter.Done(); iter.Next()) {
|
||||
if (iter.Data() < threshold) {
|
||||
iter.Remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -46,19 +46,6 @@ struct keywordSearchData
|
||||
nsString keyword;
|
||||
};
|
||||
|
||||
PLDHashOperator
|
||||
SearchBookmarkForKeyword(nsTrimInt64HashKey::KeyType aKey,
|
||||
const nsString aValue,
|
||||
void* aUserArg)
|
||||
{
|
||||
keywordSearchData* data = reinterpret_cast<keywordSearchData*>(aUserArg);
|
||||
if (data->keyword.Equals(aValue)) {
|
||||
data->itemId = aKey;
|
||||
return PL_DHASH_STOP;
|
||||
}
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
template<typename Method, typename DataType>
|
||||
class AsyncGetBookmarksForURI : public AsyncStatementCallback
|
||||
{
|
||||
@@ -2277,7 +2264,12 @@ nsNavBookmarks::UpdateKeywordsHashForRemovedBookmark(int64_t aItemId)
|
||||
keywordSearchData searchData;
|
||||
searchData.keyword.Assign(keyword);
|
||||
searchData.itemId = -1;
|
||||
mBookmarkToKeywordHash.EnumerateRead(SearchBookmarkForKeyword, &searchData);
|
||||
for (auto iter = mBookmarkToKeywordHash.Iter(); !iter.Done(); iter.Next()) {
|
||||
if (searchData.keyword.Equals(iter.Data())) {
|
||||
searchData.itemId = iter.Key();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (searchData.itemId == -1) {
|
||||
nsCOMPtr<mozIStorageAsyncStatement> stmt = mDB->GetAsyncStatement(
|
||||
"DELETE FROM moz_keywords "
|
||||
@@ -2469,7 +2461,12 @@ nsNavBookmarks::GetURIForKeyword(const nsAString& aUserCasedKeyword,
|
||||
keywordSearchData searchData;
|
||||
searchData.keyword.Assign(keyword);
|
||||
searchData.itemId = -1;
|
||||
mBookmarkToKeywordHash.EnumerateRead(SearchBookmarkForKeyword, &searchData);
|
||||
for (auto iter = mBookmarkToKeywordHash.Iter(); !iter.Done(); iter.Next()) {
|
||||
if (searchData.keyword.Equals(iter.Data())) {
|
||||
searchData.itemId = iter.Key();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (searchData.itemId == -1) {
|
||||
// Not found.
|
||||
|
||||
@@ -3833,22 +3833,15 @@ nsNavHistory::CheckIsRecentEvent(RecentEventHash* hashTable,
|
||||
//
|
||||
// This goes through our
|
||||
|
||||
static PLDHashOperator
|
||||
ExpireNonrecentEventsCallback(nsCStringHashKey::KeyType aKey,
|
||||
int64_t& aData,
|
||||
void* userArg)
|
||||
{
|
||||
int64_t* threshold = reinterpret_cast<int64_t*>(userArg);
|
||||
if (aData < *threshold)
|
||||
return PL_DHASH_REMOVE;
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
void
|
||||
nsNavHistory::ExpireNonrecentEvents(RecentEventHash* hashTable)
|
||||
{
|
||||
int64_t threshold = GetNow() - RECENT_EVENT_THRESHOLD;
|
||||
hashTable->Enumerate(ExpireNonrecentEventsCallback,
|
||||
reinterpret_cast<void*>(&threshold));
|
||||
for (auto iter = hashTable->Iter(); !iter.Done(); iter.Next()) {
|
||||
if (iter.Data() < threshold) {
|
||||
iter.Remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
//* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* -*- 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/. */
|
||||
@@ -3941,46 +3942,32 @@ nsNavHistorySeparatorResultNode::nsNavHistorySeparatorResultNode()
|
||||
}
|
||||
|
||||
|
||||
static PLDHashOperator
|
||||
RemoveBookmarkFolderObserversCallback(nsTrimInt64HashKey::KeyType aKey,
|
||||
nsNavHistoryResult::FolderObserverList*& aData,
|
||||
void* userArg)
|
||||
{
|
||||
delete aData;
|
||||
return PL_DHASH_REMOVE;
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(nsNavHistoryResult)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsNavHistoryResult)
|
||||
tmp->StopObserving();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mRootNode)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mObservers)
|
||||
tmp->mBookmarkFolderObservers.Enumerate(&RemoveBookmarkFolderObserversCallback, nullptr);
|
||||
for (auto it = tmp->mBookmarkFolderObservers.Iter(); !it.Done(); it.Next()) {
|
||||
delete it.Data();
|
||||
it.Remove();
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mAllBookmarksObservers)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mHistoryObservers)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
static PLDHashOperator
|
||||
TraverseBookmarkFolderObservers(nsTrimInt64HashKey::KeyType aKey,
|
||||
nsNavHistoryResult::FolderObserverList* &aData,
|
||||
void *aClosure)
|
||||
{
|
||||
nsCycleCollectionTraversalCallback* cb =
|
||||
static_cast<nsCycleCollectionTraversalCallback*>(aClosure);
|
||||
for (uint32_t i = 0; i < aData->Length(); ++i) {
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb,
|
||||
"mBookmarkFolderObservers value[i]");
|
||||
nsNavHistoryResultNode* node = aData->ElementAt(i);
|
||||
cb->NoteXPCOMChild(node);
|
||||
}
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsNavHistoryResult)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRootNode)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mObservers)
|
||||
tmp->mBookmarkFolderObservers.Enumerate(&TraverseBookmarkFolderObservers, &cb);
|
||||
for (auto it = tmp->mBookmarkFolderObservers.Iter(); !it.Done(); it.Next()) {
|
||||
nsNavHistoryResult::FolderObserverList*& list = it.Data();
|
||||
for (uint32_t i = 0; i < list->Length(); ++i) {
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
|
||||
"mBookmarkFolderObservers value[i]");
|
||||
nsNavHistoryResultNode* node = list->ElementAt(i);
|
||||
cb.NoteXPCOMChild(node);
|
||||
}
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAllBookmarksObservers)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mHistoryObservers)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
@@ -4012,8 +3999,11 @@ nsNavHistoryResult::nsNavHistoryResult(nsNavHistoryContainerResultNode* aRoot)
|
||||
|
||||
nsNavHistoryResult::~nsNavHistoryResult()
|
||||
{
|
||||
// delete all bookmark folder observer arrays which are allocated on the heap
|
||||
mBookmarkFolderObservers.Enumerate(&RemoveBookmarkFolderObserversCallback, nullptr);
|
||||
// Delete all heap-allocated bookmark folder observer arrays.
|
||||
for (auto it = mBookmarkFolderObservers.Iter(); !it.Done(); it.Next()) {
|
||||
delete it.Data();
|
||||
it.Remove();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
/* -*- 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/. */
|
||||
@@ -75,15 +77,6 @@ nsFormFillController::nsFormFillController() :
|
||||
MOZ_ASSERT(mController);
|
||||
}
|
||||
|
||||
struct PwmgrInputsEnumData
|
||||
{
|
||||
PwmgrInputsEnumData(nsFormFillController* aFFC, nsIDocument* aDoc)
|
||||
: mFFC(aFFC), mDoc(aDoc) {}
|
||||
|
||||
nsFormFillController* mFFC;
|
||||
nsCOMPtr<nsIDocument> mDoc;
|
||||
};
|
||||
|
||||
nsFormFillController::~nsFormFillController()
|
||||
{
|
||||
if (mListNode) {
|
||||
@@ -95,8 +88,7 @@ nsFormFillController::~nsFormFillController()
|
||||
mFocusedInputNode = nullptr;
|
||||
mFocusedInput = nullptr;
|
||||
}
|
||||
PwmgrInputsEnumData ed(this, nullptr);
|
||||
mPwmgrInputs.Enumerate(RemoveForDocumentEnumerator, &ed);
|
||||
RemoveForDocument(nullptr);
|
||||
|
||||
// Remove ourselves as a focus listener from all cached docShells
|
||||
uint32_t count = mDocShells.Length();
|
||||
@@ -867,28 +859,26 @@ nsFormFillController::HandleEvent(nsIDOMEvent* aEvent)
|
||||
StopControllingInput();
|
||||
}
|
||||
|
||||
PwmgrInputsEnumData ed(this, doc);
|
||||
mPwmgrInputs.Enumerate(RemoveForDocumentEnumerator, &ed);
|
||||
RemoveForDocument(doc);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
/* static */ PLDHashOperator
|
||||
nsFormFillController::RemoveForDocumentEnumerator(const nsINode* aKey,
|
||||
bool& aEntry,
|
||||
void* aUserData)
|
||||
void
|
||||
nsFormFillController::RemoveForDocument(nsIDocument* aDoc)
|
||||
{
|
||||
PwmgrInputsEnumData* ed = static_cast<PwmgrInputsEnumData*>(aUserData);
|
||||
if (aKey && (!ed->mDoc || aKey->OwnerDoc() == ed->mDoc)) {
|
||||
// mFocusedInputNode's observer is tracked separately, don't remove it here.
|
||||
if (aKey != ed->mFFC->mFocusedInputNode) {
|
||||
const_cast<nsINode*>(aKey)->RemoveMutationObserver(ed->mFFC);
|
||||
for (auto iter = mPwmgrInputs.Iter(); !iter.Done(); iter.Next()) {
|
||||
const nsINode* key = iter.Key();
|
||||
if (key && (!aDoc || key->OwnerDoc() == aDoc)) {
|
||||
// mFocusedInputNode's observer is tracked separately, so don't remove it
|
||||
// here.
|
||||
if (key != mFocusedInputNode) {
|
||||
const_cast<nsINode*>(key)->RemoveMutationObserver(this);
|
||||
}
|
||||
iter.Remove();
|
||||
}
|
||||
return PL_DHASH_REMOVE;
|
||||
}
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1134,8 +1124,7 @@ nsFormFillController::RemoveWindowListeners(nsIDOMWindow *aWindow)
|
||||
nsCOMPtr<nsIDOMDocument> domDoc;
|
||||
aWindow->GetDocument(getter_AddRefs(domDoc));
|
||||
nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
|
||||
PwmgrInputsEnumData ed(this, doc);
|
||||
mPwmgrInputs.Enumerate(RemoveForDocumentEnumerator, &ed);
|
||||
RemoveForDocument(doc);
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> privateDOMWindow(do_QueryInterface(aWindow));
|
||||
EventTarget* target = nullptr;
|
||||
|
||||
@@ -84,9 +84,7 @@ protected:
|
||||
|
||||
void MaybeRemoveMutationObserver(nsINode* aNode);
|
||||
|
||||
static PLDHashOperator RemoveForDocumentEnumerator(const nsINode* aKey,
|
||||
bool& aEntry,
|
||||
void* aUserData);
|
||||
void RemoveForDocument(nsIDocument* aDoc);
|
||||
bool IsEventTrusted(nsIDOMEvent *aEvent);
|
||||
// members //////////////////////////////////////////
|
||||
|
||||
|
||||
@@ -1449,6 +1449,11 @@
|
||||
"n_values": 32,
|
||||
"description": "H2: goaway reason from peer from rfc 7540. 31 is none received."
|
||||
},
|
||||
"HTTP_CONNECTION_ENTRY_CACHE_HIT_1" : {
|
||||
"expires_in_version": "never",
|
||||
"kind": "boolean",
|
||||
"description": "Fraction of sockets that used a nsConnectionEntry with history - size 300."
|
||||
},
|
||||
"DISK_CACHE_CORRUPT_DETAILS": {
|
||||
"expires_in_version": "40",
|
||||
"kind": "enumerated",
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
/* 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/. */
|
||||
|
||||
// Portions of this file are originally from narwhal.js (http://narwhaljs.org)
|
||||
// Copyright (c) 2009 Thomas Robinson <280north.com>
|
||||
// MIT license: http://opensource.org/licenses/MIT
|
||||
|
||||
"use strict";
|
||||
|
||||
this.EXPORTED_SYMBOLS = [
|
||||
"ObjectUtils"
|
||||
];
|
||||
|
||||
const {classes: Cc, interfaces: Ci, results: Cr, utils: Cu} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm", this);
|
||||
|
||||
// Used only to cause test failures.
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
||||
"resource://gre/modules/Promise.jsm");
|
||||
|
||||
this.ObjectUtils = {
|
||||
/**
|
||||
* This tests objects & values for deep equality.
|
||||
*
|
||||
* We check using the most exact approximation of equality between two objects
|
||||
* to keep the chance of false positives to a minimum.
|
||||
* `JSON.stringify` is not designed to be used for this purpose; objects may
|
||||
* have ambiguous `toJSON()` implementations that would influence the test.
|
||||
*
|
||||
* @param a (mixed) Object or value to be compared.
|
||||
* @param b (mixed) Object or value to be compared.
|
||||
* @return Boolean Whether the objects are deep equal.
|
||||
*/
|
||||
deepEqual: function(a, b) {
|
||||
return _deepEqual(a, b);
|
||||
},
|
||||
|
||||
/**
|
||||
* A thin wrapper on an object, designed to prevent client code from
|
||||
* accessing non-existent properties because of typos.
|
||||
*
|
||||
* // Without `strict`
|
||||
* let foo = { myProperty: 1 };
|
||||
* foo.MyProperty; // undefined
|
||||
*
|
||||
* // With `strict`
|
||||
* let strictFoo = ObjectUtils.strict(foo);
|
||||
* strictFoo.myProperty; // 1
|
||||
* strictFoo.MyProperty; // TypeError: No such property "MyProperty"
|
||||
*
|
||||
* Note that `strict` has no effect in non-DEBUG mode.
|
||||
*/
|
||||
strict: function(obj) {
|
||||
return _strict(obj);
|
||||
}
|
||||
};
|
||||
|
||||
// ... Start of previously MIT-licensed code.
|
||||
// This deepEqual implementation is originally from narwhal.js (http://narwhaljs.org)
|
||||
// Copyright (c) 2009 Thomas Robinson <280north.com>
|
||||
// MIT license: http://opensource.org/licenses/MIT
|
||||
|
||||
function _deepEqual(a, b) {
|
||||
// The numbering below refers to sections in the CommonJS spec.
|
||||
|
||||
// 7.1 All identical values are equivalent, as determined by ===.
|
||||
if (a === b) {
|
||||
return true;
|
||||
// 7.2 If the b value is a Date object, the a value is
|
||||
// equivalent if it is also a Date object that refers to the same time.
|
||||
} else if (instanceOf(a, "Date") && instanceOf(b, "Date")) {
|
||||
if (isNaN(a.getTime()) && isNaN(b.getTime()))
|
||||
return true;
|
||||
return a.getTime() === b.getTime();
|
||||
// 7.3 If the b value is a RegExp object, the a value is
|
||||
// equivalent if it is also a RegExp object with the same source and
|
||||
// properties (`global`, `multiline`, `lastIndex`, `ignoreCase`).
|
||||
} else if (instanceOf(a, "RegExp") && instanceOf(b, "RegExp")) {
|
||||
return a.source === b.source &&
|
||||
a.global === b.global &&
|
||||
a.multiline === b.multiline &&
|
||||
a.lastIndex === b.lastIndex &&
|
||||
a.ignoreCase === b.ignoreCase;
|
||||
// 7.4 Other pairs that do not both pass typeof value == "object",
|
||||
// equivalence is determined by ==.
|
||||
} else if (typeof a != "object" && typeof b != "object") {
|
||||
return a == b;
|
||||
// 7.5 For all other Object pairs, including Array objects, equivalence is
|
||||
// determined by having the same number of owned properties (as verified
|
||||
// with Object.prototype.hasOwnProperty.call), the same set of keys
|
||||
// (although not necessarily the same order), equivalent values for every
|
||||
// corresponding key, and an identical 'prototype' property. Note: this
|
||||
// accounts for both named and indexed properties on Arrays.
|
||||
} else {
|
||||
return objEquiv(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
function instanceOf(object, type) {
|
||||
return Object.prototype.toString.call(object) == "[object " + type + "]";
|
||||
}
|
||||
|
||||
function isUndefinedOrNull(value) {
|
||||
return value === null || value === undefined;
|
||||
}
|
||||
|
||||
function isArguments(object) {
|
||||
return instanceOf(object, "Arguments");
|
||||
}
|
||||
|
||||
function objEquiv(a, b) {
|
||||
if (isUndefinedOrNull(a) || isUndefinedOrNull(b)) {
|
||||
return false;
|
||||
}
|
||||
// An identical 'prototype' property.
|
||||
if ((a.prototype || undefined) != (b.prototype || undefined)) {
|
||||
return false;
|
||||
}
|
||||
// Object.keys may be broken through screwy arguments passing. Converting to
|
||||
// an array solves the problem.
|
||||
if (isArguments(a)) {
|
||||
if (!isArguments(b)) {
|
||||
return false;
|
||||
}
|
||||
a = pSlice.call(a);
|
||||
b = pSlice.call(b);
|
||||
return _deepEqual(a, b);
|
||||
}
|
||||
let ka, kb;
|
||||
try {
|
||||
ka = Object.keys(a);
|
||||
kb = Object.keys(b);
|
||||
} catch (e) {
|
||||
// Happens when one is a string literal and the other isn't
|
||||
return false;
|
||||
}
|
||||
// Having the same number of owned properties (keys incorporates
|
||||
// hasOwnProperty)
|
||||
if (ka.length != kb.length)
|
||||
return false;
|
||||
// The same set of keys (although not necessarily the same order),
|
||||
ka.sort();
|
||||
kb.sort();
|
||||
// Equivalent values for every corresponding key, and possibly expensive deep
|
||||
// test
|
||||
for (let key of ka) {
|
||||
if (!_deepEqual(a[key], b[key])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// ... End of previously MIT-licensed code.
|
||||
|
||||
function _strict(obj) {
|
||||
if (typeof obj != "object") {
|
||||
throw new TypeError("Expected an object");
|
||||
}
|
||||
|
||||
return new Proxy(obj, {
|
||||
get: function(target, name) {
|
||||
if (name in obj) {
|
||||
return obj[name];
|
||||
}
|
||||
|
||||
let error = new TypeError(`No such property: "${name}"`);
|
||||
Promise.reject(error); // Cause an xpcshell/mochitest failure.
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -34,6 +34,7 @@ EXTRA_JS_MODULES += [
|
||||
'LoadContextInfo.jsm',
|
||||
'Log.jsm',
|
||||
'NewTabUtils.jsm',
|
||||
'ObjectUtils.jsm',
|
||||
'PageMenu.jsm',
|
||||
'PageMetadata.jsm',
|
||||
'PermissionsUtils.jsm',
|
||||
|
||||
@@ -230,7 +230,9 @@ int NS_main(int argc, NS_tchar **argv)
|
||||
NS_tfputs(NS_T("test"), file);
|
||||
fclose(file);
|
||||
}
|
||||
symlink(path, argv[5]);
|
||||
if (symlink(path, argv[5]) != 0) {
|
||||
return 1;
|
||||
}
|
||||
NS_tsnprintf(path, sizeof(path)/sizeof(path[0]),
|
||||
NS_T("%s/%s"), NS_T("/tmp"), argv[2]);
|
||||
if (argc > 6 && !NS_tstrcmp(argv[6], NS_T("change-perm"))) {
|
||||
|
||||
@@ -54,6 +54,3 @@ if CONFIG['OS_ARCH'] == 'WINNT':
|
||||
USE_STATIC_LIBS = True
|
||||
if CONFIG['GNU_CC']:
|
||||
WIN32_EXE_LDFLAGS += ['-municode']
|
||||
|
||||
# XXX: We should fix these warnings
|
||||
ALLOW_COMPILER_WARNINGS = True
|
||||
|
||||
+11
-12
@@ -2685,20 +2685,19 @@ moz_gtk_get_widget_border(GtkThemeWidgetType widget, gint* left, gint* top,
|
||||
|
||||
*left = *top = *right = *bottom = gtk_container_get_border_width(GTK_CONTAINER(gButtonWidget));
|
||||
|
||||
/* Don't add this padding in HTML, otherwise the buttons will
|
||||
become too big and stuff the layout. */
|
||||
if (!inhtml) {
|
||||
if (widget == MOZ_GTK_TOOLBAR_BUTTON) {
|
||||
gtk_style_context_save(style);
|
||||
gtk_style_context_add_class(style, "image-button");
|
||||
}
|
||||
|
||||
moz_gtk_add_style_padding(style, left, top, right, bottom);
|
||||
|
||||
if (widget == MOZ_GTK_TOOLBAR_BUTTON)
|
||||
gtk_style_context_restore(style);
|
||||
if (widget == MOZ_GTK_TOOLBAR_BUTTON) {
|
||||
gtk_style_context_save(style);
|
||||
gtk_style_context_add_class(style, "image-button");
|
||||
}
|
||||
|
||||
moz_gtk_add_style_padding(style, left, top, right, bottom);
|
||||
|
||||
if (widget == MOZ_GTK_TOOLBAR_BUTTON)
|
||||
gtk_style_context_restore(style);
|
||||
|
||||
// XXX: Subtract 1 pixel from the border to account for the added
|
||||
// -moz-focus-inner border (Bug 1228281).
|
||||
*left -= 1; *top -= 1; *right -= 1; *bottom -= 1;
|
||||
moz_gtk_add_style_border(style, left, top, right, bottom);
|
||||
return MOZ_GTK_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -10,20 +10,8 @@
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/Move.h"
|
||||
#include "nsTHashtable.h"
|
||||
#include "prlock.h"
|
||||
#include "nsDebug.h"
|
||||
|
||||
// These are the codes returned by |EnumReadFunction| and |EnumFunction|, which
|
||||
// control the behavior of EnumerateRead() and Enumerate(). The PLD/PL_D prefix
|
||||
// is because they originated in PLDHashTable, but that class no longer uses
|
||||
// them.
|
||||
enum PLDHashOperator
|
||||
{
|
||||
PL_DHASH_NEXT = 0, // enumerator says continue
|
||||
PL_DHASH_STOP = 1, // enumerator says stop
|
||||
PL_DHASH_REMOVE = 2 // enumerator says remove
|
||||
};
|
||||
|
||||
template<class KeyClass, class DataType, class UserDataType>
|
||||
class nsBaseHashtable; // forward declaration
|
||||
|
||||
@@ -158,79 +146,6 @@ public:
|
||||
*/
|
||||
void Remove(KeyType aKey) { this->RemoveEntry(aKey); }
|
||||
|
||||
/**
|
||||
* function type provided by the application for enumeration.
|
||||
* @param aKey the key being enumerated
|
||||
* @param aData data being enumerated
|
||||
* @param aUserArg passed unchanged from Enumerate
|
||||
* @return either
|
||||
* @link PLDHashOperator::PL_DHASH_NEXT PL_DHASH_NEXT @endlink or
|
||||
* @link PLDHashOperator::PL_DHASH_STOP PL_DHASH_STOP @endlink
|
||||
*/
|
||||
typedef PLDHashOperator (*EnumReadFunction)(KeyType aKey,
|
||||
UserDataType aData,
|
||||
void* aUserArg);
|
||||
|
||||
/**
|
||||
* enumerate entries in the hashtable, without allowing changes
|
||||
* WARNING: this function is deprecated. Please use Iterator instead.
|
||||
* @param aEnumFunc enumeration callback
|
||||
* @param aUserArg passed unchanged to the EnumReadFunction
|
||||
*/
|
||||
uint32_t EnumerateRead(EnumReadFunction aEnumFunc, void* aUserArg) const
|
||||
{
|
||||
uint32_t n = 0;
|
||||
for (auto iter = this->mTable.ConstIter(); !iter.Done(); iter.Next()) {
|
||||
auto entry = static_cast<EntryType*>(iter.Get());
|
||||
PLDHashOperator op = aEnumFunc(entry->GetKey(), entry->mData, aUserArg);
|
||||
n++;
|
||||
MOZ_ASSERT(!(op & PL_DHASH_REMOVE));
|
||||
if (op & PL_DHASH_STOP) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* function type provided by the application for enumeration.
|
||||
* @param aKey the key being enumerated
|
||||
* @param aData Reference to data being enumerated, may be altered. e.g. for
|
||||
* nsInterfaceHashtable this is an nsCOMPtr reference...
|
||||
* @parm aUserArg passed unchanged from Enumerate
|
||||
* @return bitflag combination of
|
||||
* @link PLDHashOperator::PL_DHASH_REMOVE @endlink,
|
||||
* @link PLDHashOperator::PL_DHASH_NEXT PL_DHASH_NEXT @endlink, or
|
||||
* @link PLDHashOperator::PL_DHASH_STOP PL_DHASH_STOP @endlink
|
||||
*/
|
||||
typedef PLDHashOperator (*EnumFunction)(KeyType aKey,
|
||||
DataType& aData,
|
||||
void* aUserArg);
|
||||
|
||||
/**
|
||||
* enumerate entries in the hashtable, allowing changes.
|
||||
* WARNING: this function is deprecated. Please use Iterator and/or
|
||||
* MutatingIterator instead.
|
||||
* @param aEnumFunc enumeration callback
|
||||
* @param aUserArg passed unchanged to the EnumFunction
|
||||
*/
|
||||
uint32_t Enumerate(EnumFunction aEnumFunc, void* aUserArg)
|
||||
{
|
||||
uint32_t n = 0;
|
||||
for (auto iter = this->mTable.Iter(); !iter.Done(); iter.Next()) {
|
||||
auto entry = static_cast<EntryType*>(iter.Get());
|
||||
PLDHashOperator op = aEnumFunc(entry->GetKey(), entry->mData, aUserArg);
|
||||
n++;
|
||||
if (op & PL_DHASH_REMOVE) {
|
||||
iter.Remove();
|
||||
}
|
||||
if (op & PL_DHASH_STOP) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
// This is an iterator that also allows entry removal. Example usage:
|
||||
//
|
||||
// for (auto iter = table.Iter(); !iter.Done(); iter.Next()) {
|
||||
|
||||
@@ -170,32 +170,6 @@ testTHashtable(nsTHashtable<EntityToUnicodeEntry>& hash, uint32_t numEntries) {
|
||||
}
|
||||
}
|
||||
|
||||
PLDHashOperator
|
||||
nsDEnumRead(const uint32_t& aKey, const char* aData, void* userArg) {
|
||||
printf(" enumerated %u = \"%s\"\n", aKey, aData);
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
PLDHashOperator
|
||||
nsDEnum(const uint32_t& aKey, const char*& aData, void* userArg) {
|
||||
printf(" enumerated %u = \"%s\"\n", aKey, aData);
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
PLDHashOperator
|
||||
nsCEnumRead(const nsACString& aKey, TestUniChar* aData, void* userArg) {
|
||||
printf(" enumerated \"%s\" = %c\n",
|
||||
PromiseFlatCString(aKey).get(), aData->GetChar());
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
PLDHashOperator
|
||||
nsCEnum(const nsACString& aKey, nsAutoPtr<TestUniChar>& aData, void* userArg) {
|
||||
printf(" enumerated \"%s\" = %c\n",
|
||||
PromiseFlatCString(aKey).get(), aData->GetChar());
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
//
|
||||
// all this nsIFoo stuff was copied wholesale from TestCOMPtr.cpp
|
||||
//
|
||||
@@ -339,45 +313,6 @@ CreateIFoo( IFoo** result )
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PLDHashOperator
|
||||
nsIEnumRead(const uint32_t& aKey, IFoo* aFoo, void* userArg) {
|
||||
nsAutoCString str;
|
||||
aFoo->GetString(str);
|
||||
|
||||
printf(" enumerated %u = \"%s\"\n", aKey, str.get());
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
PLDHashOperator
|
||||
nsIEnum(const uint32_t& aKey, nsCOMPtr<IFoo>& aData, void* userArg) {
|
||||
nsAutoCString str;
|
||||
aData->GetString(str);
|
||||
|
||||
printf(" enumerated %u = \"%s\"\n", aKey, str.get());
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
PLDHashOperator
|
||||
nsIEnum2Read(nsISupports* aKey, uint32_t aData, void* userArg) {
|
||||
nsAutoCString str;
|
||||
nsCOMPtr<IFoo> foo = do_QueryInterface(aKey);
|
||||
foo->GetString(str);
|
||||
|
||||
|
||||
printf(" enumerated \"%s\" = %u\n", str.get(), aData);
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
PLDHashOperator
|
||||
nsIEnum2(nsISupports* aKey, uint32_t& aData, void* userArg) {
|
||||
nsAutoCString str;
|
||||
nsCOMPtr<IFoo> foo = do_QueryInterface(aKey);
|
||||
foo->GetString(str);
|
||||
|
||||
printf(" enumerated \"%s\" = %u\n", str.get(), aData);
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
} // namespace TestHashtables
|
||||
|
||||
using namespace TestHashtables;
|
||||
@@ -402,7 +337,7 @@ main(void) {
|
||||
|
||||
printf("Check enumeration...");
|
||||
count = nsTIterPrint(EntityToUnicode);
|
||||
if (count) {
|
||||
if (count != 0) {
|
||||
printf("entries remain in table!\n");
|
||||
exit (8);
|
||||
}
|
||||
@@ -417,7 +352,7 @@ main(void) {
|
||||
|
||||
printf("Check enumeration...");
|
||||
count = nsTIterPrint(EntityToUnicode);
|
||||
if (count) {
|
||||
if (count != 0) {
|
||||
printf("entries remain in table!\n");
|
||||
exit (9);
|
||||
}
|
||||
@@ -458,24 +393,32 @@ main(void) {
|
||||
printf("FOUND! BAD!\n");
|
||||
exit (13);
|
||||
}
|
||||
|
||||
|
||||
printf("not found; good.\n");
|
||||
|
||||
|
||||
printf("Enumerating:\n");
|
||||
|
||||
count = UniToEntity.EnumerateRead(nsDEnumRead, nullptr);
|
||||
|
||||
count = 0;
|
||||
for (auto iter = UniToEntity.Iter(); !iter.Done(); iter.Next()) {
|
||||
printf(" enumerated %u = \"%s\"\n", iter.Key(), iter.UserData());
|
||||
count++;
|
||||
}
|
||||
if (count != ENTITY_COUNT) {
|
||||
printf(" Bad count!\n");
|
||||
exit (14);
|
||||
}
|
||||
|
||||
|
||||
printf("Clearing...");
|
||||
UniToEntity.Clear();
|
||||
printf("OK\n");
|
||||
|
||||
printf("Checking count...");
|
||||
count = UniToEntity.Enumerate(nsDEnum, nullptr);
|
||||
if (count) {
|
||||
count = 0;
|
||||
for (auto iter = UniToEntity.Iter(); !iter.Done(); iter.Next()) {
|
||||
printf(" enumerated %u = \"%s\"\n", iter.Key(), iter.Data());
|
||||
count++;
|
||||
}
|
||||
if (count != 0) {
|
||||
printf(" Clear did not remove all entries.\n");
|
||||
exit (15);
|
||||
}
|
||||
@@ -518,24 +461,34 @@ main(void) {
|
||||
printf("FOUND! BAD!\n");
|
||||
exit (19);
|
||||
}
|
||||
|
||||
|
||||
printf("not found; good.\n");
|
||||
|
||||
|
||||
printf("Enumerating:\n");
|
||||
|
||||
count = EntToUniClass.EnumerateRead(nsCEnumRead, nullptr);
|
||||
|
||||
count = 0;
|
||||
for (auto iter = EntToUniClass.Iter(); !iter.Done(); iter.Next()) {
|
||||
printf(" enumerated \"%s\" = %c\n",
|
||||
PromiseFlatCString(iter.Key()).get(), iter.UserData()->GetChar());
|
||||
count++;
|
||||
}
|
||||
if (count != ENTITY_COUNT) {
|
||||
printf(" Bad count!\n");
|
||||
exit (20);
|
||||
}
|
||||
|
||||
|
||||
printf("Clearing...\n");
|
||||
EntToUniClass.Clear();
|
||||
printf(" Clearing OK\n");
|
||||
|
||||
printf("Checking count...");
|
||||
count = EntToUniClass.Enumerate(nsCEnum, nullptr);
|
||||
if (count) {
|
||||
count = 0;
|
||||
for (auto iter = EntToUniClass.Iter(); !iter.Done(); iter.Next()) {
|
||||
printf(" enumerated \"%s\" = %c\n",
|
||||
PromiseFlatCString(iter.Key()).get(), iter.Data()->GetChar());
|
||||
count++;
|
||||
}
|
||||
if (count != 0) {
|
||||
printf(" Clear did not remove all entries.\n");
|
||||
exit (21);
|
||||
}
|
||||
@@ -571,7 +524,7 @@ main(void) {
|
||||
|
||||
for (i = 0; i < ENTITY_COUNT; ++i) {
|
||||
printf(" Getting entry %s...", gEntities[i].mStr);
|
||||
|
||||
|
||||
if (!EntToUniClass2.Get(fooArray[i], &myChar2)) {
|
||||
printf("FAILED\n");
|
||||
exit (24);
|
||||
@@ -585,24 +538,38 @@ main(void) {
|
||||
printf("FOUND! BAD!\n");
|
||||
exit (25);
|
||||
}
|
||||
|
||||
|
||||
printf("not found; good.\n");
|
||||
|
||||
|
||||
printf("Enumerating:\n");
|
||||
|
||||
count = EntToUniClass2.EnumerateRead(nsIEnum2Read, nullptr);
|
||||
|
||||
count = 0;
|
||||
for (auto iter = EntToUniClass2.Iter(); !iter.Done(); iter.Next()) {
|
||||
nsAutoCString s;
|
||||
nsCOMPtr<IFoo> foo = do_QueryInterface(iter.Key());
|
||||
foo->GetString(s);
|
||||
printf(" enumerated \"%s\" = %u\n", s.get(), iter.UserData());
|
||||
count++;
|
||||
}
|
||||
if (count != ENTITY_COUNT) {
|
||||
printf(" Bad count!\n");
|
||||
exit (26);
|
||||
}
|
||||
|
||||
|
||||
printf("Clearing...\n");
|
||||
EntToUniClass2.Clear();
|
||||
printf(" Clearing OK\n");
|
||||
|
||||
printf("Checking count...");
|
||||
count = EntToUniClass2.Enumerate(nsIEnum2, nullptr);
|
||||
if (count) {
|
||||
count = 0;
|
||||
for (auto iter = EntToUniClass2.Iter(); !iter.Done(); iter.Next()) {
|
||||
nsAutoCString s;
|
||||
nsCOMPtr<IFoo> foo = do_QueryInterface(iter.Key());
|
||||
foo->GetString(s);
|
||||
printf(" enumerated \"%s\" = %u\n", s.get(), iter.Data());
|
||||
count++;
|
||||
}
|
||||
if (count != 0) {
|
||||
printf(" Clear did not remove all entries.\n");
|
||||
exit (27);
|
||||
}
|
||||
@@ -633,7 +600,7 @@ main(void) {
|
||||
|
||||
for (i = 0; i < ENTITY_COUNT; ++i) {
|
||||
printf(" Getting entry %s...", gEntities[i].mStr);
|
||||
|
||||
|
||||
nsCOMPtr<IFoo> myEnt;
|
||||
if (!UniToEntClass2.Get(gEntities[i].mUnicode, getter_AddRefs(myEnt))) {
|
||||
printf("FAILED\n");
|
||||
@@ -651,24 +618,36 @@ main(void) {
|
||||
printf("FOUND! BAD!\n");
|
||||
exit (31);
|
||||
}
|
||||
|
||||
|
||||
printf("not found; good.\n");
|
||||
|
||||
|
||||
printf("Enumerating:\n");
|
||||
|
||||
count = UniToEntClass2.EnumerateRead(nsIEnumRead, nullptr);
|
||||
|
||||
count = 0;
|
||||
for (auto iter = UniToEntClass2.Iter(); !iter.Done(); iter.Next()) {
|
||||
nsAutoCString s;
|
||||
iter.UserData()->GetString(s);
|
||||
printf(" enumerated %u = \"%s\"\n", iter.Key(), s.get());
|
||||
count++;
|
||||
}
|
||||
if (count != ENTITY_COUNT) {
|
||||
printf(" Bad count!\n");
|
||||
exit (32);
|
||||
}
|
||||
|
||||
|
||||
printf("Clearing...\n");
|
||||
UniToEntClass2.Clear();
|
||||
printf(" Clearing OK\n");
|
||||
|
||||
printf("Checking count...");
|
||||
count = UniToEntClass2.Enumerate(nsIEnum, nullptr);
|
||||
if (count) {
|
||||
count = 0;
|
||||
for (auto iter = UniToEntClass2.Iter(); !iter.Done(); iter.Next()) {
|
||||
nsAutoCString s;
|
||||
iter.Data()->GetString(s);
|
||||
printf(" enumerated %u = \"%s\"\n", iter.Key(), s.get());
|
||||
count++;
|
||||
}
|
||||
if (count != 0) {
|
||||
printf(" Clear did not remove all entries.\n");
|
||||
exit (33);
|
||||
}
|
||||
|
||||
@@ -345,8 +345,8 @@ TEST(PLDHashTableTest, GrowToMaxCapacity)
|
||||
numInserted++;
|
||||
}
|
||||
|
||||
// We stop when the element count is 96.875% of PL_DHASH_MAX_SIZE (see
|
||||
// MaxLoadOnGrowthFailure()).
|
||||
// We stop when the element count is 96.875% of PLDHashTable::kMaxCapacity
|
||||
// (see MaxLoadOnGrowthFailure()).
|
||||
if (numInserted !=
|
||||
PLDHashTable::kMaxCapacity - (PLDHashTable::kMaxCapacity >> 5)) {
|
||||
delete t;
|
||||
|
||||
Reference in New Issue
Block a user