author | Tim Nguyen <ntim.bugs@gmail.com> |
Tue, 21 Jul 2015 08:42:00 +0200 | |
changeset 276430 | 1cdb9a03dac2ca2ed41ac2121253d9702c701ac2 |
parent 276429 | 6b31012ac6d26a19dc516efc08e733b21118179e |
child 276431 | 4747283cf161568291eba40c66b43a80989dfeff |
push id | 69162 |
push user | cbook@mozilla.com |
push date | Tue, 15 Dec 2015 13:52:23 +0000 |
treeherder | mozilla-inbound@98d65afd9826 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | bz |
bugs | 1137681 |
milestone | 45.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -23,16 +23,17 @@ #include "mozilla/dom/workers/ServiceWorkerManager.h" #include "mozilla/EventStateManager.h" #include "mozilla/LoadInfo.h" #include "mozilla/Preferences.h" #include "mozilla/Services.h" #include "mozilla/StartupTimeline.h" #include "mozilla/Telemetry.h" #include "mozilla/unused.h" +#include "Navigator.h" #include "URIUtils.h" #include "nsIContent.h" #include "nsIContentInlines.h" #include "nsIDocument.h" #include "nsIDOMDocument.h" #include "nsIDOMElement.h" @@ -3123,16 +3124,48 @@ NS_IMETHODIMP nsDocShell::NameEquals(const char16_t* aName, bool* aResult) { NS_ENSURE_ARG_POINTER(aName); NS_ENSURE_ARG_POINTER(aResult); *aResult = mName.Equals(aName); return NS_OK; } +NS_IMETHODIMP +nsDocShell::GetCustomUserAgent(nsAString& aCustomUserAgent) +{ + aCustomUserAgent = mCustomUserAgent; + return NS_OK; +} + +NS_IMETHODIMP +nsDocShell::SetCustomUserAgent(const nsAString& aCustomUserAgent) +{ + mCustomUserAgent = aCustomUserAgent; + RefPtr<nsGlobalWindow> win = mScriptGlobal ? + mScriptGlobal->GetCurrentInnerWindowInternal() : nullptr; + if (win) { + ErrorResult ignored; + Navigator* navigator = win->GetNavigator(ignored); + ignored.SuppressException(); + if (navigator) { + navigator->ClearUserAgentCache(); + } + } + + uint32_t childCount = mChildList.Length(); + for (uint32_t i = 0; i < childCount; ++i) { + nsCOMPtr<nsIDocShell> childShell = do_QueryInterface(ChildAt(i)); + if (childShell) { + childShell->SetCustomUserAgent(aCustomUserAgent); + } + } + return NS_OK; +} + /* virtual */ int32_t nsDocShell::ItemType() { return mItemType; } NS_IMETHODIMP nsDocShell::GetItemType(int32_t* aItemType) @@ -3250,16 +3283,17 @@ nsDocShell::SetDocLoaderParent(nsDocLoad } // Curse ambiguous nsISupports inheritance! nsISupports* parent = GetAsSupports(aParent); // If parent is another docshell, we inherit all their flags for // allowing plugins, scripting etc. bool value; + nsString customUserAgent; nsCOMPtr<nsIDocShell> parentAsDocShell(do_QueryInterface(parent)); if (parentAsDocShell) { if (mAllowPlugins && NS_SUCCEEDED(parentAsDocShell->GetAllowPlugins(&value))) { SetAllowPlugins(value); } if (mAllowJavascript && NS_SUCCEEDED(parentAsDocShell->GetAllowJavascript(&value))) { SetAllowJavascript(value); } @@ -3279,16 +3313,20 @@ nsDocShell::SetDocLoaderParent(nsDocLoad SetAllowContentRetargeting(mAllowContentRetargeting && parentAsDocShell->GetAllowContentRetargetingOnChildren()); if (NS_SUCCEEDED(parentAsDocShell->GetIsActive(&value))) { SetIsActive(value); } if (parentAsDocShell->GetIsPrerendered()) { SetIsPrerendered(true); } + if (NS_SUCCEEDED(parentAsDocShell->GetCustomUserAgent(customUserAgent)) && + !customUserAgent.IsEmpty()) { + SetCustomUserAgent(customUserAgent); + } if (NS_FAILED(parentAsDocShell->GetAllowDNSPrefetch(&value))) { value = false; } SetAllowDNSPrefetch(mAllowDNSPrefetch && value); value = parentAsDocShell->GetAffectPrivateSessionLifetime(); SetAffectPrivateSessionLifetime(value); uint32_t flags; if (NS_SUCCEEDED(parentAsDocShell->GetDefaultLoadFlags(&flags))) {
--- a/docshell/base/nsDocShell.h +++ b/docshell/base/nsDocShell.h @@ -788,16 +788,17 @@ protected: FrameType GetInheritedFrameType(); bool HasUnloadedParent(); // Dimensions of the docshell nsIntRect mBounds; nsString mName; nsString mTitle; + nsString mCustomUserAgent; /** * Content-Type Hint of the most-recently initiated load. Used for * session history entries. */ nsCString mContentTypeHint; nsIntPoint mDefaultScrollbarPref; // persistent across doc loads
--- a/docshell/base/nsIDocShell.idl +++ b/docshell/base/nsIDocShell.idl @@ -38,17 +38,17 @@ interface nsIPrincipal; interface nsIWebBrowserPrint; interface nsIPrivacyTransitionObserver; interface nsIReflowObserver; interface nsIScrollObserver; interface nsITabParent; typedef unsigned long nsLoadFlags; -[scriptable, builtinclass, uuid(63adb599-6dc9-4746-972e-c22e9018020b)] +[scriptable, builtinclass, uuid(bc3524bd-023c-4fc8-ace1-472bc999fb12)] interface nsIDocShell : nsIDocShellTreeItem { /** * Loads a given URI. This will give priority to loading the requested URI * in the object implementing this interface. If it can't be loaded here * however, the URL dispatcher will go through its normal process of content * loading. * @@ -233,29 +233,34 @@ interface nsIDocShell : nsIDocShellTreeI /** * This attribute allows chrome to tie in to handle DOM events that may * be of interest to chrome. */ attribute nsIDOMEventTarget chromeEventHandler; /** + * This allows chrome to set a custom User agent on a specific docshell + */ + attribute DOMString customUserAgent; + + /** * Whether to allow plugin execution */ attribute boolean allowPlugins; /** * Whether to allow Javascript execution */ attribute boolean allowJavascript; /** * Attribute stating if refresh based redirects can be allowed */ - attribute boolean allowMetaRedirects; + attribute boolean allowMetaRedirects; /** * Attribute stating if it should allow subframes (framesets/iframes) or not */ attribute boolean allowSubframes; /** * Attribute stating whether or not images should be loaded.
--- a/docshell/test/browser/browser.ini +++ b/docshell/test/browser/browser.ini @@ -79,13 +79,14 @@ skip-if = e10s # Bug 1220927 - Test trie [browser_bug852909.js] [browser_bug92473.js] [browser_uriFixupIntegration.js] [browser_loadDisallowInherit.js] [browser_loadURI.js] [browser_multiple_pushState.js] [browser_onbeforeunload_navigation.js] [browser_search_notification.js] +[browser_ua_emulation.js] [browser_timelineMarkers-01.js] [browser_timelineMarkers-02.js] [browser_timelineMarkers-03.js] [browser_timelineMarkers-04.js] [browser_timelineMarkers-05.js]
new file mode 100644 --- /dev/null +++ b/docshell/test/browser/browser_ua_emulation.js @@ -0,0 +1,52 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Test that the docShell UA emulation works +add_task(function*() { + yield openUrl("data:text/html;charset=utf-8,<iframe id='test-iframe'></iframe>"); + + let docshell = content.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIWebNavigation) + .QueryInterface(Ci.nsIDocShell); + is(docshell.customUserAgent, "", "There should initially be no customUserAgent"); + + docshell.customUserAgent = "foo"; + is(content.navigator.userAgent, "foo", "The user agent should be changed to foo"); + + let frameWin = content.document.querySelector("#test-iframe").contentWindow; + is(frameWin.navigator.userAgent, "foo", "The UA should be passed on to frames."); + + let newFrame = content.document.createElement("iframe"); + content.document.body.appendChild(newFrame); + + let newFrameWin = newFrame.contentWindow; + is(newFrameWin.navigator.userAgent, "foo", "Newly created frames should use the new UA"); + + newFrameWin.location.reload(); + yield waitForEvent(newFrameWin, "load"); + + is(newFrameWin.navigator.userAgent, "foo", "New UA should persist across reloads"); + gBrowser.removeCurrentTab(); +}); + +function waitForEvent(target, event) { + return new Promise(function(resolve) { + target.addEventListener(event, resolve); + }); +} + +function openUrl(url) { + return new Promise(function(resolve, reject) { + window.focus(); + + let tab = window.gBrowser.selectedTab = window.gBrowser.addTab(url); + let linkedBrowser = tab.linkedBrowser; + + linkedBrowser.addEventListener("load", function onload() { + linkedBrowser.removeEventListener("load", onload, true); + resolve(tab); + }, true); + }); +}
--- a/dom/base/Navigator.cpp +++ b/dom/base/Navigator.cpp @@ -367,21 +367,32 @@ Navigator::Invalidate() //***************************************************************************** NS_IMETHODIMP Navigator::GetUserAgent(nsAString& aUserAgent) { nsCOMPtr<nsIURI> codebaseURI; nsCOMPtr<nsPIDOMWindow> window; - if (mWindow && mWindow->GetDocShell()) { + if (mWindow) { window = mWindow; - nsIDocument* doc = mWindow->GetExtantDoc(); - if (doc) { - doc->NodePrincipal()->GetURI(getter_AddRefs(codebaseURI)); + nsIDocShell* docshell = window->GetDocShell(); + nsString customUserAgent; + if (docshell) { + docshell->GetCustomUserAgent(customUserAgent); + + if (!customUserAgent.IsEmpty()) { + aUserAgent = customUserAgent; + return NS_OK; + } + + nsIDocument* doc = mWindow->GetExtantDoc(); + if (doc) { + doc->NodePrincipal()->GetURI(getter_AddRefs(codebaseURI)); + } } } return GetUserAgent(window, codebaseURI, nsContentUtils::IsCallerChrome(), aUserAgent); } NS_IMETHODIMP @@ -2736,16 +2747,22 @@ Navigator::AppName(nsAString& aAppName, aAppName = override; return; } } aAppName.AssignLiteral("Netscape"); } +void +Navigator::ClearUserAgentCache() +{ + NavigatorBinding::ClearCachedUserAgentValue(this); +} + nsresult Navigator::GetUserAgent(nsPIDOMWindow* aWindow, nsIURI* aURI, bool aIsCallerChrome, nsAString& aUserAgent) { MOZ_ASSERT(NS_IsMainThread()); if (!aIsCallerChrome) {
--- a/dom/base/Navigator.h +++ b/dom/base/Navigator.h @@ -177,16 +177,20 @@ public: static nsresult GetAppVersion(nsAString& aAppVersion, bool aUsePrefOverriddenValue); static nsresult GetUserAgent(nsPIDOMWindow* aWindow, nsIURI* aURI, bool aIsCallerChrome, nsAString& aUserAgent); + // Clears the user agent cache by calling: + // NavigatorBinding::ClearCachedUserAgentValue(this); + void ClearUserAgentCache(); + already_AddRefed<Promise> GetDataStores(const nsAString& aName, const nsAString& aOwner, ErrorResult& aRv); // Feature Detection API already_AddRefed<Promise> GetFeature(const nsAString& aName, ErrorResult& aRv);
--- a/dom/webidl/Navigator.webidl +++ b/dom/webidl/Navigator.webidl @@ -36,17 +36,17 @@ interface NavigatorID { [Constant, Cached] readonly attribute DOMString appCodeName; // constant "Mozilla" [Constant, Cached] readonly attribute DOMString appName; [Constant, Cached] readonly attribute DOMString appVersion; [Constant, Cached] readonly attribute DOMString platform; - [Constant, Cached, Throws=Workers] + [Pure, Cached, Throws=Workers] readonly attribute DOMString userAgent; [Constant, Cached] readonly attribute DOMString product; // constant "Gecko" // Everyone but WebKit/Blink supports this. See bug 679971. [Exposed=Window] boolean taintEnabled(); // constant false };