From 14f7ec3aac36f728e5e982505318d7dd2255cbf7 Mon Sep 17 00:00:00 2001 From: roytam1 Date: Thu, 10 Jun 2021 09:41:02 +0800 Subject: [PATCH] import changes from `dev' branch of rmottola/Arctic-Fox: - Bug 1173947 - Make getRandomValues message be urgent (r=mrbkap) (aca1a06a9) - Bug 1182824 - Part 1: Use move assignment rather than copy assignment with ContextState::dash. r=mattwoodrow (73af33d32) - Bug 1182824 - Part 2: Make ContextState::dash a nsTArray. r=mattwoodrow (c66c3105d) - Bug 1134166 - Restart toolbox if selected app re-opens. r=ochameau (e370c8f02) - Bug 1134166 - Close toolbox if selected app dies. r=ochameau (5acb76254) - Bug 1134166 - Check for project when updating toolbox state. r=me (c60bb8766) - Bug 1090949 - Add way to make WebIDE runtimes configurable. r=ochameau (eef01e3e6) - Bug 1090949 - Refactor WebIDE preferences panel style. r=ochameau (fe1a9c757) - Bug 1135191 - Add runtime panel with toggle. r=jryans (e2e290a67) - missing bit of Bug 1116188 - Add async ProfileGatherer (308cfdd4f) - Bug 1185737 - Propagate pause and resume commands to child processes. r=BenWa (2dd302569) - Bug 1161831 - Stop using threaddsafe ISupports for nsResProtocolHandler. r=billm (0bec61aac) - Bug 1155968 - Correct indent not multiple of 4. r=khuey (5fb8e3b20) - Bug 1183291 - Factor idl-parser into a Python package. r=khuey (63a2f0c68) - Bug 1155968 - Add blank lines where needed in xpcom/idl-parser. r=khuey (ce91a905b) - Bug 1161831 - Generate an extra macro to declare a non-virtual variant of an interface. r=billm (058876228) - Bug 1161831 - Factor the sharable bits out of nsIResProtocolHandler. r=billm (b02278fb9) - Bug 1152997 - Cleanup app update build to exclude android. r=glandium, r=mossop (6cd935294) - Bug 1170075 - Remove Print Progress UI and view source XUL files from Android. r=snorp (64796ae4a) - Bug 1180921 - Create a dumping ground for simple services in toolkit/components/utils. r=Gijs (2757d43c8) - Bug 1180921 - Support custom callbacks for allowing access per-addon load access to cross-origin URIs. r=bz,r=billm (8cc7e2c96) - Bug 1161831 - Implement moz-extension protocol. r=bz,r=billm,sr=mcmanus (5ee451357) - Bug 1161831 - Associate extension URIs with the appropriate addon ID. r=billm,sr=bz (f36655ac9) - Bug 1161831 - Forbid mapping to anything but file:// and jar:// URIs. r=billm,sr=bz (144add9de) - Bug 1180921 - Generalize test_origin to make it easier to add new origin attributes. r=gabor (b3fbc3545) - Bug 1180921 - Add the addonId OriginAttribute. r=bholley (0723d0dec) - Bug 1174093 - Don't recurse into caps/tests/mochitest during the build; r=mshal (76366d21a) - Bug 1161831 - Tests. r=billm (ed116a703) - Bug 1155547, Part 1: Fix unified build breakage in adding new sources under dom/ipc/. r=khuey (0d6875348) - Bug 1166985 - Use two image decoding threads on dual core devices. r=tn (7f07ee8b8) - Bug 1160422 - Prioritize size decodes over full decodes. r=tn (48d42c011) - Bug 1151672 - Part 1: Remove the calls to nsThreadManager::SetThreadWorking() and nsThreadManager::SetThreadIdle() due to backout of bug 970307. r=seth (0428dd4a4) - Bug 1151672 - Part 2: Block PHal::Msg_NotifyNetworkChange__ID to the Nuwa process after it is ready. r=khuey (42debf2c0) - Bug 1176034 - MessagePort should force a close() if the structured clone algorithm fails, r=bent (3afe74856) - Bug 1176034 - Implement JSAutoStructuredCloneBuffer::clear(with callbacks and closure), r=sfink (f28f6852b) - Bug 1155547, Part 2: Create PNuwa protocol (managed by PBackground) for forking content processes. r=khuey (047bc5e61) - missing bit of Bug 1170075 - Remove Print Progress UI and view source XUL (a08888308) --- browser/installer/package-manifest.in | 3 +- caps/BasePrincipal.cpp | 27 ++ caps/BasePrincipal.h | 7 +- caps/moz.build | 10 +- caps/nsIAddonPolicyService.idl | 32 ++ caps/nsNullPrincipal.h | 4 +- caps/nsPrincipal.cpp | 6 + caps/nsPrincipal.h | 8 +- caps/nsScriptSecurityManager.cpp | 30 ++ caps/nsScriptSecurityManager.h | 19 + caps/tests/mochitest/chrome.ini | 1 + caps/tests/mochitest/file_data.txt | 1 + caps/tests/mochitest/mochitest.ini | 3 + caps/tests/mochitest/resource_test_file.html | 2 + caps/tests/mochitest/test_addonMayLoad.html | 97 +++++ caps/tests/mochitest/test_extensionURL.html | 144 +++++++ caps/tests/unit/test_origin.js | 27 +- chrome/RegistryMessageUtils.h | 29 +- chrome/nsChromeRegistryChrome.cpp | 2 +- chrome/nsChromeRegistryContent.cpp | 22 +- chrome/nsChromeRegistryContent.h | 6 +- dom/base/PostMessageEvent.cpp | 8 +- dom/base/test/chrome/cpows_child.js | 4 + dom/canvas/CanvasRenderingContext2D.cpp | 12 +- dom/canvas/CanvasRenderingContext2D.h | 2 +- dom/canvas/CanvasUtils.h | 14 +- dom/ipc/ContentChild.cpp | 241 ++--------- dom/ipc/ContentChild.h | 10 +- dom/ipc/ContentParent.cpp | 82 ++-- dom/ipc/ContentParent.h | 20 +- dom/ipc/NuwaChild.cpp | 256 ++++++++++++ dom/ipc/NuwaChild.h | 34 ++ dom/ipc/NuwaParent.cpp | 263 ++++++++++++ dom/ipc/NuwaParent.h | 73 ++++ dom/ipc/PContent.ipdl | 16 +- dom/ipc/PNuwa.ipdl | 31 ++ dom/ipc/PreallocatedProcessManager.cpp | 9 +- dom/ipc/ScreenManagerParent.cpp | 1 + dom/ipc/StructuredCloneUtils.cpp | 1 + dom/ipc/TabChild.cpp | 3 + dom/ipc/moz.build | 5 + dom/ipc/nsIContentChild.h | 1 + dom/messagechannel/MessagePort.cpp | 51 +++ dom/messagechannel/MessagePort.h | 3 + dom/messagechannel/MessagePortParent.cpp | 14 + dom/messagechannel/MessagePortParent.h | 4 + dom/messagechannel/MessagePortService.cpp | 50 +++ dom/messagechannel/MessagePortService.h | 5 + dom/messagechannel/MessagePortUtils.cpp | 18 +- dom/messagechannel/tests/mochitest.ini | 1 + .../tests/test_messageChannel_forceClose.html | 36 ++ dom/webidl/ChromeUtils.webidl | 1 + dom/workers/WorkerPrivate.cpp | 37 +- image/DecodePool.cpp | 62 ++- ipc/glue/BackgroundChildImpl.cpp | 17 + ipc/glue/BackgroundChildImpl.h | 6 + ipc/glue/BackgroundParentImpl.cpp | 32 ++ ipc/glue/BackgroundParentImpl.h | 14 + ipc/glue/MessageLink.cpp | 9 +- ipc/glue/PBackground.ipdl | 6 + js/public/StructuredClone.h | 2 +- js/src/vm/StructuredClone.cpp | 26 +- netwerk/build/nsNetCID.h | 18 +- netwerk/build/nsNetModule.cpp | 15 +- .../protocol/res/ExtensionProtocolHandler.cpp | 16 + .../protocol/res/ExtensionProtocolHandler.h | 35 ++ .../res/SubstitutingProtocolHandler.cpp | 381 ++++++++++++++++++ .../res/SubstitutingProtocolHandler.h | 83 ++++ netwerk/protocol/res/moz.build | 3 + .../protocol/res/nsIResProtocolHandler.idl | 37 +- .../res/nsISubstitutingProtocolHandler.idl | 46 +++ netwerk/protocol/res/nsResProtocolHandler.cpp | 373 +---------------- netwerk/protocol/res/nsResProtocolHandler.h | 45 +-- .../mozbuild/mozbuild/action/xpidl-process.py | 6 +- .../addoncompat/addoncompat.manifest | 2 - toolkit/components/addoncompat/moz.build | 1 - .../addoncompat/remoteTagService.js | 39 -- toolkit/components/build/nsToolkitCompsCID.h | 10 +- .../components/build/nsToolkitCompsModule.cpp | 10 +- toolkit/components/moz.build | 12 +- toolkit/components/timermanager/moz.build | 21 + .../timermanager}/nsIUpdateTimerManager.idl | 0 .../timermanager}/nsUpdateTimerManager.js | 0 .../nsUpdateTimerManager.manifest | 0 .../tests/unit}/consumerNotifications.js | 0 .../timermanager/tests/unit}/xpcshell.ini | 0 .../components/utils}/moz.build | 7 +- toolkit/components/utils/simpleServices.js | 133 ++++++ toolkit/components/utils/utils.manifest | 4 + toolkit/devtools/apps/app-actor-front.js | 6 +- toolkit/devtools/webide/content/jar.mn | 3 + toolkit/devtools/webide/content/prefs.xhtml | 33 +- .../webide/content/project-listing.js | 20 +- .../webide/content/project-listing.xhtml | 2 +- .../devtools/webide/content/project-panel.js | 46 +-- .../webide/content/runtime-listing.js | 61 +++ .../webide/content/runtime-listing.xhtml | 43 ++ .../devtools/webide/content/runtime-panel.js | 26 ++ toolkit/devtools/webide/content/webide.js | 363 +++++++---------- toolkit/devtools/webide/content/webide.xul | 19 +- .../devtools/webide/modules/app-manager.js | 6 +- .../devtools/webide/modules/project-list.js | 84 +++- .../devtools/webide/modules/runtime-list.js | 232 +++++++++++ toolkit/devtools/webide/modules/runtimes.js | 2 + toolkit/devtools/webide/moz.build | 1 + toolkit/devtools/webide/test/browser_tabs.js | 3 +- toolkit/devtools/webide/test/head.js | 25 +- .../devtools/webide/test/sidebars/browser.ini | 5 + .../webide/test/sidebars/browser_tabs.js | 75 ++++ .../devtools/webide/test/sidebars/chrome.ini | 16 +- .../webide/test/sidebars/test_addons.html | 178 ++++++++ .../sidebars/test_autoconnect_runtime.html | 93 +++++ .../sidebars/test_autoselect_project.html | 93 +++++ .../sidebars/test_device_permissions.html | 83 ++++ .../sidebars/test_device_preferences.html | 90 +++++ .../test/sidebars/test_device_settings.html | 91 +++++ .../test/sidebars/test_duplicate_import.html | 4 +- .../test/sidebars/test_fullscreenToolbox.html | 72 ++++ .../webide/test/sidebars/test_import.html | 4 +- .../test/sidebars/test_manifestUpdate.html | 95 +++++ .../webide/test/sidebars/test_newapp.html | 46 +++ .../webide/test/sidebars/test_runtime.html | 76 +++- .../webide/test/sidebars/test_telemetry.html | 268 ++++++++++++ .../webide/test/test_autoconnect_runtime.html | 7 +- .../webide/test/test_autoselect_project.html | 7 +- .../devtools/webide/test/test_runtime.html | 2 +- toolkit/devtools/webide/themes/deck.css | 13 + toolkit/devtools/webide/themes/jar.mn | 3 +- ...{project-listing.css => panel-listing.css} | 21 +- toolkit/devtools/webide/themes/prefs.css | 15 - toolkit/devtools/webide/themes/webide.css | 34 +- toolkit/devtools/webide/webide-prefs.js | 1 + toolkit/moz.build | 15 +- toolkit/mozapps/update/moz.build | 45 +-- toolkit/mozapps/update/tests/Makefile.in | 6 - toolkit/mozapps/update/tests/moz.build | 50 +-- .../update/tests/unit_aus_update/xpcshell.ini | 1 - .../tests/unit_base_updater/xpcshell.ini | 1 - toolkit/xre/nsAppRunner.cpp | 4 +- toolkit/xre/nsUpdateDriver.h | 5 - tools/profiler/platform.cpp | 14 + xpcom/idl-parser/setup.py | 15 + xpcom/idl-parser/{ => xpidl}/Makefile.in | 0 xpcom/idl-parser/xpidl/__init__.py | 0 xpcom/idl-parser/{ => xpidl}/header.py | 69 +++- xpcom/idl-parser/{ => xpidl}/moz.build | 0 xpcom/idl-parser/{ => xpidl}/runtests.py | 1 + xpcom/idl-parser/{ => xpidl}/typelib.py | 17 +- xpcom/idl-parser/{ => xpidl}/xpidl.py | 23 ++ xpcom/moz.build | 2 +- xpcom/xpidl/Makefile.in | 2 +- 151 files changed, 4589 insertions(+), 1305 deletions(-) create mode 100644 caps/nsIAddonPolicyService.idl create mode 100644 caps/tests/mochitest/file_data.txt create mode 100644 caps/tests/mochitest/resource_test_file.html create mode 100644 caps/tests/mochitest/test_addonMayLoad.html create mode 100644 caps/tests/mochitest/test_extensionURL.html create mode 100644 dom/ipc/NuwaChild.cpp create mode 100644 dom/ipc/NuwaChild.h create mode 100644 dom/ipc/NuwaParent.cpp create mode 100644 dom/ipc/NuwaParent.h create mode 100644 dom/ipc/PNuwa.ipdl create mode 100644 dom/messagechannel/tests/test_messageChannel_forceClose.html create mode 100644 netwerk/protocol/res/ExtensionProtocolHandler.cpp create mode 100644 netwerk/protocol/res/ExtensionProtocolHandler.h create mode 100644 netwerk/protocol/res/SubstitutingProtocolHandler.cpp create mode 100644 netwerk/protocol/res/SubstitutingProtocolHandler.h create mode 100644 netwerk/protocol/res/nsISubstitutingProtocolHandler.idl delete mode 100644 toolkit/components/addoncompat/remoteTagService.js create mode 100644 toolkit/components/timermanager/moz.build rename toolkit/{mozapps/update => components/timermanager}/nsIUpdateTimerManager.idl (100%) rename toolkit/{mozapps/update => components/timermanager}/nsUpdateTimerManager.js (100%) rename toolkit/{mozapps/update => components/timermanager}/nsUpdateTimerManager.manifest (100%) rename toolkit/{mozapps/update/tests/unit_timermanager => components/timermanager/tests/unit}/consumerNotifications.js (100%) rename toolkit/{mozapps/update/tests/unit_timermanager => components/timermanager/tests/unit}/xpcshell.ini (100%) rename {caps/tests/mochitest => toolkit/components/utils}/moz.build (77%) create mode 100644 toolkit/components/utils/simpleServices.js create mode 100644 toolkit/components/utils/utils.manifest create mode 100644 toolkit/devtools/webide/content/runtime-listing.js create mode 100644 toolkit/devtools/webide/content/runtime-listing.xhtml create mode 100644 toolkit/devtools/webide/content/runtime-panel.js create mode 100644 toolkit/devtools/webide/modules/runtime-list.js create mode 100644 toolkit/devtools/webide/test/sidebars/browser_tabs.js create mode 100644 toolkit/devtools/webide/test/sidebars/test_addons.html create mode 100644 toolkit/devtools/webide/test/sidebars/test_autoconnect_runtime.html create mode 100644 toolkit/devtools/webide/test/sidebars/test_autoselect_project.html create mode 100644 toolkit/devtools/webide/test/sidebars/test_device_permissions.html create mode 100644 toolkit/devtools/webide/test/sidebars/test_device_preferences.html create mode 100644 toolkit/devtools/webide/test/sidebars/test_device_settings.html create mode 100644 toolkit/devtools/webide/test/sidebars/test_fullscreenToolbox.html create mode 100644 toolkit/devtools/webide/test/sidebars/test_manifestUpdate.html create mode 100644 toolkit/devtools/webide/test/sidebars/test_newapp.html create mode 100644 toolkit/devtools/webide/test/sidebars/test_telemetry.html rename toolkit/devtools/webide/themes/{project-listing.css => panel-listing.css} (72%) delete mode 100644 toolkit/devtools/webide/themes/prefs.css create mode 100644 xpcom/idl-parser/setup.py rename xpcom/idl-parser/{ => xpidl}/Makefile.in (100%) create mode 100644 xpcom/idl-parser/xpidl/__init__.py rename xpcom/idl-parser/{ => xpidl}/header.py (91%) rename xpcom/idl-parser/{ => xpidl}/moz.build (100%) rename xpcom/idl-parser/{ => xpidl}/runtests.py (99%) rename xpcom/idl-parser/{ => xpidl}/typelib.py (96%) rename xpcom/idl-parser/{ => xpidl}/xpidl.py (99%) diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in index 6ef7511802..b770359c00 100644 --- a/browser/installer/package-manifest.in +++ b/browser/installer/package-manifest.in @@ -446,7 +446,8 @@ @RESPATH@/components/addoncompat.manifest @RESPATH@/components/multiprocessShims.js @RESPATH@/components/defaultShims.js -@RESPATH@/components/remoteTagService.js +@RESPATH@/components/utils.manifest +@RESPATH@/components/simpleServices.js @RESPATH@/components/pluginGlue.manifest @RESPATH@/components/ProcessSingleton.manifest @RESPATH@/components/MainProcessSingleton.js diff --git a/caps/BasePrincipal.cpp b/caps/BasePrincipal.cpp index 7463c3cbba..5255e7086f 100644 --- a/caps/BasePrincipal.cpp +++ b/caps/BasePrincipal.cpp @@ -6,6 +6,7 @@ #include "mozilla/BasePrincipal.h" +#include "nsIAddonPolicyService.h" #include "nsIContentSecurityPolicy.h" #include "nsIObjectInputStream.h" #include "nsIObjectOutputStream.h" @@ -15,6 +16,7 @@ #include "nsIURIWithPrincipal.h" #include "nsNullPrincipal.h" #include "nsScriptSecurityManager.h" +#include "nsServiceManagerUtils.h" #include "mozilla/dom/CSPDictionariesBinding.h" #include "mozilla/dom/ToJSValue.h" @@ -41,6 +43,10 @@ OriginAttributes::CreateSuffix(nsACString& aStr) const params->Set(NS_LITERAL_STRING("inBrowser"), NS_LITERAL_STRING("1")); } + if (!mAddonId.IsEmpty()) { + params->Set(NS_LITERAL_STRING("addonId"), mAddonId); + } + aStr.Truncate(); params->Serialize(value); @@ -88,6 +94,12 @@ public: return true; } + if (aName.EqualsLiteral("addonId")) { + MOZ_RELEASE_ASSERT(mOriginAttributes->mAddonId.IsEmpty()); + mOriginAttributes->mAddonId.Assign(aValue); + return true; + } + // No other attributes are supported. return false; } @@ -335,4 +347,19 @@ BasePrincipal::CreateCodebasePrincipal(nsIURI* aURI, OriginAttributes& aAttrs) return codebase.forget(); } +bool +BasePrincipal::AddonAllowsLoad(nsIURI* aURI) +{ + if (mOriginAttributes.mAddonId.IsEmpty()) { + return false; + } + + nsCOMPtr aps = do_GetService("@mozilla.org/addons/policy-service;1"); + NS_ENSURE_TRUE(aps, false); + + bool allowed = false; + nsresult rv = aps->AddonMayLoadURI(mOriginAttributes.mAddonId, aURI, &allowed); + return NS_SUCCEEDED(rv) && allowed; +} + } // namespace mozilla diff --git a/caps/BasePrincipal.h b/caps/BasePrincipal.h index fa890de425..13e814388a 100644 --- a/caps/BasePrincipal.h +++ b/caps/BasePrincipal.h @@ -34,7 +34,8 @@ public: bool operator==(const OriginAttributes& aOther) const { return mAppId == aOther.mAppId && - mInBrowser == aOther.mInBrowser; + mInBrowser == aOther.mInBrowser && + mAddonId == aOther.mAddonId; } bool operator!=(const OriginAttributes& aOther) const { @@ -105,6 +106,10 @@ protected: virtual nsresult GetOriginInternal(nsACString& aOrigin) = 0; virtual bool SubsumesInternal(nsIPrincipal* aOther, DocumentDomainConsideration aConsider) = 0; + // Helper to check whether this principal is associated with an addon that + // allows unprivileged code to load aURI. + bool AddonAllowsLoad(nsIURI* aURI); + nsCOMPtr mCSP; OriginAttributes mOriginAttributes; }; diff --git a/caps/moz.build b/caps/moz.build index c50409655d..7eec703652 100644 --- a/caps/moz.build +++ b/caps/moz.build @@ -4,11 +4,17 @@ # 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/. -TEST_DIRS += ['tests/mochitest'] - +MOCHITEST_MANIFESTS += ['tests/mochitest/mochitest.ini'] +MOCHITEST_CHROME_MANIFESTS += ['tests/mochitest/chrome.ini'] XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini'] +# Hack to make this file available as a resource:// URI. +TESTING_JS_MODULES += [ + 'tests/mochitest/resource_test_file.html', +] + XPIDL_SOURCES += [ + 'nsIAddonPolicyService.idl', 'nsIDomainPolicy.idl', 'nsIPrincipal.idl', 'nsIScriptSecurityManager.idl', diff --git a/caps/nsIAddonPolicyService.idl b/caps/nsIAddonPolicyService.idl new file mode 100644 index 0000000000..7a9c1f6621 --- /dev/null +++ b/caps/nsIAddonPolicyService.idl @@ -0,0 +1,32 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsISupports.idl" +#include "nsIURI.idl" + +/** + * This interface allows the security manager to query custom per-addon security + * policy. + */ +[scriptable,uuid(8a034ef9-9d14-4c5d-8319-06c1ab574baa)] +interface nsIAddonPolicyService : nsISupports +{ + /** + * Returns true if unprivileged code associated with the given addon may load + * data from |aURI|. + */ + boolean addonMayLoadURI(in AString aAddonId, in nsIURI aURI); + + /** + * Returns true if a given extension:// URI is web-accessible. + */ + boolean extensionURILoadableByAnyone(in nsIURI aURI); + + /** + * Maps an extension URI to the ID of the addon it belongs to. + */ + AString extensionURIToAddonId(in nsIURI aURI); +}; diff --git a/caps/nsNullPrincipal.h b/caps/nsNullPrincipal.h index 9d267e12fb..6590ee2114 100644 --- a/caps/nsNullPrincipal.h +++ b/caps/nsNullPrincipal.h @@ -23,8 +23,8 @@ class nsIURI; #define NS_NULLPRINCIPAL_CID \ -{ 0xe502ffb8, 0x5d95, 0x48e8, \ - { 0x82, 0x3c, 0x0d, 0x29, 0xd8, 0x3a, 0x59, 0x33 } } +{ 0x34a19ab6, 0xca47, 0x4098, \ + { 0xa7, 0xb8, 0x4a, 0xfc, 0xdd, 0xcd, 0x8f, 0x88 } } #define NS_NULLPRINCIPAL_CONTRACTID "@mozilla.org/nullprincipal;1" #define NS_NULLPRINCIPAL_SCHEME "moz-nullprincipal" diff --git a/caps/nsPrincipal.cpp b/caps/nsPrincipal.cpp index fffbf59b94..d9609c388a 100644 --- a/caps/nsPrincipal.cpp +++ b/caps/nsPrincipal.cpp @@ -236,6 +236,12 @@ nsPrincipal::CheckMayLoad(nsIURI* aURI, bool aReport, bool aAllowIfInheritsPrinc return NS_OK; } + // If this principal is associated with an addon, check whether that addon + // has been given permission to load from this domain. + if (AddonAllowsLoad(aURI)) { + return NS_OK; + } + if (nsScriptSecurityManager::SecurityCompareURIs(mCodebase, aURI)) { return NS_OK; } diff --git a/caps/nsPrincipal.h b/caps/nsPrincipal.h index 5380312284..e5f4f5576f 100644 --- a/caps/nsPrincipal.h +++ b/caps/nsPrincipal.h @@ -112,12 +112,12 @@ private: #define NS_PRINCIPAL_CONTRACTID "@mozilla.org/principal;1" #define NS_PRINCIPAL_CID \ - { 0xb7c8505e, 0xc56d, 0x4191, \ - { 0xa1, 0x5e, 0x5d, 0xcb, 0x88, 0x9b, 0xa0, 0x94 }} +{ 0xb02c3023, 0x5b37, 0x472a, \ + { 0xa2, 0xcd, 0x35, 0xaa, 0x5e, 0xe2, 0xa8, 0x19 } } #define NS_EXPANDEDPRINCIPAL_CONTRACTID "@mozilla.org/expandedprincipal;1" #define NS_EXPANDEDPRINCIPAL_CID \ - { 0x38539471, 0x68cc, 0x4a6f, \ - { 0x81, 0x20, 0xdb, 0xd5, 0x4a, 0x22, 0x0a, 0x13 }} +{ 0xe8ee88b0, 0x5571, 0x4086, \ + { 0xa4, 0x5b, 0x39, 0xa7, 0x16, 0x90, 0x6b, 0xdb } } #endif // nsPrincipal_h__ diff --git a/caps/nsScriptSecurityManager.cpp b/caps/nsScriptSecurityManager.cpp index 2ddd69395d..1c4cb9cef4 100644 --- a/caps/nsScriptSecurityManager.cpp +++ b/caps/nsScriptSecurityManager.cpp @@ -340,6 +340,20 @@ nsScriptSecurityManager::GetChannelResultPrincipal(nsIChannel* aChannel, return GetChannelURIPrincipal(aChannel, aPrincipal); } +nsresult +nsScriptSecurityManager::MaybeSetAddonIdFromURI(OriginAttributes& aAttrs, nsIURI* aURI) +{ + nsAutoCString scheme; + nsresult rv = aURI->GetScheme(scheme); + NS_ENSURE_SUCCESS(rv, rv); + if (scheme.EqualsLiteral("moz-extension") && GetAddonPolicyService()) { + rv = GetAddonPolicyService()->ExtensionURIToAddonId(aURI, aAttrs.mAddonId); + NS_ENSURE_SUCCESS(rv, rv); + } + + return NS_OK; +} + /* The principal of the URI that this channel is loading. This is never * affected by things like sandboxed loads, or loads where we forcefully * inherit the principal. Think of this as the principal of the server @@ -371,6 +385,8 @@ nsScriptSecurityManager::GetChannelURIPrincipal(nsIChannel* aChannel, } OriginAttributes attrs(UNKNOWN_APP_ID, false); + rv = MaybeSetAddonIdFromURI(attrs, uri); + NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr prin = BasePrincipal::CreateCodebasePrincipal(uri, attrs); prin.forget(aPrincipal); return *aPrincipal ? NS_OK : NS_ERROR_FAILURE; @@ -732,6 +748,16 @@ nsScriptSecurityManager::CheckLoadURIWithPrincipal(nsIPrincipal* aPrincipal, // the methods that work on chains of nested URIs and they will only look // at the flags for our one URI. + // Special case: moz-extension has a whitelist of URIs that are loadable by + // anyone. + if (targetScheme.EqualsLiteral("moz-extension") && GetAddonPolicyService()) { + bool loadable = false; + rv = GetAddonPolicyService()->ExtensionURILoadableByAnyone(targetBaseURI, &loadable); + if (NS_SUCCEEDED(rv) && loadable) { + return NS_OK; + } + } + // Check for system target URI rv = DenyAccessIfURIHasFlags(targetBaseURI, nsIProtocolHandler::URI_DANGEROUS_TO_LOAD); @@ -1062,6 +1088,8 @@ nsScriptSecurityManager:: OriginAttributes attrs; aLoadContext->GetAppId(&attrs.mAppId); aLoadContext->GetIsInBrowserElement(&attrs.mInBrowser); + nsresult rv = MaybeSetAddonIdFromURI(attrs, aURI); + NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr prin = BasePrincipal::CreateCodebasePrincipal(aURI, attrs); prin.forget(aPrincipal); return *aPrincipal ? NS_OK : NS_ERROR_FAILURE; @@ -1074,6 +1102,8 @@ nsScriptSecurityManager::GetDocShellCodebasePrincipal(nsIURI* aURI, { // XXXbholley - Make this more general in bug 1165466. OriginAttributes attrs(aDocShell->GetAppId(), aDocShell->GetIsInBrowserElement()); + nsresult rv = MaybeSetAddonIdFromURI(attrs, aURI); + NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr prin = BasePrincipal::CreateCodebasePrincipal(aURI, attrs); prin.forget(aPrincipal); return *aPrincipal ? NS_OK : NS_ERROR_FAILURE; diff --git a/caps/nsScriptSecurityManager.h b/caps/nsScriptSecurityManager.h index 342e9b84ac..13d3474da8 100644 --- a/caps/nsScriptSecurityManager.h +++ b/caps/nsScriptSecurityManager.h @@ -8,10 +8,15 @@ #define nsScriptSecurityManager_h__ #include "nsIScriptSecurityManager.h" + +#include "nsIAddonPolicyService.h" +#include "mozilla/Maybe.h" +#include "nsIAddonPolicyService.h" #include "nsIPrincipal.h" #include "nsCOMPtr.h" #include "nsIChannelEventSink.h" #include "nsIObserver.h" +#include "nsServiceManagerUtils.h" #include "plstr.h" #include "js/TypeDecls.h" @@ -115,6 +120,9 @@ private: inline void AddSitesToFileURIWhitelist(const nsCString& aSiteList); + // If aURI is a moz-extension:// URI, set mAddonId to the associated addon. + nsresult MaybeSetAddonIdFromURI(mozilla::OriginAttributes& aAttrs, nsIURI* aURI); + nsCOMPtr mSystemPrincipal; bool mPrefInitialized; bool mIsJavaScriptEnabled; @@ -124,6 +132,17 @@ private: // policy machinery will be removed soon. nsCOMPtr mDomainPolicy; + // Cached addon policy service. We can't generate this in Init() because + // that's too early to get a service. + mozilla::Maybe> mAddonPolicyService; + nsIAddonPolicyService* GetAddonPolicyService() + { + if (mAddonPolicyService.isNothing()) { + mAddonPolicyService.emplace(do_GetService("@mozilla.org/addons/policy-service;1")); + } + return mAddonPolicyService.ref(); + } + static bool sStrictFileOriginPolicy; static nsIIOService *sIOService; diff --git a/caps/tests/mochitest/chrome.ini b/caps/tests/mochitest/chrome.ini index 71b166f659..65bfedd1a9 100644 --- a/caps/tests/mochitest/chrome.ini +++ b/caps/tests/mochitest/chrome.ini @@ -4,6 +4,7 @@ support-files = file_disableScript.html [test_bug995943.xul] +[test_addonMayLoad.html] [test_disableScript.xul] [test_principal_jarprefix_origin_appid_appstatus.html] # jarPrefix test doesn't work on Windows, see bug 776296. diff --git a/caps/tests/mochitest/file_data.txt b/caps/tests/mochitest/file_data.txt new file mode 100644 index 0000000000..26d7bd8488 --- /dev/null +++ b/caps/tests/mochitest/file_data.txt @@ -0,0 +1 @@ +server data fetched over XHR diff --git a/caps/tests/mochitest/mochitest.ini b/caps/tests/mochitest/mochitest.ini index 187150a05c..e005135f9a 100644 --- a/caps/tests/mochitest/mochitest.ini +++ b/caps/tests/mochitest/mochitest.ini @@ -1,5 +1,6 @@ [DEFAULT] support-files = + file_data.txt file_disableScript.html [test_app_principal_equality.html] @@ -10,3 +11,5 @@ skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop spec [test_bug423375.html] [test_bug470804.html] [test_disallowInheritPrincipal.html] +[test_extensionURL.html] +skip-if = (os == 'android' || buildapp == 'b2g') # Bug 1185773 for android, nonsensical on b2g diff --git a/caps/tests/mochitest/resource_test_file.html b/caps/tests/mochitest/resource_test_file.html new file mode 100644 index 0000000000..8201bd70e0 --- /dev/null +++ b/caps/tests/mochitest/resource_test_file.html @@ -0,0 +1,2 @@ + +resource test file diff --git a/caps/tests/mochitest/test_addonMayLoad.html b/caps/tests/mochitest/test_addonMayLoad.html new file mode 100644 index 0000000000..286284bfe8 --- /dev/null +++ b/caps/tests/mochitest/test_addonMayLoad.html @@ -0,0 +1,97 @@ + + + + + + Test for Bug 1180921 + + + + + + +Mozilla Bug 1180921 +

+ +
+
+ + diff --git a/caps/tests/mochitest/test_extensionURL.html b/caps/tests/mochitest/test_extensionURL.html new file mode 100644 index 0000000000..6c1d7e09a0 --- /dev/null +++ b/caps/tests/mochitest/test_extensionURL.html @@ -0,0 +1,144 @@ + + + + + + Test for Bug 1161831 + + + + + +Mozilla Bug 1161831 +

+ +
+
+ + diff --git a/caps/tests/unit/test_origin.js b/caps/tests/unit/test_origin.js index 33fed1395a..ef462719e7 100644 --- a/caps/tests/unit/test_origin.js +++ b/caps/tests/unit/test_origin.js @@ -25,9 +25,10 @@ function checkCrossOrigin(a, b) { a.originAttributes.inBrowser == b.originAttributes.inBrowser); } -function checkOriginAttributes(prin, appId, inBrowser, suffix) { - do_check_eq(prin.originAttributes.appId, appId || 0); - do_check_eq(prin.originAttributes.inBrowser, inBrowser || false); +function checkOriginAttributes(prin, attrs, suffix) { + attrs = attrs || {}; + do_check_eq(prin.originAttributes.appId, attrs.appId || 0); + do_check_eq(prin.originAttributes.inBrowser, attrs.inBrowser || false); do_check_eq(prin.originSuffix, suffix || ''); if (!prin.isNullPrincipal && !prin.origin.startsWith('[')) { do_check_true(BrowserUtils.principalFromOrigin(prin.origin).equals(prin)); @@ -67,29 +68,34 @@ function run_test() { // Just app. var exampleOrg_app = ssm.createCodebasePrincipal(makeURI('http://example.org'), {appId: 42}); var nullPrin_app = ssm.createNullPrincipal({appId: 42}); - checkOriginAttributes(exampleOrg_app, 42, false, '!appId=42'); - checkOriginAttributes(nullPrin_app, 42, false, '!appId=42'); + checkOriginAttributes(exampleOrg_app, {appId: 42}, '!appId=42'); + checkOriginAttributes(nullPrin_app, {appId: 42}, '!appId=42'); do_check_eq(exampleOrg_app.origin, 'http://example.org!appId=42'); // Just browser. var exampleOrg_browser = ssm.createCodebasePrincipal(makeURI('http://example.org'), {inBrowser: true}); var nullPrin_browser = ssm.createNullPrincipal({inBrowser: true}); - checkOriginAttributes(exampleOrg_browser, 0, true, '!inBrowser=1'); - checkOriginAttributes(nullPrin_browser, 0, true, '!inBrowser=1'); + checkOriginAttributes(exampleOrg_browser, {inBrowser: true}, '!inBrowser=1'); + checkOriginAttributes(nullPrin_browser, {inBrowser: true}, '!inBrowser=1'); do_check_eq(exampleOrg_browser.origin, 'http://example.org!inBrowser=1'); // App and browser. var exampleOrg_appBrowser = ssm.createCodebasePrincipal(makeURI('http://example.org'), {inBrowser: true, appId: 42}); var nullPrin_appBrowser = ssm.createNullPrincipal({inBrowser: true, appId: 42}); - checkOriginAttributes(exampleOrg_appBrowser, 42, true, '!appId=42&inBrowser=1'); - checkOriginAttributes(nullPrin_appBrowser, 42, true, '!appId=42&inBrowser=1'); + checkOriginAttributes(exampleOrg_appBrowser, {appId: 42, inBrowser: true}, '!appId=42&inBrowser=1'); + checkOriginAttributes(nullPrin_appBrowser, {appId: 42, inBrowser: true}, '!appId=42&inBrowser=1'); do_check_eq(exampleOrg_appBrowser.origin, 'http://example.org!appId=42&inBrowser=1'); // App and browser, different domain. var exampleCom_appBrowser = ssm.createCodebasePrincipal(makeURI('https://www.example.com:123'), {appId: 42, inBrowser: true}); - checkOriginAttributes(exampleCom_appBrowser, 42, true, '!appId=42&inBrowser=1'); + checkOriginAttributes(exampleCom_appBrowser, {appId: 42, inBrowser: true}, '!appId=42&inBrowser=1'); do_check_eq(exampleCom_appBrowser.origin, 'https://www.example.com:123!appId=42&inBrowser=1'); + // Addon. + var exampleOrg_addon = ssm.createCodebasePrincipal(makeURI('http://example.org'), {addonId: 'dummy'}); + checkOriginAttributes(exampleOrg_addon, { addonId: "dummy" }, '!addonId=dummy'); + do_check_eq(exampleOrg_addon.origin, 'http://example.org!addonId=dummy'); + // Check that all of the above are cross-origin. checkCrossOrigin(exampleOrg_app, exampleOrg); checkCrossOrigin(exampleOrg_app, nullPrin_app); @@ -98,4 +104,5 @@ function run_test() { checkCrossOrigin(exampleOrg_appBrowser, exampleOrg_app); checkCrossOrigin(exampleOrg_appBrowser, nullPrin_appBrowser); checkCrossOrigin(exampleOrg_appBrowser, exampleCom_appBrowser); + checkCrossOrigin(exampleOrg_addon, exampleOrg); } diff --git a/chrome/RegistryMessageUtils.h b/chrome/RegistryMessageUtils.h index 1f8879cdbf..2d2e7d276b 100644 --- a/chrome/RegistryMessageUtils.h +++ b/chrome/RegistryMessageUtils.h @@ -39,14 +39,16 @@ struct ChromePackage } }; -struct ResourceMapping +struct SubstitutionMapping { - nsCString resource; + nsCString scheme; + nsCString path; SerializedURI resolvedURI; - bool operator ==(const ResourceMapping& rhs) const + bool operator ==(const SubstitutionMapping& rhs) const { - return resource.Equals(rhs.resource) && + return scheme.Equals(rhs.scheme) && + path.Equals(rhs.path) && resolvedURI == rhs.resolvedURI; } }; @@ -134,24 +136,27 @@ struct ParamTraits }; template <> -struct ParamTraits +struct ParamTraits { - typedef ResourceMapping paramType; + typedef SubstitutionMapping paramType; static void Write(Message* aMsg, const paramType& aParam) { - WriteParam(aMsg, aParam.resource); + WriteParam(aMsg, aParam.scheme); + WriteParam(aMsg, aParam.path); WriteParam(aMsg, aParam.resolvedURI); } static bool Read(const Message* aMsg, void** aIter, paramType* aResult) { - nsCString resource; + nsCString scheme, path; SerializedURI resolvedURI; - if (ReadParam(aMsg, aIter, &resource) && + if (ReadParam(aMsg, aIter, &scheme) && + ReadParam(aMsg, aIter, &path) && ReadParam(aMsg, aIter, &resolvedURI)) { - aResult->resource = resource; + aResult->scheme = scheme; + aResult->path = path; aResult->resolvedURI = resolvedURI; return true; } @@ -160,7 +165,9 @@ struct ParamTraits static void Log(const paramType& aParam, std::wstring* aLog) { - aLog->append(StringPrintf(L"[%s, %s, %u]", aParam.resource.get(), + aLog->append(StringPrintf(L"[%s://%s, %s, %u]", + aParam.scheme.get(), + aParam.path.get(), aParam.resolvedURI.spec.get())); } }; diff --git a/chrome/nsChromeRegistryChrome.cpp b/chrome/nsChromeRegistryChrome.cpp index dc5474b5f7..151fd4ce0e 100644 --- a/chrome/nsChromeRegistryChrome.cpp +++ b/chrome/nsChromeRegistryChrome.cpp @@ -445,7 +445,7 @@ nsChromeRegistryChrome::SendRegisteredChrome( mozilla::dom::PContentParent* aParent) { InfallibleTArray packages; - InfallibleTArray resources; + InfallibleTArray resources; InfallibleTArray overrides; EnumerationArgs args = { diff --git a/chrome/nsChromeRegistryContent.cpp b/chrome/nsChromeRegistryContent.cpp index eec49b2237..3714d3e439 100644 --- a/chrome/nsChromeRegistryContent.cpp +++ b/chrome/nsChromeRegistryContent.cpp @@ -17,7 +17,7 @@ nsChromeRegistryContent::nsChromeRegistryContent() void nsChromeRegistryContent::RegisterRemoteChrome( const InfallibleTArray& aPackages, - const InfallibleTArray& aResources, + const InfallibleTArray& aSubstitutions, const InfallibleTArray& aOverrides, const nsACString& aLocale, bool aReset) @@ -36,9 +36,9 @@ nsChromeRegistryContent::RegisterRemoteChrome( RegisterPackage(aPackages[i]); } - for (uint32_t i = aResources.Length(); i > 0; ) { + for (uint32_t i = aSubstitutions.Length(); i > 0; ) { --i; - RegisterResource(aResources[i]); + RegisterSubstitution(aSubstitutions[i]); } for (uint32_t i = aOverrides.Length(); i > 0; ) { @@ -94,32 +94,32 @@ nsChromeRegistryContent::RegisterPackage(const ChromePackage& aPackage) } void -nsChromeRegistryContent::RegisterResource(const ResourceMapping& aResource) +nsChromeRegistryContent::RegisterSubstitution(const SubstitutionMapping& aSubstitution) { nsCOMPtr io (do_GetIOService()); if (!io) return; nsCOMPtr ph; - nsresult rv = io->GetProtocolHandler("resource", getter_AddRefs(ph)); + nsresult rv = io->GetProtocolHandler(aSubstitution.scheme.get(), getter_AddRefs(ph)); if (NS_FAILED(rv)) return; - nsCOMPtr rph (do_QueryInterface(ph)); - if (!rph) + nsCOMPtr sph (do_QueryInterface(ph)); + if (!sph) return; nsCOMPtr resolvedURI; - if (aResource.resolvedURI.spec.Length()) { + if (aSubstitution.resolvedURI.spec.Length()) { nsresult rv = NS_NewURI(getter_AddRefs(resolvedURI), - aResource.resolvedURI.spec, - aResource.resolvedURI.charset.get(), + aSubstitution.resolvedURI.spec, + aSubstitution.resolvedURI.charset.get(), nullptr, io); if (NS_FAILED(rv)) return; } - rv = rph->SetSubstitution(aResource.resource, resolvedURI); + rv = sph->SetSubstitution(aSubstitution.path, resolvedURI); if (NS_FAILED(rv)) return; } diff --git a/chrome/nsChromeRegistryContent.h b/chrome/nsChromeRegistryContent.h index e7dc8848a4..fc164f6643 100644 --- a/chrome/nsChromeRegistryContent.h +++ b/chrome/nsChromeRegistryContent.h @@ -10,7 +10,7 @@ #include "nsClassHashtable.h" struct ChromePackage; -struct ResourceMapping; +struct SubstitutionMapping; struct OverrideMapping; class nsChromeRegistryContent : public nsChromeRegistry @@ -19,7 +19,7 @@ class nsChromeRegistryContent : public nsChromeRegistry nsChromeRegistryContent(); void RegisterRemoteChrome(const InfallibleTArray& aPackages, - const InfallibleTArray& aResources, + const InfallibleTArray& aResources, const InfallibleTArray& aOverrides, const nsACString& aLocale, bool aReset); @@ -41,7 +41,7 @@ class nsChromeRegistryContent : public nsChromeRegistry void RegisterPackage(const ChromePackage& aPackage); void RegisterOverride(const OverrideMapping& aOverride); - void RegisterResource(const ResourceMapping& aResource); + void RegisterSubstitution(const SubstitutionMapping& aResource); private: struct PackageEntry diff --git a/dom/base/PostMessageEvent.cpp b/dom/base/PostMessageEvent.cpp index 534d389cda..f375a672a7 100644 --- a/dom/base/PostMessageEvent.cpp +++ b/dom/base/PostMessageEvent.cpp @@ -238,7 +238,13 @@ PostMessageEvent::FreeTransferStructuredClone(uint32_t aTag, uint64_t aExtraData, void* aClosure) { - // Nothing to do. + if (aTag == SCTAG_DOM_MAP_MESSAGEPORT) { + MOZ_ASSERT(aClosure); + MOZ_ASSERT(!aContent); + + StructuredCloneInfo* scInfo = static_cast(aClosure); + MessagePort::ForceClose(scInfo->event->GetPortIdentifier(aExtraData)); + } } PostMessageEvent::PostMessageEvent(nsGlobalWindow* aSource, diff --git a/dom/base/test/chrome/cpows_child.js b/dom/base/test/chrome/cpows_child.js index dd58273aa9..999ffc67e8 100644 --- a/dom/base/test/chrome/cpows_child.js +++ b/dom/base/test/chrome/cpows_child.js @@ -90,6 +90,10 @@ function make_json() function parent_test(finish) { function f(check_func) { + // Make sure this doesn't crash. + let array = new Uint32Array(10); + content.crypto.getRandomValues(array); + let result = check_func(10); ok(result == 20, "calling function in parent worked"); return result; diff --git a/dom/canvas/CanvasRenderingContext2D.cpp b/dom/canvas/CanvasRenderingContext2D.cpp index 02d602b440..6083180f27 100644 --- a/dom/canvas/CanvasRenderingContext2D.cpp +++ b/dom/canvas/CanvasRenderingContext2D.cpp @@ -2797,7 +2797,7 @@ void CanvasRenderingContext2D::DrawFocusIfNeeded(mozilla::dom::Element& aElement Stroke(); // set dashing for foreground - FallibleTArray& dash = CurrentState().dash; + nsTArray& dash = CurrentState().dash; for (uint32_t i = 0; i < 2; ++i) { if (!dash.AppendElement(1, fallible)) { aRv.Throw(NS_ERROR_OUT_OF_MEMORY); @@ -4071,11 +4071,11 @@ CanvasRenderingContext2D::SetMozDash(JSContext* cx, const JS::Value& mozDash, ErrorResult& error) { - FallibleTArray dash; + nsTArray dash; error = JSValToDashArray(cx, mozDash, dash); if (!error.Failed()) { ContextState& state = CurrentState(); - state.dash = dash; + state.dash = Move(dash); if (state.dash.IsEmpty()) { state.dashOffset = 0; } @@ -4103,7 +4103,7 @@ void CanvasRenderingContext2D::SetLineDash(const Sequence& aSegments, ErrorResult& aRv) { - FallibleTArray dash; + nsTArray dash; for (uint32_t x = 0; x < aSegments.Length(); x++) { if (aSegments[x] < 0.0) { @@ -4126,12 +4126,12 @@ CanvasRenderingContext2D::SetLineDash(const Sequence& aSegments, } } - CurrentState().dash = dash; + CurrentState().dash = Move(dash); } void CanvasRenderingContext2D::GetLineDash(nsTArray& aSegments) const { - const FallibleTArray& dash = CurrentState().dash; + const nsTArray& dash = CurrentState().dash; aSegments.Clear(); for (uint32_t x = 0; x < dash.Length(); x++) { diff --git a/dom/canvas/CanvasRenderingContext2D.h b/dom/canvas/CanvasRenderingContext2D.h index 4be8a8445f..d1743cdae0 100644 --- a/dom/canvas/CanvasRenderingContext2D.h +++ b/dom/canvas/CanvasRenderingContext2D.h @@ -1064,7 +1064,7 @@ protected: mozilla::gfx::Float miterLimit; mozilla::gfx::Float globalAlpha; mozilla::gfx::Float shadowBlur; - FallibleTArray dash; + nsTArray dash; mozilla::gfx::Float dashOffset; mozilla::gfx::CompositionOp op; diff --git a/dom/canvas/CanvasUtils.h b/dom/canvas/CanvasUtils.h index 118f709652..044b847053 100644 --- a/dom/canvas/CanvasUtils.h +++ b/dom/canvas/CanvasUtils.h @@ -84,20 +84,10 @@ inline bool FloatValidate (double f1, double f2, double f3, double f4, double f5 #undef VALIDATE -template -nsresult -JSValToDashArray(JSContext* cx, const JS::Value& val, - FallibleTArray& dashArray); - -template -JS::Value -DashArrayToJSVal(FallibleTArray& dashArray, - JSContext* cx, mozilla::ErrorResult& rv); - template nsresult JSValToDashArray(JSContext* cx, const JS::Value& patternArray, - FallibleTArray& dashes) + nsTArray& dashes) { // The cap is pretty arbitrary. 16k should be enough for // anybody... @@ -149,7 +139,7 @@ JSValToDashArray(JSContext* cx, const JS::Value& patternArray, template void -DashArrayToJSVal(FallibleTArray& dashes, +DashArrayToJSVal(nsTArray& dashes, JSContext* cx, JS::MutableHandle retval, mozilla::ErrorResult& rv) diff --git a/dom/ipc/ContentChild.cpp b/dom/ipc/ContentChild.cpp index f7c8b3614d..fa3ee4730b 100644 --- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -149,9 +149,9 @@ #endif #ifdef MOZ_NUWA_PROCESS -#include #include "ipc/Nuwa.h" #endif +#include "NuwaChild.h" #ifdef MOZ_GAMEPAD #include "mozilla/dom/GamepadService.h" @@ -216,19 +216,6 @@ using namespace mozilla::system; #endif using namespace mozilla::widget; -#ifdef MOZ_NUWA_PROCESS -static bool sNuwaForking = false; - -// The size of the reserved stack (in unsigned ints). It's used to reserve space -// to push sigsetjmp() in NuwaCheckpointCurrentThread() to higher in the stack -// so that after it returns and do other work we don't garble the stack we want -// to preserve in NuwaCheckpointCurrentThread(). -#define RESERVED_INT_STACK 128 - -// A sentinel value for checking whether RESERVED_INT_STACK is large enough. -#define STACK_SENTINEL_VALUE 0xdeadbeef -#endif - namespace mozilla { namespace dom { @@ -535,7 +522,7 @@ ContentChild* ContentChild::sSingleton; // Performs initialization that is not fork-safe, i.e. that must be done after // forking from the Nuwa process. -static void +void InitOnContentProcessCreated() { #ifdef MOZ_NUWA_PROCESS @@ -1831,7 +1818,7 @@ ContentChild::DeallocPWebrtcGlobalChild(PWebrtcGlobalChild *aActor) bool ContentChild::RecvRegisterChrome(InfallibleTArray&& packages, - InfallibleTArray&& resources, + InfallibleTArray&& resources, InfallibleTArray&& overrides, const nsCString& locale, const bool& reset) @@ -1859,8 +1846,8 @@ ContentChild::RecvRegisterChromeItem(const ChromeRegistryItem& item) chromeRegistry->RegisterOverride(item.get_OverrideMapping()); break; - case ChromeRegistryItem::TResourceMapping: - chromeRegistry->RegisterResource(item.get_ResourceMapping()); + case ChromeRegistryItem::TSubstitutionMapping: + chromeRegistry->RegisterSubstitution(item.get_SubstitutionMapping()); break; default: @@ -2183,8 +2170,25 @@ ContentChild::RecvCycleCollect() #ifdef MOZ_NUWA_PROCESS static void -OnFinishNuwaPreparation () +OnFinishNuwaPreparation() { + // We want to ensure that the PBackground actor gets cloned in the Nuwa + // process before we freeze. Also, we have to do this to avoid deadlock. + // Protocols that are "opened" (e.g. PBackground, PCompositor) block the + // main thread to wait for the IPC thread during the open operation. + // NuwaSpawnWait() blocks the IPC thread to wait for the main thread when + // the Nuwa process is forked. Unless we ensure that the two cannot happen + // at the same time then we risk deadlock. Spinning the event loop here + // guarantees the ordering is safe for PBackground. + while (!BackgroundChild::GetForCurrentThread()) { + if (NS_WARN_IF(!NS_ProcessNextEvent())) { + return; + } + } + + // This will create the actor. + unused << mozilla::dom::NuwaChild::GetSingleton(); + MakeNuwaProcess(); } #endif @@ -2470,87 +2474,6 @@ ContentChild::DeallocPOfflineCacheUpdateChild(POfflineCacheUpdateChild* actor) return true; } -#ifdef MOZ_NUWA_PROCESS -class CallNuwaSpawn : public nsRunnable -{ -public: - NS_IMETHOD Run() - { - NuwaSpawn(); - if (IsNuwaProcess()) { - return NS_OK; - } - - // In the new process. - ContentChild* child = ContentChild::GetSingleton(); - child->SetProcessName(NS_LITERAL_STRING("(Preallocated app)"), false); - - // Perform other after-fork initializations. - InitOnContentProcessCreated(); - - return NS_OK; - } -}; - -static void -DoNuwaFork() -{ - NuwaSpawnPrepare(); // NuwaSpawn will be blocked. - - { - nsCOMPtr callSpawn(new CallNuwaSpawn()); - NS_DispatchToMainThread(callSpawn); - } - - // IOThread should be blocked here for waiting NuwaSpawn(). - NuwaSpawnWait(); // Now! NuwaSpawn can go. - // Here, we can make sure the spawning was finished. -} - -/** - * This function should keep IO thread in a stable state and freeze it - * until the spawning is finished. - */ -static void -RunNuwaFork() -{ - if (NuwaCheckpointCurrentThread()) { - DoNuwaFork(); - } -} -#endif - -bool -ContentChild::RecvNuwaFork() -{ -#ifdef MOZ_NUWA_PROCESS - if (sNuwaForking) { // No reentry. - return true; - } - sNuwaForking = true; - - // We want to ensure that the PBackground actor gets cloned in the Nuwa - // process before we freeze. Also, we have to do this to avoid deadlock. - // Protocols that are "opened" (e.g. PBackground, PCompositor) block the - // main thread to wait for the IPC thread during the open operation. - // NuwaSpawnWait() blocks the IPC thread to wait for the main thread when - // the Nuwa process is forked. Unless we ensure that the two cannot happen - // at the same time then we risk deadlock. Spinning the event loop here - // guarantees the ordering is safe for PBackground. - while (!BackgroundChild::GetForCurrentThread()) { - if (NS_WARN_IF(!NS_ProcessNextEvent())) { - return false; - } - } - - MessageLoop* ioloop = XRE_GetIOMessageLoop(); - ioloop->PostTask(FROM_HERE, NewRunnableFunction(RunNuwaFork)); - return true; -#else - return false; // Makes the underlying IPC channel abort. -#endif -} - bool ContentChild::RecvOnAppThemeChanged() { @@ -2590,6 +2513,18 @@ ContentChild::RecvStopProfiler() return true; } +bool +ContentChild::RecvPauseProfiler(const bool& aPause) +{ + if (aPause) { + profiler_pause(); + } else { + profiler_resume(); + } + + return true; +} + bool ContentChild::RecvGatherProfile() { @@ -2874,109 +2809,3 @@ ContentChild::RecvEndDragSession(const bool& aDoneDrag, } // namespace dom } // namespace mozilla -extern "C" { - -#if defined(MOZ_NUWA_PROCESS) -NS_EXPORT void -GetProtoFdInfos(NuwaProtoFdInfo* aInfoList, - size_t aInfoListSize, - size_t* aInfoSize) -{ - size_t i = 0; - - mozilla::dom::ContentChild* content = - mozilla::dom::ContentChild::GetSingleton(); - aInfoList[i].protoId = content->GetProtocolId(); - aInfoList[i].originFd = - content->GetTransport()->GetFileDescriptor(); - i++; - - IToplevelProtocol* actors[NUWA_TOPLEVEL_MAX]; - size_t count = content->GetOpenedActorsUnsafe(actors, ArrayLength(actors)); - for (size_t j = 0; j < count; j++) { - IToplevelProtocol* actor = actors[j]; - if (i >= aInfoListSize) { - NS_RUNTIMEABORT("Too many top level protocols!"); - } - - aInfoList[i].protoId = actor->GetProtocolId(); - aInfoList[i].originFd = - actor->GetTransport()->GetFileDescriptor(); - i++; - } - - if (i > NUWA_TOPLEVEL_MAX) { - NS_RUNTIMEABORT("Too many top level protocols!"); - } - *aInfoSize = i; -} - -class RunAddNewIPCProcess : public nsRunnable -{ -public: - RunAddNewIPCProcess(pid_t aPid, - nsTArray& aMaps) - : mPid(aPid) - { - mMaps.SwapElements(aMaps); - } - - NS_IMETHOD Run() - { - mozilla::dom::ContentChild::GetSingleton()-> - SendAddNewProcess(mPid, mMaps); - - MOZ_ASSERT(sNuwaForking); - sNuwaForking = false; - - return NS_OK; - } - -private: - pid_t mPid; - nsTArray mMaps; -}; - -/** - * AddNewIPCProcess() is called by Nuwa process to tell the parent - * process that a new process is created. - * - * In the newly created process, ResetContentChildTransport() is called to - * reset fd for the IPC Channel and the session. - */ -NS_EXPORT void -AddNewIPCProcess(pid_t aPid, NuwaProtoFdInfo* aInfoList, size_t aInfoListSize) -{ - nsTArray maps; - - for (size_t i = 0; i < aInfoListSize; i++) { - int _fd = aInfoList[i].newFds[NUWA_NEWFD_PARENT]; - mozilla::ipc::FileDescriptor fd(_fd); - mozilla::ipc::ProtocolFdMapping map(aInfoList[i].protoId, fd); - maps.AppendElement(map); - } - - nsRefPtr runner = new RunAddNewIPCProcess(aPid, maps); - NS_DispatchToMainThread(runner); -} - -NS_EXPORT void -OnNuwaProcessReady() -{ - mozilla::dom::ContentChild* content = - mozilla::dom::ContentChild::GetSingleton(); - content->SendNuwaReady(); -} - -NS_EXPORT void -AfterNuwaFork() -{ - SetCurrentProcessPrivileges(base::PRIVILEGES_DEFAULT); -#if defined(XP_LINUX) && defined(MOZ_SANDBOX) - mozilla::SandboxEarlyInit(XRE_GetProcessType(), /* isNuwa: */ false); -#endif -} - -#endif // MOZ_NUWA_PROCESS - -} diff --git a/dom/ipc/ContentChild.h b/dom/ipc/ContentChild.h index d10252b79f..5340bc040c 100644 --- a/dom/ipc/ContentChild.h +++ b/dom/ipc/ContentChild.h @@ -21,7 +21,7 @@ struct ChromePackage; class nsIObserver; -struct ResourceMapping; +struct SubstitutionMapping; struct OverrideMapping; class nsIDomainPolicy; @@ -278,7 +278,7 @@ public: virtual bool DeallocPSpeechSynthesisChild(PSpeechSynthesisChild* aActor) override; virtual bool RecvRegisterChrome(InfallibleTArray&& packages, - InfallibleTArray&& resources, + InfallibleTArray&& resources, InfallibleTArray&& overrides, const nsCString& locale, const bool& reset) override; @@ -359,8 +359,6 @@ public: const bool& aIsHotSwappable) override; virtual bool RecvVolumeRemoved(const nsString& aFsName) override; - virtual bool RecvNuwaFork() override; - virtual bool RecvNotifyProcessPriorityChanged(const hal::ProcessPriority& aPriority) override; virtual bool RecvMinimizeMemoryUsage() override; @@ -389,6 +387,7 @@ public: const double& aInterval, nsTArray&& aFeatures, nsTArray&& aThreadNameFilters) override; + virtual bool RecvPauseProfiler(const bool& aPause) override; virtual bool RecvStopProfiler() override; virtual bool RecvGatherProfile() override; virtual bool RecvDomainSetChanged(const uint32_t& aSetType, const uint32_t& aChangeType, @@ -510,6 +509,9 @@ private: DISALLOW_EVIL_CONSTRUCTORS(ContentChild); }; +void +InitOnContentProcessCreated(); + uint64_t NextWindowID(); diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index 2e30a7f89b..127dbd4655 100755 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -41,6 +41,7 @@ #include "mozilla/dom/ExternalHelperAppParent.h" #include "mozilla/dom/FileSystemRequestParent.h" #include "mozilla/dom/GeolocationBinding.h" +#include "mozilla/dom/NuwaParent.h" #include "mozilla/dom/PContentBridgeParent.h" #include "mozilla/dom/PContentPermissionRequestParent.h" #include "mozilla/dom/PCycleCollectWithLogsParent.h" @@ -75,6 +76,7 @@ #include "mozilla/layers/ImageBridgeParent.h" #include "mozilla/layers/SharedBufferManagerParent.h" #include "mozilla/LookAndFeel.h" +#include "mozilla/Move.h" #include "mozilla/net/NeckoParent.h" #include "mozilla/plugins/PluginBridge.h" #include "mozilla/Preferences.h" @@ -665,6 +667,8 @@ static const char* sObserverTopics[] = { #ifdef MOZ_ENABLE_PROFILER_SPS "profiler-started", "profiler-stopped", + "profiler-paused", + "profiler-resumed", "profiler-subprocess-gather", "profiler-subprocess", #endif @@ -2766,47 +2770,54 @@ ContentParent::RecvDataStoreGetStores( return true; } -bool -ContentParent::RecvNuwaReady() +void +ContentParent::ForkNewProcess(bool aBlocking) { #ifdef MOZ_NUWA_PROCESS - if (!IsNuwaProcess()) { - NS_ERROR( - nsPrintfCString( - "Terminating child process %d for unauthorized IPC message: NuwaReady", - Pid()).get()); + uint32_t pid; + auto fds = MakeUnique>(); - KillHard("NuwaReady"); - return false; - } - sNuwaReady = true; - PreallocatedProcessManager::OnNuwaReady(); - return true; + MOZ_ASSERT(IsNuwaProcess() && mNuwaParent); + + if (mNuwaParent->ForkNewProcess(pid, mozilla::Move(fds), aBlocking)) { + OnNewProcessCreated(pid, mozilla::Move(fds)); + } #else - NS_ERROR("ContentParent::RecvNuwaReady() not implemented!"); - return false; + NS_ERROR("ContentParent::ForkNewProcess() not implemented!"); #endif } -bool -ContentParent::RecvAddNewProcess(const uint32_t& aPid, - InfallibleTArray&& aFds) +void +ContentParent::OnNuwaReady() { #ifdef MOZ_NUWA_PROCESS - if (!IsNuwaProcess()) { - NS_ERROR( - nsPrintfCString( - "Terminating child process %d for unauthorized IPC message: " - "AddNewProcess(%d)", Pid(), aPid).get()); + // Protection from unauthorized IPC message is done in PNuwa protocol. + // Just assert that this actor is really for the Nuwa process. + MOZ_ASSERT(IsNuwaProcess()); + + sNuwaReady = true; + PreallocatedProcessManager::OnNuwaReady(); + return; +#else + NS_ERROR("ContentParent::OnNuwaReady() not implemented!"); + return; +#endif +} + +void +ContentParent::OnNewProcessCreated(uint32_t aPid, + UniquePtr>&& aFds) +{ +#ifdef MOZ_NUWA_PROCESS + // Protection from unauthorized IPC message is done in PNuwa protocol. + // Just assert that this actor is really for the Nuwa process. + MOZ_ASSERT(IsNuwaProcess()); - KillHard("AddNewProcess"); - return false; - } nsRefPtr content; content = new ContentParent(this, MAGIC_PREALLOCATED_APP_MANIFEST_URL, aPid, - Move(aFds)); + Move(*aFds.get())); content->Init(); size_t numNuwaPrefUpdates = sNuwaPrefUpdates ? @@ -2834,10 +2845,10 @@ ContentParent::RecvAddNewProcess(const uint32_t& aPid, "Unexpected values"); PreallocatedProcessManager::PublishSpareProcess(content); - return true; + return; #else - NS_ERROR("ContentParent::RecvAddNewProcess() not implemented!"); - return false; + NS_ERROR("ContentParent::OnNewProcessCreated() not implemented!"); + return; #endif } @@ -3057,6 +3068,17 @@ ContentParent::Observe(nsISupports* aSubject, else if (!strcmp(aTopic, "profiler-stopped")) { unused << SendStopProfiler(); } + else if (!strcmp(aTopic, "profiler-paused")) { + unused << SendPauseProfiler(true); + } + else if (!strcmp(aTopic, "profiler-resumed")) { + unused << SendPauseProfiler(false); + } + else if (!strcmp(aTopic, "profiler-subprocess-gather")) { + mGatherer = static_cast(aSubject); + mGatherer->WillGatherOOPProfile(); + unused << SendGatherProfile(); + } else if (!strcmp(aTopic, "profiler-subprocess")) { nsCOMPtr pse = do_QueryInterface(aSubject); if (pse) { diff --git a/dom/ipc/ContentParent.h b/dom/ipc/ContentParent.h index 69438a6614..3e1b47535c 100644 --- a/dom/ipc/ContentParent.h +++ b/dom/ipc/ContentParent.h @@ -7,6 +7,7 @@ #ifndef mozilla_dom_ContentParent_h #define mozilla_dom_ContentParent_h +#include "mozilla/dom/NuwaParent.h" #include "mozilla/dom/PContentParent.h" #include "mozilla/dom/nsIContentParent.h" #include "mozilla/ipc/GeckoChildProcessHost.h" @@ -375,6 +376,9 @@ public: bool HasGamepadListener() const { return mHasGamepadListener; } + void SetNuwaParent(NuwaParent* aNuwaParent) { mNuwaParent = aNuwaParent; } + void ForkNewProcess(bool aBlocking); + protected: void OnChannelConnected(int32_t pid) override; virtual void ActorDestroy(ActorDestroyReason why) override; @@ -763,10 +767,10 @@ private: virtual bool RecvSystemMessageHandled() override; - virtual bool RecvNuwaReady() override; - - virtual bool RecvAddNewProcess(const uint32_t& aPid, - InfallibleTArray&& aFds) override; + // Callbacks from NuwaParent. + void OnNuwaReady(); + void OnNewProcessCreated(uint32_t aPid, + UniquePtr>&& aFds); virtual bool RecvCreateFakeVolume(const nsString& fsName, const nsString& mountPoint) override; @@ -902,6 +906,9 @@ private: bool mShutdownPending; bool mIPCOpen; + // Allows NuwaParent to access OnNuwaReady() and OnNewProcessCreated(). + friend class NuwaParent; + nsRefPtr mConsoleService; nsConsoleService* GetConsoleService(); @@ -919,6 +926,11 @@ private: #endif PProcessHangMonitorParent* mHangMonitorActor; + + // NuwaParent and ContentParent hold strong references to each other. The + // cycle will be broken when either actor is destroyed. + nsRefPtr mNuwaParent; + #ifdef MOZ_ENABLE_PROFILER_SPS nsRefPtr mGatherer; #endif diff --git a/dom/ipc/NuwaChild.cpp b/dom/ipc/NuwaChild.cpp new file mode 100644 index 0000000000..cda41ae4db --- /dev/null +++ b/dom/ipc/NuwaChild.cpp @@ -0,0 +1,256 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ContentChild.h" +#ifdef MOZ_NUWA_PROCESS +#include "ipc/Nuwa.h" +#endif +#include "mozilla/dom/ContentChild.h" +#include "mozilla/ipc/BackgroundChild.h" +#include "mozilla/ipc/PBackgroundChild.h" +#include "mozilla/ipc/ProtocolUtils.h" +#if defined(MOZ_CONTENT_SANDBOX) +#if defined(XP_LINUX) +#include "mozilla/Sandbox.h" +#include "mozilla/SandboxInfo.h" +#elif defined(XP_MACOSX) +#include "mozilla/Sandbox.h" +#endif +#endif +#include "mozilla/unused.h" +#include "nsXULAppAPI.h" +#include "NuwaChild.h" + + +using namespace mozilla::ipc; +using namespace mozilla::dom; + +namespace mozilla { +namespace dom { + +#ifdef MOZ_NUWA_PROCESS + +namespace { + +class CallNuwaSpawn: public nsRunnable +{ +public: + NS_IMETHOD Run() + { + NuwaSpawn(); + if (IsNuwaProcess()) { + return NS_OK; + } + + // In the new process. + ContentChild* child = ContentChild::GetSingleton(); + child->InitProcessAttributes(); + + // Perform other after-fork initializations. + InitOnContentProcessCreated(); + + return NS_OK; + } +}; + +static void +DoNuwaFork() +{ + NuwaSpawnPrepare(); // NuwaSpawn will be blocked. + + { + nsCOMPtr callSpawn(new CallNuwaSpawn()); + NS_DispatchToMainThread(callSpawn); + } + + // IOThread should be blocked here for waiting NuwaSpawn(). + NuwaSpawnWait(); // Now! NuwaSpawn can go. + // Here, we can make sure the spawning was finished. +} + +/** + * This function should keep IO thread in a stable state and freeze it + * until the spawning is finished. + */ +static void +RunNuwaFork() +{ + if (NuwaCheckpointCurrentThread()) { + DoNuwaFork(); + } +} + +static bool sNuwaForking = false; + +void +NuwaFork() +{ + if (sNuwaForking) { // No reentry. + return; + } + sNuwaForking = true; + + MessageLoop* ioloop = XRE_GetIOMessageLoop(); + ioloop->PostTask(FROM_HERE, NewRunnableFunction(RunNuwaFork)); +} + +} // Anonymous namespace. + +#endif + +NuwaChild* NuwaChild::sSingleton; + +NuwaChild* +NuwaChild::GetSingleton() +{ + MOZ_ASSERT(NS_IsMainThread()); + + if (!sSingleton) { + PNuwaChild* nuwaChild = + BackgroundChild::GetForCurrentThread()->SendPNuwaConstructor(); + MOZ_ASSERT(nuwaChild); + + sSingleton = static_cast(nuwaChild); + } + + return sSingleton; +} + + +bool +NuwaChild::RecvFork() +{ +#ifdef MOZ_NUWA_PROCESS + if (!IsNuwaProcess()) { + NS_ERROR( + nsPrintfCString( + "Terminating child process %d for unauthorized IPC message: " + "RecvFork(%d)", getpid()).get()); + return false; + } + + nsCOMPtr runnable = + NS_NewRunnableFunction(&NuwaFork); + MOZ_ASSERT(runnable); + MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable))); + + return true; +#else + NS_ERROR("NuwaChild::RecvFork() not implemented!"); + return false; +#endif +} + +} // namespace dom +} // namespace mozilla + + +extern "C" { + +#if defined(MOZ_NUWA_PROCESS) +NS_EXPORT void +GetProtoFdInfos(NuwaProtoFdInfo* aInfoList, + size_t aInfoListSize, + size_t* aInfoSize) +{ + size_t i = 0; + + mozilla::dom::ContentChild* content = + mozilla::dom::ContentChild::GetSingleton(); + aInfoList[i].protoId = content->GetProtocolId(); + aInfoList[i].originFd = + content->GetTransport()->GetFileDescriptor(); + i++; + + IToplevelProtocol* actors[NUWA_TOPLEVEL_MAX]; + size_t count = content->GetOpenedActorsUnsafe(actors, ArrayLength(actors)); + for (size_t j = 0; j < count; j++) { + IToplevelProtocol* actor = actors[j]; + if (i >= aInfoListSize) { + NS_RUNTIMEABORT("Too many top level protocols!"); + } + + aInfoList[i].protoId = actor->GetProtocolId(); + aInfoList[i].originFd = + actor->GetTransport()->GetFileDescriptor(); + i++; + } + + if (i > NUWA_TOPLEVEL_MAX) { + NS_RUNTIMEABORT("Too many top level protocols!"); + } + *aInfoSize = i; +} + +class RunAddNewIPCProcess : public nsRunnable +{ +public: + RunAddNewIPCProcess(pid_t aPid, + nsTArray& aMaps) + : mPid(aPid) + { + mMaps.SwapElements(aMaps); + } + + NS_IMETHOD Run() + { + NuwaChild::GetSingleton()->SendAddNewProcess(mPid, mMaps); + + MOZ_ASSERT(sNuwaForking); + sNuwaForking = false; + + return NS_OK; + } + +private: + pid_t mPid; + nsTArray mMaps; +}; + +/** + * AddNewIPCProcess() is called by Nuwa process to tell the parent + * process that a new process is created. + * + * In the newly created process, ResetContentChildTransport() is called to + * reset fd for the IPC Channel and the session. + */ +NS_EXPORT void +AddNewIPCProcess(pid_t aPid, NuwaProtoFdInfo* aInfoList, size_t aInfoListSize) +{ + nsTArray maps; + + for (size_t i = 0; i < aInfoListSize; i++) { + int _fd = aInfoList[i].newFds[NUWA_NEWFD_PARENT]; + mozilla::ipc::FileDescriptor fd(_fd); + mozilla::ipc::ProtocolFdMapping map(aInfoList[i].protoId, fd); + maps.AppendElement(map); + } + + nsRefPtr runner = new RunAddNewIPCProcess(aPid, maps); + NS_DispatchToMainThread(runner); +} + +NS_EXPORT void +OnNuwaProcessReady() +{ + NuwaChild* nuwaChild = NuwaChild::GetSingleton(); + MOZ_ASSERT(nuwaChild); + + mozilla::unused << nuwaChild->SendNotifyReady(); +} + +NS_EXPORT void +AfterNuwaFork() +{ + SetCurrentProcessPrivileges(base::PRIVILEGES_DEFAULT); +#if defined(XP_LINUX) && defined(MOZ_SANDBOX) + mozilla::SandboxEarlyInit(XRE_GetProcessType(), /* isNuwa: */ false); +#endif +} + +#endif // MOZ_NUWA_PROCESS + +} diff --git a/dom/ipc/NuwaChild.h b/dom/ipc/NuwaChild.h new file mode 100644 index 0000000000..3a65d16081 --- /dev/null +++ b/dom/ipc/NuwaChild.h @@ -0,0 +1,34 @@ +/* -*- 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/. */ + +#ifndef mozilla_dom_NuwaChild_h +#define mozilla_dom_NuwaChild_h + +#include "mozilla/Assertions.h" +#include "mozilla/dom/PNuwaChild.h" +#include "nsThreadUtils.h" + +namespace mozilla { +namespace dom { +class NuwaChild: public mozilla::dom::PNuwaChild +{ +public: + virtual bool RecvFork() override; + + virtual void ActorDestroy(ActorDestroyReason aWhy) override + { } + + static NuwaChild* GetSingleton(); + +private: + static NuwaChild* sSingleton; +}; + +} // namespace dom +} // namespace mozilla + +#endif + diff --git a/dom/ipc/NuwaParent.cpp b/dom/ipc/NuwaParent.cpp new file mode 100644 index 0000000000..c377703896 --- /dev/null +++ b/dom/ipc/NuwaParent.cpp @@ -0,0 +1,263 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/dom/ContentParent.h" +#include "mozilla/ipc/BackgroundParent.h" +#include "mozilla/ipc/PBackgroundParent.h" +#include "mozilla/unused.h" +#include "nsThreadUtils.h" +#include "NuwaParent.h" + +using namespace mozilla::ipc; +using namespace mozilla::dom; +using namespace IPC; + +namespace mozilla { +namespace dom { + +/*static*/ NuwaParent* +NuwaParent::Alloc() { + nsRefPtr actor = new NuwaParent(); + return actor.forget().take(); +} + +/*static*/ bool +NuwaParent::ActorConstructed(mozilla::dom::PNuwaParent *aActor) +{ + NuwaParent* actor = static_cast(aActor); + actor->ActorConstructed(); + + return true; +} + +/*static*/ bool +NuwaParent::Dealloc(mozilla::dom::PNuwaParent *aActor) +{ + nsRefPtr actor = dont_AddRef(static_cast(aActor)); + return true; +} + +NuwaParent::NuwaParent() + : mBlocked(false) + , mMonitor("NuwaParent") + , mClonedActor(nullptr) + , mWorkerThread(do_GetCurrentThread()) + , mNewProcessPid(0) +{ + AssertIsOnBackgroundThread(); +} + +NuwaParent::~NuwaParent() +{ + // Both the worker thread and the main thread (ContentParent) hold a ref to + // this. The instance may be destroyed on either thread. + MOZ_ASSERT(!mContentParent); +} + +inline void +NuwaParent::AssertIsOnWorkerThread() +{ + nsCOMPtr currentThread = do_GetCurrentThread(); + MOZ_ASSERT(currentThread == mWorkerThread); +} + +bool +NuwaParent::ActorConstructed() +{ + AssertIsOnWorkerThread(); + MOZ_ASSERT(Manager()); + MOZ_ASSERT(!mContentParent); + + mContentParent = BackgroundParent::GetContentParent(Manager()); + if (!mContentParent) { + return false; + } + + // mContentParent is guaranteed to be alive. It's safe to set its backward ref + // to this. + mContentParent->SetNuwaParent(this); + return true; +} + +mozilla::ipc::IProtocol* +NuwaParent::CloneProtocol(Channel* aChannel, + ProtocolCloneContext* aCtx) +{ + MOZ_ASSERT(NS_IsMainThread()); + nsRefPtr self = this; + + MonitorAutoLock lock(mMonitor); + + // Alloc NuwaParent on the worker thread. + nsCOMPtr runnable = NS_NewRunnableFunction([self] () -> void + { + MonitorAutoLock lock(self->mMonitor); + // XXX Calling NuwaParent::Alloc() leads to a compilation error. Use + // self->Alloc() as a workaround. + self->mClonedActor = self->Alloc(); + lock.Notify(); + }); + MOZ_ASSERT(runnable); + MOZ_ALWAYS_TRUE(NS_SUCCEEDED(mWorkerThread->Dispatch(runnable, + NS_DISPATCH_NORMAL))); + + while (!mClonedActor) { + lock.Wait(); + } + nsRefPtr actor = mClonedActor; + mClonedActor = nullptr; + + // mManager of the cloned actor is assigned after returning from this method. + // We can't call ActorConstructed() right after Alloc() in the above runnable. + // To be safe we dispatch a runnable to the current thread to do it. + runnable = NS_NewRunnableFunction([actor] () -> void + { + MOZ_ASSERT(NS_IsMainThread()); + + nsCOMPtr nested = NS_NewRunnableFunction([actor] () -> void + { + AssertIsOnBackgroundThread(); + + // Call NuwaParent::ActorConstructed() on the worker thread. + actor->ActorConstructed(); + + // The actor can finally be deleted after fully constructed. + mozilla::unused << actor->Send__delete__(actor); + }); + MOZ_ASSERT(nested); + MOZ_ALWAYS_TRUE(NS_SUCCEEDED( + actor->mWorkerThread->Dispatch(nested, NS_DISPATCH_NORMAL))); + }); + + MOZ_ASSERT(runnable); + MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable))); + + return actor; +} + +void +NuwaParent::ActorDestroy(ActorDestroyReason aWhy) +{ + AssertIsOnWorkerThread(); + + nsRefPtr self = this; + nsCOMPtr runnable = NS_NewRunnableFunction([self] () -> void + { + // These extra nsRefPtr serve as kungFuDeathGrip to keep both objects from + // deletion in breaking the ref cycle. + nsRefPtr contentParent = self->mContentParent; + + contentParent->SetNuwaParent(nullptr); + // Need to clear the ref to ContentParent on the main thread. + self->mContentParent = nullptr; + }); + MOZ_ASSERT(runnable); + MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable))); +} + +bool +NuwaParent::RecvNotifyReady() +{ +#ifdef MOZ_NUWA_PROCESS + if (!mContentParent || !mContentParent->IsNuwaProcess()) { + NS_ERROR("Received NotifyReady() message from a non-Nuwa process."); + return false; + } + + // Creating a NonOwningRunnableMethod here is safe because refcount changes of + // mContentParent have to go the the main thread. The mContentParent will + // be alive when the runnable runs. + nsCOMPtr runnable = + NS_NewNonOwningRunnableMethod(mContentParent.get(), + &ContentParent::OnNuwaReady); + MOZ_ASSERT(runnable); + MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable))); + + return true; +#else + NS_ERROR("NuwaParent::RecvNotifyReady() not implemented!"); + return false; +#endif +} + +bool +NuwaParent::RecvAddNewProcess(const uint32_t& aPid, + nsTArray&& aFds) +{ +#ifdef MOZ_NUWA_PROCESS + if (!mContentParent || !mContentParent->IsNuwaProcess()) { + NS_ERROR("Received AddNewProcess() message from a non-Nuwa process."); + return false; + } + + mNewProcessPid = aPid; + mNewProcessFds->SwapElements(aFds); + MonitorAutoLock lock(mMonitor); + if (mBlocked) { + // Unblock ForkNewProcess(). + mMonitor.Notify(); + mBlocked = false; + } else { + nsCOMPtr runnable = + NS_NewNonOwningRunnableMethodWithArgs< + uint32_t, + UniquePtr>&& >( + mContentParent.get(), + &ContentParent::OnNewProcessCreated, + mNewProcessPid, + Move(mNewProcessFds)); + MOZ_ASSERT(runnable); + MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable))); + } + return true; +#else + NS_ERROR("NuwaParent::RecvAddNewProcess() not implemented!"); + return false; +#endif +} + +bool +NuwaParent::ForkNewProcess(uint32_t& aPid, + UniquePtr>&& aFds, + bool aBlocking) +{ + MOZ_ASSERT(mWorkerThread); + MOZ_ASSERT(NS_IsMainThread()); + + mNewProcessFds = Move(aFds); + + nsRefPtr self = this; + nsCOMPtr runnable = NS_NewRunnableFunction([self] () -> void + { + mozilla::unused << self->SendFork(); + }); + MOZ_ASSERT(runnable); + MOZ_ALWAYS_TRUE(NS_SUCCEEDED(mWorkerThread->Dispatch(runnable, + NS_DISPATCH_NORMAL))); + if (!aBlocking) { + return false; + } + + MonitorAutoLock lock(mMonitor); + mBlocked = true; + while (mBlocked) { + // This will be notified in NuwaParent::RecvAddNewProcess(). + lock.Wait(); + } + + if (!mNewProcessPid) { + return false; + } + + aPid = mNewProcessPid; + aFds = Move(mNewProcessFds); + + mNewProcessPid = 0; + return true; +} + +} // namespace dom +} // namespace mozilla diff --git a/dom/ipc/NuwaParent.h b/dom/ipc/NuwaParent.h new file mode 100644 index 0000000000..538bc5122a --- /dev/null +++ b/dom/ipc/NuwaParent.h @@ -0,0 +1,73 @@ +/* -*- 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/. */ + +#ifndef mozilla_dom_NuwaParent_h +#define mozilla_dom_NuwaParent_h + +#include "base/message_loop.h" +#include "mozilla/dom/PNuwaParent.h" +#include "mozilla/Monitor.h" +#include "mozilla/nsRefPtr.h" + +namespace mozilla { +namespace dom { + +class ContentParent; + +class NuwaParent : public mozilla::dom::PNuwaParent +{ +public: + explicit NuwaParent(); + + // Called on the main thread. + bool ForkNewProcess(uint32_t& aPid, + UniquePtr>&& aFds, + bool aBlocking); + + // Called on the background thread. + bool ActorConstructed(); + + // Both the worker thread and the main thread hold a ref to this. + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(NuwaParent) + + // Functions to be invoked by the manager of this actor to alloc/dealloc the + // actor. + static NuwaParent* Alloc(); + static bool ActorConstructed(mozilla::dom::PNuwaParent *aActor); + static bool Dealloc(mozilla::dom::PNuwaParent *aActor); + +protected: + virtual ~NuwaParent(); + + virtual bool RecvNotifyReady() override; + virtual bool RecvAddNewProcess(const uint32_t& aPid, + nsTArray&& aFds) override; + virtual mozilla::ipc::IProtocol* + CloneProtocol(Channel* aChannel, + ProtocolCloneContext* aCtx) override; + + virtual void ActorDestroy(ActorDestroyReason aWhy) override; + +private: + void AssertIsOnWorkerThread(); + + bool mBlocked; + mozilla::Monitor mMonitor; + NuwaParent* mClonedActor; + + nsCOMPtr mWorkerThread; + + uint32_t mNewProcessPid; + UniquePtr> mNewProcessFds; + + // The mutual reference will be broken on the main thread. + nsRefPtr mContentParent; +}; + +} // namespace dom +} // namespace mozilla + +#endif diff --git a/dom/ipc/PContent.ipdl b/dom/ipc/PContent.ipdl index 9e1a5e1291..d595fbfec3 100644 --- a/dom/ipc/PContent.ipdl +++ b/dom/ipc/PContent.ipdl @@ -71,7 +71,7 @@ include "mozilla/dom/TabMessageUtils.h"; using GeoPosition from "nsGeoPositionIPCSerialiser.h"; using struct ChromePackage from "mozilla/chrome/RegistryMessageUtils.h"; -using struct ResourceMapping from "mozilla/chrome/RegistryMessageUtils.h"; +using struct SubstitutionMapping from "mozilla/chrome/RegistryMessageUtils.h"; using struct OverrideMapping from "mozilla/chrome/RegistryMessageUtils.h"; using base::ChildPrivileges from "base/process_util.h"; using base::ProcessId from "base/process.h"; @@ -93,7 +93,7 @@ union ChromeRegistryItem { ChromePackage; OverrideMapping; - ResourceMapping; + SubstitutionMapping; }; namespace mozilla { @@ -519,7 +519,7 @@ child: PTestShell(); - RegisterChrome(ChromePackage[] packages, ResourceMapping[] resources, + RegisterChrome(ChromePackage[] packages, SubstitutionMapping[] substitutions, OverrideMapping[] overrides, nsCString locale, bool reset); RegisterChromeItem(ChromeRegistryItem item); @@ -577,9 +577,6 @@ child: // Notify volume is removed. VolumeRemoved(nsString fsName); - // Ask the Nuwa process to create a new child process. - NuwaFork(); - NotifyProcessPriorityChanged(ProcessPriority priority); MinimizeMemoryUsage(); @@ -620,6 +617,7 @@ child: async StartProfiler(uint32_t aEntries, double aInterval, nsCString[] aFeatures, nsCString[] aThreadNameFilters); async StopProfiler(); + async PauseProfiler(bool aPause); async GatherProfile(); @@ -728,7 +726,7 @@ parent: PFileSystemRequest(FileSystemParams params); - sync GetRandomValues(uint32_t length) + prio(urgent) sync GetRandomValues(uint32_t length) returns (uint8_t[] randomValues); async GetSystemMemory(uint64_t getterId); @@ -884,10 +882,6 @@ parent: // Notify the parent that the child has finished handling a system message. async SystemMessageHandled(); - NuwaReady(); - - sync AddNewProcess(uint32_t pid, ProtocolFdMapping[] aFds); - // called by the child (test code only) to propagate volume changes to the parent async CreateFakeVolume(nsString fsName, nsString mountPoint); async SetFakeVolumeState(nsString fsName, int32_t fsState); diff --git a/dom/ipc/PNuwa.ipdl b/dom/ipc/PNuwa.ipdl new file mode 100644 index 0000000000..8da39194d4 --- /dev/null +++ b/dom/ipc/PNuwa.ipdl @@ -0,0 +1,31 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +include protocol PBackground; +include ProtocolTypes; + +namespace mozilla { +namespace dom { + +sync protocol PNuwa +{ + manager PBackground; + +child: + // Ask the Nuwa process to create a new child process. + async Fork(); + + // This message will be sent to non-Nuwa process, or to Nuwa process during + // test. + async __delete__(); + +parent: + async NotifyReady(); + sync AddNewProcess(uint32_t pid, ProtocolFdMapping[] aFds); +}; + +} // namespace layout +} // namespace mozilla + diff --git a/dom/ipc/PreallocatedProcessManager.cpp b/dom/ipc/PreallocatedProcessManager.cpp index 989360a99f..5193af464d 100644 --- a/dom/ipc/PreallocatedProcessManager.cpp +++ b/dom/ipc/PreallocatedProcessManager.cpp @@ -267,10 +267,15 @@ PreallocatedProcessManagerImpl::GetSpareProcess() { MOZ_ASSERT(NS_IsMainThread()); - if (mSpareProcesses.IsEmpty()) { + if (!mIsNuwaReady) { return nullptr; } + if (mSpareProcesses.IsEmpty()) { + // After this call, there should be a spare process. + mPreallocatedAppProcess->ForkNewProcess(true); + } + nsRefPtr process = mSpareProcesses.LastElement(); mSpareProcesses.RemoveElementAt(mSpareProcesses.Length() - 1); @@ -358,7 +363,7 @@ PreallocatedProcessManagerImpl::PreallocatedProcessReady() void PreallocatedProcessManagerImpl::NuwaFork() { - mozilla::unused << mPreallocatedAppProcess->SendNuwaFork(); + mPreallocatedAppProcess->ForkNewProcess(false); } #endif diff --git a/dom/ipc/ScreenManagerParent.cpp b/dom/ipc/ScreenManagerParent.cpp index 45e290382e..058709edea 100644 --- a/dom/ipc/ScreenManagerParent.cpp +++ b/dom/ipc/ScreenManagerParent.cpp @@ -4,6 +4,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "mozilla/dom/ContentParent.h" #include "mozilla/dom/TabParent.h" #include "mozilla/unused.h" #include "nsIWidget.h" diff --git a/dom/ipc/StructuredCloneUtils.cpp b/dom/ipc/StructuredCloneUtils.cpp index dfcb140cb8..de2fb029a9 100644 --- a/dom/ipc/StructuredCloneUtils.cpp +++ b/dom/ipc/StructuredCloneUtils.cpp @@ -13,6 +13,7 @@ #include "mozilla/dom/BindingUtils.h" #include "mozilla/dom/BlobBinding.h" #include "mozilla/dom/File.h" +#include "mozilla/dom/ToJSValue.h" #include "nsContentUtils.h" #include "nsJSEnvironment.h" #include "MainThreadUtils.h" diff --git a/dom/ipc/TabChild.cpp b/dom/ipc/TabChild.cpp index 6627d92af7..744d048343 100644 --- a/dom/ipc/TabChild.cpp +++ b/dom/ipc/TabChild.cpp @@ -8,6 +8,8 @@ #include "TabChild.h" +#include "AudioChannelService.h" +#include "gfxPrefs.h" #ifdef ACCESSIBILITY #include "mozilla/a11y/DocAccessibleChild.h" #endif @@ -30,6 +32,7 @@ #include "mozilla/layers/ImageBridgeChild.h" #include "mozilla/layers/ShadowLayers.h" #include "mozilla/layout/RenderFrameChild.h" +#include "mozilla/LookAndFeel.h" #include "mozilla/MouseEvents.h" #include "mozilla/Services.h" #include "mozilla/StaticPtr.h" diff --git a/dom/ipc/moz.build b/dom/ipc/moz.build index e603f4bf36..e0d71df3a1 100644 --- a/dom/ipc/moz.build +++ b/dom/ipc/moz.build @@ -32,6 +32,8 @@ EXPORTS.mozilla.dom += [ 'FilePickerParent.h', 'nsIContentChild.h', 'nsIContentParent.h', + 'NuwaChild.h', + 'NuwaParent.h', 'PermissionMessageUtils.h', 'StructuredCloneUtils.h', 'TabChild.h', @@ -59,6 +61,8 @@ UNIFIED_SOURCES += [ 'FilePickerParent.cpp', 'nsIContentChild.cpp', 'nsIContentParent.cpp', + 'NuwaChild.cpp', + 'NuwaParent.cpp', 'PermissionMessageUtils.cpp', 'PreallocatedProcessManager.cpp', 'ProcessPriorityManager.cpp', @@ -94,6 +98,7 @@ IPDL_SOURCES += [ 'PDocumentRenderer.ipdl', 'PFilePicker.ipdl', 'PMemoryReportRequest.ipdl', + 'PNuwa.ipdl', 'PPluginWidget.ipdl', 'PProcessHangMonitor.ipdl', 'PScreenManager.ipdl', diff --git a/dom/ipc/nsIContentChild.h b/dom/ipc/nsIContentChild.h index ab5a23ddc0..957cbd4b31 100644 --- a/dom/ipc/nsIContentChild.h +++ b/dom/ipc/nsIContentChild.h @@ -12,6 +12,7 @@ #include "nsISupports.h" #include "nsTArrayForwardDeclare.h" #include "mozilla/dom/CPOWManagerGetter.h" +#include "mozilla/jsipc/CrossProcessObjectWrappers.h" #define NS_ICONTENTCHILD_IID \ { 0x4eed2e73, 0x94ba, 0x48a8, \ diff --git a/dom/messagechannel/MessagePort.cpp b/dom/messagechannel/MessagePort.cpp index 6a328bb969..c922bbed9b 100644 --- a/dom/messagechannel/MessagePort.cpp +++ b/dom/messagechannel/MessagePort.cpp @@ -21,6 +21,7 @@ #include "mozilla/dom/WorkerScope.h" #include "mozilla/ipc/BackgroundChild.h" #include "mozilla/ipc/PBackgroundChild.h" +#include "mozilla/unused.h" #include "nsContentUtils.h" #include "nsGlobalWindow.h" #include "nsPresContext.h" @@ -249,6 +250,50 @@ private: } }; +class ForceCloseHelper final : public nsIIPCBackgroundChildCreateCallback +{ +public: + NS_DECL_ISUPPORTS + + static void ForceClose(const MessagePortIdentifier& aIdentifier) + { + PBackgroundChild* actor = + mozilla::ipc::BackgroundChild::GetForCurrentThread(); + if (actor) { + unused << actor->SendMessagePortForceClose(aIdentifier.uuid(), + aIdentifier.destinationUuid(), + aIdentifier.sequenceId()); + return; + } + + nsRefPtr helper = new ForceCloseHelper(aIdentifier); + if (NS_WARN_IF(!mozilla::ipc::BackgroundChild::GetOrCreateForCurrentThread(helper))) { + MOZ_CRASH(); + } + } + +private: + explicit ForceCloseHelper(const MessagePortIdentifier& aIdentifier) + : mIdentifier(aIdentifier) + {} + + ~ForceCloseHelper() {} + + void ActorFailed() override + { + MOZ_CRASH("Failed to create a PBackgroundChild actor!"); + } + + void ActorCreated(mozilla::ipc::PBackgroundChild* aActor) override + { + ForceClose(mIdentifier); + } + + const MessagePortIdentifier mIdentifier; +}; + +NS_IMPL_ISUPPORTS(ForceCloseHelper, nsIIPCBackgroundChildCreateCallback) + } // anonymous namespace MessagePort::MessagePort(nsPIDOMWindow* aWindow) @@ -863,5 +908,11 @@ MessagePort::RemoveDocFromBFCache() bfCacheEntry->RemoveFromBFCacheSync(); } +/* static */ void +MessagePort::ForceClose(const MessagePortIdentifier& aIdentifier) +{ + ForceCloseHelper::ForceClose(aIdentifier); +} + } // namespace dom } // namespace mozilla diff --git a/dom/messagechannel/MessagePort.h b/dom/messagechannel/MessagePort.h index 63081a0833..ede640ba6a 100644 --- a/dom/messagechannel/MessagePort.h +++ b/dom/messagechannel/MessagePort.h @@ -86,6 +86,9 @@ public: Create(nsPIDOMWindow* aWindow, const MessagePortIdentifier& aIdentifier, ErrorResult& aRv); + static void + ForceClose(const MessagePortIdentifier& aIdentifier); + virtual JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; diff --git a/dom/messagechannel/MessagePortParent.cpp b/dom/messagechannel/MessagePortParent.cpp index 25dadafdab..917606bf09 100644 --- a/dom/messagechannel/MessagePortParent.cpp +++ b/dom/messagechannel/MessagePortParent.cpp @@ -159,5 +159,19 @@ MessagePortParent::Close() mEntangled = false; } +/* static */ bool +MessagePortParent::ForceClose(const nsID& aUUID, + const nsID& aDestinationUUID, + const uint32_t& aSequenceID) +{ + MessagePortService* service = MessagePortService::Get(); + if (!service) { + NS_WARNING("The service must exist if we want to close an existing MessagePort."); + return false; + } + + return service->ForceClose(aUUID, aDestinationUUID, aSequenceID); +} + } // dom namespace } // mozilla namespace diff --git a/dom/messagechannel/MessagePortParent.h b/dom/messagechannel/MessagePortParent.h index 46dbb19ff0..1dcfb53e79 100644 --- a/dom/messagechannel/MessagePortParent.h +++ b/dom/messagechannel/MessagePortParent.h @@ -36,6 +36,10 @@ public: return mUUID; } + static bool ForceClose(const nsID& aUUID, + const nsID& aDestinationUUID, + const uint32_t& aSequenceID); + private: virtual bool RecvPostMessages(nsTArray&& aMessages) override; diff --git a/dom/messagechannel/MessagePortService.cpp b/dom/messagechannel/MessagePortService.cpp index 0d75e6ba19..afd5ab98af 100644 --- a/dom/messagechannel/MessagePortService.cpp +++ b/dom/messagechannel/MessagePortService.cpp @@ -6,16 +6,27 @@ #include "MessagePortService.h" #include "MessagePortParent.h" #include "SharedMessagePortMessage.h" +#include "mozilla/ipc/BackgroundParent.h" #include "mozilla/StaticPtr.h" #include "mozilla/unused.h" #include "nsDataHashtable.h" #include "nsTArray.h" +using mozilla::ipc::AssertIsOnBackgroundThread; + namespace mozilla { namespace dom { namespace { + StaticRefPtr gInstance; + +void +AssertIsInMainProcess() +{ + MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default); +} + } // anonymous namespace class MessagePortService::MessagePortServiceData final @@ -53,9 +64,21 @@ public: FallibleTArray> mMessages; }; +/* static */ MessagePortService* +MessagePortService::Get() +{ + AssertIsInMainProcess(); + AssertIsOnBackgroundThread(); + + return gInstance; +} + /* static */ MessagePortService* MessagePortService::GetOrCreate() { + AssertIsInMainProcess(); + AssertIsOnBackgroundThread(); + if (!gInstance) { gInstance = new MessagePortService(); } @@ -248,6 +271,12 @@ MessagePortService::CloseAll(const nsID& aUUID) CloseAll(destinationUUID); + // CloseAll calls itself recursively and it can happen that it deletes + // itself. Before continuing we must check if we are still alive. + if (!gInstance) { + return; + } + #ifdef DEBUG mPorts.EnumerateRead(CloseAllDebugCheck, const_cast(&aUUID)); #endif @@ -324,5 +353,26 @@ MessagePortService::ParentDestroy(MessagePortParent* aParent) CloseAll(aParent->ID()); } +bool +MessagePortService::ForceClose(const nsID& aUUID, + const nsID& aDestinationUUID, + const uint32_t& aSequenceID) +{ + MessagePortServiceData* data; + if (!mPorts.Get(aUUID, &data)) { + NS_WARNING("Unknown MessagePort in ForceClose()"); + return true; + } + + if (!data->mDestinationUUID.Equals(aDestinationUUID) || + data->mSequenceID != aSequenceID) { + NS_WARNING("DestinationUUID and/or sequenceID do not match."); + return false; + } + + CloseAll(aUUID); + return true; +} + } // dom namespace } // mozilla namespace diff --git a/dom/messagechannel/MessagePortService.h b/dom/messagechannel/MessagePortService.h index 437cf2393c..faae81fcbc 100644 --- a/dom/messagechannel/MessagePortService.h +++ b/dom/messagechannel/MessagePortService.h @@ -20,6 +20,7 @@ class MessagePortService final public: NS_INLINE_DECL_REFCOUNTING(MessagePortService) + static MessagePortService* Get(); static MessagePortService* GetOrCreate(); bool RequestEntangling(MessagePortParent* aParent, @@ -38,6 +39,10 @@ public: void ParentDestroy(MessagePortParent* aParent); + bool ForceClose(const nsID& aUUID, + const nsID& aDestinationUUID, + const uint32_t& aSequenceID); + private: ~MessagePortService() {} diff --git a/dom/messagechannel/MessagePortUtils.cpp b/dom/messagechannel/MessagePortUtils.cpp index 06b330b7f4..ccd3b13043 100644 --- a/dom/messagechannel/MessagePortUtils.cpp +++ b/dom/messagechannel/MessagePortUtils.cpp @@ -141,7 +141,7 @@ ReadTransfer(JSContext* aCx, JSStructuredCloneReader* aReader, ErrorResult rv; nsRefPtr port = MessagePort::Create(closure->mWindow, - closure->mClosure.mMessagePortIdentifiers[(uint32_t)aExtraData], + closure->mClosure.mMessagePortIdentifiers[aExtraData], rv); if (NS_WARN_IF(rv.Failed())) { return false; @@ -195,13 +195,27 @@ WriteTransfer(JSContext* aCx, JS::Handle aObj, void* aClosure, return true; } +void +FreeTransfer(uint32_t aTag, JS::TransferableOwnership aOwnership, + void* aContent, uint64_t aExtraData, void* aClosure) +{ + MOZ_ASSERT(aClosure); + auto* closure = static_cast(aClosure); + + if (aTag == SCTAG_DOM_MAP_MESSAGEPORT) { + MOZ_ASSERT(!aContent); + MOZ_ASSERT(aExtraData < closure->mClosure.mMessagePortIdentifiers.Length()); + MessagePort::ForceClose(closure->mClosure.mMessagePortIdentifiers[(uint32_t)aExtraData]); + } +} + const JSStructuredCloneCallbacks gCallbacks = { Read, Write, Error, ReadTransfer, WriteTransfer, - nullptr + FreeTransfer, }; } // anonymous namespace diff --git a/dom/messagechannel/tests/mochitest.ini b/dom/messagechannel/tests/mochitest.ini index fc5cecd130..8633b3cdc9 100644 --- a/dom/messagechannel/tests/mochitest.ini +++ b/dom/messagechannel/tests/mochitest.ini @@ -23,3 +23,4 @@ support-files = [test_messageChannel_sharedWorker.html] [test_messageChannel_sharedWorker2.html] [test_messageChannel_any.html] +[test_messageChannel_forceClose.html] diff --git a/dom/messagechannel/tests/test_messageChannel_forceClose.html b/dom/messagechannel/tests/test_messageChannel_forceClose.html new file mode 100644 index 0000000000..dae2292ab8 --- /dev/null +++ b/dom/messagechannel/tests/test_messageChannel_forceClose.html @@ -0,0 +1,36 @@ + + + + + + Test for Bug 1176034 - start/close + + + + +Mozilla Bug 1176034 +
+
+
+ + + diff --git a/dom/webidl/ChromeUtils.webidl b/dom/webidl/ChromeUtils.webidl index 35b8aead90..dc4cf6ce37 100644 --- a/dom/webidl/ChromeUtils.webidl +++ b/dom/webidl/ChromeUtils.webidl @@ -32,4 +32,5 @@ interface ChromeUtils : ThreadSafeChromeUtils { dictionary OriginAttributesDictionary { unsigned long appId = 0; boolean inBrowser = false; + DOMString addonId = ""; }; diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp index 8f4959a3ba..2fa2e361d0 100644 --- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp @@ -765,7 +765,14 @@ struct WorkerStructuredCloneCallbacks FreeTransfer(uint32_t aTag, JS::TransferableOwnership aOwnership, void *aContent, uint64_t aExtraData, void* aClosure) { - // Nothing to do. + if (aTag == SCTAG_DOM_MAP_MESSAGEPORT) { + MOZ_ASSERT(aClosure); + MOZ_ASSERT(!aContent); + auto* closure = static_cast(aClosure); + + MOZ_ASSERT(aExtraData < closure->mMessagePortIdentifiers.Length()); + dom::MessagePort::ForceClose(closure->mMessagePortIdentifiers[aExtraData]); + } } }; @@ -3516,12 +3523,38 @@ WorkerPrivateParent::DispatchMessageEventToMessagePort( AssertIsOnMainThread(); JSAutoStructuredCloneBuffer buffer(Move(aBuffer)); + const JSStructuredCloneCallbacks* callbacks = + WorkerStructuredCloneCallbacks(true); + + class MOZ_STACK_CLASS AutoCloneBufferCleaner final + { + public: + AutoCloneBufferCleaner(JSAutoStructuredCloneBuffer& aBuffer, + const JSStructuredCloneCallbacks* aCallbacks, + WorkerStructuredCloneClosure& aClosure) + : mBuffer(aBuffer) + , mCallbacks(aCallbacks) + , mClosure(aClosure) + {} + + ~AutoCloneBufferCleaner() + { + mBuffer.clear(mCallbacks, &mClosure); + } + + private: + JSAutoStructuredCloneBuffer& mBuffer; + const JSStructuredCloneCallbacks* mCallbacks; + WorkerStructuredCloneClosure& mClosure; + }; WorkerStructuredCloneClosure closure; closure.mClonedObjects.SwapElements(aClosure.mClonedObjects); MOZ_ASSERT(aClosure.mMessagePorts.IsEmpty()); closure.mMessagePortIdentifiers.SwapElements(aClosure.mMessagePortIdentifiers); + AutoCloneBufferCleaner bufferCleaner(buffer, callbacks, closure); + SharedWorker* sharedWorker; if (!mSharedWorkers.Get(aMessagePortSerial, &sharedWorker)) { // SharedWorker has already been unregistered? @@ -3549,8 +3582,6 @@ WorkerPrivateParent::DispatchMessageEventToMessagePort( return false; } - buffer.clear(); - nsRefPtr event = new MessageEvent(port, nullptr, nullptr); nsresult rv = event->InitMessageEvent(NS_LITERAL_STRING("message"), false, false, data, diff --git a/image/DecodePool.cpp b/image/DecodePool.cpp index eece31ef19..08c0617eea 100644 --- a/image/DecodePool.cpp +++ b/image/DecodePool.cpp @@ -192,6 +192,7 @@ public: /// Pushes a new decode work item. void PushWork(Decoder* aDecoder) { + MOZ_ASSERT(aDecoder); nsRefPtr decoder(aDecoder); MonitorAutoLock lock(mMonitor); @@ -201,43 +202,41 @@ public: return; } - mQueue.AppendElement(Move(decoder)); + if (aDecoder->IsSizeDecode()) { + mSizeDecodeQueue.AppendElement(Move(decoder)); + } else { + mFullDecodeQueue.AppendElement(Move(decoder)); + } + mMonitor.Notify(); } /// Pops a new work item, blocking if necessary. Work PopWork() { - Work work; - MonitorAutoLock lock(mMonitor); do { - if (!mQueue.IsEmpty()) { - // XXX(seth): This is NOT efficient, obviously, since we're removing an - // element from the front of the array. However, it's not worth - // implementing something better right now, because we are replacing - // this FIFO behavior with LIFO behavior very soon. - work.mType = Work::Type::DECODE; - work.mDecoder = mQueue.ElementAt(0); - mQueue.RemoveElementAt(0); + // XXX(seth): The queue popping code below is NOT efficient, obviously, + // since we're removing an element from the front of the array. However, + // it's not worth implementing something better right now, because we are + // replacing this FIFO behavior with LIFO behavior very soon. -#ifdef MOZ_NUWA_PROCESS - nsThreadManager::get()->SetThreadWorking(); -#endif // MOZ_NUWA_PROCESS + // Prioritize size decodes over full decodes. + if (!mSizeDecodeQueue.IsEmpty()) { + return PopWorkFromQueue(mSizeDecodeQueue); + } - return work; + if (!mFullDecodeQueue.IsEmpty()) { + return PopWorkFromQueue(mFullDecodeQueue); } if (mShuttingDown) { + Work work; work.mType = Work::Type::SHUTDOWN; return work; } -#ifdef MOZ_NUWA_PROCESS - nsThreadManager::get()->SetThreadIdle(nullptr); -#endif // MOZ_NUWA_PROCESS - // Nothing to do; block until some work is available. mMonitor.Wait(); } while (true); @@ -246,11 +245,22 @@ public: private: ~DecodePoolImpl() { } + Work PopWorkFromQueue(nsTArray>& aQueue) + { + Work work; + work.mType = Work::Type::DECODE; + work.mDecoder = aQueue.ElementAt(0); + aQueue.RemoveElementAt(0); + + return work; + } + nsThreadPoolNaming mThreadNaming; // mMonitor guards mQueue and mShuttingDown. Monitor mMonitor; - nsTArray> mQueue; + nsTArray> mSizeDecodeQueue; + nsTArray> mFullDecodeQueue; bool mShuttingDown; }; @@ -319,7 +329,17 @@ DecodePool::DecodePool() int32_t prefLimit = gfxPrefs::ImageMTDecodingLimit(); uint32_t limit; if (prefLimit <= 0) { - limit = max(PR_GetNumberOfProcessors(), 2) - 1; + int32_t numCores = PR_GetNumberOfProcessors(); + if (numCores <= 1) { + limit = 1; + } else if (numCores == 2) { + // On an otherwise mostly idle system, having two image decoding threads + // doubles decoding performance, so it's worth doing on dual-core devices, + // even if under load we can't actually get that level of parallelism. + limit = 2; + } else { + limit = numCores - 1; + } } else { limit = static_cast(prefLimit); } diff --git a/ipc/glue/BackgroundChildImpl.cpp b/ipc/glue/BackgroundChildImpl.cpp index a1f53a4052..aa1fc4ca4d 100644 --- a/ipc/glue/BackgroundChildImpl.cpp +++ b/ipc/glue/BackgroundChildImpl.cpp @@ -15,6 +15,7 @@ #include "mozilla/dom/indexedDB/PBackgroundIDBFactoryChild.h" #include "mozilla/dom/ipc/BlobChild.h" #include "mozilla/dom/MessagePortChild.h" +#include "mozilla/dom/NuwaChild.h" #include "mozilla/ipc/PBackgroundTestChild.h" #include "mozilla/layout/VsyncChild.h" #include "mozilla/net/PUDPSocketChild.h" @@ -58,6 +59,7 @@ using mozilla::net::PUDPSocketChild; using mozilla::dom::cache::PCacheChild; using mozilla::dom::cache::PCacheStorageChild; using mozilla::dom::cache::PCacheStreamControlChild; +using mozilla::dom::PNuwaChild; // ----------------------------------------------------------------------------- // BackgroundChildImpl::ThreadLocal @@ -363,6 +365,21 @@ BackgroundChildImpl::DeallocPMessagePortChild(PMessagePortChild* aActor) return true; } +PNuwaChild* +BackgroundChildImpl::AllocPNuwaChild() +{ + return new mozilla::dom::NuwaChild(); +} + +bool +BackgroundChildImpl::DeallocPNuwaChild(PNuwaChild* aActor) +{ + MOZ_ASSERT(aActor); + + delete aActor; + return true; +} + } // namespace ipc } // namespace mozilla diff --git a/ipc/glue/BackgroundChildImpl.h b/ipc/glue/BackgroundChildImpl.h index c40db905a7..7c75658302 100644 --- a/ipc/glue/BackgroundChildImpl.h +++ b/ipc/glue/BackgroundChildImpl.h @@ -128,6 +128,12 @@ protected: virtual bool DeallocPMessagePortChild(PMessagePortChild* aActor) override; + + virtual PNuwaChild* + AllocPNuwaChild() override; + + virtual bool + DeallocPNuwaChild(PNuwaChild* aActor) override; }; class BackgroundChildImpl::ThreadLocal final diff --git a/ipc/glue/BackgroundParentImpl.cpp b/ipc/glue/BackgroundParentImpl.cpp index a3d86d50c1..7eab37025b 100644 --- a/ipc/glue/BackgroundParentImpl.cpp +++ b/ipc/glue/BackgroundParentImpl.cpp @@ -10,6 +10,7 @@ #include "mozilla/AppProcessChecker.h" #include "mozilla/Assertions.h" #include "mozilla/dom/ContentParent.h" +#include "mozilla/dom/NuwaParent.h" #include "mozilla/dom/PBlobParent.h" #include "mozilla/dom/MessagePortParent.h" #include "mozilla/dom/ServiceWorkerRegistrar.h" @@ -43,6 +44,8 @@ using mozilla::dom::cache::PCacheStorageParent; using mozilla::dom::cache::PCacheStreamControlParent; using mozilla::dom::MessagePortParent; using mozilla::dom::PMessagePortParent; +using mozilla::dom::PNuwaParent; +using mozilla::dom::NuwaParent; using mozilla::dom::UDPSocketParent; namespace { @@ -234,6 +237,24 @@ BackgroundParentImpl::DeallocPFileDescriptorSetParent( return true; } +PNuwaParent* +BackgroundParentImpl::AllocPNuwaParent() +{ + return mozilla::dom::NuwaParent::Alloc(); +} + +bool +BackgroundParentImpl::RecvPNuwaConstructor(PNuwaParent* aActor) +{ + return mozilla::dom::NuwaParent::ActorConstructed(aActor); +} + +bool +BackgroundParentImpl::DeallocPNuwaParent(PNuwaParent *aActor) +{ + return mozilla::dom::NuwaParent::Dealloc(aActor); +} + BackgroundParentImpl::PVsyncParent* BackgroundParentImpl::AllocPVsyncParent() { @@ -602,6 +623,17 @@ BackgroundParentImpl::DeallocPMessagePortParent(PMessagePortParent* aActor) return true; } +bool +BackgroundParentImpl::RecvMessagePortForceClose(const nsID& aUUID, + const nsID& aDestinationUUID, + const uint32_t& aSequenceID) +{ + AssertIsInMainProcess(); + AssertIsOnBackgroundThread(); + + return MessagePortParent::ForceClose(aUUID, aDestinationUUID, aSequenceID); +} + } // namespace ipc } // namespace mozilla diff --git a/ipc/glue/BackgroundParentImpl.h b/ipc/glue/BackgroundParentImpl.h index 6ccafe9f7e..4c3b36c91d 100644 --- a/ipc/glue/BackgroundParentImpl.h +++ b/ipc/glue/BackgroundParentImpl.h @@ -86,6 +86,15 @@ protected: virtual bool DeallocPBroadcastChannelParent(PBroadcastChannelParent* aActor) override; + virtual PNuwaParent* + AllocPNuwaParent() override; + + virtual bool + RecvPNuwaConstructor(PNuwaParent* aActor) override; + + virtual bool + DeallocPNuwaParent(PNuwaParent* aActor) override; + virtual PServiceWorkerManagerParent* AllocPServiceWorkerManagerParent() override; @@ -143,6 +152,11 @@ protected: virtual bool DeallocPMessagePortParent(PMessagePortParent* aActor) override; + + virtual bool + RecvMessagePortForceClose(const nsID& aUUID, + const nsID& aDestinationUUID, + const uint32_t& aSequenceID) override; }; } // namespace ipc diff --git a/ipc/glue/MessageLink.cpp b/ipc/glue/MessageLink.cpp index 83cebe301d..6a760ff7b7 100644 --- a/ipc/glue/MessageLink.cpp +++ b/ipc/glue/MessageLink.cpp @@ -13,7 +13,9 @@ #ifdef MOZ_NUWA_PROCESS #include "ipc/Nuwa.h" #include "mozilla/Preferences.h" -#include "mozilla/dom/ContentParent.h" +#include "mozilla/dom/PContent.h" +#include "mozilla/dom/PNuwa.h" +#include "mozilla/hal_sandbox/PHal.h" #endif #include "mozilla/Assertions.h" @@ -175,9 +177,10 @@ ProcessLink::SendMessage(Message *msg) #ifdef MOZ_NUWA_PROCESS if (mIsToNuwaProcess && mozilla::dom::ContentParent::IsNuwaReady()) { switch (msg->type()) { - case mozilla::dom::PContent::Msg_NuwaFork__ID: - case mozilla::dom::PContent::Reply_AddNewProcess__ID: + case mozilla::dom::PNuwa::Msg_Fork__ID: + case mozilla::dom::PNuwa::Reply_AddNewProcess__ID: case mozilla::dom::PContent::Msg_NotifyPhoneStateChange__ID: + case mozilla::hal_sandbox::PHal::Msg_NotifyNetworkChange__ID: case GOODBYE_MESSAGE_TYPE: break; default: diff --git a/ipc/glue/PBackground.ipdl b/ipc/glue/PBackground.ipdl index cd3e8f2b2d..d0397c1857 100644 --- a/ipc/glue/PBackground.ipdl +++ b/ipc/glue/PBackground.ipdl @@ -12,6 +12,7 @@ include protocol PCacheStreamControl; include protocol PFileDescriptorSet; include protocol PMessagePort; include protocol PMedia; +include protocol PNuwa; include protocol PServiceWorkerManager; include protocol PUDPSocket; include protocol PVsync; @@ -38,6 +39,7 @@ sync protocol PBackground manages PFileDescriptorSet; manages PMessagePort; manages PMedia; + manages PNuwa; manages PServiceWorkerManager; manages PUDPSocket; manages PVsync; @@ -63,6 +65,10 @@ parent: PMessagePort(nsID uuid, nsID destinationUuid, uint32_t sequenceId); + PNuwa(); + + MessagePortForceClose(nsID uuid, nsID destinationUuid, uint32_t sequenceId); + child: PCache(); PCacheStreamControl(); diff --git a/js/public/StructuredClone.h b/js/public/StructuredClone.h index 967eefdaf5..85ca99a8c1 100644 --- a/js/public/StructuredClone.h +++ b/js/public/StructuredClone.h @@ -192,7 +192,7 @@ class JS_PUBLIC_API(JSAutoStructuredCloneBuffer) { uint64_t* data() const { return data_; } size_t nbytes() const { return nbytes_; } - void clear(); + void clear(const JSStructuredCloneCallbacks* optionalCallbacks=nullptr, void* closure=nullptr); // Copy some memory. It will be automatically freed by the destructor. bool copy(const uint64_t* data, size_t nbytes, uint32_t version=JS_STRUCTURED_CLONE_VERSION); diff --git a/js/src/vm/StructuredClone.cpp b/js/src/vm/StructuredClone.cpp index deee4a204f..c4100d6ded 100644 --- a/js/src/vm/StructuredClone.cpp +++ b/js/src/vm/StructuredClone.cpp @@ -2032,17 +2032,23 @@ JSAutoStructuredCloneBuffer::operator=(JSAutoStructuredCloneBuffer&& other) } void -JSAutoStructuredCloneBuffer::clear() +JSAutoStructuredCloneBuffer::clear(const JSStructuredCloneCallbacks* optionalCallbacks, + void* optionalClosure) { - if (data_) { - if (ownTransferables_ == OwnsTransferablesIfAny) - DiscardTransferables(data_, nbytes_, callbacks_, closure_); - ownTransferables_ = NoTransferables; - js_free(data_); - data_ = nullptr; - nbytes_ = 0; - version_ = 0; - } + if (!data_) + return; + + const JSStructuredCloneCallbacks* callbacks = + optionalCallbacks ? optionalCallbacks : callbacks_; + void* closure = optionalClosure ? optionalClosure : closure_; + + if (ownTransferables_ == OwnsTransferablesIfAny) + DiscardTransferables(data_, nbytes_, callbacks, closure); + ownTransferables_ = NoTransferables; + js_free(data_); + data_ = nullptr; + nbytes_ = 0; + version_ = 0; } bool diff --git a/netwerk/build/nsNetCID.h b/netwerk/build/nsNetCID.h index 05d6da450c..77290eb817 100644 --- a/netwerk/build/nsNetCID.h +++ b/netwerk/build/nsNetCID.h @@ -637,14 +637,20 @@ {0x8c, 0xda, 0x00, 0x60, 0xb0, 0xfc, 0x14, 0xa3} \ } -#define NS_RESURL_CID \ -{ /* ff8fe7ec-2f74-4408-b742-6b7a546029a8 */ \ - 0xff8fe7ec, \ - 0x2f74, \ - 0x4408, \ - {0xb7, 0x42, 0x6b, 0x7a, 0x54, 0x60, 0x29, 0xa8} \ +#define NS_EXTENSIONPROTOCOLHANDLER_CID \ +{ /* aea16cd0-f020-4138-b068-0716c4a15b5a */ \ + 0xaea16cd0, \ + 0xf020, \ + 0x4138, \ + {0xb0, 0x68, 0x07, 0x16, 0xc4, 0xa1, 0x5b, 0x5a} \ } +#define NS_SUBSTITUTINGURL_CID \ +{ 0xdea9657c, \ + 0x18cf, \ + 0x4984, \ + { 0xbd, 0xe9, 0xcc, 0xef, 0x5d, 0x8a, 0xb4, 0x73 } \ +} /****************************************************************************** * netwerk/protocol/file/ classes diff --git a/netwerk/build/nsNetModule.cpp b/netwerk/build/nsNetModule.cpp index 8a1ff797f0..0357ccbc00 100644 --- a/netwerk/build/nsNetModule.cpp +++ b/netwerk/build/nsNetModule.cpp @@ -270,8 +270,14 @@ namespace net { #ifdef NECKO_PROTOCOL_res // resource #include "nsResProtocolHandler.h" +#include "ExtensionProtocolHandler.h" +#include "SubstitutingProtocolHandler.h" NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsResProtocolHandler, Init) -NS_GENERIC_FACTORY_CONSTRUCTOR(nsResURL) + +namespace mozilla { +NS_GENERIC_FACTORY_CONSTRUCTOR(ExtensionProtocolHandler) +NS_GENERIC_FACTORY_CONSTRUCTOR(SubstitutingURL) +} // namespace mozilla #endif #ifdef NECKO_PROTOCOL_device @@ -755,7 +761,8 @@ NS_DEFINE_NAMED_CID(NS_FTPPROTOCOLHANDLER_CID); #endif #ifdef NECKO_PROTOCOL_res NS_DEFINE_NAMED_CID(NS_RESPROTOCOLHANDLER_CID); -NS_DEFINE_NAMED_CID(NS_RESURL_CID); +NS_DEFINE_NAMED_CID(NS_EXTENSIONPROTOCOLHANDLER_CID); +NS_DEFINE_NAMED_CID(NS_SUBSTITUTINGURL_CID); #endif NS_DEFINE_NAMED_CID(NS_ABOUTPROTOCOLHANDLER_CID); NS_DEFINE_NAMED_CID(NS_SAFEABOUTPROTOCOLHANDLER_CID); @@ -900,7 +907,8 @@ static const mozilla::Module::CIDEntry kNeckoCIDs[] = { #endif #ifdef NECKO_PROTOCOL_res { &kNS_RESPROTOCOLHANDLER_CID, false, nullptr, nsResProtocolHandlerConstructor }, - { &kNS_RESURL_CID, false, nullptr, nsResURLConstructor }, + { &kNS_EXTENSIONPROTOCOLHANDLER_CID, false, nullptr, mozilla::ExtensionProtocolHandlerConstructor }, + { &kNS_SUBSTITUTINGURL_CID, false, nullptr, mozilla::SubstitutingURLConstructor }, #endif { &kNS_ABOUTPROTOCOLHANDLER_CID, false, nullptr, nsAboutProtocolHandlerConstructor }, { &kNS_SAFEABOUTPROTOCOLHANDLER_CID, false, nullptr, nsSafeAboutProtocolHandlerConstructor }, @@ -1055,6 +1063,7 @@ static const mozilla::Module::ContractIDEntry kNeckoContracts[] = { #endif #ifdef NECKO_PROTOCOL_res { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "resource", &kNS_RESPROTOCOLHANDLER_CID }, + { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "moz-extension", &kNS_EXTENSIONPROTOCOLHANDLER_CID }, #endif { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "about", &kNS_ABOUTPROTOCOLHANDLER_CID }, { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "moz-safe-about", &kNS_SAFEABOUTPROTOCOLHANDLER_CID }, diff --git a/netwerk/protocol/res/ExtensionProtocolHandler.cpp b/netwerk/protocol/res/ExtensionProtocolHandler.cpp new file mode 100644 index 0000000000..2d6032b984 --- /dev/null +++ b/netwerk/protocol/res/ExtensionProtocolHandler.cpp @@ -0,0 +1,16 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ExtensionProtocolHandler.h" + +namespace mozilla { + +NS_IMPL_QUERY_INTERFACE(ExtensionProtocolHandler, nsISubstitutingProtocolHandler, + nsIProtocolHandler, nsISupportsWeakReference) +NS_IMPL_ADDREF_INHERITED(ExtensionProtocolHandler, SubstitutingProtocolHandler) +NS_IMPL_RELEASE_INHERITED(ExtensionProtocolHandler, SubstitutingProtocolHandler) + +} // namespace mozilla diff --git a/netwerk/protocol/res/ExtensionProtocolHandler.h b/netwerk/protocol/res/ExtensionProtocolHandler.h new file mode 100644 index 0000000000..7b022b9c74 --- /dev/null +++ b/netwerk/protocol/res/ExtensionProtocolHandler.h @@ -0,0 +1,35 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef ExtensionProtocolHandler_h___ +#define ExtensionProtocolHandler_h___ + +#include "SubstitutingProtocolHandler.h" +#include "nsWeakReference.h" + +namespace mozilla { + +class ExtensionProtocolHandler final : public nsISubstitutingProtocolHandler, + public mozilla::SubstitutingProtocolHandler, + public nsSupportsWeakReference +{ +public: + NS_DECL_ISUPPORTS_INHERITED + NS_FORWARD_NSIPROTOCOLHANDLER(mozilla::SubstitutingProtocolHandler::) + NS_FORWARD_NSISUBSTITUTINGPROTOCOLHANDLER(mozilla::SubstitutingProtocolHandler::) + + // In general a moz-extension URI is only loadable by chrome, but a whitelisted + // subset are web-accessible (see nsIAddonPolicyService). + ExtensionProtocolHandler() + : SubstitutingProtocolHandler("moz-extension", URI_STD | URI_DANGEROUS_TO_LOAD | URI_IS_LOCAL_RESOURCE) + {} + +protected: + ~ExtensionProtocolHandler() {} +}; + +} // namespace mozilla + +#endif /* ExtensionProtocolHandler_h___ */ diff --git a/netwerk/protocol/res/SubstitutingProtocolHandler.cpp b/netwerk/protocol/res/SubstitutingProtocolHandler.cpp new file mode 100644 index 0000000000..9bfa1f3442 --- /dev/null +++ b/netwerk/protocol/res/SubstitutingProtocolHandler.cpp @@ -0,0 +1,381 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/chrome/RegistryMessageUtils.h" +#include "mozilla/dom/ContentParent.h" +#include "mozilla/unused.h" + +#include "SubstitutingProtocolHandler.h" +#include "nsIIOService.h" +#include "nsIFile.h" +#include "nsNetCID.h" +#include "nsNetUtil.h" +#include "nsURLHelper.h" +#include "nsEscape.h" + +using mozilla::dom::ContentParent; + +namespace mozilla { + +// Log module for Substituting Protocol logging. We keep the pre-existing module +// name of "nsResProtocol" to avoid disruption. +static PRLogModuleInfo *gResLog; + +static NS_DEFINE_CID(kSubstitutingURLCID, NS_SUBSTITUTINGURL_CID); + +//--------------------------------------------------------------------------------- +// SubstitutingURL : overrides nsStandardURL::GetFile to provide nsIFile resolution +//--------------------------------------------------------------------------------- + +nsresult +SubstitutingURL::EnsureFile() +{ + nsAutoCString ourScheme; + nsresult rv = GetScheme(ourScheme); + NS_ENSURE_SUCCESS(rv, rv); + + // Get the handler associated with this scheme. It would be nice to just + // pass this in when constructing SubstitutingURLs, but we need a generic + // factory constructor. + nsCOMPtr io = do_GetIOService(&rv); + nsCOMPtr handler; + rv = io->GetProtocolHandler(ourScheme.get(), getter_AddRefs(handler)); + NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr substHandler = do_QueryInterface(handler); + MOZ_ASSERT(substHandler); + + nsAutoCString spec; + rv = substHandler->ResolveURI(this, spec); + if (NS_FAILED(rv)) + return rv; + + nsAutoCString scheme; + rv = net_ExtractURLScheme(spec, nullptr, nullptr, &scheme); + if (NS_FAILED(rv)) + return rv; + + // Bug 585869: + // In most cases, the scheme is jar if it's not file. + // Regardless, net_GetFileFromURLSpec should be avoided + // when the scheme isn't file. + if (!scheme.EqualsLiteral("file")) + return NS_ERROR_NO_INTERFACE; + + return net_GetFileFromURLSpec(spec, getter_AddRefs(mFile)); +} + +/* virtual */ nsStandardURL* +SubstitutingURL::StartClone() +{ + SubstitutingURL *clone = new SubstitutingURL(); + return clone; +} + +NS_IMETHODIMP +SubstitutingURL::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc) +{ + *aClassIDNoAlloc = kSubstitutingURLCID; + return NS_OK; +} + +SubstitutingProtocolHandler::SubstitutingProtocolHandler(const char* aScheme, uint32_t aFlags, + bool aEnforceFileOrJar) + : mScheme(aScheme) + , mFlags(aFlags) + , mSubstitutions(16) + , mEnforceFileOrJar(aEnforceFileOrJar) +{ + nsresult rv; + mIOService = do_GetIOService(&rv); + MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv) && mIOService); + + if (!gResLog) { + gResLog = PR_NewLogModule("nsResProtocol"); + } +} + +// +// IPC marshalling. +// + +struct EnumerateSubstitutionArg +{ + EnumerateSubstitutionArg(nsCString& aScheme, nsTArray& aMappings) + : mScheme(aScheme), mMappings(aMappings) {} + nsCString& mScheme; + nsTArray& mMappings; +}; + +static PLDHashOperator +EnumerateSubstitution(const nsACString& aKey, + nsIURI* aURI, + void* aArg) +{ + auto arg = static_cast(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& aMappings) +{ + EnumerateSubstitutionArg arg(mScheme, aMappings); + mSubstitutions.EnumerateRead(&EnumerateSubstitution, &arg); +} + +void +SubstitutingProtocolHandler::SendSubstitution(const nsACString& aRoot, nsIURI* aBaseURI) +{ + if (GeckoProcessType_Content == XRE_GetProcessType()) { + return; + } + + nsTArray parents; + ContentParent::GetAll(parents); + if (!parents.Length()) { + return; + } + + SubstitutionMapping mapping; + mapping.scheme = mScheme; + mapping.path = aRoot; + if (aBaseURI) { + aBaseURI->GetSpec(mapping.resolvedURI.spec); + aBaseURI->GetOriginCharset(mapping.resolvedURI.charset); + } + + for (uint32_t i = 0; i < parents.Length(); i++) { + unused << parents[i]->SendRegisterChromeItem(mapping); + } +} + +//---------------------------------------------------------------------------- +// nsIProtocolHandler +//---------------------------------------------------------------------------- + +nsresult +SubstitutingProtocolHandler::GetScheme(nsACString &result) +{ + result = mScheme; + return NS_OK; +} + +nsresult +SubstitutingProtocolHandler::GetDefaultPort(int32_t *result) +{ + *result = -1; + return NS_OK; +} + +nsresult +SubstitutingProtocolHandler::GetProtocolFlags(uint32_t *result) +{ + *result = mFlags; + return NS_OK; +} + +nsresult +SubstitutingProtocolHandler::NewURI(const nsACString &aSpec, + const char *aCharset, + nsIURI *aBaseURI, + nsIURI **result) +{ + nsresult rv; + + nsRefPtr url = new SubstitutingURL(); + if (!url) + return NS_ERROR_OUT_OF_MEMORY; + + // unescape any %2f and %2e to make sure nsStandardURL coalesces them. + // Later net_GetFileFromURLSpec() will do a full unescape and we want to + // treat them the same way the file system will. (bugs 380994, 394075) + nsAutoCString spec; + const char *src = aSpec.BeginReading(); + const char *end = aSpec.EndReading(); + const char *last = src; + + spec.SetCapacity(aSpec.Length()+1); + for ( ; src < end; ++src) { + if (*src == '%' && (src < end-2) && *(src+1) == '2') { + char ch = '\0'; + if (*(src+2) == 'f' || *(src+2) == 'F') { + ch = '/'; + } else if (*(src+2) == 'e' || *(src+2) == 'E') { + ch = '.'; + } + + if (ch) { + if (last < src) { + spec.Append(last, src-last); + } + spec.Append(ch); + src += 2; + last = src+1; // src will be incremented by the loop + } + } + } + if (last < src) + spec.Append(last, src-last); + + rv = url->Init(nsIStandardURL::URLTYPE_STANDARD, -1, spec, aCharset, aBaseURI); + if (NS_SUCCEEDED(rv)) { + url.forget(result); + } + return rv; +} + +nsresult +SubstitutingProtocolHandler::NewChannel2(nsIURI* uri, + nsILoadInfo* aLoadInfo, + nsIChannel** result) +{ + NS_ENSURE_ARG_POINTER(uri); + nsAutoCString spec; + nsresult rv = ResolveURI(uri, spec); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr newURI; + rv = NS_NewURI(getter_AddRefs(newURI), spec); + NS_ENSURE_SUCCESS(rv, rv); + + rv = NS_NewChannelInternal(result, newURI, aLoadInfo); + NS_ENSURE_SUCCESS(rv, rv); + + nsLoadFlags loadFlags = 0; + (*result)->GetLoadFlags(&loadFlags); + (*result)->SetLoadFlags(loadFlags & ~nsIChannel::LOAD_REPLACE); + return (*result)->SetOriginalURI(uri); +} + +nsresult +SubstitutingProtocolHandler::NewChannel(nsIURI* uri, nsIChannel* *result) +{ + return NewChannel2(uri, nullptr, result); +} + +nsresult +SubstitutingProtocolHandler::AllowPort(int32_t port, const char *scheme, bool *_retval) +{ + // don't override anything. + *_retval = false; + return NS_OK; +} + +//---------------------------------------------------------------------------- +// nsISubstitutingProtocolHandler +//---------------------------------------------------------------------------- + +nsresult +SubstitutingProtocolHandler::SetSubstitution(const nsACString& root, nsIURI *baseURI) +{ + if (!baseURI) { + mSubstitutions.Remove(root); + SendSubstitution(root, baseURI); + return NS_OK; + } + + // If baseURI isn't a same-scheme URI, we can set the substitution immediately. + nsAutoCString scheme; + nsresult rv = baseURI->GetScheme(scheme); + NS_ENSURE_SUCCESS(rv, rv); + if (!scheme.Equals(mScheme)) { + if (mEnforceFileOrJar && !scheme.EqualsLiteral("file") && !scheme.EqualsLiteral("jar")) { + NS_WARNING("Refusing to create substituting URI to non-file:// target"); + return NS_ERROR_INVALID_ARG; + } + + mSubstitutions.Put(root, baseURI); + SendSubstitution(root, baseURI); + return NS_OK; + } + + // baseURI is a same-type substituting URI, let's resolve it first. + nsAutoCString newBase; + rv = ResolveURI(baseURI, newBase); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr newBaseURI; + rv = mIOService->NewURI(newBase, nullptr, nullptr, getter_AddRefs(newBaseURI)); + NS_ENSURE_SUCCESS(rv, rv); + + mSubstitutions.Put(root, newBaseURI); + SendSubstitution(root, newBaseURI); + return NS_OK; +} + +nsresult +SubstitutingProtocolHandler::GetSubstitution(const nsACString& root, nsIURI **result) +{ + NS_ENSURE_ARG_POINTER(result); + + if (mSubstitutions.Get(root, result)) + return NS_OK; + + return GetSubstitutionInternal(root, result); +} + +nsresult +SubstitutingProtocolHandler::HasSubstitution(const nsACString& root, bool *result) +{ + NS_ENSURE_ARG_POINTER(result); + + *result = mSubstitutions.Get(root, nullptr); + return NS_OK; +} + +nsresult +SubstitutingProtocolHandler::ResolveURI(nsIURI *uri, nsACString &result) +{ + nsresult rv; + + nsAutoCString host; + nsAutoCString path; + + rv = uri->GetAsciiHost(host); + if (NS_FAILED(rv)) return rv; + + rv = uri->GetPath(path); + if (NS_FAILED(rv)) return rv; + + // Unescape the path so we can perform some checks on it. + nsAutoCString unescapedPath(path); + NS_UnescapeURL(unescapedPath); + + // Don't misinterpret the filepath as an absolute URI. + if (unescapedPath.FindChar(':') != -1) + return NS_ERROR_MALFORMED_URI; + + if (unescapedPath.FindChar('\\') != -1) + return NS_ERROR_MALFORMED_URI; + + const char *p = path.get() + 1; // path always starts with a slash + NS_ASSERTION(*(p-1) == '/', "Path did not begin with a slash!"); + + if (*p == '/') + return NS_ERROR_MALFORMED_URI; + + nsCOMPtr baseURI; + rv = GetSubstitution(host, getter_AddRefs(baseURI)); + if (NS_FAILED(rv)) return rv; + + rv = baseURI->Resolve(nsDependentCString(p, path.Length()-1), result); + + if (MOZ_LOG_TEST(gResLog, LogLevel::Debug)) { + nsAutoCString spec; + uri->GetAsciiSpec(spec); + MOZ_LOG(gResLog, LogLevel::Debug, ("%s\n -> %s\n", spec.get(), PromiseFlatCString(result).get())); + } + return rv; +} + +} // namespace mozilla diff --git a/netwerk/protocol/res/SubstitutingProtocolHandler.h b/netwerk/protocol/res/SubstitutingProtocolHandler.h new file mode 100644 index 0000000000..d3180aadb3 --- /dev/null +++ b/netwerk/protocol/res/SubstitutingProtocolHandler.h @@ -0,0 +1,83 @@ +/* -*- 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/. */ + +#ifndef SubstitutingProtocolHandler_h___ +#define SubstitutingProtocolHandler_h___ + +#include "nsISubstitutingProtocolHandler.h" + +#include "nsInterfaceHashtable.h" +#include "nsIOService.h" +#include "nsStandardURL.h" +#include "mozilla/chrome/RegistryMessageUtils.h" + +class nsIIOService; + +namespace mozilla { + +// +// Base class for resource://-like substitution protocols. +// +// If you add a new protocol, make sure to change nsChromeRegistryChrome +// to properly invoke CollectSubstitutions at the right time. +class SubstitutingProtocolHandler +{ +public: + SubstitutingProtocolHandler(const char* aScheme, uint32_t aFlags, bool aEnforceFileOrJar = true); + + NS_INLINE_DECL_REFCOUNTING(SubstitutingProtocolHandler); + NS_DECL_NON_VIRTUAL_NSIPROTOCOLHANDLER; + NS_DECL_NON_VIRTUAL_NSISUBSTITUTINGPROTOCOLHANDLER; + + void CollectSubstitutions(InfallibleTArray& aResources); + +protected: + virtual ~SubstitutingProtocolHandler() {} + + void SendSubstitution(const nsACString& aRoot, nsIURI* aBaseURI); + + // Override this in the subclass to try additional lookups after checking + // mSubstitutions. + virtual nsresult GetSubstitutionInternal(const nsACString& aRoot, nsIURI** aResult) + { + *aResult = nullptr; + return NS_ERROR_NOT_AVAILABLE; + } + + nsIIOService* IOService() { return mIOService; } + +private: + nsCString mScheme; + uint32_t mFlags; + nsInterfaceHashtable mSubstitutions; + nsCOMPtr mIOService; + + // In general, we expect the principal of a document loaded from a + // substituting URI to be a codebase principal for that URI (rather than + // a principal for whatever is underneath). However, this only works if + // the protocol handler for the underlying URI doesn't set an explicit + // owner (which chrome:// does, for example). So we want to require that + // substituting URIs only map to other URIs of the same type, or to + // file:// and jar:// URIs. + // + // Enforcing this for ye olde resource:// URIs could carry compat risks, so + // we just try to enforce it on new protocols going forward. + bool mEnforceFileOrJar; +}; + +// SubstitutingURL : overrides nsStandardURL::GetFile to provide nsIFile resolution +class SubstitutingURL : public nsStandardURL +{ +public: + SubstitutingURL() : nsStandardURL(true) {} + virtual nsStandardURL* StartClone(); + virtual nsresult EnsureFile(); + NS_IMETHOD GetClassIDNoAlloc(nsCID *aCID); +}; + +} // namespace mozilla + +#endif /* SubstitutingProtocolHandler_h___ */ diff --git a/netwerk/protocol/res/moz.build b/netwerk/protocol/res/moz.build index 3875aedf9c..665807f4a6 100644 --- a/netwerk/protocol/res/moz.build +++ b/netwerk/protocol/res/moz.build @@ -6,12 +6,15 @@ XPIDL_SOURCES += [ 'nsIResProtocolHandler.idl', + 'nsISubstitutingProtocolHandler.idl', ] XPIDL_MODULE = 'necko_res' SOURCES += [ + 'ExtensionProtocolHandler.cpp', 'nsResProtocolHandler.cpp', + 'SubstitutingProtocolHandler.cpp', ] FAIL_ON_WARNINGS = True diff --git a/netwerk/protocol/res/nsIResProtocolHandler.idl b/netwerk/protocol/res/nsIResProtocolHandler.idl index 0548d3c499..56c597f4c7 100644 --- a/netwerk/protocol/res/nsIResProtocolHandler.idl +++ b/netwerk/protocol/res/nsIResProtocolHandler.idl @@ -3,43 +3,12 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "nsIProtocolHandler.idl" +#include "nsISubstitutingProtocolHandler.idl" /** * Protocol handler interface for the resource:// protocol */ -[scriptable, uuid(067ca872-e947-4bd6-8946-a479cb6ba5dd)] -interface nsIResProtocolHandler : nsIProtocolHandler +[scriptable, uuid(241d34ac-9ed5-46d7-910c-7a9d914aa0c5)] +interface nsIResProtocolHandler : nsISubstitutingProtocolHandler { - /** - * Sets the substitution for the root key: - * resource://root/path ==> baseURI.resolve(path) - * - * A null baseURI removes the specified substitution. - * - * A root key should always be lowercase; however, this may not be - * enforced. - */ - void setSubstitution(in ACString root, in nsIURI baseURI); - - /** - * Gets the substitution for the root key. - * - * @throws NS_ERROR_NOT_AVAILABLE if none exists. - */ - nsIURI getSubstitution(in ACString root); - - /** - * Returns TRUE if the substitution exists and FALSE otherwise. - */ - boolean hasSubstitution(in ACString root); - - /** - * Utility function to resolve a resource URI. A resolved URI is not - * guaranteed to reference a resource that exists (ie. opening a channel to - * the resolved URI may fail). - * - * @throws NS_ERROR_NOT_AVAILABLE if resURI.host() is an unknown root key. - */ - AUTF8String resolveURI(in nsIURI resURI); }; diff --git a/netwerk/protocol/res/nsISubstitutingProtocolHandler.idl b/netwerk/protocol/res/nsISubstitutingProtocolHandler.idl new file mode 100644 index 0000000000..e2c816a855 --- /dev/null +++ b/netwerk/protocol/res/nsISubstitutingProtocolHandler.idl @@ -0,0 +1,46 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsIProtocolHandler.idl" + +/** + * Protocol handler superinterface for a protocol which performs substitutions + * from URIs of its scheme to URIs of another scheme. + */ +[scriptable, uuid(154c64fd-a69e-4105-89f8-bd7dfe621372)] +interface nsISubstitutingProtocolHandler : nsIProtocolHandler +{ + /** + * Sets the substitution for the root key: + * resource://root/path ==> baseURI.resolve(path) + * + * A null baseURI removes the specified substitution. + * + * A root key should always be lowercase; however, this may not be + * enforced. + */ + void setSubstitution(in ACString root, in nsIURI baseURI); + + /** + * Gets the substitution for the root key. + * + * @throws NS_ERROR_NOT_AVAILABLE if none exists. + */ + nsIURI getSubstitution(in ACString root); + + /** + * Returns TRUE if the substitution exists and FALSE otherwise. + */ + boolean hasSubstitution(in ACString root); + + /** + * Utility function to resolve a substituted URI. A resolved URI is not + * guaranteed to reference a resource that exists (ie. opening a channel to + * the resolved URI may fail). + * + * @throws NS_ERROR_NOT_AVAILABLE if resURI.host() is an unknown root key. + */ + AUTF8String resolveURI(in nsIURI resURI); +}; diff --git a/netwerk/protocol/res/nsResProtocolHandler.cpp b/netwerk/protocol/res/nsResProtocolHandler.cpp index f13cedb4d3..9dbef19b47 100644 --- a/netwerk/protocol/res/nsResProtocolHandler.cpp +++ b/netwerk/protocol/res/nsResProtocolHandler.cpp @@ -21,108 +21,13 @@ using mozilla::dom::ContentParent; using mozilla::LogLevel; using mozilla::unused; -static NS_DEFINE_CID(kResURLCID, NS_RESURL_CID); - -static nsResProtocolHandler *gResHandler = nullptr; - -// -// Log module for Resource Protocol logging... -// -// To enable logging (see prlog.h for full details): -// -// set NSPR_LOG_MODULES=nsResProtocol:5 -// set NSPR_LOG_FILE=log.txt -// -// this enables LogLevel::Debug level information and places all output in -// the file log.txt -// -static PRLogModuleInfo *gResLog; - #define kAPP NS_LITERAL_CSTRING("app") #define kGRE NS_LITERAL_CSTRING("gre") -//---------------------------------------------------------------------------- -// nsResURL : overrides nsStandardURL::GetFile to provide nsIFile resolution -//---------------------------------------------------------------------------- - -nsresult -nsResURL::EnsureFile() -{ - nsresult rv; - - NS_ENSURE_TRUE(gResHandler, NS_ERROR_NOT_AVAILABLE); - - nsAutoCString spec; - rv = gResHandler->ResolveURI(this, spec); - if (NS_FAILED(rv)) - return rv; - - nsAutoCString scheme; - rv = net_ExtractURLScheme(spec, nullptr, nullptr, &scheme); - if (NS_FAILED(rv)) - return rv; - - // Bug 585869: - // In most cases, the scheme is jar if it's not file. - // Regardless, net_GetFileFromURLSpec should be avoided - // when the scheme isn't file. - if (!scheme.EqualsLiteral("file")) - return NS_ERROR_NO_INTERFACE; - - rv = net_GetFileFromURLSpec(spec, getter_AddRefs(mFile)); -#ifdef DEBUG_bsmedberg - if (NS_SUCCEEDED(rv)) { - bool exists = true; - mFile->Exists(&exists); - if (!exists) { - printf("resource %s doesn't exist!\n", spec.get()); - } - } -#endif - - return rv; -} - -/* virtual */ nsStandardURL* -nsResURL::StartClone() -{ - nsResURL *clone = new nsResURL(); - return clone; -} - -NS_IMETHODIMP -nsResURL::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc) -{ - *aClassIDNoAlloc = kResURLCID; - return NS_OK; -} - -//---------------------------------------------------------------------------- -// nsResProtocolHandler -//---------------------------------------------------------------------------- - -nsResProtocolHandler::nsResProtocolHandler() - : mSubstitutions(16) -{ - gResLog = PR_NewLogModule("nsResProtocol"); - - NS_ASSERTION(!gResHandler, "res handler already created!"); - gResHandler = this; -} - -nsResProtocolHandler::~nsResProtocolHandler() -{ - gResHandler = nullptr; -} - nsresult nsResProtocolHandler::Init() { nsresult rv; - - mIOService = do_GetIOService(&rv); - NS_ENSURE_SUCCESS(rv, rv); - nsAutoCString appURI, greURI; rv = mozilla::Omnijar::GetURIString(mozilla::Omnijar::APP, appURI); NS_ENSURE_SUCCESS(rv, rv); @@ -165,226 +70,19 @@ nsResProtocolHandler::Init() return rv; } -static PLDHashOperator -EnumerateSubstitution(const nsACString& aKey, - nsIURI* aURI, - void* aArg) -{ - nsTArray* resources = - static_cast*>(aArg); - SerializedURI uri; - if (aURI) { - aURI->GetSpec(uri.spec); - aURI->GetOriginCharset(uri.charset); - } - - ResourceMapping resource = { - nsCString(aKey), uri - }; - resources->AppendElement(resource); - return (PLDHashOperator)PL_DHASH_NEXT; -} - -void -nsResProtocolHandler::CollectSubstitutions(InfallibleTArray& aResources) -{ - mSubstitutions.EnumerateRead(&EnumerateSubstitution, &aResources); -} - //---------------------------------------------------------------------------- // nsResProtocolHandler::nsISupports //---------------------------------------------------------------------------- -NS_IMPL_ISUPPORTS(nsResProtocolHandler, - nsIResProtocolHandler, - nsIProtocolHandler, - nsISupportsWeakReference) +NS_IMPL_QUERY_INTERFACE(nsResProtocolHandler, nsIResProtocolHandler, + nsISubstitutingProtocolHandler, nsIProtocolHandler, + nsISupportsWeakReference) +NS_IMPL_ADDREF_INHERITED(nsResProtocolHandler, SubstitutingProtocolHandler) +NS_IMPL_RELEASE_INHERITED(nsResProtocolHandler, SubstitutingProtocolHandler) -//---------------------------------------------------------------------------- -// nsResProtocolHandler::nsIProtocolHandler -//---------------------------------------------------------------------------- - -NS_IMETHODIMP -nsResProtocolHandler::GetScheme(nsACString &result) +nsresult +nsResProtocolHandler::GetSubstitutionInternal(const nsACString& root, nsIURI **result) { - result.AssignLiteral("resource"); - return NS_OK; -} - -NS_IMETHODIMP -nsResProtocolHandler::GetDefaultPort(int32_t *result) -{ - *result = -1; // no port for res: URLs - return NS_OK; -} - -NS_IMETHODIMP -nsResProtocolHandler::GetProtocolFlags(uint32_t *result) -{ - // XXXbz Is this really true for all resource: URIs? Could we - // somehow give different flags to some of them? - *result = URI_STD | URI_IS_UI_RESOURCE | URI_IS_LOCAL_RESOURCE; - return NS_OK; -} - -NS_IMETHODIMP -nsResProtocolHandler::NewURI(const nsACString &aSpec, - const char *aCharset, - nsIURI *aBaseURI, - nsIURI **result) -{ - nsresult rv; - - nsRefPtr resURL = new nsResURL(); - if (!resURL) - return NS_ERROR_OUT_OF_MEMORY; - - // unescape any %2f and %2e to make sure nsStandardURL coalesces them. - // Later net_GetFileFromURLSpec() will do a full unescape and we want to - // treat them the same way the file system will. (bugs 380994, 394075) - nsAutoCString spec; - const char *src = aSpec.BeginReading(); - const char *end = aSpec.EndReading(); - const char *last = src; - - spec.SetCapacity(aSpec.Length()+1); - for ( ; src < end; ++src) { - if (*src == '%' && (src < end-2) && *(src+1) == '2') { - char ch = '\0'; - if (*(src+2) == 'f' || *(src+2) == 'F') - ch = '/'; - else if (*(src+2) == 'e' || *(src+2) == 'E') - ch = '.'; - - if (ch) { - if (last < src) - spec.Append(last, src-last); - spec.Append(ch); - src += 2; - last = src+1; // src will be incremented by the loop - } - } - } - if (last < src) - spec.Append(last, src-last); - - rv = resURL->Init(nsIStandardURL::URLTYPE_STANDARD, -1, spec, aCharset, aBaseURI); - if (NS_SUCCEEDED(rv)) { - resURL.forget(result); - } - return rv; -} - -NS_IMETHODIMP -nsResProtocolHandler::NewChannel2(nsIURI* uri, - nsILoadInfo* aLoadInfo, - nsIChannel** result) -{ - NS_ENSURE_ARG_POINTER(uri); - nsAutoCString spec; - nsresult rv = ResolveURI(uri, spec); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr newURI; - rv = NS_NewURI(getter_AddRefs(newURI), spec); - NS_ENSURE_SUCCESS(rv, rv); - - rv = NS_NewChannelInternal(result, - newURI, - aLoadInfo); - NS_ENSURE_SUCCESS(rv, rv); - - nsLoadFlags loadFlags = 0; - (*result)->GetLoadFlags(&loadFlags); - (*result)->SetLoadFlags(loadFlags & ~nsIChannel::LOAD_REPLACE); - return (*result)->SetOriginalURI(uri); -} - -NS_IMETHODIMP -nsResProtocolHandler::NewChannel(nsIURI* uri, nsIChannel* *result) -{ - return NewChannel2(uri, nullptr, result); -} - -NS_IMETHODIMP -nsResProtocolHandler::AllowPort(int32_t port, const char *scheme, bool *_retval) -{ - // don't override anything. - *_retval = false; - return NS_OK; -} - -//---------------------------------------------------------------------------- -// nsResProtocolHandler::nsIResProtocolHandler -//---------------------------------------------------------------------------- - -static void -SendResourceSubstitution(const nsACString& root, nsIURI* baseURI) -{ - if (GeckoProcessType_Content == XRE_GetProcessType()) { - return; - } - - ResourceMapping resourceMapping; - resourceMapping.resource = root; - if (baseURI) { - baseURI->GetSpec(resourceMapping.resolvedURI.spec); - baseURI->GetOriginCharset(resourceMapping.resolvedURI.charset); - } - - nsTArray parents; - ContentParent::GetAll(parents); - if (!parents.Length()) { - return; - } - - for (uint32_t i = 0; i < parents.Length(); i++) { - unused << parents[i]->SendRegisterChromeItem(resourceMapping); - } -} - -NS_IMETHODIMP -nsResProtocolHandler::SetSubstitution(const nsACString& root, nsIURI *baseURI) -{ - if (!baseURI) { - mSubstitutions.Remove(root); - SendResourceSubstitution(root, baseURI); - return NS_OK; - } - - // If baseURI isn't a resource URI, we can set the substitution immediately. - nsAutoCString scheme; - nsresult rv = baseURI->GetScheme(scheme); - NS_ENSURE_SUCCESS(rv, rv); - if (!scheme.EqualsLiteral("resource")) { - mSubstitutions.Put(root, baseURI); - SendResourceSubstitution(root, baseURI); - return NS_OK; - } - - // baseURI is a resource URI, let's resolve it first. - nsAutoCString newBase; - rv = ResolveURI(baseURI, newBase); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr newBaseURI; - rv = mIOService->NewURI(newBase, nullptr, nullptr, - getter_AddRefs(newBaseURI)); - NS_ENSURE_SUCCESS(rv, rv); - - mSubstitutions.Put(root, newBaseURI); - SendResourceSubstitution(root, newBaseURI); - return NS_OK; -} - -NS_IMETHODIMP -nsResProtocolHandler::GetSubstitution(const nsACString& root, nsIURI **result) -{ - NS_ENSURE_ARG_POINTER(result); - - if (mSubstitutions.Get(root, result)) - return NS_OK; - // try invoking the directory service for "resource:root" nsAutoCString key; @@ -396,64 +94,9 @@ nsResProtocolHandler::GetSubstitution(const nsACString& root, nsIURI **result) if (NS_FAILED(rv)) return NS_ERROR_NOT_AVAILABLE; - rv = mIOService->NewFileURI(file, result); + rv = IOService()->NewFileURI(file, result); if (NS_FAILED(rv)) return NS_ERROR_NOT_AVAILABLE; return NS_OK; } - -NS_IMETHODIMP -nsResProtocolHandler::HasSubstitution(const nsACString& root, bool *result) -{ - NS_ENSURE_ARG_POINTER(result); - - *result = mSubstitutions.Get(root, nullptr); - return NS_OK; -} - -NS_IMETHODIMP -nsResProtocolHandler::ResolveURI(nsIURI *uri, nsACString &result) -{ - nsresult rv; - - nsAutoCString host; - nsAutoCString path; - - rv = uri->GetAsciiHost(host); - if (NS_FAILED(rv)) return rv; - - rv = uri->GetPath(path); - if (NS_FAILED(rv)) return rv; - - // Unescape the path so we can perform some checks on it. - nsAutoCString unescapedPath(path); - NS_UnescapeURL(unescapedPath); - - // Don't misinterpret the filepath as an absolute URI. - if (unescapedPath.FindChar(':') != -1) - return NS_ERROR_MALFORMED_URI; - - if (unescapedPath.FindChar('\\') != -1) - return NS_ERROR_MALFORMED_URI; - - const char *p = path.get() + 1; // path always starts with a slash - NS_ASSERTION(*(p-1) == '/', "Path did not begin with a slash!"); - - if (*p == '/') - return NS_ERROR_MALFORMED_URI; - - nsCOMPtr baseURI; - rv = GetSubstitution(host, getter_AddRefs(baseURI)); - if (NS_FAILED(rv)) return rv; - - rv = baseURI->Resolve(nsDependentCString(p, path.Length()-1), result); - - if (MOZ_LOG_TEST(gResLog, LogLevel::Debug)) { - nsAutoCString spec; - uri->GetAsciiSpec(spec); - MOZ_LOG(gResLog, LogLevel::Debug, - ("%s\n -> %s\n", spec.get(), PromiseFlatCString(result).get())); - } - return rv; -} diff --git a/netwerk/protocol/res/nsResProtocolHandler.h b/netwerk/protocol/res/nsResProtocolHandler.h index 7670a7caa4..d3e1d0d303 100644 --- a/netwerk/protocol/res/nsResProtocolHandler.h +++ b/netwerk/protocol/res/nsResProtocolHandler.h @@ -6,46 +6,35 @@ #ifndef nsResProtocolHandler_h___ #define nsResProtocolHandler_h___ +#include "SubstitutingProtocolHandler.h" + #include "nsIResProtocolHandler.h" #include "nsInterfaceHashtable.h" #include "nsWeakReference.h" #include "nsStandardURL.h" -class nsIIOService; -struct ResourceMapping; - -// nsResURL : overrides nsStandardURL::GetFile to provide nsIFile resolution -class nsResURL : public nsStandardURL +struct SubstitutionMapping; +class nsResProtocolHandler final : public nsIResProtocolHandler, + public mozilla::SubstitutingProtocolHandler, + public nsSupportsWeakReference { public: - nsResURL() : nsStandardURL(true) {} - virtual nsStandardURL* StartClone(); - virtual nsresult EnsureFile(); - NS_IMETHOD GetClassIDNoAlloc(nsCID *aCID); -}; - -class nsResProtocolHandler final : public nsIResProtocolHandler, public nsSupportsWeakReference -{ -public: - NS_DECL_THREADSAFE_ISUPPORTS - NS_DECL_NSIPROTOCOLHANDLER + NS_DECL_ISUPPORTS_INHERITED NS_DECL_NSIRESPROTOCOLHANDLER - nsResProtocolHandler(); + NS_FORWARD_NSIPROTOCOLHANDLER(mozilla::SubstitutingProtocolHandler::) + NS_FORWARD_NSISUBSTITUTINGPROTOCOLHANDLER(mozilla::SubstitutingProtocolHandler::) + + nsResProtocolHandler() + : SubstitutingProtocolHandler("resource", URI_STD | URI_IS_UI_RESOURCE | URI_IS_LOCAL_RESOURCE, + /* aEnforceFileOrJar = */ false) + {} nsresult Init(); - void CollectSubstitutions(InfallibleTArray& aResources); - -private: - virtual ~nsResProtocolHandler(); - - nsresult Init(nsIFile *aOmniJar); - nsresult AddSpecialDir(const char* aSpecialDir, const nsACString& aSubstitution); - nsInterfaceHashtable mSubstitutions; - nsCOMPtr mIOService; - - friend class nsResURL; +protected: + nsresult GetSubstitutionInternal(const nsACString& aRoot, nsIURI** aResult) override; + virtual ~nsResProtocolHandler() {} }; #endif /* nsResProtocolHandler_h___ */ diff --git a/python/mozbuild/mozbuild/action/xpidl-process.py b/python/mozbuild/mozbuild/action/xpidl-process.py index 6a8f58dfd8..3fc0741821 100755 --- a/python/mozbuild/mozbuild/action/xpidl-process.py +++ b/python/mozbuild/mozbuild/action/xpidl-process.py @@ -16,9 +16,9 @@ import sys from io import BytesIO from buildconfig import topsrcdir -from header import print_header -from typelib import write_typelib -from xpidl import IDLParser +from xpidl.header import print_header +from xpidl.typelib import write_typelib +from xpidl.xpidl import IDLParser from xpt import xpt_link from mozbuild.makeutil import Makefile diff --git a/toolkit/components/addoncompat/addoncompat.manifest b/toolkit/components/addoncompat/addoncompat.manifest index 4228c8a1a0..fe38f47d80 100644 --- a/toolkit/components/addoncompat/addoncompat.manifest +++ b/toolkit/components/addoncompat/addoncompat.manifest @@ -2,5 +2,3 @@ component {1363d5f0-d95e-11e3-9c1a-0800200c9a66} multiprocessShims.js contract @mozilla.org/addons/multiprocess-shims;1 {1363d5f0-d95e-11e3-9c1a-0800200c9a66} component {50bc93ce-602a-4bef-bf3a-61fc749c4caf} defaultShims.js contract @mozilla.org/addons/default-addon-shims;1 {50bc93ce-602a-4bef-bf3a-61fc749c4caf} -component {dfd07380-6083-11e4-9803-0800200c9a66} remoteTagService.js -contract @mozilla.org/addons/remote-tag-service;1 {dfd07380-6083-11e4-9803-0800200c9a66} diff --git a/toolkit/components/addoncompat/moz.build b/toolkit/components/addoncompat/moz.build index 9e4e1eddd4..b5e1769403 100644 --- a/toolkit/components/addoncompat/moz.build +++ b/toolkit/components/addoncompat/moz.build @@ -10,7 +10,6 @@ EXTRA_COMPONENTS += [ 'addoncompat.manifest', 'defaultShims.js', 'multiprocessShims.js', - 'remoteTagService.js', ] EXTRA_JS_MODULES += [ diff --git a/toolkit/components/addoncompat/remoteTagService.js b/toolkit/components/addoncompat/remoteTagService.js deleted file mode 100644 index 9c1a443baa..0000000000 --- a/toolkit/components/addoncompat/remoteTagService.js +++ /dev/null @@ -1,39 +0,0 @@ -/* 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/. */ - -"use strict"; - -const Cu = Components.utils; -const Ci = Components.interfaces; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); - -function RemoteTagServiceService() -{ -} - -RemoteTagServiceService.prototype = { - classID: Components.ID("{dfd07380-6083-11e4-9803-0800200c9a66}"), - QueryInterface: XPCOMUtils.generateQI([Ci.nsIRemoteTagService, Ci.nsISupportsWeakReference]), - - /** - * CPOWs can have user data attached to them. This data originates - * in the local process from this function, getRemoteObjectTag. It's - * sent along with the CPOW to the remote process, where it can be - * fetched with Components.utils.getCrossProcessWrapperTag. - */ - getRemoteObjectTag: function(target) { - if (target instanceof Ci.nsIDocShellTreeItem) { - return "ContentDocShellTreeItem"; - } - - if (target instanceof Ci.nsIDOMDocument) { - return "ContentDocument"; - } - - return "generic"; - } -}; - -this.NSGetFactory = XPCOMUtils.generateNSGetFactory([RemoteTagServiceService]); diff --git a/toolkit/components/build/nsToolkitCompsCID.h b/toolkit/components/build/nsToolkitCompsCID.h index b911c08b9c..34742c7916 100644 --- a/toolkit/components/build/nsToolkitCompsCID.h +++ b/toolkit/components/build/nsToolkitCompsCID.h @@ -2,12 +2,6 @@ * 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/. */ -#if defined(MOZ_UPDATER) -# if !defined(MOZ_WIDGET_ANDROID) -# define USE_MOZ_UPDATER -# endif -#endif - #define NS_ALERTSERVICE_CONTRACTID \ "@mozilla.org/alerts-service;1" @@ -90,7 +84,7 @@ #define NS_APPSTARTUP_CONTRACTID \ "@mozilla.org/toolkit/app-startup;1" -#if defined(USE_MOZ_UPDATER) +#if defined(MOZ_UPDATER) && !defined(MOZ_WIDGET_ANDROID) #define NS_UPDATEPROCESSOR_CONTRACTID \ "@mozilla.org/updates/update-processor;1" #endif @@ -173,7 +167,7 @@ #define NS_FAVICONSERVICE_CID \ { 0x984e3259, 0x9266, 0x49cf, { 0xb6, 0x05, 0x60, 0xb0, 0x22, 0xa0, 0x07, 0x56 } } -#if defined(USE_MOZ_UPDATER) +#if defined(MOZ_UPDATER) && !defined(MOZ_WIDGET_ANDROID) #define NS_UPDATEPROCESSOR_CID \ { 0xf3dcf644, 0x79e8, 0x4f59, { 0xa1, 0xbb, 0x87, 0x84, 0x54, 0x48, 0x8e, 0xf9 } } #endif diff --git a/toolkit/components/build/nsToolkitCompsModule.cpp b/toolkit/components/build/nsToolkitCompsModule.cpp index 971eac7a2a..acd96d9e4f 100644 --- a/toolkit/components/build/nsToolkitCompsModule.cpp +++ b/toolkit/components/build/nsToolkitCompsModule.cpp @@ -8,7 +8,7 @@ #include "nsUserInfo.h" #include "nsToolkitCompsCID.h" #include "nsFindService.h" -#if defined(USE_MOZ_UPDATER) +#if defined(MOZ_UPDATER) && !defined(MOZ_WIDGET_ANDROID) #include "nsUpdateDriver.h" #endif @@ -75,7 +75,7 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsDownloadProxy) NS_GENERIC_FACTORY_CONSTRUCTOR(nsTypeAheadFind) NS_GENERIC_FACTORY_CONSTRUCTOR(nsBrowserStatusFilter) -#if defined(USE_MOZ_UPDATER) +#if defined(MOZ_UPDATER) && !defined(MOZ_WIDGET_ANDROID) NS_GENERIC_FACTORY_CONSTRUCTOR(nsUpdateProcessor) #endif NS_GENERIC_FACTORY_CONSTRUCTOR(FinalizationWitnessService) @@ -100,7 +100,7 @@ NS_DEFINE_NAMED_CID(NS_DOWNLOAD_CID); NS_DEFINE_NAMED_CID(NS_FIND_SERVICE_CID); NS_DEFINE_NAMED_CID(NS_TYPEAHEADFIND_CID); NS_DEFINE_NAMED_CID(NS_BROWSERSTATUSFILTER_CID); -#if defined(USE_MOZ_UPDATER) +#if defined(MOZ_UPDATER) && !defined(MOZ_WIDGET_ANDROID) NS_DEFINE_NAMED_CID(NS_UPDATEPROCESSOR_CID); #endif NS_DEFINE_NAMED_CID(FINALIZATIONWITNESSSERVICE_CID); @@ -125,7 +125,7 @@ static const Module::CIDEntry kToolkitCIDs[] = { { &kNS_FIND_SERVICE_CID, false, nullptr, nsFindServiceConstructor }, { &kNS_TYPEAHEADFIND_CID, false, nullptr, nsTypeAheadFindConstructor }, { &kNS_BROWSERSTATUSFILTER_CID, false, nullptr, nsBrowserStatusFilterConstructor }, -#if defined(USE_MOZ_UPDATER) +#if defined(MOZ_UPDATER) && !defined(MOZ_WIDGET_ANDROID) { &kNS_UPDATEPROCESSOR_CID, false, nullptr, nsUpdateProcessorConstructor }, #endif { &kFINALIZATIONWITNESSSERVICE_CID, false, nullptr, FinalizationWitnessServiceConstructor }, @@ -151,7 +151,7 @@ static const Module::ContractIDEntry kToolkitContracts[] = { { NS_FIND_SERVICE_CONTRACTID, &kNS_FIND_SERVICE_CID }, { NS_TYPEAHEADFIND_CONTRACTID, &kNS_TYPEAHEADFIND_CID }, { NS_BROWSERSTATUSFILTER_CONTRACTID, &kNS_BROWSERSTATUSFILTER_CID }, -#if defined(USE_MOZ_UPDATER) +#if defined(MOZ_UPDATER) && !defined(MOZ_WIDGET_ANDROID) { NS_UPDATEPROCESSOR_CONTRACTID, &kNS_UPDATEPROCESSOR_CID }, #endif { FINALIZATIONWITNESSSERVICE_CONTRACTID, &kFINALIZATIONWITNESSSERVICE_CID }, diff --git a/toolkit/components/moz.build b/toolkit/components/moz.build index 66f9da6e9f..98a5e18d85 100644 --- a/toolkit/components/moz.build +++ b/toolkit/components/moz.build @@ -50,14 +50,21 @@ DIRS += [ 'statusfilter', 'telemetry', 'thumbnails', + 'timermanager', 'typeaheadfind', + 'utils', 'urlformatter', 'viewconfig', - 'viewsource', 'workerloader', 'xulstore' ] +if CONFIG['MOZ_BUILD_APP'] != 'mobile/android': + DIRS += ['viewsource']; + + if CONFIG['NS_PRINTING']: + DIRS += ['printing'] + if CONFIG['MOZ_SOCIAL']: DIRS += ['social'] @@ -70,9 +77,6 @@ if CONFIG['MOZ_FEEDS']: if CONFIG['MOZ_HELP_VIEWER']: DIRS += ['help'] -if CONFIG['NS_PRINTING']: - DIRS += ['printing'] - if CONFIG['MOZ_XUL']: DIRS += ['autocomplete', 'satchel'] diff --git a/toolkit/components/timermanager/moz.build b/toolkit/components/timermanager/moz.build new file mode 100644 index 0000000000..d9dfac4d29 --- /dev/null +++ b/toolkit/components/timermanager/moz.build @@ -0,0 +1,21 @@ +# -*- 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/. + +XPIDL_MODULE = 'update' + +XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini'] + +XPIDL_SOURCES += [ + 'nsIUpdateTimerManager.idl', +] + +EXTRA_COMPONENTS += [ + 'nsUpdateTimerManager.js', + 'nsUpdateTimerManager.manifest', +] + +with Files('**'): + BUG_COMPONENT = ('Toolkit', 'Application Update') diff --git a/toolkit/mozapps/update/nsIUpdateTimerManager.idl b/toolkit/components/timermanager/nsIUpdateTimerManager.idl similarity index 100% rename from toolkit/mozapps/update/nsIUpdateTimerManager.idl rename to toolkit/components/timermanager/nsIUpdateTimerManager.idl diff --git a/toolkit/mozapps/update/nsUpdateTimerManager.js b/toolkit/components/timermanager/nsUpdateTimerManager.js similarity index 100% rename from toolkit/mozapps/update/nsUpdateTimerManager.js rename to toolkit/components/timermanager/nsUpdateTimerManager.js diff --git a/toolkit/mozapps/update/nsUpdateTimerManager.manifest b/toolkit/components/timermanager/nsUpdateTimerManager.manifest similarity index 100% rename from toolkit/mozapps/update/nsUpdateTimerManager.manifest rename to toolkit/components/timermanager/nsUpdateTimerManager.manifest diff --git a/toolkit/mozapps/update/tests/unit_timermanager/consumerNotifications.js b/toolkit/components/timermanager/tests/unit/consumerNotifications.js similarity index 100% rename from toolkit/mozapps/update/tests/unit_timermanager/consumerNotifications.js rename to toolkit/components/timermanager/tests/unit/consumerNotifications.js diff --git a/toolkit/mozapps/update/tests/unit_timermanager/xpcshell.ini b/toolkit/components/timermanager/tests/unit/xpcshell.ini similarity index 100% rename from toolkit/mozapps/update/tests/unit_timermanager/xpcshell.ini rename to toolkit/components/timermanager/tests/unit/xpcshell.ini diff --git a/caps/tests/mochitest/moz.build b/toolkit/components/utils/moz.build similarity index 77% rename from caps/tests/mochitest/moz.build rename to toolkit/components/utils/moz.build index 76deffb6d1..a78fde5f29 100644 --- a/caps/tests/mochitest/moz.build +++ b/toolkit/components/utils/moz.build @@ -4,6 +4,7 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. -MOCHITEST_MANIFESTS += ['mochitest.ini'] -MOCHITEST_CHROME_MANIFESTS += ['chrome.ini'] - +EXTRA_COMPONENTS += [ + 'simpleServices.js', + 'utils.manifest', +] diff --git a/toolkit/components/utils/simpleServices.js b/toolkit/components/utils/simpleServices.js new file mode 100644 index 0000000000..69b727d9ec --- /dev/null +++ b/toolkit/components/utils/simpleServices.js @@ -0,0 +1,133 @@ +/* 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/. */ + +/* + * Dumping ground for simple services for which the isolation of a full global + * is overkill. Be careful about namespace pollution, and be mindful about + * importing lots of JSMs in global scope, since this file will almost certainly + * be loaded from enough callsites that any such imports will always end up getting + * eagerly loaded at startup. + */ + +"use strict"; + +const Cu = Components.utils; +const Ci = Components.interfaces; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); + +function RemoteTagServiceService() +{ +} + +RemoteTagServiceService.prototype = { + classID: Components.ID("{dfd07380-6083-11e4-9803-0800200c9a66}"), + QueryInterface: XPCOMUtils.generateQI([Ci.nsIRemoteTagService, Ci.nsISupportsWeakReference]), + + /** + * CPOWs can have user data attached to them. This data originates + * in the local process from this function, getRemoteObjectTag. It's + * sent along with the CPOW to the remote process, where it can be + * fetched with Components.utils.getCrossProcessWrapperTag. + */ + getRemoteObjectTag: function(target) { + if (target instanceof Ci.nsIDocShellTreeItem) { + return "ContentDocShellTreeItem"; + } + + if (target instanceof Ci.nsIDOMDocument) { + return "ContentDocument"; + } + + return "generic"; + } +}; + +function AddonPolicyService() +{ + this.wrappedJSObject = this; + this.mayLoadURICallbacks = new Map(); +} + +AddonPolicyService.prototype = { + classID: Components.ID("{89560ed3-72e3-498d-a0e8-ffe50334d7c5}"), + QueryInterface: XPCOMUtils.generateQI([Ci.nsIAddonPolicyService]), + + /* + * Invokes a callback (if any) associated with the addon to determine whether + * unprivileged code running within the addon is allowed to perform loads from + * the given URI. + * + * @see nsIAddonPolicyService.addonMayLoadURI + */ + addonMayLoadURI(aAddonId, aURI) { + let cb = this.mayLoadURICallbacks[aAddonId]; + return cb ? cb(aURI) : false; + }, + + /* + * Invokes a callback (if any) to determine if an extension URI should be + * web-accessible. + * + * @see nsIAddonPolicyService.extensionURILoadableByAnyone + */ + extensionURILoadableByAnyone(aURI) { + if (aURI.scheme != "moz-extension") { + throw new TypeError("non-extension URI passed"); + } + + let cb = this.extensionURILoadCallback; + return cb ? cb(aURI) : false; + }, + + /* + * Maps an extension URI to an addon ID. + * + * @see nsIAddonPolicyService.extensionURIToAddonId + */ + extensionURIToAddonId(aURI) { + if (aURI.scheme != "moz-extension") { + throw new TypeError("non-extension URI passed"); + } + + let cb = this.extensionURIToAddonIdCallback; + if (!cb) { + throw new Error("no callback set to map extension URIs to addon Ids"); + } + return cb(aURI); + }, + + /* + * Sets the callbacks used in addonMayLoadURI above. Not accessible over + * XPCOM - callers should use .wrappedJSObject on the service to call it + * directly. + */ + setAddonLoadURICallback(aAddonId, aCallback) { + this.mayLoadURICallbacks[aAddonId] = aCallback; + }, + + /* + * Sets the callback used in extensionURILoadableByAnyone above. Not + * accessible over XPCOM - callers should use .wrappedJSObject on the + * service to call it directly. + */ + setExtensionURILoadCallback(aCallback) { + var old = this.extensionURILoadCallback; + this.extensionURILoadCallback = aCallback; + return old; + }, + + /* + * Sets the callback used in extensionURIToAddonId above. Not accessible over + * XPCOM - callers should use .wrappedJSObject on the service to call it + * directly. + */ + setExtensionURIToAddonIdCallback(aCallback) { + var old = this.extensionURIToAddonIdCallback; + this.extensionURIToAddonIdCallback = aCallback; + return old; + } +}; + +this.NSGetFactory = XPCOMUtils.generateNSGetFactory([RemoteTagServiceService, AddonPolicyService]); diff --git a/toolkit/components/utils/utils.manifest b/toolkit/components/utils/utils.manifest new file mode 100644 index 0000000000..b08c5d519e --- /dev/null +++ b/toolkit/components/utils/utils.manifest @@ -0,0 +1,4 @@ +component {dfd07380-6083-11e4-9803-0800200c9a66} simpleServices.js +contract @mozilla.org/addons/remote-tag-service;1 {dfd07380-6083-11e4-9803-0800200c9a66} +component {89560ed3-72e3-498d-a0e8-ffe50334d7c5} simpleServices.js +contract @mozilla.org/addons/policy-service;1 {89560ed3-72e3-498d-a0e8-ffe50334d7c5} diff --git a/toolkit/devtools/apps/app-actor-front.js b/toolkit/devtools/apps/app-actor-front.js index db4271594d..f5751e8ec8 100644 --- a/toolkit/devtools/apps/app-actor-front.js +++ b/toolkit/devtools/apps/app-actor-front.js @@ -5,6 +5,7 @@ const {FileUtils} = Cu.import("resource://gre/modules/FileUtils.jsm"); const {NetUtil} = Cu.import("resource://gre/modules/NetUtil.jsm"); const {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}); const {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {}); +const DevToolsUtils = devtools.require("devtools/toolkit/DevToolsUtils.js"); const EventEmitter = require("devtools/toolkit/event-emitter"); // XXX: bug 912476 make this module a real protocol.js front @@ -617,8 +618,9 @@ AppActorFront.prototype = { for (let [manifestURL, app] of this._apps) { promises.push(app.getIcon()); } - return promise.all(promises) - .then(null, () => {}); // Ignore any failure + + return DevToolsUtils.settleAll(promises) + .then(null, () => {}); }, _listenAppEvents: function (listener) { diff --git a/toolkit/devtools/webide/content/jar.mn b/toolkit/devtools/webide/content/jar.mn index a178df8cf6..db79fdb513 100644 --- a/toolkit/devtools/webide/content/jar.mn +++ b/toolkit/devtools/webide/content/jar.mn @@ -31,5 +31,8 @@ webide.jar: content/project-listing.xhtml (project-listing.xhtml) content/project-listing.js (project-listing.js) content/project-panel.js (project-panel.js) + content/runtime-panel.js (runtime-panel.js) + content/runtime-listing.xhtml (runtime-listing.xhtml) + content/runtime-listing.js (runtime-listing.js) content/simulator.js (simulator.js) content/simulator.xhtml (simulator.xhtml) diff --git a/toolkit/devtools/webide/content/prefs.xhtml b/toolkit/devtools/webide/content/prefs.xhtml index 5ec2d32a19..16e58b8b16 100644 --- a/toolkit/devtools/webide/content/prefs.xhtml +++ b/toolkit/devtools/webide/content/prefs.xhtml @@ -13,7 +13,6 @@ - @@ -29,6 +28,12 @@

&prefs_general_title;

    +
  • + +
  • -
  • - -