mirror of
https://github.com/microsoft/playwright.git
synced 2024-12-17 16:21:55 +03:00
c4e3ed85c0
When innerWindow is restored from the history state, we do not receive content-document-global-created notification, but would still like to know that window is now using a different inner window to reset the state. This introduces a new notification juggler-dom-window-reused. At the same time, goBack()/goForward() sometimes do not initiate navigation synchronously, so our check for pendingNaivgationId() does not work. Instead, we rely on canGoBack, and assume that client will not need the navigationId synchronously.
1811 lines
71 KiB
Diff
1811 lines
71 KiB
Diff
diff --git a/accessible/base/NotificationController.h b/accessible/base/NotificationController.h
|
|
index f239731e0ff06cb01a4c0e8cf0ba4ff5014f88e0..53447ef12eb59bd065abbfd031bd6336a60020a2 100644
|
|
--- a/accessible/base/NotificationController.h
|
|
+++ b/accessible/base/NotificationController.h
|
|
@@ -284,6 +284,8 @@ class NotificationController final : public EventQueue,
|
|
}
|
|
#endif
|
|
|
|
+ bool IsUpdatePendingForJugglerAccessibility() { return IsUpdatePending(); }
|
|
+
|
|
protected:
|
|
virtual ~NotificationController();
|
|
|
|
diff --git a/accessible/interfaces/nsIAccessibleDocument.idl b/accessible/interfaces/nsIAccessibleDocument.idl
|
|
index a91df31c96afda66f478a5a38eaa4352039c2a0b..ee777c1746284027fb3aa2f1686f8082af9d89ee 100644
|
|
--- a/accessible/interfaces/nsIAccessibleDocument.idl
|
|
+++ b/accessible/interfaces/nsIAccessibleDocument.idl
|
|
@@ -72,4 +72,9 @@ interface nsIAccessibleDocument : nsISupports
|
|
* Return the child document accessible at the given index.
|
|
*/
|
|
nsIAccessibleDocument getChildDocumentAt(in unsigned long index);
|
|
+
|
|
+ /**
|
|
+ * Return whether it is updating.
|
|
+ */
|
|
+ readonly attribute boolean isUpdatePendingForJugglerAccessibility;
|
|
};
|
|
diff --git a/accessible/xpcom/xpcAccessibleDocument.cpp b/accessible/xpcom/xpcAccessibleDocument.cpp
|
|
index e3dbe73f22252f11080c3f266b2309f842eba9dc..87f50fe3df7cc8f9bc26dabd5ee571cae270912a 100644
|
|
--- a/accessible/xpcom/xpcAccessibleDocument.cpp
|
|
+++ b/accessible/xpcom/xpcAccessibleDocument.cpp
|
|
@@ -143,6 +143,15 @@ xpcAccessibleDocument::GetVirtualCursor(nsIAccessiblePivot** aVirtualCursor) {
|
|
return NS_OK;
|
|
}
|
|
|
|
+
|
|
+NS_IMETHODIMP
|
|
+xpcAccessibleDocument::GetIsUpdatePendingForJugglerAccessibility(bool* updating) {
|
|
+ NS_ENSURE_ARG_POINTER(updating);
|
|
+ *updating = Intl()->Controller()->IsUpdatePendingForJugglerAccessibility();
|
|
+ return NS_OK;
|
|
+}
|
|
+
|
|
+
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// xpcAccessibleDocument
|
|
|
|
diff --git a/accessible/xpcom/xpcAccessibleDocument.h b/accessible/xpcom/xpcAccessibleDocument.h
|
|
index f042cc1081850ac60e329b70b5569f8b97d4e4dc..65bcff9b41b9471ef1427e3ea330481c194409bc 100644
|
|
--- a/accessible/xpcom/xpcAccessibleDocument.h
|
|
+++ b/accessible/xpcom/xpcAccessibleDocument.h
|
|
@@ -48,6 +48,8 @@ class xpcAccessibleDocument : public xpcAccessibleHyperText,
|
|
nsIAccessibleDocument** aDocument) final;
|
|
NS_IMETHOD GetVirtualCursor(nsIAccessiblePivot** aVirtualCursor) final;
|
|
|
|
+ NS_IMETHOD GetIsUpdatePendingForJugglerAccessibility(bool* aUpdating) final;
|
|
+
|
|
/**
|
|
* Return XPCOM wrapper for the internal accessible.
|
|
*/
|
|
diff --git a/browser/installer/allowed-dupes.mn b/browser/installer/allowed-dupes.mn
|
|
index 382881ff9cea80fc1dd1320c2f013c82409bff9a..98efc6a6af65f5a723443bd69d1f31b3666c3683 100644
|
|
--- a/browser/installer/allowed-dupes.mn
|
|
+++ b/browser/installer/allowed-dupes.mn
|
|
@@ -64,6 +64,12 @@ browser/defaults/settings/pinning/pins.json
|
|
browser/defaults/settings/main/example.json
|
|
browser/defaults/settings/main/search-default-override-allowlist.json
|
|
|
|
+# Juggler/marionette files
|
|
+chrome/juggler/content/content/floating-scrollbars.css
|
|
+browser/chrome/devtools/skin/floating-scrollbars-responsive-design.css
|
|
+chrome/juggler/content/server/stream-utils.js
|
|
+chrome/marionette/content/stream-utils.js
|
|
+
|
|
#ifdef MOZ_EME_WIN32_ARTIFACT
|
|
gmp-clearkey/0.1/manifest.json
|
|
i686/gmp-clearkey/0.1/manifest.json
|
|
diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in
|
|
index e011b74cc4b4014362397137e92a1f27e29b43c7..c3ac23c2416363ce897741ca457fa9086b4cdd05 100644
|
|
--- a/browser/installer/package-manifest.in
|
|
+++ b/browser/installer/package-manifest.in
|
|
@@ -211,6 +211,11 @@
|
|
@RESPATH@/components/marionette.js
|
|
#endif
|
|
|
|
+@RESPATH@/chrome/juggler@JAREXT@
|
|
+@RESPATH@/chrome/juggler.manifest
|
|
+@RESPATH@/components/juggler.manifest
|
|
+@RESPATH@/components/juggler.js
|
|
+
|
|
#if defined(ENABLE_TESTS) && defined(MOZ_DEBUG)
|
|
@RESPATH@/components/TestInterfaceJS.js
|
|
@RESPATH@/components/TestInterfaceJS.manifest
|
|
diff --git a/devtools/server/socket/websocket-server.js b/devtools/server/socket/websocket-server.js
|
|
index 040c7b124dec6bb254563bbe74fe50012cb077a3..b4e6b8132786af70e8ad0dce88b67c2835307f88 100644
|
|
--- a/devtools/server/socket/websocket-server.js
|
|
+++ b/devtools/server/socket/websocket-server.js
|
|
@@ -133,13 +133,12 @@ function writeHttpResponse(output, response) {
|
|
* Process the WebSocket handshake headers and return the key to be sent in
|
|
* Sec-WebSocket-Accept response header.
|
|
*/
|
|
-function processRequest({ requestLine, headers }) {
|
|
+function processRequest({ requestLine, headers }, expectedPath) {
|
|
const [method, path] = requestLine.split(" ");
|
|
if (method !== "GET") {
|
|
throw new Error("The handshake request must use GET method");
|
|
}
|
|
-
|
|
- if (path !== "/") {
|
|
+ if (path !== expectedPath) {
|
|
throw new Error("The handshake request has unknown path");
|
|
}
|
|
|
|
@@ -189,13 +188,13 @@ function computeKey(key) {
|
|
/**
|
|
* Perform the server part of a WebSocket opening handshake on an incoming connection.
|
|
*/
|
|
-const serverHandshake = async function(input, output) {
|
|
+const serverHandshake = async function(input, output, expectedPath) {
|
|
// Read the request
|
|
const request = await readHttpRequest(input);
|
|
|
|
try {
|
|
// Check and extract info from the request
|
|
- const { acceptKey } = processRequest(request);
|
|
+ const { acceptKey } = processRequest(request, expectedPath);
|
|
|
|
// Send response headers
|
|
await writeHttpResponse(output, [
|
|
@@ -217,8 +216,8 @@ const serverHandshake = async function(input, output) {
|
|
* Performs the WebSocket handshake and waits for the WebSocket to open.
|
|
* Returns Promise with a WebSocket ready to send and receive messages.
|
|
*/
|
|
-const accept = async function(transport, input, output) {
|
|
- await serverHandshake(input, output);
|
|
+const accept = async function(transport, input, output, expectedPath) {
|
|
+ await serverHandshake(input, output, expectedPath || "/");
|
|
|
|
const transportProvider = {
|
|
setListener(upgradeListener) {
|
|
diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp
|
|
index 2424029f2783fe2af012f033c75c497b3c493bd6..56b0aa8f51798666f80cdfce5ace18260185c6ee 100644
|
|
--- a/docshell/base/nsDocShell.cpp
|
|
+++ b/docshell/base/nsDocShell.cpp
|
|
@@ -15,6 +15,12 @@
|
|
# include <unistd.h> // for getpid()
|
|
#endif
|
|
|
|
+#if JS_HAS_INTL_API && !MOZ_SYSTEM_ICU
|
|
+# include "unicode/locid.h"
|
|
+#endif /* JS_HAS_INTL_API && !MOZ_SYSTEM_ICU */
|
|
+
|
|
+#include "js/LocaleSensitive.h"
|
|
+
|
|
#include "mozilla/ArrayUtils.h"
|
|
#include "mozilla/Attributes.h"
|
|
#include "mozilla/AutoRestore.h"
|
|
@@ -57,6 +63,7 @@
|
|
#include "mozilla/dom/ContentFrameMessageManager.h"
|
|
#include "mozilla/dom/DocGroup.h"
|
|
#include "mozilla/dom/Element.h"
|
|
+#include "mozilla/dom/Geolocation.h"
|
|
#include "mozilla/dom/HTMLAnchorElement.h"
|
|
#include "mozilla/dom/PerformanceNavigation.h"
|
|
#include "mozilla/dom/PermissionMessageUtils.h"
|
|
@@ -77,6 +84,7 @@
|
|
#include "mozilla/dom/LoadURIOptionsBinding.h"
|
|
#include "mozilla/dom/JSWindowActorChild.h"
|
|
#include "mozilla/ipc/ProtocolUtils.h"
|
|
+#include "mozilla/dom/WorkerCommon.h"
|
|
#include "mozilla/net/DocumentChannel.h"
|
|
#include "mozilla/net/UrlClassifierFeatureFactory.h"
|
|
#include "ReferrerInfo.h"
|
|
@@ -100,6 +108,7 @@
|
|
#include "nsIDocShellTreeItem.h"
|
|
#include "nsIDocShellTreeOwner.h"
|
|
#include "mozilla/dom/Document.h"
|
|
+#include "mozilla/dom/Element.h"
|
|
#include "nsIDocumentLoaderFactory.h"
|
|
#include "nsIDOMWindow.h"
|
|
#include "nsIEditingSession.h"
|
|
@@ -190,6 +199,7 @@
|
|
#include "nsGlobalWindow.h"
|
|
#include "nsISearchService.h"
|
|
#include "nsJSEnvironment.h"
|
|
+#include "nsJSUtils.h"
|
|
#include "nsNetCID.h"
|
|
#include "nsNetUtil.h"
|
|
#include "nsObjectLoadingContent.h"
|
|
@@ -379,6 +389,11 @@ nsDocShell::nsDocShell(BrowsingContext* aBrowsingContext,
|
|
mAllowWindowControl(true),
|
|
mUseErrorPages(true),
|
|
mCSSErrorReportingEnabled(false),
|
|
+ mFileInputInterceptionEnabled(false),
|
|
+ mOverrideHasFocus(false),
|
|
+ mBypassCSPEnabled(false),
|
|
+ mOnlineOverride(nsIDocShell::ONLINE_OVERRIDE_NONE),
|
|
+ mColorSchemeOverride(COLOR_SCHEME_OVERRIDE_NONE),
|
|
mAllowAuth(mItemType == typeContent),
|
|
mAllowKeywordFixup(false),
|
|
mIsOffScreenBrowser(false),
|
|
@@ -1249,6 +1264,7 @@ bool nsDocShell::SetCurrentURI(nsIURI* aURI, nsIRequest* aRequest,
|
|
isSubFrame = mLSHE->GetIsSubFrame();
|
|
}
|
|
|
|
+ FireOnFrameLocationChange(this, aRequest, aURI, aLocationFlags);
|
|
if (!isSubFrame && !isRoot) {
|
|
/*
|
|
* We don't want to send OnLocationChange notifications when
|
|
@@ -3079,6 +3095,184 @@ nsDocShell::GetMessageManager(ContentFrameMessageManager** aMessageManager) {
|
|
return NS_OK;
|
|
}
|
|
|
|
+// =============== Juggler Begin =======================
|
|
+
|
|
+nsDocShell* nsDocShell::GetRootDocShell() {
|
|
+ nsCOMPtr<nsIDocShellTreeItem> rootAsItem;
|
|
+ GetInProcessSameTypeRootTreeItem(getter_AddRefs(rootAsItem));
|
|
+ nsCOMPtr<nsIDocShell> rootShell = do_QueryInterface(rootAsItem);
|
|
+ return nsDocShell::Cast(rootShell);
|
|
+}
|
|
+
|
|
+NS_IMETHODIMP
|
|
+nsDocShell::GetBypassCSPEnabled(bool* aEnabled) {
|
|
+ MOZ_ASSERT(aEnabled);
|
|
+ *aEnabled = mBypassCSPEnabled;
|
|
+ return NS_OK;
|
|
+}
|
|
+
|
|
+NS_IMETHODIMP
|
|
+nsDocShell::SetBypassCSPEnabled(bool aEnabled) {
|
|
+ mBypassCSPEnabled = aEnabled;
|
|
+ return NS_OK;
|
|
+}
|
|
+
|
|
+bool nsDocShell::IsBypassCSPEnabled() {
|
|
+ return GetRootDocShell()->mBypassCSPEnabled;
|
|
+}
|
|
+
|
|
+NS_IMETHODIMP
|
|
+nsDocShell::GetOverrideHasFocus(bool* aEnabled) {
|
|
+ MOZ_ASSERT(aEnabled);
|
|
+ *aEnabled = mOverrideHasFocus;
|
|
+ return NS_OK;
|
|
+}
|
|
+
|
|
+NS_IMETHODIMP
|
|
+nsDocShell::SetOverrideHasFocus(bool aEnabled) {
|
|
+ mOverrideHasFocus = aEnabled;
|
|
+ return NS_OK;
|
|
+}
|
|
+
|
|
+bool nsDocShell::ShouldOverrideHasFocus() const {
|
|
+ return mOverrideHasFocus;
|
|
+}
|
|
+
|
|
+NS_IMETHODIMP
|
|
+nsDocShell::GetLanguageOverride(nsAString& aLanguageOverride) {
|
|
+ MOZ_ASSERT(aEnabled);
|
|
+ aLanguageOverride = GetRootDocShell()->mLanguageOverride;
|
|
+ return NS_OK;
|
|
+}
|
|
+
|
|
+
|
|
+static void SetIcuLocale(const nsAString& aLanguageOverride) {
|
|
+ icu::Locale locale(NS_LossyConvertUTF16toASCII(aLanguageOverride).get());
|
|
+ if (icu::Locale::getDefault() == locale)
|
|
+ return;
|
|
+ UErrorCode error_code = U_ZERO_ERROR;
|
|
+ const char* lang = locale.getLanguage();
|
|
+ if (lang != nullptr && *lang != '\0') {
|
|
+ icu::Locale::setDefault(locale, error_code);
|
|
+ } else {
|
|
+ fprintf(stderr, "SetIcuLocale Failed to set the ICU default locale to %s\n", NS_LossyConvertUTF16toASCII(aLanguageOverride).get());
|
|
+ }
|
|
+
|
|
+ AutoJSAPI jsapi;
|
|
+ jsapi.Init();
|
|
+ JSContext* cx = jsapi.cx();
|
|
+ JS_ResetDefaultLocale(JS_GetRuntime(cx));
|
|
+
|
|
+ ResetDefaultLocaleInAllWorkers();
|
|
+}
|
|
+
|
|
+NS_IMETHODIMP
|
|
+nsDocShell::SetLanguageOverride(const nsAString& aLanguageOverride) {
|
|
+ mLanguageOverride = aLanguageOverride;
|
|
+ SetIcuLocale(aLanguageOverride);
|
|
+ return NS_OK;
|
|
+}
|
|
+
|
|
+NS_IMETHODIMP
|
|
+nsDocShell::OverrideTimezone(const nsAString& aTimezoneOverride,
|
|
+ bool* aSuccess) {
|
|
+ NS_ENSURE_ARG(aSuccess);
|
|
+ NS_LossyConvertUTF16toASCII timeZoneId(aTimezoneOverride);
|
|
+ *aSuccess = nsJSUtils::SetTimeZoneOverride(timeZoneId.get());
|
|
+
|
|
+ // Set TZ which affects localtime_s().
|
|
+ auto setTimeZoneEnv = [](const char* value) {
|
|
+#if defined(_WIN32)
|
|
+ return _putenv_s("TZ", value) == 0;
|
|
+#else
|
|
+ return setenv("TZ", value, true) == 0;
|
|
+#endif /* _WIN32 */
|
|
+ };
|
|
+ if (*aSuccess) {
|
|
+ *aSuccess = setTimeZoneEnv(timeZoneId.get());
|
|
+ if (!*aSuccess) {
|
|
+ fprintf(stderr, "Failed to set 'TZ' to '%s'\n", timeZoneId.get());
|
|
+ }
|
|
+ }
|
|
+ return NS_OK;
|
|
+}
|
|
+
|
|
+NS_IMETHODIMP
|
|
+nsDocShell::GetFileInputInterceptionEnabled(bool* aEnabled) {
|
|
+ MOZ_ASSERT(aEnabled);
|
|
+ *aEnabled = GetRootDocShell()->mFileInputInterceptionEnabled;
|
|
+ return NS_OK;
|
|
+}
|
|
+
|
|
+NS_IMETHODIMP
|
|
+nsDocShell::SetFileInputInterceptionEnabled(bool aEnabled) {
|
|
+ mFileInputInterceptionEnabled = aEnabled;
|
|
+ return NS_OK;
|
|
+}
|
|
+
|
|
+bool nsDocShell::IsFileInputInterceptionEnabled() {
|
|
+ return GetRootDocShell()->mFileInputInterceptionEnabled;
|
|
+}
|
|
+
|
|
+void nsDocShell::FilePickerShown(mozilla::dom::Element* element) {
|
|
+ nsCOMPtr<nsIObserverService> observerService =
|
|
+ mozilla::services::GetObserverService();
|
|
+ observerService->NotifyObservers(
|
|
+ ToSupports(element), "juggler-file-picker-shown", nullptr);
|
|
+}
|
|
+
|
|
+RefPtr<nsGeolocationService> nsDocShell::GetGeolocationServiceOverride() {
|
|
+ return GetRootDocShell()->mGeolocationServiceOverride;
|
|
+}
|
|
+
|
|
+NS_IMETHODIMP
|
|
+nsDocShell::SetGeolocationOverride(nsIDOMGeoPosition* aGeolocationOverride) {
|
|
+ if (aGeolocationOverride) {
|
|
+ if (!mGeolocationServiceOverride) {
|
|
+ mGeolocationServiceOverride = new nsGeolocationService();
|
|
+ mGeolocationServiceOverride->Init();
|
|
+ }
|
|
+ mGeolocationServiceOverride->Update(aGeolocationOverride);
|
|
+ } else {
|
|
+ mGeolocationServiceOverride = nullptr;
|
|
+ }
|
|
+ return NS_OK;
|
|
+}
|
|
+
|
|
+NS_IMETHODIMP
|
|
+nsDocShell::GetOnlineOverride(OnlineOverride* aOnlineOverride) {
|
|
+ *aOnlineOverride = GetRootDocShell()->mOnlineOverride;
|
|
+ return NS_OK;
|
|
+}
|
|
+
|
|
+NS_IMETHODIMP
|
|
+nsDocShell::SetOnlineOverride(OnlineOverride aOnlineOverride) {
|
|
+ // We don't have a way to verify this coming from Javascript, so this check is
|
|
+ // still needed.
|
|
+ if (!(aOnlineOverride == ONLINE_OVERRIDE_NONE ||
|
|
+ aOnlineOverride == ONLINE_OVERRIDE_ONLINE ||
|
|
+ aOnlineOverride == ONLINE_OVERRIDE_OFFLINE)) {
|
|
+ return NS_ERROR_INVALID_ARG;
|
|
+ }
|
|
+
|
|
+ mOnlineOverride = aOnlineOverride;
|
|
+ return NS_OK;
|
|
+}
|
|
+
|
|
+NS_IMETHODIMP
|
|
+nsDocShell::GetColorSchemeOverride(ColorSchemeOverride* aColorSchemeOverride) {
|
|
+ *aColorSchemeOverride = GetRootDocShell()->mColorSchemeOverride;
|
|
+ return NS_OK;
|
|
+}
|
|
+
|
|
+NS_IMETHODIMP
|
|
+nsDocShell::SetColorSchemeOverride(ColorSchemeOverride aColorSchemeOverride) {
|
|
+ mColorSchemeOverride = aColorSchemeOverride;
|
|
+ return NS_OK;
|
|
+}
|
|
+
|
|
+// =============== Juggler End =======================
|
|
+
|
|
NS_IMETHODIMP
|
|
nsDocShell::GetIsNavigating(bool* aOut) {
|
|
*aOut = mIsNavigating;
|
|
@@ -8195,6 +8389,12 @@ nsresult nsDocShell::PerformRetargeting(nsDocShellLoadState* aLoadState,
|
|
true, // aForceNoOpener
|
|
getter_AddRefs(newBC));
|
|
MOZ_ASSERT(!newBC);
|
|
+ if (rv == NS_OK) {
|
|
+ nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
|
|
+ if (observerService) {
|
|
+ observerService->NotifyObservers(GetAsSupports(this), "juggler-window-open-in-new-context", nullptr);
|
|
+ }
|
|
+ }
|
|
return rv;
|
|
}
|
|
|
|
@@ -11698,6 +11898,9 @@ class OnLinkClickEvent : public Runnable {
|
|
mNoOpenerImplied, nullptr, nullptr,
|
|
mIsUserTriggered, mTriggeringPrincipal, mCsp);
|
|
}
|
|
+ nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
|
|
+ observerService->NotifyObservers(ToSupports(mContent), "juggler-link-click-sync", nullptr);
|
|
+
|
|
return NS_OK;
|
|
}
|
|
|
|
@@ -11787,6 +11990,8 @@ nsresult nsDocShell::OnLinkClick(
|
|
this, aContent, aURI, target, aFileName, aPostDataStream,
|
|
aHeadersDataStream, noOpenerImplied, aIsUserTriggered, aIsTrusted,
|
|
aTriggeringPrincipal, aCsp);
|
|
+ nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
|
|
+ observerService->NotifyObservers(ToSupports(aContent), "juggler-link-click", nullptr);
|
|
return Dispatch(TaskCategory::UI, ev.forget());
|
|
}
|
|
|
|
diff --git a/docshell/base/nsDocShell.h b/docshell/base/nsDocShell.h
|
|
index dcffed8e55371a4f0aeae408de3a94e4e3a9ab95..5f6b2243ac054f414573736fc23b75509b2a8f5b 100644
|
|
--- a/docshell/base/nsDocShell.h
|
|
+++ b/docshell/base/nsDocShell.h
|
|
@@ -13,6 +13,7 @@
|
|
#include "Units.h"
|
|
#include "jsapi.h"
|
|
#include "mozilla/BasePrincipal.h"
|
|
+#include "mozilla/dom/Geolocation.h"
|
|
#include "mozilla/HalScreenConfiguration.h"
|
|
#include "mozilla/LinkedList.h"
|
|
#include "mozilla/Maybe.h"
|
|
@@ -25,6 +26,7 @@
|
|
#include "mozilla/UniquePtr.h"
|
|
#include "mozilla/WeakPtr.h"
|
|
#include "mozilla/dom/BrowsingContext.h"
|
|
+#include "mozilla/dom/Element.h"
|
|
#include "mozilla/dom/ChildSHistory.h"
|
|
#include "mozilla/dom/ProfileTimelineMarkerBinding.h"
|
|
#include "mozilla/dom/WindowProxyHolder.h"
|
|
@@ -479,6 +481,15 @@ class nsDocShell final : public nsDocLoader,
|
|
|
|
void SetWillChangeProcess() { mWillChangeProcess = true; }
|
|
|
|
+ bool IsFileInputInterceptionEnabled();
|
|
+ void FilePickerShown(mozilla::dom::Element* element);
|
|
+
|
|
+ bool ShouldOverrideHasFocus() const;
|
|
+
|
|
+ bool IsBypassCSPEnabled();
|
|
+
|
|
+ RefPtr<nsGeolocationService> GetGeolocationServiceOverride();
|
|
+
|
|
// Create a content viewer within this nsDocShell for the given
|
|
// `WindowGlobalChild` actor.
|
|
nsresult CreateContentViewerForActor(
|
|
@@ -1020,6 +1031,8 @@ class nsDocShell final : public nsDocLoader,
|
|
|
|
bool CSSErrorReportingEnabled() const { return mCSSErrorReportingEnabled; }
|
|
|
|
+ nsDocShell* GetRootDocShell();
|
|
+
|
|
// Handles retrieval of subframe session history for nsDocShell::LoadURI. If a
|
|
// load is requested in a subframe of the current DocShell, the subframe
|
|
// loadType may need to reflect the loadType of the parent document, or in
|
|
@@ -1262,6 +1275,14 @@ class nsDocShell final : public nsDocLoader,
|
|
bool mAllowWindowControl : 1;
|
|
bool mUseErrorPages : 1;
|
|
bool mCSSErrorReportingEnabled : 1;
|
|
+ bool mFileInputInterceptionEnabled: 1;
|
|
+ bool mOverrideHasFocus : 1;
|
|
+ bool mBypassCSPEnabled : 1;
|
|
+ nsString mLanguageOverride;
|
|
+ RefPtr<nsGeolocationService> mGeolocationServiceOverride;
|
|
+ OnlineOverride mOnlineOverride;
|
|
+ ColorSchemeOverride mColorSchemeOverride;
|
|
+
|
|
bool mAllowAuth : 1;
|
|
bool mAllowKeywordFixup : 1;
|
|
bool mIsOffScreenBrowser : 1;
|
|
diff --git a/docshell/base/nsIDocShell.idl b/docshell/base/nsIDocShell.idl
|
|
index 01dc4734eb191adf6572b9b628b4682eda017e19..0929fa0c324d5bc6e09a9d71ac4d8f4fbacca946 100644
|
|
--- a/docshell/base/nsIDocShell.idl
|
|
+++ b/docshell/base/nsIDocShell.idl
|
|
@@ -44,6 +44,7 @@ interface nsIURI;
|
|
interface nsIChannel;
|
|
interface nsIContentViewer;
|
|
interface nsIContentSecurityPolicy;
|
|
+interface nsIDOMGeoPosition;
|
|
interface nsIDocShellLoadInfo;
|
|
interface nsIEditor;
|
|
interface nsIEditingSession;
|
|
@@ -1010,6 +1011,33 @@ interface nsIDocShell : nsIDocShellTreeItem
|
|
*/
|
|
void synchronizeLayoutHistoryState();
|
|
|
|
+ attribute boolean fileInputInterceptionEnabled;
|
|
+
|
|
+ attribute boolean overrideHasFocus;
|
|
+
|
|
+ attribute boolean bypassCSPEnabled;
|
|
+
|
|
+ attribute AString languageOverride;
|
|
+
|
|
+ boolean overrideTimezone(in AString timezoneId);
|
|
+
|
|
+ cenum OnlineOverride: 8 {
|
|
+ ONLINE_OVERRIDE_NONE = 0,
|
|
+ ONLINE_OVERRIDE_ONLINE = 1,
|
|
+ ONLINE_OVERRIDE_OFFLINE = 2,
|
|
+ };
|
|
+ [infallible] attribute nsIDocShell_OnlineOverride onlineOverride;
|
|
+
|
|
+ cenum ColorSchemeOverride : 8 {
|
|
+ COLOR_SCHEME_OVERRIDE_LIGHT,
|
|
+ COLOR_SCHEME_OVERRIDE_DARK,
|
|
+ COLOR_SCHEME_OVERRIDE_NO_PREFERENCE,
|
|
+ COLOR_SCHEME_OVERRIDE_NONE, /* This clears the override. */
|
|
+ };
|
|
+ [infallible] attribute nsIDocShell_ColorSchemeOverride colorSchemeOverride;
|
|
+
|
|
+ void setGeolocationOverride(in nsIDOMGeoPosition position);
|
|
+
|
|
/**
|
|
* This attempts to save any applicable layout history state (like
|
|
* scroll position) in the nsISHEntry. This is normally done
|
|
diff --git a/dom/base/Document.cpp b/dom/base/Document.cpp
|
|
index 3ea8d9829cbfb59e7095a21ff53993cb7716e9f2..b882a58f17a701cbced7b38f959a40e9e964b96a 100644
|
|
--- a/dom/base/Document.cpp
|
|
+++ b/dom/base/Document.cpp
|
|
@@ -3216,6 +3216,9 @@ void Document::SendToConsole(nsCOMArray<nsISecurityConsoleMessage>& aMessages) {
|
|
}
|
|
|
|
void Document::ApplySettingsFromCSP(bool aSpeculative) {
|
|
+ if (mDocumentContainer && mDocumentContainer->IsBypassCSPEnabled())
|
|
+ return;
|
|
+
|
|
nsresult rv = NS_OK;
|
|
if (!aSpeculative) {
|
|
// 1) apply settings from regular CSP
|
|
@@ -3270,6 +3273,11 @@ nsresult Document::InitCSP(nsIChannel* aChannel) {
|
|
return NS_OK;
|
|
}
|
|
|
|
+ nsCOMPtr<nsIDocShell> shell(mDocumentContainer);
|
|
+ if (shell && nsDocShell::Cast(shell)->IsBypassCSPEnabled()) {
|
|
+ return NS_OK;
|
|
+ }
|
|
+
|
|
// If this is a data document - no need to set CSP.
|
|
if (mLoadedAsData) {
|
|
return NS_OK;
|
|
@@ -4030,6 +4038,10 @@ bool Document::HasFocus(ErrorResult& rv) const {
|
|
return false;
|
|
}
|
|
|
|
+ if (IsActive() && mDocumentContainer->ShouldOverrideHasFocus()) {
|
|
+ return true;
|
|
+ }
|
|
+
|
|
// Is there a focused DOMWindow?
|
|
nsCOMPtr<mozIDOMWindowProxy> focusedWindow;
|
|
fm->GetFocusedWindow(getter_AddRefs(focusedWindow));
|
|
@@ -16322,6 +16334,19 @@ void Document::RemoveToplevelLoadingDocument(Document* aDoc) {
|
|
|
|
StylePrefersColorScheme Document::PrefersColorScheme(
|
|
IgnoreRFP aIgnoreRFP) const {
|
|
+ auto* docShell = static_cast<nsDocShell*>(GetDocShell());
|
|
+ nsIDocShell::ColorSchemeOverride colorScheme;
|
|
+ if (docShell->GetColorSchemeOverride(&colorScheme) == NS_OK &&
|
|
+ colorScheme != nsIDocShell::COLOR_SCHEME_OVERRIDE_NONE) {
|
|
+ switch (colorScheme) {
|
|
+ case nsIDocShell::COLOR_SCHEME_OVERRIDE_LIGHT:
|
|
+ return StylePrefersColorScheme::Light;
|
|
+ case nsIDocShell::COLOR_SCHEME_OVERRIDE_DARK:
|
|
+ return StylePrefersColorScheme::Dark;
|
|
+ case nsIDocShell::COLOR_SCHEME_OVERRIDE_NO_PREFERENCE:
|
|
+ return StylePrefersColorScheme::NoPreference;
|
|
+ };
|
|
+ }
|
|
if (aIgnoreRFP == IgnoreRFP::No &&
|
|
nsContentUtils::ShouldResistFingerprinting(this)) {
|
|
return StylePrefersColorScheme::Light;
|
|
diff --git a/dom/base/Navigator.cpp b/dom/base/Navigator.cpp
|
|
index aa3fa6719f05a1aeb45f03f85a7e169d42f96bb8..4f3131229fe053a2b125327839fc64178fc15b62 100644
|
|
--- a/dom/base/Navigator.cpp
|
|
+++ b/dom/base/Navigator.cpp
|
|
@@ -327,14 +327,18 @@ void Navigator::GetAppName(nsAString& aAppName, CallerType aCallerType) const {
|
|
* for more detail.
|
|
*/
|
|
/* static */
|
|
-void Navigator::GetAcceptLanguages(nsTArray<nsString>& aLanguages) {
|
|
+void Navigator::GetAcceptLanguages(const nsString* aLanguageOverride, nsTArray<nsString>& aLanguages) {
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
aLanguages.Clear();
|
|
|
|
// E.g. "de-de, en-us,en".
|
|
nsAutoString acceptLang;
|
|
- Preferences::GetLocalizedString("intl.accept_languages", acceptLang);
|
|
+ if (aLanguageOverride && aLanguageOverride->Length())
|
|
+ acceptLang = *aLanguageOverride;
|
|
+ else
|
|
+ Preferences::GetLocalizedString("intl.accept_languages", acceptLang);
|
|
+
|
|
|
|
// Split values on commas.
|
|
nsCharSeparatedTokenizer langTokenizer(acceptLang, ',');
|
|
@@ -390,7 +394,9 @@ void Navigator::GetLanguage(nsAString& aLanguage) {
|
|
}
|
|
|
|
void Navigator::GetLanguages(nsTArray<nsString>& aLanguages) {
|
|
- GetAcceptLanguages(aLanguages);
|
|
+ nsString languageOverride;
|
|
+ mWindow->GetDocShell()->GetLanguageOverride(languageOverride);
|
|
+ GetAcceptLanguages(&languageOverride, aLanguages);
|
|
|
|
// The returned value is cached by the binding code. The window listens to the
|
|
// accept languages change and will clear the cache when needed. It has to
|
|
@@ -541,7 +547,13 @@ bool Navigator::CookieEnabled() {
|
|
return granted;
|
|
}
|
|
|
|
-bool Navigator::OnLine() { return !NS_IsOffline(); }
|
|
+bool Navigator::OnLine() {
|
|
+ nsDocShell* docShell = static_cast<nsDocShell*>(GetDocShell());
|
|
+ nsIDocShell::OnlineOverride onlineOverride;
|
|
+ if (!docShell || docShell->GetOnlineOverride(&onlineOverride) != NS_OK || onlineOverride == nsIDocShell::ONLINE_OVERRIDE_NONE)
|
|
+ return !NS_IsOffline();
|
|
+ return onlineOverride == nsIDocShell::ONLINE_OVERRIDE_ONLINE;
|
|
+}
|
|
|
|
void Navigator::GetBuildID(nsAString& aBuildID, CallerType aCallerType,
|
|
ErrorResult& aRv) const {
|
|
diff --git a/dom/base/Navigator.h b/dom/base/Navigator.h
|
|
index e268e2bbe8add1b43f6e4d6507cc7810d707a344..a34a7a292a02ea8d94042475a43ae3a05710c207 100644
|
|
--- a/dom/base/Navigator.h
|
|
+++ b/dom/base/Navigator.h
|
|
@@ -216,7 +216,7 @@ class Navigator final : public nsISupports, public nsWrapperCache {
|
|
|
|
StorageManager* Storage();
|
|
|
|
- static void GetAcceptLanguages(nsTArray<nsString>& aLanguages);
|
|
+ static void GetAcceptLanguages(const nsString* aLanguageOverride, nsTArray<nsString>& aLanguages);
|
|
|
|
dom::MediaCapabilities* MediaCapabilities();
|
|
dom::MediaSession* MediaSession();
|
|
diff --git a/dom/base/nsGlobalWindowOuter.cpp b/dom/base/nsGlobalWindowOuter.cpp
|
|
index da9d56e843a2c762dc7d5527712cdd3d30418f7f..aa3d2d6022b60ac3a263c2d1df4eb12714d8e728 100644
|
|
--- a/dom/base/nsGlobalWindowOuter.cpp
|
|
+++ b/dom/base/nsGlobalWindowOuter.cpp
|
|
@@ -2430,7 +2430,7 @@ nsresult nsGlobalWindowOuter::SetNewDocument(Document* aDocument,
|
|
&nsGlobalWindowInner::FireOnNewGlobalObject));
|
|
}
|
|
|
|
- if (newInnerWindow && !newInnerWindow->mHasNotifiedGlobalCreated && mDoc) {
|
|
+ if (newInnerWindow && mDoc) {
|
|
// We should probably notify. However if this is the, arguably bad,
|
|
// situation when we're creating a temporary non-chrome-about-blank
|
|
// document in a chrome docshell, don't notify just yet. Instead wait
|
|
@@ -2449,10 +2449,16 @@ nsresult nsGlobalWindowOuter::SetNewDocument(Document* aDocument,
|
|
}();
|
|
|
|
if (!isContentAboutBlankInChromeDocshell) {
|
|
- newInnerWindow->mHasNotifiedGlobalCreated = true;
|
|
- nsContentUtils::AddScriptRunner(NewRunnableMethod(
|
|
- "nsGlobalWindowOuter::DispatchDOMWindowCreated", this,
|
|
- &nsGlobalWindowOuter::DispatchDOMWindowCreated));
|
|
+ if (!newInnerWindow->mHasNotifiedGlobalCreated) {
|
|
+ newInnerWindow->mHasNotifiedGlobalCreated = true;
|
|
+ nsContentUtils::AddScriptRunner(NewRunnableMethod(
|
|
+ "nsGlobalWindowOuter::DispatchDOMWindowCreated", this,
|
|
+ &nsGlobalWindowOuter::DispatchDOMWindowCreated));
|
|
+ } else if (!reUseInnerWindow) {
|
|
+ nsContentUtils::AddScriptRunner(NewRunnableMethod(
|
|
+ "nsGlobalWindowOuter::JugglerDispatchDOMWindowReused", this,
|
|
+ &nsGlobalWindowOuter::JugglerDispatchDOMWindowReused));
|
|
+ }
|
|
}
|
|
}
|
|
|
|
@@ -2609,6 +2615,19 @@ void nsGlobalWindowOuter::DispatchDOMWindowCreated() {
|
|
}
|
|
}
|
|
|
|
+void nsGlobalWindowOuter::JugglerDispatchDOMWindowReused() {
|
|
+ nsCOMPtr<nsIObserverService> observerService =
|
|
+ mozilla::services::GetObserverService();
|
|
+ if (observerService && mDoc) {
|
|
+ nsIPrincipal* principal = mDoc->NodePrincipal();
|
|
+ if (!principal->IsSystemPrincipal()) {
|
|
+ observerService->NotifyObservers(static_cast<nsIDOMWindow*>(this),
|
|
+ "juggler-dom-window-reused",
|
|
+ nullptr);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
void nsGlobalWindowOuter::ClearStatus() { SetStatusOuter(EmptyString()); }
|
|
|
|
void nsGlobalWindowOuter::SetDocShell(nsDocShell* aDocShell) {
|
|
@@ -3861,6 +3880,14 @@ Maybe<CSSIntSize> nsGlobalWindowOuter::GetRDMDeviceSize(
|
|
}
|
|
}
|
|
}
|
|
+ if (topInProcessContentDoc) {
|
|
+ nsIDocShell* docShell = topInProcessContentDoc->GetDocShell();
|
|
+ if (docShell && docShell->GetDeviceSizeIsPageSize()) {
|
|
+ nsPresContext* presContext = docShell->GetPresContext();
|
|
+ if (presContext)
|
|
+ return Some(CSSPixel::FromAppUnitsRounded(presContext->GetVisibleArea().Size()));
|
|
+ }
|
|
+ }
|
|
return Nothing();
|
|
}
|
|
|
|
diff --git a/dom/base/nsGlobalWindowOuter.h b/dom/base/nsGlobalWindowOuter.h
|
|
index d2a8f0219f21800ef7800ed637c1f61d454a99a6..7e88989437613cec54d6bbf551afd572e28c4221 100644
|
|
--- a/dom/base/nsGlobalWindowOuter.h
|
|
+++ b/dom/base/nsGlobalWindowOuter.h
|
|
@@ -319,6 +319,7 @@ class nsGlobalWindowOuter final : public mozilla::dom::EventTarget,
|
|
|
|
// Outer windows only.
|
|
void DispatchDOMWindowCreated();
|
|
+ void JugglerDispatchDOMWindowReused();
|
|
|
|
// Outer windows only.
|
|
virtual void EnsureSizeAndPositionUpToDate() override;
|
|
diff --git a/dom/base/nsINode.cpp b/dom/base/nsINode.cpp
|
|
index 7c0d4bd261bf053c7cab4091522dc1e52118eba1..e320e6bfb0402eb07ae53272264278bad9638519 100644
|
|
--- a/dom/base/nsINode.cpp
|
|
+++ b/dom/base/nsINode.cpp
|
|
@@ -1260,6 +1260,48 @@ void nsINode::GetBoxQuadsFromWindowOrigin(const BoxQuadOptions& aOptions,
|
|
mozilla::GetBoxQuadsFromWindowOrigin(this, aOptions, aResult, aRv);
|
|
}
|
|
|
|
+void nsINode::ScrollRectIntoViewIfNeeded(int32_t x, int32_t y,
|
|
+ int32_t w, int32_t h,
|
|
+ ErrorResult& aRv) {
|
|
+ aRv = NS_ERROR_UNEXPECTED;
|
|
+ nsCOMPtr<Document> document = OwnerDoc();
|
|
+ if (!document) {
|
|
+ return aRv.ThrowNotFoundError("Node is detached from document");
|
|
+ }
|
|
+ PresShell* presShell = document->GetPresShell();
|
|
+ if (!presShell) {
|
|
+ return aRv.ThrowNotFoundError("Node is detached from document");
|
|
+ }
|
|
+ if (!IsContent()) {
|
|
+ return aRv.ThrowNotFoundError("Node does not have a layout object");
|
|
+ }
|
|
+ aRv = NS_OK;
|
|
+ nsIFrame* primaryFrame = AsContent()->GetPrimaryFrame(FlushType::Frames);
|
|
+ if (!primaryFrame) {
|
|
+ return aRv.ThrowNotFoundError("Node does not have a layout object");
|
|
+ }
|
|
+ nsRect rect;
|
|
+ if (x == -1 && y == -1 && w == -1 && h == -1) {
|
|
+ rect = primaryFrame->GetRectRelativeToSelf();
|
|
+ } else {
|
|
+ rect = nsRect(nsPresContext::CSSPixelsToAppUnits(x),
|
|
+ nsPresContext::CSSPixelsToAppUnits(y),
|
|
+ nsPresContext::CSSPixelsToAppUnits(w),
|
|
+ nsPresContext::CSSPixelsToAppUnits(h));
|
|
+ }
|
|
+ presShell->ScrollFrameRectIntoView(
|
|
+ primaryFrame, rect,
|
|
+ ScrollAxis(kScrollToCenter, WhenToScroll::Always),
|
|
+ ScrollAxis(kScrollToCenter, WhenToScroll::Always),
|
|
+ ScrollFlags::ScrollOverflowHidden);
|
|
+ // If a _visual_ scroll update is pending, cancel it; otherwise, it will
|
|
+ // clobber next scroll (e.g. subsequent window.scrollTo(0, 0) wlll break).
|
|
+ if (presShell->GetPendingVisualScrollUpdate()) {
|
|
+ presShell->AcknowledgePendingVisualScrollUpdate();
|
|
+ presShell->ClearPendingVisualScrollUpdate();
|
|
+ }
|
|
+}
|
|
+
|
|
already_AddRefed<DOMQuad> nsINode::ConvertQuadFromNode(
|
|
DOMQuad& aQuad, const GeometryNode& aFrom,
|
|
const ConvertCoordinateOptions& aOptions, CallerType aCallerType,
|
|
diff --git a/dom/base/nsINode.h b/dom/base/nsINode.h
|
|
index 8a58b9e21cb6c79a8d28104fef866c9809776bce..1e58cfbfa6ef9f3f5f80055321f21980cda5c093 100644
|
|
--- a/dom/base/nsINode.h
|
|
+++ b/dom/base/nsINode.h
|
|
@@ -2044,6 +2044,10 @@ class nsINode : public mozilla::dom::EventTarget {
|
|
nsTArray<RefPtr<DOMQuad>>& aResult,
|
|
ErrorResult& aRv);
|
|
|
|
+ void ScrollRectIntoViewIfNeeded(int32_t x, int32_t y,
|
|
+ int32_t w, int32_t h,
|
|
+ ErrorResult& aRv);
|
|
+
|
|
already_AddRefed<DOMQuad> ConvertQuadFromNode(
|
|
DOMQuad& aQuad, const TextOrElementOrDocument& aFrom,
|
|
const ConvertCoordinateOptions& aOptions, CallerType aCallerType,
|
|
diff --git a/dom/base/nsJSUtils.cpp b/dom/base/nsJSUtils.cpp
|
|
index 048563cc8e58e282d94bbbd568a7aaa8f655b84f..37ab6d489c1e079bdd5398323db5541cdc88cde7 100644
|
|
--- a/dom/base/nsJSUtils.cpp
|
|
+++ b/dom/base/nsJSUtils.cpp
|
|
@@ -564,6 +564,11 @@ bool nsJSUtils::GetScopeChainForElement(
|
|
return true;
|
|
}
|
|
|
|
+/* static */
|
|
+bool nsJSUtils::SetTimeZoneOverride(const char* timezoneId) {
|
|
+ return JS::SetTimeZoneOverride(timezoneId);
|
|
+}
|
|
+
|
|
/* static */
|
|
void nsJSUtils::ResetTimeZone() { JS::ResetTimeZone(); }
|
|
|
|
diff --git a/dom/base/nsJSUtils.h b/dom/base/nsJSUtils.h
|
|
index cd7b816d011e236895cdeff88a96bf75334726d3..60d62ac411b4c4c17bf860f2a29b71802133abb2 100644
|
|
--- a/dom/base/nsJSUtils.h
|
|
+++ b/dom/base/nsJSUtils.h
|
|
@@ -237,6 +237,7 @@ class nsJSUtils {
|
|
JSContext* aCx, mozilla::dom::Element* aElement,
|
|
JS::MutableHandleVector<JSObject*> aScopeChain);
|
|
|
|
+ static bool SetTimeZoneOverride(const char* timezoneId);
|
|
static void ResetTimeZone();
|
|
|
|
static bool DumpEnabled();
|
|
diff --git a/dom/geolocation/Geolocation.cpp b/dom/geolocation/Geolocation.cpp
|
|
index 51c04d2f40f51c9163183559d6a92ea7b0179e17..72084201c77a4dfeabb9a2a6d42a3348b5aa6485 100644
|
|
--- a/dom/geolocation/Geolocation.cpp
|
|
+++ b/dom/geolocation/Geolocation.cpp
|
|
@@ -23,6 +23,7 @@
|
|
#include "nsComponentManagerUtils.h"
|
|
#include "nsContentPermissionHelper.h"
|
|
#include "nsContentUtils.h"
|
|
+#include "nsDocShell.h"
|
|
#include "nsGlobalWindow.h"
|
|
#include "mozilla/dom/Document.h"
|
|
#include "nsINamed.h"
|
|
@@ -294,10 +295,8 @@ nsGeolocationRequest::Allow(JS::HandleValue aChoices) {
|
|
return NS_OK;
|
|
}
|
|
|
|
- RefPtr<nsGeolocationService> gs =
|
|
- nsGeolocationService::GetGeolocationService();
|
|
-
|
|
- bool canUseCache = false;
|
|
+ nsGeolocationService* gs = mLocator->GetGeolocationService();
|
|
+ bool canUseCache = gs != nsGeolocationService::sService.get();
|
|
CachedPositionAndAccuracy lastPosition = gs->GetCachedPosition();
|
|
if (lastPosition.position) {
|
|
DOMTimeStamp cachedPositionTime_ms;
|
|
@@ -467,8 +466,7 @@ void nsGeolocationRequest::Shutdown() {
|
|
// If there are no other high accuracy requests, the geolocation service will
|
|
// notify the provider to switch to the default accuracy.
|
|
if (mOptions && mOptions->mEnableHighAccuracy) {
|
|
- RefPtr<nsGeolocationService> gs =
|
|
- nsGeolocationService::GetGeolocationService();
|
|
+ nsGeolocationService* gs = mLocator ? mLocator->GetGeolocationService() : nullptr;
|
|
if (gs) {
|
|
gs->UpdateAccuracy();
|
|
}
|
|
@@ -745,8 +743,14 @@ void nsGeolocationService::StopDevice() {
|
|
StaticRefPtr<nsGeolocationService> nsGeolocationService::sService;
|
|
|
|
already_AddRefed<nsGeolocationService>
|
|
-nsGeolocationService::GetGeolocationService() {
|
|
+nsGeolocationService::GetGeolocationService(nsDocShell* docShell) {
|
|
RefPtr<nsGeolocationService> result;
|
|
+ if (docShell) {
|
|
+ result = docShell->GetGeolocationServiceOverride();
|
|
+ if (result)
|
|
+ return result.forget();
|
|
+ }
|
|
+
|
|
if (nsGeolocationService::sService) {
|
|
result = nsGeolocationService::sService;
|
|
|
|
@@ -838,7 +842,9 @@ nsresult Geolocation::Init(nsPIDOMWindowInner* aContentDom) {
|
|
// If no aContentDom was passed into us, we are being used
|
|
// by chrome/c++ and have no mOwner, no mPrincipal, and no need
|
|
// to prompt.
|
|
- mService = nsGeolocationService::GetGeolocationService();
|
|
+ nsCOMPtr<Document> doc = aContentDom ? aContentDom->GetDoc() : nullptr;
|
|
+ mService = nsGeolocationService::GetGeolocationService(
|
|
+ doc ? static_cast<nsDocShell*>(doc->GetDocShell()) : nullptr);
|
|
if (mService) {
|
|
mService->AddLocator(this);
|
|
}
|
|
diff --git a/dom/geolocation/Geolocation.h b/dom/geolocation/Geolocation.h
|
|
index d92bd1c738016f93c66dbdc449c70937c37b6f9a..a4c1f0ca974470342cb8136705d78cfc00e35083 100644
|
|
--- a/dom/geolocation/Geolocation.h
|
|
+++ b/dom/geolocation/Geolocation.h
|
|
@@ -57,7 +57,7 @@ struct CachedPositionAndAccuracy {
|
|
class nsGeolocationService final : public nsIGeolocationUpdate,
|
|
public nsIObserver {
|
|
public:
|
|
- static already_AddRefed<nsGeolocationService> GetGeolocationService();
|
|
+ static already_AddRefed<nsGeolocationService> GetGeolocationService(nsDocShell* docShell = nullptr);
|
|
static mozilla::StaticRefPtr<nsGeolocationService> sService;
|
|
|
|
NS_DECL_THREADSAFE_ISUPPORTS
|
|
@@ -182,6 +182,8 @@ class Geolocation final : public nsIGeolocationUpdate, public nsWrapperCache {
|
|
// null.
|
|
static already_AddRefed<Geolocation> NonWindowSingleton();
|
|
|
|
+ nsGeolocationService* GetGeolocationService() { return mService; };
|
|
+
|
|
private:
|
|
~Geolocation();
|
|
|
|
diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp
|
|
index 82a7d54d6e7ae6949422ac82ab36d2d88f407a7c..595067b6954ed53ffe0fb266e7666cc7ec1fd3f1 100644
|
|
--- a/dom/html/HTMLInputElement.cpp
|
|
+++ b/dom/html/HTMLInputElement.cpp
|
|
@@ -44,6 +44,7 @@
|
|
#include "nsMappedAttributes.h"
|
|
#include "nsIFormControl.h"
|
|
#include "mozilla/dom/Document.h"
|
|
+#include "nsDocShell.h"
|
|
#include "nsIFormControlFrame.h"
|
|
#include "nsITextControlFrame.h"
|
|
#include "nsIFrame.h"
|
|
@@ -706,6 +707,12 @@ nsresult HTMLInputElement::InitFilePicker(FilePickerType aType) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
+ nsDocShell* docShell = static_cast<nsDocShell*>(win->GetDocShell());
|
|
+ if (docShell && docShell->IsFileInputInterceptionEnabled()) {
|
|
+ docShell->FilePickerShown(this);
|
|
+ return NS_OK;
|
|
+ }
|
|
+
|
|
if (IsPopupBlocked()) {
|
|
return NS_OK;
|
|
}
|
|
diff --git a/dom/ipc/BrowserChild.cpp b/dom/ipc/BrowserChild.cpp
|
|
index 2b17323d8a939a18a788d34367a8c427740c0f17..b4764f1c0406b4f93b6936b32104f3de1a813233 100644
|
|
--- a/dom/ipc/BrowserChild.cpp
|
|
+++ b/dom/ipc/BrowserChild.cpp
|
|
@@ -3569,6 +3569,13 @@ NS_IMETHODIMP BrowserChild::OnStateChange(nsIWebProgress* aWebProgress,
|
|
return NS_OK;
|
|
}
|
|
|
|
+NS_IMETHODIMP BrowserChild::OnFrameLocationChange(nsIWebProgress *aWebProgress,
|
|
+ nsIRequest *aRequest,
|
|
+ nsIURI *aLocation,
|
|
+ uint32_t aFlags) {
|
|
+ return NS_OK;
|
|
+}
|
|
+
|
|
NS_IMETHODIMP BrowserChild::OnProgressChange(nsIWebProgress* aWebProgress,
|
|
nsIRequest* aRequest,
|
|
int32_t aCurSelfProgress,
|
|
diff --git a/dom/script/ScriptSettings.cpp b/dom/script/ScriptSettings.cpp
|
|
index 3f69c0f398ab6d849fe011e836343c09110673ef..4c06a9100a1d41119cb2984ee3734a1043a9c50a 100644
|
|
--- a/dom/script/ScriptSettings.cpp
|
|
+++ b/dom/script/ScriptSettings.cpp
|
|
@@ -142,6 +142,30 @@ ScriptSettingsStackEntry::~ScriptSettingsStackEntry() {
|
|
MOZ_ASSERT_IF(mGlobalObject, mGlobalObject->HasJSGlobal());
|
|
}
|
|
|
|
+static nsIGlobalObject* UnwrapSandboxGlobal(nsIGlobalObject* global) {
|
|
+ if (!global)
|
|
+ return global;
|
|
+ JSObject* globalObject = global->GetGlobalJSObject();
|
|
+ if (!globalObject)
|
|
+ return global;
|
|
+ JSContext* cx = nsContentUtils::GetCurrentJSContext();
|
|
+ if (!cx)
|
|
+ return global;
|
|
+ JS::Rooted<JSObject*> proto(cx);
|
|
+ JS::RootedObject rootedGlobal(cx, globalObject);
|
|
+ if (!JS_GetPrototype(cx, rootedGlobal, &proto))
|
|
+ return global;
|
|
+ if (!proto || !xpc::IsSandboxPrototypeProxy(proto))
|
|
+ return global;
|
|
+ // If this is a sandbox associated with a DOMWindow via a
|
|
+ // sandboxPrototype, use that DOMWindow. This supports GreaseMonkey
|
|
+ // and JetPack content scripts.
|
|
+ proto = js::CheckedUnwrapDynamic(proto, cx, /* stopAtWindowProxy = */ false);
|
|
+ if (!proto)
|
|
+ return global;
|
|
+ return xpc::WindowGlobalOrNull(proto);
|
|
+}
|
|
+
|
|
// If the entry or incumbent global ends up being something that the subject
|
|
// principal doesn't subsume, we don't want to use it. This never happens on
|
|
// the web, but can happen with asymmetric privilege relationships (i.e.
|
|
@@ -169,7 +193,7 @@ static nsIGlobalObject* ClampToSubject(nsIGlobalObject* aGlobalOrNull) {
|
|
NS_ENSURE_TRUE(globalPrin, GetCurrentGlobal());
|
|
if (!nsContentUtils::SubjectPrincipalOrSystemIfNativeCaller()
|
|
->SubsumesConsideringDomain(globalPrin)) {
|
|
- return GetCurrentGlobal();
|
|
+ return UnwrapSandboxGlobal(GetCurrentGlobal());
|
|
}
|
|
|
|
return aGlobalOrNull;
|
|
diff --git a/dom/security/nsCSPUtils.cpp b/dom/security/nsCSPUtils.cpp
|
|
index c553ad7e85e0afe1225a1d349523d067e19d5846..0318ac69ce03a37f0138ea563b11aa567bd56454 100644
|
|
--- a/dom/security/nsCSPUtils.cpp
|
|
+++ b/dom/security/nsCSPUtils.cpp
|
|
@@ -121,6 +121,11 @@ void CSP_ApplyMetaCSPToDoc(mozilla::dom::Document& aDoc,
|
|
return;
|
|
}
|
|
|
|
+ if (aDoc.GetDocShell() &&
|
|
+ nsDocShell::Cast(aDoc.GetDocShell())->IsBypassCSPEnabled()) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
nsAutoString policyStr(
|
|
nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(
|
|
aPolicyStr));
|
|
diff --git a/dom/webidl/GeometryUtils.webidl b/dom/webidl/GeometryUtils.webidl
|
|
index 2f71b284ee5f7e11f117c447834b48355784448c..d996e0a3cbbb19c1dc320c305c6d74037bffa0d3 100644
|
|
--- a/dom/webidl/GeometryUtils.webidl
|
|
+++ b/dom/webidl/GeometryUtils.webidl
|
|
@@ -27,6 +27,9 @@ interface mixin GeometryUtils {
|
|
[Throws, Func="nsINode::HasBoxQuadsSupport", NeedsCallerType]
|
|
sequence<DOMQuad> getBoxQuads(optional BoxQuadOptions options = {});
|
|
|
|
+ [ChromeOnly, Throws, Func="nsINode::HasBoxQuadsSupport"]
|
|
+ void scrollRectIntoViewIfNeeded(long x, long y, long w, long h);
|
|
+
|
|
/* getBoxQuadsFromWindowOrigin is similar to getBoxQuads, but the
|
|
* returned quads are further translated relative to the window
|
|
* origin -- which is not the layout origin. Further translation
|
|
diff --git a/dom/workers/RuntimeService.cpp b/dom/workers/RuntimeService.cpp
|
|
index 50db4fa62bc99a71c4f1e37f622dd71b5bbdc6cd..3b0bc9f7633212a27a43bafcb4e3c53709dee990 100644
|
|
--- a/dom/workers/RuntimeService.cpp
|
|
+++ b/dom/workers/RuntimeService.cpp
|
|
@@ -1019,7 +1019,7 @@ void PrefLanguagesChanged(const char* /* aPrefName */, void* /* aClosure */) {
|
|
AssertIsOnMainThread();
|
|
|
|
nsTArray<nsString> languages;
|
|
- Navigator::GetAcceptLanguages(languages);
|
|
+ Navigator::GetAcceptLanguages(nullptr, languages);
|
|
|
|
RuntimeService* runtime = RuntimeService::GetService();
|
|
if (runtime) {
|
|
@@ -1218,8 +1218,7 @@ bool RuntimeService::RegisterWorker(WorkerPrivate* aWorkerPrivate) {
|
|
}
|
|
|
|
// The navigator overridden properties should have already been read.
|
|
-
|
|
- Navigator::GetAcceptLanguages(mNavigatorProperties.mLanguages);
|
|
+ Navigator::GetAcceptLanguages(nullptr, mNavigatorProperties.mLanguages);
|
|
mNavigatorPropertiesLoaded = true;
|
|
}
|
|
|
|
@@ -1969,6 +1968,11 @@ void RuntimeService::PropagateFirstPartyStorageAccessGranted(
|
|
}
|
|
}
|
|
|
|
+void RuntimeService::ResetDefaultLocaleInAllWorkers() {
|
|
+ AssertIsOnMainThread();
|
|
+ BROADCAST_ALL_WORKERS(ResetDefaultLocale);
|
|
+}
|
|
+
|
|
void RuntimeService::NoteIdleThread(WorkerThread* aThread) {
|
|
AssertIsOnMainThread();
|
|
MOZ_ASSERT(aThread);
|
|
@@ -2383,6 +2387,14 @@ void PropagateFirstPartyStorageAccessGrantedToWorkers(
|
|
}
|
|
}
|
|
|
|
+void ResetDefaultLocaleInAllWorkers() {
|
|
+ AssertIsOnMainThread();
|
|
+ RuntimeService* runtime = RuntimeService::GetService();
|
|
+ if (runtime) {
|
|
+ runtime->ResetDefaultLocaleInAllWorkers();
|
|
+ }
|
|
+}
|
|
+
|
|
WorkerPrivate* GetWorkerPrivateFromContext(JSContext* aCx) {
|
|
MOZ_ASSERT(!NS_IsMainThread());
|
|
MOZ_ASSERT(aCx);
|
|
diff --git a/dom/workers/RuntimeService.h b/dom/workers/RuntimeService.h
|
|
index 9321a7abfe68483dbf013ce05418a6474d20103e..4800763806d8d3bb665d4ae912cf916292838ffc 100644
|
|
--- a/dom/workers/RuntimeService.h
|
|
+++ b/dom/workers/RuntimeService.h
|
|
@@ -117,6 +117,8 @@ class RuntimeService final : public nsIObserver {
|
|
|
|
void PropagateFirstPartyStorageAccessGranted(nsPIDOMWindowInner* aWindow);
|
|
|
|
+ void ResetDefaultLocaleInAllWorkers();
|
|
+
|
|
const NavigatorProperties& GetNavigatorProperties() const {
|
|
return mNavigatorProperties;
|
|
}
|
|
diff --git a/dom/workers/WorkerCommon.h b/dom/workers/WorkerCommon.h
|
|
index f5e5c232d424e25607fb2fcf089c747708e02104..ada9c56f9d31d8d1c7c4c918403f14279358a4a8 100644
|
|
--- a/dom/workers/WorkerCommon.h
|
|
+++ b/dom/workers/WorkerCommon.h
|
|
@@ -47,6 +47,8 @@ void ResumeWorkersForWindow(nsPIDOMWindowInner* aWindow);
|
|
void PropagateFirstPartyStorageAccessGrantedToWorkers(
|
|
nsPIDOMWindowInner* aWindow);
|
|
|
|
+void ResetDefaultLocaleInAllWorkers();
|
|
+
|
|
// All of these are implemented in WorkerScope.cpp
|
|
|
|
bool IsWorkerGlobal(JSObject* global);
|
|
diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp
|
|
index a0ab199295e766ff336840cba9644fd44b9011a6..add07f04046105b96bcade37980444982660af47 100644
|
|
--- a/dom/workers/WorkerPrivate.cpp
|
|
+++ b/dom/workers/WorkerPrivate.cpp
|
|
@@ -651,6 +651,18 @@ class UpdateContextOptionsRunnable final : public WorkerControlRunnable {
|
|
}
|
|
};
|
|
|
|
+class ResetDefaultLocaleRunnable final : public WorkerControlRunnable {
|
|
+ public:
|
|
+ explicit ResetDefaultLocaleRunnable(WorkerPrivate* aWorkerPrivate)
|
|
+ : WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount) {}
|
|
+
|
|
+ virtual bool WorkerRun(JSContext* aCx,
|
|
+ WorkerPrivate* aWorkerPrivate) override {
|
|
+ aWorkerPrivate->ResetDefaultLocaleInternal(aCx);
|
|
+ return true;
|
|
+ }
|
|
+};
|
|
+
|
|
class UpdateLanguagesRunnable final : public WorkerRunnable {
|
|
nsTArray<nsString> mLanguages;
|
|
|
|
@@ -1830,6 +1842,16 @@ void WorkerPrivate::UpdateContextOptions(
|
|
}
|
|
}
|
|
|
|
+void WorkerPrivate::ResetDefaultLocale() {
|
|
+ AssertIsOnParentThread();
|
|
+
|
|
+ RefPtr<ResetDefaultLocaleRunnable> runnable =
|
|
+ new ResetDefaultLocaleRunnable(this);
|
|
+ if (!runnable->Dispatch()) {
|
|
+ NS_WARNING("Failed to reset default locale in worker!");
|
|
+ }
|
|
+}
|
|
+
|
|
void WorkerPrivate::UpdateLanguages(const nsTArray<nsString>& aLanguages) {
|
|
AssertIsOnParentThread();
|
|
|
|
@@ -4790,6 +4812,15 @@ void WorkerPrivate::UpdateContextOptionsInternal(
|
|
}
|
|
}
|
|
|
|
+void WorkerPrivate::ResetDefaultLocaleInternal(JSContext* aCx) {
|
|
+ JS_ResetDefaultLocale(JS_GetRuntime(aCx));
|
|
+
|
|
+ MOZ_ACCESS_THREAD_BOUND(mWorkerThreadAccessible, data);
|
|
+ for (uint32_t index = 0; index < data->mChildWorkers.Length(); index++) {
|
|
+ data->mChildWorkers[index]->ResetDefaultLocale();
|
|
+ }
|
|
+}
|
|
+
|
|
void WorkerPrivate::UpdateLanguagesInternal(
|
|
const nsTArray<nsString>& aLanguages) {
|
|
WorkerGlobalScope* globalScope = GlobalScope();
|
|
diff --git a/dom/workers/WorkerPrivate.h b/dom/workers/WorkerPrivate.h
|
|
index 82d04ec3a72f3390a43c98eb2ae91f0d15a83631..b197bb0718ed712af2a7c08d2ef691de1bde1d98 100644
|
|
--- a/dom/workers/WorkerPrivate.h
|
|
+++ b/dom/workers/WorkerPrivate.h
|
|
@@ -297,6 +297,8 @@ class WorkerPrivate : public RelativeTimeline {
|
|
void UpdateContextOptionsInternal(JSContext* aCx,
|
|
const JS::ContextOptions& aContextOptions);
|
|
|
|
+ void ResetDefaultLocaleInternal(JSContext* aCx);
|
|
+
|
|
void UpdateLanguagesInternal(const nsTArray<nsString>& aLanguages);
|
|
|
|
void UpdateJSWorkerMemoryParameterInternal(JSContext* aCx, JSGCParamKey key,
|
|
@@ -875,6 +877,8 @@ class WorkerPrivate : public RelativeTimeline {
|
|
|
|
void UpdateContextOptions(const JS::ContextOptions& aContextOptions);
|
|
|
|
+ void ResetDefaultLocale();
|
|
+
|
|
void UpdateLanguages(const nsTArray<nsString>& aLanguages);
|
|
|
|
void UpdateJSWorkerMemoryParameter(JSGCParamKey key, Maybe<uint32_t> value);
|
|
diff --git a/js/public/Date.h b/js/public/Date.h
|
|
index e7a54d86c44499a3ec2adf1c156b9f9dfb0bc6b4..f56c1b419c4cb52bc371f6b8dbfffba464326fc4 100644
|
|
--- a/js/public/Date.h
|
|
+++ b/js/public/Date.h
|
|
@@ -56,6 +56,8 @@ namespace JS {
|
|
*/
|
|
extern JS_PUBLIC_API void ResetTimeZone();
|
|
|
|
+extern JS_PUBLIC_API bool SetTimeZoneOverride(const char* timezoneId);
|
|
+
|
|
class ClippedTime;
|
|
inline ClippedTime TimeClip(double time);
|
|
|
|
diff --git a/js/src/debugger/Object.cpp b/js/src/debugger/Object.cpp
|
|
index add42a1c2da3fca6a4469435498a4c6d824d8f47..72a7f8eff3302586d6567287380ec5de9c1c5165 100644
|
|
--- a/js/src/debugger/Object.cpp
|
|
+++ b/js/src/debugger/Object.cpp
|
|
@@ -2385,7 +2385,11 @@ Maybe<Completion> DebuggerObject::call(JSContext* cx,
|
|
invokeArgs[i].set(args2[i]);
|
|
}
|
|
|
|
+ // Disable CSP for the scope of the call.
|
|
+ const JSSecurityCallbacks* securityCallbacks = JS_GetSecurityCallbacks(cx);
|
|
+ JS_SetSecurityCallbacks(cx, nullptr);
|
|
ok = js::Call(cx, calleev, thisv, invokeArgs, &result);
|
|
+ JS_SetSecurityCallbacks(cx, securityCallbacks);
|
|
}
|
|
}
|
|
|
|
diff --git a/js/src/vm/DateTime.cpp b/js/src/vm/DateTime.cpp
|
|
index d27ba46016e0a01bd57dde7acc219eaaee9e65ca..3cfa6ec99272339238a4494b62b008de7036d426 100644
|
|
--- a/js/src/vm/DateTime.cpp
|
|
+++ b/js/src/vm/DateTime.cpp
|
|
@@ -168,6 +168,11 @@ void js::DateTimeInfo::internalResetTimeZone(ResetTimeZoneMode mode) {
|
|
}
|
|
}
|
|
|
|
+void js::DateTimeInfo::internalSetTimeZoneOverride(mozilla::UniquePtr<icu::TimeZone> timeZone) {
|
|
+ timeZoneOverride_ = std::move(timeZone);
|
|
+ internalResetTimeZone(ResetTimeZoneMode::ResetEvenIfOffsetUnchanged);
|
|
+}
|
|
+
|
|
void js::DateTimeInfo::updateTimeZone() {
|
|
MOZ_ASSERT(timeZoneStatus_ != TimeZoneStatus::Valid);
|
|
|
|
@@ -528,10 +533,27 @@ void js::ResetTimeZoneInternal(ResetTimeZoneMode mode) {
|
|
js::DateTimeInfo::resetTimeZone(mode);
|
|
}
|
|
|
|
+void js::SetTimeZoneOverrideInternal(mozilla::UniquePtr<icu::TimeZone> timeZone) {
|
|
+ auto guard = js::DateTimeInfo::instance->lock();
|
|
+ guard->internalSetTimeZoneOverride(std::move(timeZone));
|
|
+}
|
|
+
|
|
JS_PUBLIC_API void JS::ResetTimeZone() {
|
|
js::ResetTimeZoneInternal(js::ResetTimeZoneMode::ResetEvenIfOffsetUnchanged);
|
|
}
|
|
|
|
+JS_PUBLIC_API bool JS::SetTimeZoneOverride(const char* timeZoneId) {
|
|
+ // Validate timezone id.
|
|
+ mozilla::UniquePtr<icu::TimeZone> timeZone(icu::TimeZone::createTimeZone(
|
|
+ icu::UnicodeString(timeZoneId, -1, US_INV)));
|
|
+ if (!timeZone || *timeZone == icu::TimeZone::getUnknown()) {
|
|
+ fprintf(stderr, "Invalid timezone id: %s\n", timeZoneId);
|
|
+ return false;
|
|
+ }
|
|
+ js::SetTimeZoneOverrideInternal(std::move(timeZone));
|
|
+ return true;
|
|
+}
|
|
+
|
|
#if defined(XP_WIN)
|
|
static bool IsOlsonCompatibleWindowsTimeZoneId(const char* tz) {
|
|
// ICU ignores the TZ environment variable on Windows and instead directly
|
|
@@ -726,6 +748,11 @@ void js::ResyncICUDefaultTimeZone() {
|
|
|
|
void js::DateTimeInfo::internalResyncICUDefaultTimeZone() {
|
|
#if JS_HAS_INTL_API && !MOZ_SYSTEM_ICU
|
|
+ if (timeZoneOverride_) {
|
|
+ icu::TimeZone::setDefault(*timeZoneOverride_);
|
|
+ return;
|
|
+ }
|
|
+
|
|
if (const char* tz = std::getenv("TZ")) {
|
|
icu::UnicodeString tzid;
|
|
|
|
diff --git a/js/src/vm/DateTime.h b/js/src/vm/DateTime.h
|
|
index 25c5b01fc54c8d45da8ceb7cf6ba163bee3c5361..490c5ce49cd9b5f804df59abbfb0450fb9d1f877 100644
|
|
--- a/js/src/vm/DateTime.h
|
|
+++ b/js/src/vm/DateTime.h
|
|
@@ -67,6 +67,8 @@ enum class ResetTimeZoneMode : bool {
|
|
*/
|
|
extern void ResetTimeZoneInternal(ResetTimeZoneMode mode);
|
|
|
|
+extern void SetTimeZoneOverrideInternal(mozilla::UniquePtr<icu::TimeZone> timeZone);
|
|
+
|
|
/**
|
|
* ICU's default time zone, used for various date/time formatting operations
|
|
* that include the local time in the representation, is allowed to go stale
|
|
@@ -206,6 +208,7 @@ class DateTimeInfo {
|
|
// and js::ResyncICUDefaultTimeZone().
|
|
friend void js::ResetTimeZoneInternal(ResetTimeZoneMode);
|
|
friend void js::ResyncICUDefaultTimeZone();
|
|
+ friend void js::SetTimeZoneOverrideInternal(mozilla::UniquePtr<icu::TimeZone>);
|
|
|
|
static void resetTimeZone(ResetTimeZoneMode mode) {
|
|
auto guard = instance->lock();
|
|
@@ -302,6 +305,8 @@ class DateTimeInfo {
|
|
JS::UniqueChars locale_;
|
|
JS::UniqueTwoByteChars standardName_;
|
|
JS::UniqueTwoByteChars daylightSavingsName_;
|
|
+
|
|
+ mozilla::UniquePtr<icu::TimeZone> timeZoneOverride_;
|
|
#else
|
|
// Restrict the data-time range to the minimum required time_t range as
|
|
// specified in POSIX. Most operating systems support 64-bit time_t
|
|
@@ -317,6 +322,8 @@ class DateTimeInfo {
|
|
|
|
void internalResetTimeZone(ResetTimeZoneMode mode);
|
|
|
|
+ void internalSetTimeZoneOverride(mozilla::UniquePtr<icu::TimeZone> timeZone);
|
|
+
|
|
void updateTimeZone();
|
|
|
|
void internalResyncICUDefaultTimeZone();
|
|
diff --git a/parser/html/nsHtml5TreeOpExecutor.cpp b/parser/html/nsHtml5TreeOpExecutor.cpp
|
|
index d315012c8ae284fdb0df50efd672ec4cbd77f2ad..baddcde3fd380c886a53056917841cf281d12277 100644
|
|
--- a/parser/html/nsHtml5TreeOpExecutor.cpp
|
|
+++ b/parser/html/nsHtml5TreeOpExecutor.cpp
|
|
@@ -1091,9 +1091,12 @@ void nsHtml5TreeOpExecutor::AddSpeculationCSP(const nsAString& aCSP) {
|
|
if (!StaticPrefs::security_csp_enable()) {
|
|
return;
|
|
}
|
|
-
|
|
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
|
|
|
+ if (mDocShell && static_cast<nsDocShell*>(mDocShell.get())->IsBypassCSPEnabled()) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
nsresult rv = NS_OK;
|
|
nsCOMPtr<nsIContentSecurityPolicy> preloadCsp = mDocument->GetPreloadCsp();
|
|
if (!preloadCsp) {
|
|
diff --git a/security/manager/ssl/SSLServerCertVerification.cpp b/security/manager/ssl/SSLServerCertVerification.cpp
|
|
index 429b216be8b54b7c1a47d41df7d78953899a61ae..a5afb34a3df138d37df9be80e1fd40d2b7a0f98c 100644
|
|
--- a/security/manager/ssl/SSLServerCertVerification.cpp
|
|
+++ b/security/manager/ssl/SSLServerCertVerification.cpp
|
|
@@ -1185,8 +1185,8 @@ PRErrorCode AuthCertificateParseResults(
|
|
return SEC_ERROR_NO_MEMORY;
|
|
}
|
|
nsresult rv = overrideService->HasMatchingOverride(
|
|
- aHostName, aPort, nssCert, &overrideBits, &isTemporaryOverride,
|
|
- &haveOverride);
|
|
+ aHostName, aPort, aOriginAttributes.mUserContextId, nssCert,
|
|
+ &overrideBits, &isTemporaryOverride, &haveOverride);
|
|
if (NS_SUCCEEDED(rv) && haveOverride) {
|
|
// remove the errors that are already overriden
|
|
remainingDisplayErrors &= ~overrideBits;
|
|
diff --git a/security/manager/ssl/nsCertOverrideService.cpp b/security/manager/ssl/nsCertOverrideService.cpp
|
|
index d6b9e8f606b4d4871793d4c8ca85d7bfe0e86f37..fed251dec07057bd9a9398023e47bef5bd2ef6c4 100644
|
|
--- a/security/manager/ssl/nsCertOverrideService.cpp
|
|
+++ b/security/manager/ssl/nsCertOverrideService.cpp
|
|
@@ -413,13 +413,20 @@ nsCertOverrideService::RememberTemporaryValidityOverrideUsingFingerprint(
|
|
|
|
NS_IMETHODIMP
|
|
nsCertOverrideService::HasMatchingOverride(const nsACString& aHostName,
|
|
- int32_t aPort, nsIX509Cert* aCert,
|
|
+ int32_t aPort,
|
|
+ uint32_t aUserContextId,
|
|
+ nsIX509Cert* aCert,
|
|
uint32_t* aOverrideBits,
|
|
bool* aIsTemporary, bool* _retval) {
|
|
bool disableAllSecurityCheck = false;
|
|
{
|
|
MutexAutoLock lock(mMutex);
|
|
- disableAllSecurityCheck = mDisableAllSecurityCheck;
|
|
+ if (aUserContextId) {
|
|
+ disableAllSecurityCheck = mUserContextIdsWithDisabledSecurityChecks.has(
|
|
+ aUserContextId);
|
|
+ } else {
|
|
+ disableAllSecurityCheck = mDisableAllSecurityCheck;
|
|
+ }
|
|
}
|
|
if (disableAllSecurityCheck) {
|
|
nsCertOverride::OverrideBits all = nsCertOverride::OverrideBits::Untrusted |
|
|
@@ -632,12 +639,21 @@ static bool IsDebugger() {
|
|
|
|
NS_IMETHODIMP
|
|
nsCertOverrideService::
|
|
- SetDisableAllSecurityChecksAndLetAttackersInterceptMyData(bool aDisable) {
|
|
- if (!(PR_GetEnv("XPCSHELL_TEST_PROFILE_DIR") || IsDebugger())) {
|
|
+ SetDisableAllSecurityChecksAndLetAttackersInterceptMyData(
|
|
+ bool aDisable, uint32_t aUserContextId) {
|
|
+ if (false /* juggler hacks */ && !(PR_GetEnv("XPCSHELL_TEST_PROFILE_DIR") || IsDebugger())) {
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
}
|
|
|
|
MutexAutoLock lock(mMutex);
|
|
+ if (aUserContextId) {
|
|
+ if (aDisable) {
|
|
+ mozilla::Unused << mUserContextIdsWithDisabledSecurityChecks.put(aUserContextId);
|
|
+ } else {
|
|
+ mUserContextIdsWithDisabledSecurityChecks.remove(aUserContextId);
|
|
+ }
|
|
+ return NS_OK;
|
|
+ }
|
|
mDisableAllSecurityCheck = aDisable;
|
|
return NS_OK;
|
|
}
|
|
diff --git a/security/manager/ssl/nsCertOverrideService.h b/security/manager/ssl/nsCertOverrideService.h
|
|
index a9fd392c18e330c107a5b2cf9720a9b6f6abd3db..ac2e2739ab2fffddea417dd73fba76d3dc639490 100644
|
|
--- a/security/manager/ssl/nsCertOverrideService.h
|
|
+++ b/security/manager/ssl/nsCertOverrideService.h
|
|
@@ -120,6 +120,7 @@ class nsCertOverrideService final : public nsICertOverrideService,
|
|
~nsCertOverrideService();
|
|
|
|
bool mDisableAllSecurityCheck;
|
|
+ mozilla::HashSet<uint32_t> mUserContextIdsWithDisabledSecurityChecks;
|
|
mozilla::Mutex mMutex;
|
|
nsCOMPtr<nsIFile> mSettingsFile;
|
|
nsTHashtable<nsCertOverrideEntry> mSettingsTable;
|
|
diff --git a/security/manager/ssl/nsICertOverrideService.idl b/security/manager/ssl/nsICertOverrideService.idl
|
|
index 6f0f8259b309c0a299c9c80b2943a498b0f1b0e6..03d17899be96bc87dc78f06277e1bd9eb93d08f8 100644
|
|
--- a/security/manager/ssl/nsICertOverrideService.idl
|
|
+++ b/security/manager/ssl/nsICertOverrideService.idl
|
|
@@ -98,6 +98,7 @@ interface nsICertOverrideService : nsISupports {
|
|
[must_use]
|
|
boolean hasMatchingOverride(in AUTF8String aHostName,
|
|
in int32_t aPort,
|
|
+ in uint32_t aUserContextId,
|
|
in nsIX509Cert aCert,
|
|
out uint32_t aOverrideBits,
|
|
out boolean aIsTemporary);
|
|
@@ -137,5 +138,7 @@ interface nsICertOverrideService : nsISupports {
|
|
* @param aDisable If true, disable all security check and make
|
|
* hasMatchingOverride always return true.
|
|
*/
|
|
- void setDisableAllSecurityChecksAndLetAttackersInterceptMyData(in boolean aDisable);
|
|
+ void setDisableAllSecurityChecksAndLetAttackersInterceptMyData(
|
|
+ in boolean aDisable,
|
|
+ [optional] in uint32_t aUserContextId);
|
|
};
|
|
diff --git a/services/settings/Utils.jsm b/services/settings/Utils.jsm
|
|
index be2dafd39c1e9be513e910359841ffa6b3374ec7..665a7ccbbf5d5fb6ccb77da30c3e23ebf691b940 100644
|
|
--- a/services/settings/Utils.jsm
|
|
+++ b/services/settings/Utils.jsm
|
|
@@ -55,7 +55,7 @@ var Utils = {
|
|
Ci.nsIEnvironment
|
|
);
|
|
const isXpcshell = env.exists("XPCSHELL_TEST_PROFILE_DIR");
|
|
- return AppConstants.RELEASE_OR_BETA && !Cu.isInAutomation && !isXpcshell
|
|
+ return false && !Cu.isInAutomation && !isXpcshell
|
|
? "https://firefox.settings.services.mozilla.com/v1"
|
|
: gServerURL;
|
|
},
|
|
diff --git a/toolkit/components/startup/nsAppStartup.cpp b/toolkit/components/startup/nsAppStartup.cpp
|
|
index 73d33f54032c0ec785145214fe572d6655ca12b2..87daad40c1d811b75e3b8acab6837469e8443383 100644
|
|
--- a/toolkit/components/startup/nsAppStartup.cpp
|
|
+++ b/toolkit/components/startup/nsAppStartup.cpp
|
|
@@ -335,7 +335,7 @@ nsAppStartup::Quit(uint32_t aMode) {
|
|
nsCOMPtr<nsISimpleEnumerator> windowEnumerator;
|
|
nsCOMPtr<nsIWindowMediator> mediator(
|
|
do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
|
|
- if (mediator) {
|
|
+ if (ferocity != eForceQuit && mediator) {
|
|
mediator->GetEnumerator(nullptr, getter_AddRefs(windowEnumerator));
|
|
if (windowEnumerator) {
|
|
bool more;
|
|
diff --git a/toolkit/components/statusfilter/nsBrowserStatusFilter.cpp b/toolkit/components/statusfilter/nsBrowserStatusFilter.cpp
|
|
index ba7205c529c402512532c840225a535ce14fed5d..4597d7e950313dff1888aaf35cab49f04ae506bd 100644
|
|
--- a/toolkit/components/statusfilter/nsBrowserStatusFilter.cpp
|
|
+++ b/toolkit/components/statusfilter/nsBrowserStatusFilter.cpp
|
|
@@ -176,8 +176,16 @@ nsBrowserStatusFilter::OnStateChange(nsIWebProgress* aWebProgress,
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
-nsBrowserStatusFilter::OnProgressChange(nsIWebProgress* aWebProgress,
|
|
- nsIRequest* aRequest,
|
|
+nsBrowserStatusFilter::OnFrameLocationChange(nsIWebProgress *aWebProgress,
|
|
+ nsIRequest *aRequest,
|
|
+ nsIURI *aLocation,
|
|
+ uint32_t aFlags) {
|
|
+ return NS_OK;
|
|
+}
|
|
+
|
|
+NS_IMETHODIMP
|
|
+nsBrowserStatusFilter::OnProgressChange(nsIWebProgress *aWebProgress,
|
|
+ nsIRequest *aRequest,
|
|
int32_t aCurSelfProgress,
|
|
int32_t aMaxSelfProgress,
|
|
int32_t aCurTotalProgress,
|
|
diff --git a/toolkit/mozapps/update/UpdateService.jsm b/toolkit/mozapps/update/UpdateService.jsm
|
|
index c01d6aadef1ff34ac255d0ad5851b32f4c7a7f0b..452d5ccb8f0480d82f04793f200ea903b869cca7 100644
|
|
--- a/toolkit/mozapps/update/UpdateService.jsm
|
|
+++ b/toolkit/mozapps/update/UpdateService.jsm
|
|
@@ -3076,7 +3076,7 @@ UpdateService.prototype = {
|
|
).running;
|
|
}
|
|
|
|
- return (
|
|
+ return true || (
|
|
(Cu.isInAutomation || marionetteRunning) &&
|
|
Services.prefs.getBoolPref(PREF_APP_UPDATE_DISABLEDFORTESTING, false)
|
|
);
|
|
diff --git a/toolkit/toolkit.mozbuild b/toolkit/toolkit.mozbuild
|
|
index d092b8b223464ce9218272c81e75a77d38730dbb..bf80011e2cd59bd58b4f23788a56756d04b58a35 100644
|
|
--- a/toolkit/toolkit.mozbuild
|
|
+++ b/toolkit/toolkit.mozbuild
|
|
@@ -167,6 +167,7 @@ if CONFIG['ENABLE_MARIONETTE']:
|
|
DIRS += [
|
|
'/testing/firefox-ui',
|
|
'/testing/marionette',
|
|
+ '/juggler',
|
|
'/toolkit/components/telemetry/tests/marionette',
|
|
]
|
|
|
|
diff --git a/uriloader/base/nsDocLoader.cpp b/uriloader/base/nsDocLoader.cpp
|
|
index 06b2b7936d1833c482d894f3efa085173278a8da..f66866c8ff2918d7c8c5be9fc100d00b84f95db9 100644
|
|
--- a/uriloader/base/nsDocLoader.cpp
|
|
+++ b/uriloader/base/nsDocLoader.cpp
|
|
@@ -779,6 +779,13 @@ void nsDocLoader::DocLoaderIsEmpty(bool aFlushLayout) {
|
|
("DocLoader:%p: Firing load event for document.open\n",
|
|
this));
|
|
|
|
+ nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
|
|
+ if (os) {
|
|
+ nsIPrincipal* principal = doc->NodePrincipal();
|
|
+ if (!principal->IsSystemPrincipal())
|
|
+ os->NotifyObservers(ToSupports(doc), "juggler-document-open-loaded", nullptr);
|
|
+ }
|
|
+
|
|
// This is a very cut-down version of
|
|
// nsDocumentViewer::LoadComplete that doesn't do various things
|
|
// that are not relevant here because this wasn't an actual
|
|
@@ -1385,6 +1392,24 @@ void nsDocLoader::FireOnLocationChange(nsIWebProgress* aWebProgress,
|
|
}
|
|
}
|
|
|
|
+void nsDocLoader::FireOnFrameLocationChange(nsIWebProgress* aWebProgress,
|
|
+ nsIRequest* aRequest,
|
|
+ nsIURI *aUri,
|
|
+ uint32_t aFlags) {
|
|
+ NOTIFY_LISTENERS(nsIWebProgress::NOTIFY_FRAME_LOCATION,
|
|
+ nsCOMPtr<nsIWebProgressListener2> listener2 =
|
|
+ do_QueryReferent(info.mWeakListener);
|
|
+ if (!listener2)
|
|
+ continue;
|
|
+ listener2->OnFrameLocationChange(aWebProgress, aRequest, aUri, aFlags);
|
|
+ );
|
|
+
|
|
+ // Pass the notification up to the parent...
|
|
+ if (mParent) {
|
|
+ mParent->FireOnFrameLocationChange(aWebProgress, aRequest, aUri, aFlags);
|
|
+ }
|
|
+}
|
|
+
|
|
void nsDocLoader::FireOnStatusChange(nsIWebProgress* aWebProgress,
|
|
nsIRequest* aRequest, nsresult aStatus,
|
|
const char16_t* aMessage) {
|
|
diff --git a/uriloader/base/nsDocLoader.h b/uriloader/base/nsDocLoader.h
|
|
index 5b735c57cedcec62d185a256c945c72371822df6..079245720df84c9f7722ceae6502db58479454ae 100644
|
|
--- a/uriloader/base/nsDocLoader.h
|
|
+++ b/uriloader/base/nsDocLoader.h
|
|
@@ -209,6 +209,11 @@ class nsDocLoader : public nsIDocumentLoader,
|
|
nsIURI* aURI, int32_t aDelay,
|
|
bool aSameURI);
|
|
|
|
+ void FireOnFrameLocationChange(nsIWebProgress* aWebProgress,
|
|
+ nsIRequest* aRequest,
|
|
+ nsIURI *aUri,
|
|
+ uint32_t aFlags);
|
|
+
|
|
// this function is overridden by the docshell, it is provided so that we
|
|
// can pass more information about redirect state (the normal OnStateChange
|
|
// doesn't get the new channel).
|
|
diff --git a/uriloader/base/nsIWebProgress.idl b/uriloader/base/nsIWebProgress.idl
|
|
index b0cde5026dc7c414e8f20300ac2b7d735dbd846e..09ebb0ef6799cf6a74fe529d4d000c6bed2c9497 100644
|
|
--- a/uriloader/base/nsIWebProgress.idl
|
|
+++ b/uriloader/base/nsIWebProgress.idl
|
|
@@ -87,6 +87,10 @@ interface nsIWebProgress : nsISupports
|
|
* NOTIFY_REFRESH
|
|
* Receive onRefreshAttempted events.
|
|
* This is defined on nsIWebProgressListener2.
|
|
+ *
|
|
+ * NOTIFY_FRAME_LOCATION
|
|
+ * Receive onFrameLocationChange events.
|
|
+ * This is defined on nsIWebProgressListener2.
|
|
*/
|
|
const unsigned long NOTIFY_PROGRESS = 0x00000010;
|
|
const unsigned long NOTIFY_STATUS = 0x00000020;
|
|
@@ -94,11 +98,12 @@ interface nsIWebProgress : nsISupports
|
|
const unsigned long NOTIFY_LOCATION = 0x00000080;
|
|
const unsigned long NOTIFY_REFRESH = 0x00000100;
|
|
const unsigned long NOTIFY_CONTENT_BLOCKING = 0x00000200;
|
|
+ const unsigned long NOTIFY_FRAME_LOCATION = 0x00000400;
|
|
|
|
/**
|
|
* This flag enables all notifications.
|
|
*/
|
|
- const unsigned long NOTIFY_ALL = 0x000003ff;
|
|
+ const unsigned long NOTIFY_ALL = 0x000007ff;
|
|
|
|
/**
|
|
* Registers a listener to receive web progress events.
|
|
diff --git a/uriloader/base/nsIWebProgressListener2.idl b/uriloader/base/nsIWebProgressListener2.idl
|
|
index 87701f8d2cfee8bd84acd28c62b3be4989c9474c..ae1aa85c019cb21d4f7e79c35e8afe72709468a1 100644
|
|
--- a/uriloader/base/nsIWebProgressListener2.idl
|
|
+++ b/uriloader/base/nsIWebProgressListener2.idl
|
|
@@ -66,4 +66,27 @@ interface nsIWebProgressListener2 : nsIWebProgressListener {
|
|
in nsIURI aRefreshURI,
|
|
in long aMillis,
|
|
in boolean aSameURI);
|
|
+
|
|
+ /**
|
|
+ * Called when the location of the window or its subframes changes. This is not
|
|
+ * when a load is requested, but rather once it is verified that the load is
|
|
+ * going to occur in the given window. For instance, a load that starts in a
|
|
+ * window might send progress and status messages for the new site, but it
|
|
+ * will not send the onLocationChange until we are sure that we are loading
|
|
+ * this new page here.
|
|
+ *
|
|
+ * @param aWebProgress
|
|
+ * The nsIWebProgress instance that fired the notification.
|
|
+ * @param aRequest
|
|
+ * The associated nsIRequest. This may be null in some cases.
|
|
+ * @param aLocation
|
|
+ * The URI of the location that is being loaded.
|
|
+ * @param aFlags
|
|
+ * This is a value which explains the situation or the reason why
|
|
+ * the location has changed.
|
|
+ */
|
|
+ void onFrameLocationChange(in nsIWebProgress aWebProgress,
|
|
+ in nsIRequest aRequest,
|
|
+ in nsIURI aLocation,
|
|
+ [optional] in unsigned long aFlags);
|
|
};
|
|
diff --git a/uriloader/exthandler/nsExternalHelperAppService.cpp b/uriloader/exthandler/nsExternalHelperAppService.cpp
|
|
index 0808085752eab5ad43bc54d2fac8771fc6d2a1d1..cea94060a58b6c58848d6c6beb54d1108eba168e 100644
|
|
--- a/uriloader/exthandler/nsExternalHelperAppService.cpp
|
|
+++ b/uriloader/exthandler/nsExternalHelperAppService.cpp
|
|
@@ -99,6 +99,7 @@
|
|
|
|
#include "mozilla/Components.h"
|
|
#include "mozilla/ClearOnShutdown.h"
|
|
+#include "mozilla/ErrorNames.h"
|
|
#include "mozilla/Preferences.h"
|
|
#include "mozilla/ipc/URIUtils.h"
|
|
|
|
@@ -840,6 +841,12 @@ NS_IMETHODIMP nsExternalHelperAppService::ApplyDecodingForExtension(
|
|
return NS_OK;
|
|
}
|
|
|
|
+NS_IMETHODIMP nsExternalHelperAppService::SetDownloadInterceptor(
|
|
+ nsIDownloadInterceptor* interceptor) {
|
|
+ mInterceptor = interceptor;
|
|
+ return NS_OK;
|
|
+}
|
|
+
|
|
nsresult nsExternalHelperAppService::GetFileTokenForPath(
|
|
const char16_t* aPlatformAppPath, nsIFile** aFile) {
|
|
nsDependentString platformAppPath(aPlatformAppPath);
|
|
@@ -1428,7 +1435,12 @@ nsresult nsExternalAppHandler::SetUpTempFile(nsIChannel* aChannel) {
|
|
// Strip off the ".part" from mTempLeafName
|
|
mTempLeafName.Truncate(mTempLeafName.Length() - ArrayLength(".part") + 1);
|
|
|
|
+ return CreateSaverForTempFile();
|
|
+}
|
|
+
|
|
+nsresult nsExternalAppHandler::CreateSaverForTempFile() {
|
|
MOZ_ASSERT(!mSaver, "Output file initialization called more than once!");
|
|
+ nsresult rv;
|
|
mSaver =
|
|
do_CreateInstance(NS_BACKGROUNDFILESAVERSTREAMLISTENER_CONTRACTID, &rv);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
@@ -1588,7 +1600,36 @@ NS_IMETHODIMP nsExternalAppHandler::OnStartRequest(nsIRequest* request) {
|
|
return NS_OK;
|
|
}
|
|
|
|
- rv = SetUpTempFile(aChannel);
|
|
+ bool isIntercepted = false;
|
|
+ nsCOMPtr<nsIDownloadInterceptor> interceptor = mExtProtSvc->mInterceptor;
|
|
+ if (interceptor) {
|
|
+ nsCOMPtr<nsIFile> fileToUse;
|
|
+ rv = interceptor->InterceptDownloadRequest(this, request, mBrowsingContext, getter_AddRefs(fileToUse), &isIntercepted);
|
|
+ if (!NS_SUCCEEDED(rv)) {
|
|
+ LOG((" failed to call nsIDowloadInterceptor.interceptDownloadRequest"));
|
|
+ return rv;
|
|
+ }
|
|
+ if (isIntercepted) {
|
|
+ LOG((" request interceped by nsIDowloadInterceptor"));
|
|
+ if (fileToUse) {
|
|
+ mTempFile = fileToUse;
|
|
+ rv = mTempFile->GetLeafName(mTempLeafName);
|
|
+ NS_ENSURE_SUCCESS(rv, rv);
|
|
+ } else {
|
|
+ Cancel(NS_BINDING_ABORTED);
|
|
+ return NS_OK;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // Temp file is the final destination when download is intercepted. In that
|
|
+ // case we only need to create saver (and not create transfer later). Not creating
|
|
+ // mTransfer also cuts off all downloads handling logic in the js compoenents and
|
|
+ // browser UI.
|
|
+ if (isIntercepted)
|
|
+ rv = CreateSaverForTempFile();
|
|
+ else
|
|
+ rv = SetUpTempFile(aChannel);
|
|
if (NS_FAILED(rv)) {
|
|
nsresult transferError = rv;
|
|
|
|
@@ -1636,6 +1677,11 @@ NS_IMETHODIMP nsExternalAppHandler::OnStartRequest(nsIRequest* request) {
|
|
mMimeInfo->GetAlwaysAskBeforeHandling(&alwaysAsk);
|
|
nsAutoCString MIMEType;
|
|
mMimeInfo->GetMIMEType(MIMEType);
|
|
+
|
|
+ if (isIntercepted) {
|
|
+ return NS_OK;
|
|
+ }
|
|
+
|
|
if (alwaysAsk) {
|
|
// But we *don't* ask if this mimeInfo didn't come from
|
|
// our user configuration datastore and the user has said
|
|
@@ -2043,6 +2089,15 @@ nsExternalAppHandler::OnSaveComplete(nsIBackgroundFileSaver* aSaver,
|
|
NotifyTransfer(aStatus);
|
|
}
|
|
|
|
+ if (!mCanceled) {
|
|
+ nsCOMPtr<nsIDownloadInterceptor> interceptor = mExtProtSvc->mInterceptor;
|
|
+ if (interceptor) {
|
|
+ nsCString noError;
|
|
+ nsresult rv = interceptor->OnDownloadComplete(this, noError);
|
|
+ MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed to call nsIDowloadInterceptor.OnDownloadComplete");
|
|
+ }
|
|
+ }
|
|
+
|
|
return NS_OK;
|
|
}
|
|
|
|
@@ -2422,6 +2477,14 @@ NS_IMETHODIMP nsExternalAppHandler::Cancel(nsresult aReason) {
|
|
}
|
|
}
|
|
|
|
+ nsCOMPtr<nsIDownloadInterceptor> interceptor = mExtProtSvc->mInterceptor;
|
|
+ if (interceptor) {
|
|
+ nsCString errorName;
|
|
+ GetErrorName(aReason, errorName);
|
|
+ nsresult rv = interceptor->OnDownloadComplete(this, errorName);
|
|
+ MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed notify nsIDowloadInterceptor about cancel");
|
|
+ }
|
|
+
|
|
// Break our reference cycle with the helper app dialog (set up in
|
|
// OnStartRequest)
|
|
mDialog = nullptr;
|
|
diff --git a/uriloader/exthandler/nsExternalHelperAppService.h b/uriloader/exthandler/nsExternalHelperAppService.h
|
|
index 566d14ee83adfedd3fe7a0f985356602f131241b..51eb63f74a171370a1b40a4c978c50d6ca2c288e 100644
|
|
--- a/uriloader/exthandler/nsExternalHelperAppService.h
|
|
+++ b/uriloader/exthandler/nsExternalHelperAppService.h
|
|
@@ -190,6 +190,8 @@ class nsExternalHelperAppService : public nsIExternalHelperAppService,
|
|
mozilla::dom::BrowsingContext* aContentContext, bool aForceSave,
|
|
nsIInterfaceRequestor* aWindowContext,
|
|
nsIStreamListener** aStreamListener);
|
|
+
|
|
+ nsCOMPtr<nsIDownloadInterceptor> mInterceptor;
|
|
};
|
|
|
|
/**
|
|
@@ -372,6 +374,9 @@ class nsExternalAppHandler final : public nsIStreamListener,
|
|
* Upon successful return, both mTempFile and mSaver will be valid.
|
|
*/
|
|
nsresult SetUpTempFile(nsIChannel* aChannel);
|
|
+
|
|
+ nsresult CreateSaverForTempFile();
|
|
+
|
|
/**
|
|
* When we download a helper app, we are going to retarget all load
|
|
* notifications into our own docloader and load group instead of
|
|
diff --git a/uriloader/exthandler/nsIExternalHelperAppService.idl b/uriloader/exthandler/nsIExternalHelperAppService.idl
|
|
index ea8b9b08f3e6f6e99b8a4fa3fa427beb8c5f5945..a7ec2bd3afe53d500f0cd8f800223ee291340c18 100644
|
|
--- a/uriloader/exthandler/nsIExternalHelperAppService.idl
|
|
+++ b/uriloader/exthandler/nsIExternalHelperAppService.idl
|
|
@@ -6,6 +6,8 @@
|
|
|
|
#include "nsICancelable.idl"
|
|
|
|
+webidl BrowsingContext;
|
|
+interface nsIHelperAppLauncher;
|
|
interface nsIURI;
|
|
interface nsIRequest;
|
|
interface nsIStreamListener;
|
|
@@ -20,6 +22,17 @@ webidl BrowsingContext;
|
|
class nsExternalAppHandler;
|
|
%}
|
|
|
|
+/**
|
|
+ * Interceptor interface used by Juggler.
|
|
+ */
|
|
+[scriptable, uuid(9a20e9b0-75d0-11ea-bc55-0242ac130003)]
|
|
+interface nsIDownloadInterceptor : nsISupports
|
|
+{
|
|
+ bool interceptDownloadRequest(in nsIHelperAppLauncher aHandler, in nsIRequest aRequest, in BrowsingContext aBrowsingContext, out nsIFile file);
|
|
+
|
|
+ void onDownloadComplete(in nsIHelperAppLauncher aHandler, in ACString aErrorName);
|
|
+};
|
|
+
|
|
/**
|
|
* The external helper app service is used for finding and launching
|
|
* platform specific external applications for a given mime content type.
|
|
@@ -48,7 +61,7 @@ interface nsIExternalHelperAppService : nsISupports
|
|
in nsIInterfaceRequestor aContentContext,
|
|
in boolean aForceSave,
|
|
[optional] in nsIInterfaceRequestor aWindowContext);
|
|
-
|
|
+
|
|
/**
|
|
* Binds an external helper application to a stream listener. The caller
|
|
* should pump data into the returned stream listener. When the OnStopRequest
|
|
@@ -81,6 +94,7 @@ interface nsIExternalHelperAppService : nsISupports
|
|
boolean applyDecodingForExtension(in AUTF8String aExtension,
|
|
in ACString aEncodingType);
|
|
|
|
+ void setDownloadInterceptor(in nsIDownloadInterceptor interceptor);
|
|
};
|
|
|
|
/**
|