mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-19 08:15:31 +00:00
Merge mozilla-central to autoland. a=merge CLOSED TREE
This commit is contained in:
commit
a40be3ff67
@ -1396,12 +1396,13 @@ nsAccessibilityService::CreateAccessibleByFrameType(nsIFrame* aFrame,
|
||||
|
||||
if (table) {
|
||||
nsIContent* parentContent =
|
||||
aContent->GetParentOrHostNode()->AsContent();
|
||||
aContent->GetParentOrShadowHostNode()->AsContent();
|
||||
nsIFrame* parentFrame = nullptr;
|
||||
if (parentContent) {
|
||||
parentFrame = parentContent->GetPrimaryFrame();
|
||||
if (!parentFrame || !parentFrame->IsTableWrapperFrame()) {
|
||||
parentContent = parentContent->GetParentOrHostNode()->AsContent();
|
||||
parentContent =
|
||||
parentContent->GetParentOrShadowHostNode()->AsContent();
|
||||
if (parentContent) {
|
||||
parentFrame = parentContent->GetPrimaryFrame();
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ function test() {
|
||||
Services.prefs.clearUserPref(kpkpEnforcementPref);
|
||||
Services.prefs.clearUserPref(khpkpPinninEnablePref);
|
||||
let uri = Services.io.newURI("https://" + kPinningDomain);
|
||||
gSSService.removeState(Ci.nsISiteSecurityService.HEADER_HPKP, uri, 0);
|
||||
gSSService.resetState(Ci.nsISiteSecurityService.HEADER_HPKP, uri, 0);
|
||||
});
|
||||
whenNewTabLoaded(window, loadPinningPage);
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ add_task(async function test_star_redirect() {
|
||||
let sss = Cc["@mozilla.org/ssservice;1"].getService(
|
||||
Ci.nsISiteSecurityService
|
||||
);
|
||||
sss.removeState(
|
||||
sss.resetState(
|
||||
Ci.nsISiteSecurityService.HEADER_HSTS,
|
||||
NetUtil.newURI("http://example.com/"),
|
||||
0
|
||||
|
@ -83,7 +83,7 @@ buildscript {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'org.mozilla.apilint:apilint:0.2.2'
|
||||
classpath 'org.mozilla.apilint:apilint:0.2.1'
|
||||
classpath 'com.android.tools.build:gradle:3.1.4'
|
||||
classpath 'com.getkeepsafe.dexcount:dexcount-gradle-plugin:0.8.2'
|
||||
classpath 'org.apache.commons:commons-exec:1.3'
|
||||
|
@ -54,7 +54,7 @@ function startTest() {
|
||||
.getService(Ci.nsIIOService);
|
||||
for (let {url} of TEST_CASES) {
|
||||
let uri = gIOService.newURI(url);
|
||||
gSSService.removeState(Ci.nsISiteSecurityService.HEADER_HPKP, uri, 0);
|
||||
gSSService.resetState(Ci.nsISiteSecurityService.HEADER_HPKP, uri, 0);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -48,7 +48,7 @@ function startTest()
|
||||
.getService(Ci.nsIIOService);
|
||||
|
||||
let uri = gIOService.newURI(TEST_CASES[0].url);
|
||||
gSSService.removeState(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0);
|
||||
gSSService.resetState(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0);
|
||||
});
|
||||
|
||||
info("Test detection of HTTP Strict Transport Security.");
|
||||
|
@ -760,7 +760,7 @@ static nsINode* FindChromeAccessOnlySubtreeOwner(nsINode* aNode) {
|
||||
aNode = aNode->GetParentNode();
|
||||
}
|
||||
|
||||
return aNode ? aNode->GetParentOrHostNode() : nullptr;
|
||||
return aNode ? aNode->GetParentOrShadowHostNode() : nullptr;
|
||||
}
|
||||
|
||||
already_AddRefed<nsINode> FindChromeAccessOnlySubtreeOwner(
|
||||
@ -991,8 +991,8 @@ void nsIContent::GetEventTargetParent(EventChainPreVisitor& aVisitor) {
|
||||
// dispatching event to Window object in a content page and
|
||||
// propagating the event to a chrome Element.
|
||||
if (targetInKnownToBeHandledScope &&
|
||||
nsContentUtils::ContentIsShadowIncludingDescendantOf(
|
||||
this, targetInKnownToBeHandledScope->SubtreeRoot())) {
|
||||
IsShadowIncludingInclusiveDescendantOf(
|
||||
targetInKnownToBeHandledScope->SubtreeRoot())) {
|
||||
// Part of step 11.4.
|
||||
// "If target's root is a shadow-including inclusive ancestor of
|
||||
// parent, then"
|
||||
|
@ -2200,32 +2200,6 @@ bool nsContentUtils::ContentIsHostIncludingDescendantOf(
|
||||
return false;
|
||||
}
|
||||
|
||||
bool nsContentUtils::ContentIsShadowIncludingDescendantOf(
|
||||
const nsINode* aPossibleDescendant, const nsINode* aPossibleAncestor) {
|
||||
MOZ_ASSERT(aPossibleDescendant, "The possible descendant is null!");
|
||||
MOZ_ASSERT(aPossibleAncestor, "The possible ancestor is null!");
|
||||
|
||||
if (aPossibleAncestor == aPossibleDescendant->GetComposedDoc()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
do {
|
||||
if (aPossibleDescendant == aPossibleAncestor) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (aPossibleDescendant->NodeType() == nsINode::DOCUMENT_FRAGMENT_NODE) {
|
||||
ShadowRoot* shadowRoot =
|
||||
ShadowRoot::FromNode(const_cast<nsINode*>(aPossibleDescendant));
|
||||
aPossibleDescendant = shadowRoot ? shadowRoot->GetHost() : nullptr;
|
||||
} else {
|
||||
aPossibleDescendant = aPossibleDescendant->GetParentNode();
|
||||
}
|
||||
} while (aPossibleDescendant);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// static
|
||||
bool nsContentUtils::ContentIsCrossDocDescendantOf(nsINode* aPossibleDescendant,
|
||||
nsINode* aPossibleAncestor) {
|
||||
@ -2285,7 +2259,7 @@ nsINode* nsContentUtils::Retarget(nsINode* aTargetA, nsINode* aTargetB) {
|
||||
}
|
||||
|
||||
// or A's root is a shadow-including inclusive ancestor of B...
|
||||
if (nsContentUtils::ContentIsShadowIncludingDescendantOf(aTargetB, root)) {
|
||||
if (aTargetB->IsShadowIncludingInclusiveDescendantOf(root)) {
|
||||
// ...then return A.
|
||||
return aTargetA;
|
||||
}
|
||||
|
@ -345,13 +345,6 @@ class nsContentUtils {
|
||||
static bool ContentIsHostIncludingDescendantOf(
|
||||
const nsINode* aPossibleDescendant, const nsINode* aPossibleAncestor);
|
||||
|
||||
/**
|
||||
* Similar to above, but does special case only ShadowRoot,
|
||||
* not HTMLTemplateElement.
|
||||
*/
|
||||
static bool ContentIsShadowIncludingDescendantOf(
|
||||
const nsINode* aPossibleDescendant, const nsINode* aPossibleAncestor);
|
||||
|
||||
/**
|
||||
* Similar to nsINode::IsInclusiveDescendantOf except it crosses document
|
||||
* boundaries, this function uses ancestor/descendant relations in the
|
||||
|
@ -131,6 +131,26 @@ bool nsINode::IsInclusiveDescendantOf(const nsINode* aNode) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool nsINode::IsShadowIncludingInclusiveDescendantOf(
|
||||
const nsINode* aNode) const {
|
||||
MOZ_ASSERT(aNode, "The node is nullptr.");
|
||||
|
||||
if (this->GetComposedDoc() == aNode) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const nsINode* node = this;
|
||||
do {
|
||||
if (node == aNode) {
|
||||
return true;
|
||||
}
|
||||
|
||||
node = node->GetParentOrShadowHostNode();
|
||||
} while (node);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
nsINode::nsSlots::nsSlots() : mWeakReference(nullptr) {}
|
||||
|
||||
nsINode::nsSlots::~nsSlots() {
|
||||
@ -261,7 +281,7 @@ nsINode* nsINode::GetRootNode(const GetRootNodeOptions& aOptions) {
|
||||
return SubtreeRoot();
|
||||
}
|
||||
|
||||
nsINode* nsINode::GetParentOrHostNode() const {
|
||||
nsINode* nsINode::GetParentOrShadowHostNode() const {
|
||||
if (mParent) {
|
||||
return mParent;
|
||||
}
|
||||
|
@ -424,6 +424,13 @@ class nsINode : public mozilla::dom::EventTarget {
|
||||
*/
|
||||
bool IsInclusiveDescendantOf(const nsINode* aNode) const;
|
||||
|
||||
/**
|
||||
* https://dom.spec.whatwg.org/#concept-shadow-including-inclusive-descendant
|
||||
*
|
||||
* @param aNode must not be nullptr.
|
||||
*/
|
||||
bool IsShadowIncludingInclusiveDescendantOf(const nsINode* aNode) const;
|
||||
|
||||
/**
|
||||
* Return this node as a document fragment. Asserts IsDocumentFragment().
|
||||
*
|
||||
@ -884,11 +891,7 @@ class nsINode : public mozilla::dom::EventTarget {
|
||||
*/
|
||||
nsINode* GetParentNode() const { return mParent; }
|
||||
|
||||
/**
|
||||
* This is similar to above, but in case 'this' is ShadowRoot, we return its
|
||||
* host element.
|
||||
*/
|
||||
nsINode* GetParentOrHostNode() const;
|
||||
nsINode* GetParentOrShadowHostNode() const;
|
||||
|
||||
enum FlattenedParentType { eNotForStyle, eForStyle };
|
||||
|
||||
|
@ -114,6 +114,7 @@ BrowserParent* BrowserBridgeParent::Manager() {
|
||||
void BrowserBridgeParent::Destroy() {
|
||||
if (mBrowserParent) {
|
||||
mBrowserParent->Destroy();
|
||||
mBrowserParent->SetBrowserBridgeParent(nullptr);
|
||||
mBrowserParent = nullptr;
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,8 @@
|
||||
#include "mozilla/dom/CancelContentJSOptionsBinding.h"
|
||||
#include "mozilla/dom/WindowGlobalParent.h"
|
||||
|
||||
#include "nsIObserverService.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
@ -68,7 +70,14 @@ void BrowserHost::DestroyComplete() {
|
||||
}
|
||||
mRoot->SetOwnerElement(nullptr);
|
||||
mRoot->Destroy();
|
||||
mRoot->SetBrowserHost(nullptr);
|
||||
mRoot = nullptr;
|
||||
|
||||
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
|
||||
if (os) {
|
||||
os->NotifyObservers(NS_ISUPPORTS_CAST(nsIRemoteTab*, this),
|
||||
"ipc:browser-destroyed", nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
bool BrowserHost::Show(const ScreenIntSize& aSize, bool aParentIsActive) {
|
||||
|
@ -675,7 +675,6 @@ void BrowserParent::ActorDestroy(ActorDestroyReason why) {
|
||||
// Tell our embedder that the tab is now going away unless we're an
|
||||
// out-of-process iframe.
|
||||
RefPtr<nsFrameLoader> frameLoader = GetFrameLoader(true);
|
||||
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
|
||||
if (frameLoader) {
|
||||
ReceiveMessage(CHILD_PROCESS_SHUTDOWN_MESSAGE, false, nullptr, nullptr,
|
||||
nullptr);
|
||||
@ -694,10 +693,6 @@ void BrowserParent::ActorDestroy(ActorDestroyReason why) {
|
||||
}
|
||||
|
||||
mFrameLoader = nullptr;
|
||||
if (os && mBrowserHost) {
|
||||
os->NotifyObservers(NS_ISUPPORTS_CAST(nsIRemoteTab*, mBrowserHost),
|
||||
"ipc:browser-destroyed", nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult BrowserParent::RecvMoveFocus(
|
||||
@ -3712,20 +3707,18 @@ void BrowserParent::LiveResizeStarted() { SuppressDisplayport(true); }
|
||||
void BrowserParent::LiveResizeStopped() { SuppressDisplayport(false); }
|
||||
|
||||
void BrowserParent::SetBrowserBridgeParent(BrowserBridgeParent* aBrowser) {
|
||||
// We should not have either a browser bridge or browser host yet
|
||||
MOZ_ASSERT(!mBrowserBridgeParent);
|
||||
MOZ_ASSERT(!mBrowserHost);
|
||||
// We should not have owner content yet
|
||||
MOZ_ASSERT(!mFrameElement);
|
||||
// We should either be clearing out our reference to a browser bridge, or not
|
||||
// have either a browser bridge, browser host, or owner content yet.
|
||||
MOZ_ASSERT(!aBrowser ||
|
||||
(!mBrowserBridgeParent && !mBrowserHost && !mFrameElement));
|
||||
mBrowserBridgeParent = aBrowser;
|
||||
}
|
||||
|
||||
void BrowserParent::SetBrowserHost(BrowserHost* aBrowser) {
|
||||
// We should not have either a browser bridge or browser host yet
|
||||
MOZ_ASSERT(!mBrowserBridgeParent);
|
||||
MOZ_ASSERT(!mBrowserHost);
|
||||
// We should not have owner content yet
|
||||
MOZ_ASSERT(!mFrameElement);
|
||||
// We should either be clearing out our reference to a browser host, or not
|
||||
// have either a browser bridge, browser host, or owner content yet.
|
||||
MOZ_ASSERT(!aBrowser ||
|
||||
(!mBrowserBridgeParent && !mBrowserHost && !mFrameElement));
|
||||
mBrowserHost = aBrowser;
|
||||
}
|
||||
|
||||
|
@ -244,8 +244,8 @@ bool SVGUseElement::IsCyclicReferenceTo(const Element& aTarget) const {
|
||||
if (mOriginal && mOriginal->IsCyclicReferenceTo(aTarget)) {
|
||||
return true;
|
||||
}
|
||||
for (nsINode* parent = GetParentOrHostNode(); parent;
|
||||
parent = parent->GetParentOrHostNode()) {
|
||||
for (nsINode* parent = GetParentOrShadowHostNode(); parent;
|
||||
parent = parent->GetParentOrShadowHostNode()) {
|
||||
if (parent == &aTarget) {
|
||||
return true;
|
||||
}
|
||||
|
@ -10048,7 +10048,7 @@ nsresult HTMLEditRules::ConfirmSelectionInBody() {
|
||||
// XXXsmaug this code is insane.
|
||||
nsINode* temp = selectionStartPoint.GetContainer();
|
||||
while (temp && !temp->IsHTMLElement(nsGkAtoms::body)) {
|
||||
temp = temp->GetParentOrHostNode();
|
||||
temp = temp->GetParentOrShadowHostNode();
|
||||
}
|
||||
|
||||
// If we aren't in the <body> element, force the issue.
|
||||
@ -10074,7 +10074,7 @@ nsresult HTMLEditRules::ConfirmSelectionInBody() {
|
||||
// XXXsmaug this code is insane.
|
||||
temp = selectionEndPoint.GetContainer();
|
||||
while (temp && !temp->IsHTMLElement(nsGkAtoms::body)) {
|
||||
temp = temp->GetParentOrHostNode();
|
||||
temp = temp->GetParentOrShadowHostNode();
|
||||
}
|
||||
|
||||
// If we aren't in the <body> element, force the issue.
|
||||
|
@ -222,8 +222,7 @@ nsresult mozInlineSpellStatus::InitForNavigation(
|
||||
}
|
||||
// the anchor node might not be in the DOM anymore, check
|
||||
if (root && aOldAnchorNode &&
|
||||
!nsContentUtils::ContentIsShadowIncludingDescendantOf(aOldAnchorNode,
|
||||
root)) {
|
||||
!aOldAnchorNode->IsShadowIncludingInclusiveDescendantOf(root)) {
|
||||
*aContinue = false;
|
||||
return NS_OK;
|
||||
}
|
||||
@ -1271,10 +1270,8 @@ nsresult mozInlineSpellChecker::DoSpellCheck(
|
||||
// aWordUtil.GetRootNode()
|
||||
nsINode* rootNode = aWordUtil.GetRootNode();
|
||||
if (!beginNode->IsInComposedDoc() || !endNode->IsInComposedDoc() ||
|
||||
!nsContentUtils::ContentIsShadowIncludingDescendantOf(beginNode,
|
||||
rootNode) ||
|
||||
!nsContentUtils::ContentIsShadowIncludingDescendantOf(endNode,
|
||||
rootNode)) {
|
||||
!beginNode->IsShadowIncludingInclusiveDescendantOf(rootNode) ||
|
||||
!endNode->IsShadowIncludingInclusiveDescendantOf(rootNode)) {
|
||||
// Just bail out and don't try to spell-check this
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -4725,7 +4725,7 @@ UniquePtr<RangePaintInfo> PresShell::CreateRangePaintInfo(
|
||||
break;
|
||||
}
|
||||
|
||||
ancestor = ancestor->GetParentOrHostNode();
|
||||
ancestor = ancestor->GetParentOrShadowHostNode();
|
||||
}
|
||||
|
||||
// use the nearest ancestor frame that includes all continuations as the
|
||||
|
@ -1669,7 +1669,7 @@ int32_t nsLayoutUtils::DoCompareTreePosition(
|
||||
AutoTArray<nsINode*, 32> content1Ancestors;
|
||||
nsINode* c1;
|
||||
for (c1 = aContent1; c1 && c1 != aCommonAncestor;
|
||||
c1 = c1->GetParentOrHostNode()) {
|
||||
c1 = c1->GetParentOrShadowHostNode()) {
|
||||
content1Ancestors.AppendElement(c1);
|
||||
}
|
||||
if (!c1 && aCommonAncestor) {
|
||||
@ -1681,7 +1681,7 @@ int32_t nsLayoutUtils::DoCompareTreePosition(
|
||||
AutoTArray<nsINode*, 32> content2Ancestors;
|
||||
nsINode* c2;
|
||||
for (c2 = aContent2; c2 && c2 != aCommonAncestor;
|
||||
c2 = c2->GetParentOrHostNode()) {
|
||||
c2 = c2->GetParentOrShadowHostNode()) {
|
||||
content2Ancestors.AppendElement(c2);
|
||||
}
|
||||
if (!c2 && aCommonAncestor) {
|
||||
@ -1718,7 +1718,7 @@ int32_t nsLayoutUtils::DoCompareTreePosition(
|
||||
|
||||
// content1Ancestor != content2Ancestor, so they must be siblings with the
|
||||
// same parent
|
||||
nsINode* parent = content1Ancestor->GetParentOrHostNode();
|
||||
nsINode* parent = content1Ancestor->GetParentOrShadowHostNode();
|
||||
#ifdef DEBUG
|
||||
// TODO: remove the uglyness, see bug 598468.
|
||||
NS_ASSERTION(gPreventAssertInCompareTreePosition || parent,
|
||||
|
@ -56,6 +56,9 @@ import java.util.AbstractSequentialList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.json.JSONObject;
|
||||
import org.mozilla.gecko.util.BundleEventListener;
|
||||
import org.mozilla.gecko.util.EventCallback;
|
||||
import org.mozilla.gecko.util.GeckoBundle;
|
||||
import org.mozilla.geckoview.AllowOrDeny;
|
||||
import org.mozilla.geckoview.CompositorController;
|
||||
import org.mozilla.geckoview.ContentBlocking;
|
||||
@ -475,7 +478,6 @@ package org.mozilla.geckoview {
|
||||
method @UiThread default public void onFirstComposite(@NonNull GeckoSession);
|
||||
method @UiThread default public void onFocusRequest(@NonNull GeckoSession);
|
||||
method @UiThread default public void onFullScreen(@NonNull GeckoSession, boolean);
|
||||
method @UiThread default public void onKill(@NonNull GeckoSession);
|
||||
method @UiThread default public void onTitleChange(@NonNull GeckoSession, @Nullable String);
|
||||
method @UiThread default public void onWebAppManifest(@NonNull GeckoSession, @NonNull JSONObject);
|
||||
}
|
||||
@ -1106,7 +1108,7 @@ package org.mozilla.geckoview {
|
||||
method default public void onPortMessage(@NonNull Object, @NonNull WebExtension.Port);
|
||||
}
|
||||
|
||||
public class WebExtensionController {
|
||||
public class WebExtensionController implements BundleEventListener {
|
||||
ctor protected WebExtensionController(GeckoRuntime, WebExtensionEventDispatcher);
|
||||
method @UiThread @Nullable public WebExtensionController.TabDelegate getTabDelegate();
|
||||
method @UiThread public void setTabDelegate(@Nullable WebExtensionController.TabDelegate);
|
||||
|
@ -4,15 +4,12 @@
|
||||
|
||||
package org.mozilla.geckoview.test
|
||||
|
||||
import android.app.ActivityManager
|
||||
import android.content.Context
|
||||
import android.graphics.Matrix
|
||||
import android.graphics.SurfaceTexture
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.LocaleList
|
||||
import android.os.Process
|
||||
import org.mozilla.geckoview.AllowOrDeny
|
||||
import org.mozilla.geckoview.GeckoResult
|
||||
import org.mozilla.geckoview.GeckoSession
|
||||
@ -22,7 +19,6 @@ import org.mozilla.geckoview.test.rule.GeckoSessionTestRule.IgnoreCrash
|
||||
import org.mozilla.geckoview.test.rule.GeckoSessionTestRule.WithDisplay
|
||||
import org.mozilla.geckoview.test.util.Callbacks
|
||||
|
||||
import android.support.annotation.AnyThread
|
||||
import android.support.test.filters.MediumTest
|
||||
import android.support.test.filters.SdkSuppress
|
||||
import android.support.test.runner.AndroidJUnit4
|
||||
@ -41,7 +37,6 @@ import org.json.JSONObject
|
||||
import org.junit.Assume.assumeThat
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mozilla.gecko.GeckoAppShell
|
||||
import org.mozilla.geckoview.test.rule.GeckoSessionTestRule
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@ -104,7 +99,7 @@ class ContentDelegateTest : BaseSessionTest() {
|
||||
assertThat("Session should be closed after a crash",
|
||||
session.isOpen, equalTo(false))
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
// Recover immediately
|
||||
mainSession.open()
|
||||
@ -175,62 +170,6 @@ class ContentDelegateTest : BaseSessionTest() {
|
||||
}
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
fun killContentProcess() {
|
||||
val context = GeckoAppShell.getApplicationContext()
|
||||
val manager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
|
||||
for (info in manager.runningAppProcesses) {
|
||||
if (info.processName.endsWith(":tab")) {
|
||||
Process.killProcess(info.pid)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@IgnoreCrash
|
||||
@Test fun killContent() {
|
||||
assumeThat(sessionRule.env.isMultiprocess, equalTo(true))
|
||||
assumeThat(sessionRule.env.isDebugBuild && sessionRule.env.isX86,
|
||||
equalTo(false))
|
||||
|
||||
killContentProcess()
|
||||
mainSession.waitUntilCalled(object : Callbacks.ContentDelegate {
|
||||
@AssertCalled(count = 1)
|
||||
override fun onKill(session: GeckoSession) {
|
||||
assertThat("Session should be closed after being killed",
|
||||
session.isOpen, equalTo(false))
|
||||
}
|
||||
})
|
||||
|
||||
mainSession.open()
|
||||
mainSession.loadTestPath(HELLO_HTML_PATH)
|
||||
mainSession.waitUntilCalled(object : Callbacks.ProgressDelegate {
|
||||
@AssertCalled(count = 1)
|
||||
override fun onPageStop(session: GeckoSession, success: Boolean) {
|
||||
assertThat("Page should load successfully", success, equalTo(true))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@IgnoreCrash
|
||||
@Test fun killContentMultipleSessions() {
|
||||
assumeThat(sessionRule.env.isMultiprocess, equalTo(true))
|
||||
assumeThat(sessionRule.env.isDebugBuild && sessionRule.env.isX86,
|
||||
equalTo(false))
|
||||
|
||||
val newSession = sessionRule.createOpenSession()
|
||||
killContentProcess()
|
||||
|
||||
val remainingSessions = mutableListOf(newSession, mainSession)
|
||||
while (remainingSessions.isNotEmpty()) {
|
||||
sessionRule.waitUntilCalled(object : Callbacks.ContentDelegate {
|
||||
@AssertCalled(count = 1)
|
||||
override fun onKill(session: GeckoSession) {
|
||||
remainingSessions.remove(session)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TextInputDelegateTest is parameterized, so we put this test under ContentDelegateTest.
|
||||
@SdkSuppress(minSdkVersion = 23)
|
||||
@Test fun autofill() {
|
||||
|
@ -103,7 +103,7 @@ public class GeckoSessionTestRule implements TestRule {
|
||||
sOnNewSession = GeckoSession.NavigationDelegate.class.getMethod(
|
||||
"onNewSession", GeckoSession.class, String.class);
|
||||
sOnCrash = GeckoSession.ContentDelegate.class.getMethod(
|
||||
"onKill", GeckoSession.class);
|
||||
"onCrash", GeckoSession.class);
|
||||
} catch (final NoSuchMethodException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
@ -81,8 +81,11 @@ public class RuntimeCreator {
|
||||
runtimeSettingsBuilder.arguments(new String[]{"-purgecaches"})
|
||||
.extras(InstrumentationRegistry.getArguments())
|
||||
.remoteDebuggingEnabled(true)
|
||||
.consoleOutput(true)
|
||||
.crashHandler(TestCrashHandler.class);
|
||||
.consoleOutput(true);
|
||||
|
||||
if (new Environment().isAutomation()) {
|
||||
runtimeSettingsBuilder.crashHandler(TestCrashHandler.class);
|
||||
}
|
||||
|
||||
TEST_SUPPORT_WEB_EXTENSION.setMessageDelegate(sMessageDelegate, "browser");
|
||||
|
||||
|
@ -194,7 +194,7 @@ public final class GeckoRuntime implements Parcelable {
|
||||
if ("Gecko:Exited".equals(event) && mDelegate != null) {
|
||||
mDelegate.onShutdown();
|
||||
EventDispatcher.getInstance().unregisterUiThreadListener(mEventListener, "Gecko:Exited");
|
||||
} else if ("GeckoView:ContentCrashReport".equals(event) && crashHandler != null) {
|
||||
} else if ("GeckoView:ContentCrash".equals(event) && crashHandler != null) {
|
||||
final Context context = GeckoAppShell.getApplicationContext();
|
||||
Intent i = new Intent(ACTION_CRASHED, null,
|
||||
context, crashHandler);
|
||||
@ -244,7 +244,7 @@ public final class GeckoRuntime implements Parcelable {
|
||||
throw new IllegalArgumentException("Crash handler service must run in a separate process");
|
||||
}
|
||||
|
||||
EventDispatcher.getInstance().registerUiThreadListener(mEventListener, "GeckoView:ContentCrashReport");
|
||||
EventDispatcher.getInstance().registerUiThreadListener(mEventListener, "GeckoView:ContentCrash");
|
||||
|
||||
flags |= GeckoThread.FLAG_ENABLE_NATIVE_CRASHREPORTER;
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
|
@ -440,7 +440,6 @@ public class GeckoSession implements Parcelable {
|
||||
"GeckoViewContent", this,
|
||||
new String[]{
|
||||
"GeckoView:ContentCrash",
|
||||
"GeckoView:ContentKill",
|
||||
"GeckoView:ContextMenu",
|
||||
"GeckoView:DOMTitleChanged",
|
||||
"GeckoView:DOMWindowClose",
|
||||
@ -456,12 +455,10 @@ public class GeckoSession implements Parcelable {
|
||||
final String event,
|
||||
final GeckoBundle message,
|
||||
final EventCallback callback) {
|
||||
|
||||
if ("GeckoView:ContentCrash".equals(event)) {
|
||||
close();
|
||||
delegate.onCrash(GeckoSession.this);
|
||||
} else if ("GeckoView:ContentKill".equals(event)) {
|
||||
close();
|
||||
delegate.onKill(GeckoSession.this);
|
||||
} else if ("GeckoView:ContextMenu".equals(event)) {
|
||||
final ContentDelegate.ContextElement elem =
|
||||
new ContentDelegate.ContextElement(
|
||||
@ -3126,24 +3123,11 @@ public class GeckoSession implements Parcelable {
|
||||
* is preserved. Most applications will want to call
|
||||
* {@link #loadUri(Uri)} or {@link #restoreState(SessionState)} at this point.
|
||||
*
|
||||
* @param session The GeckoSession for which the content process has crashed.
|
||||
* @param session The GeckoSession that crashed.
|
||||
*/
|
||||
@UiThread
|
||||
default void onCrash(@NonNull GeckoSession session) {}
|
||||
|
||||
/**
|
||||
* The content process hosting this GeckoSession has been killed. The
|
||||
* GeckoSession is now closed and unusable. You may call
|
||||
* {@link #open(GeckoRuntime)} to recover the session, but no state
|
||||
* is preserved. Most applications will want to call
|
||||
* {@link #loadUri(Uri)} or {@link #restoreState(SessionState)} at this point.
|
||||
*
|
||||
* @param session The GeckoSession for which the content process has been killed.
|
||||
*/
|
||||
@UiThread
|
||||
default void onKill(@NonNull GeckoSession session) {}
|
||||
|
||||
|
||||
/**
|
||||
* Notification that the first content composition has occurred.
|
||||
* This callback is invoked for the first content composite after either
|
||||
|
@ -8,7 +8,7 @@ import org.mozilla.gecko.util.BundleEventListener;
|
||||
import org.mozilla.gecko.util.EventCallback;
|
||||
import org.mozilla.gecko.util.GeckoBundle;
|
||||
|
||||
public class WebExtensionController {
|
||||
public class WebExtensionController implements BundleEventListener {
|
||||
public interface TabDelegate {
|
||||
/**
|
||||
* Called when tabs.create is invoked, this method returns a *newly-created* session
|
||||
@ -28,23 +28,10 @@ public class WebExtensionController {
|
||||
private GeckoRuntime mRuntime;
|
||||
private WebExtensionEventDispatcher mDispatcher;
|
||||
private TabDelegate mTabDelegate;
|
||||
private final EventListener mEventListener;
|
||||
|
||||
protected WebExtensionController(final GeckoRuntime runtime, final WebExtensionEventDispatcher dispatcher) {
|
||||
mRuntime = runtime;
|
||||
mDispatcher = dispatcher;
|
||||
mEventListener = new EventListener();
|
||||
}
|
||||
|
||||
private class EventListener implements BundleEventListener {
|
||||
@Override
|
||||
public void handleMessage(final String event, final GeckoBundle message,
|
||||
final EventCallback callback) {
|
||||
if ("GeckoView:WebExtension:NewTab".equals(event)) {
|
||||
newTab(message, callback);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@UiThread
|
||||
@ -52,14 +39,14 @@ public class WebExtensionController {
|
||||
if (delegate == null) {
|
||||
if (mTabDelegate != null) {
|
||||
EventDispatcher.getInstance().unregisterUiThreadListener(
|
||||
mEventListener,
|
||||
this,
|
||||
"GeckoView:WebExtension:NewTab"
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if (mTabDelegate == null) {
|
||||
EventDispatcher.getInstance().registerUiThreadListener(
|
||||
mEventListener,
|
||||
this,
|
||||
"GeckoView:WebExtension:NewTab"
|
||||
);
|
||||
}
|
||||
@ -102,4 +89,13 @@ public class WebExtensionController {
|
||||
callback.sendSuccess(session.getId());
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(final String event, final GeckoBundle message,
|
||||
final EventCallback callback) {
|
||||
if ("GeckoView:WebExtension:NewTab".equals(event)) {
|
||||
newTab(message, callback);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -34,9 +34,6 @@ exclude: true
|
||||
[`browser.tabs.create`][69.6] calls by WebExtensions.
|
||||
|
||||
[69.6]: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs/create
|
||||
[69.7]: ../GeckoSession.ContentDelegate.html#onKill
|
||||
|
||||
- Created `onKill` to `ContentDelegate` to differentiate from crashes.
|
||||
|
||||
## v68
|
||||
- Added [`GeckoRuntime#configurationChanged`][68.1] to notify the device
|
||||
@ -350,4 +347,4 @@ exclude: true
|
||||
[65.24]: ../CrashReporter.html#sendCrashReport-android.content.Context-android.os.Bundle-java.lang.String-
|
||||
[65.25]: ../GeckoResult.html
|
||||
|
||||
[api-version]: a48d987bbc9301577c072823070ff5541e0fa211
|
||||
[api-version]: 3d726407275d906a54c1fc86eb92f2c3bfaaa3d0
|
||||
|
@ -65,7 +65,7 @@ var ContentCrashHandler = {
|
||||
const [minidumpPath, extrasPath] = getPendingMinidump(dumpID);
|
||||
|
||||
EventDispatcher.instance.sendRequest({
|
||||
type: "GeckoView:ContentCrashReport",
|
||||
type: "GeckoView:ContentCrash",
|
||||
minidumpPath,
|
||||
extrasPath,
|
||||
success: true,
|
||||
|
@ -60,7 +60,6 @@ class GeckoViewContent extends GeckoViewModule {
|
||||
);
|
||||
|
||||
Services.obs.addObserver(this, "oop-frameloader-crashed");
|
||||
Services.obs.addObserver(this, "ipc:content-shutdown");
|
||||
}
|
||||
|
||||
onDisable() {
|
||||
@ -90,7 +89,6 @@ class GeckoViewContent extends GeckoViewModule {
|
||||
);
|
||||
|
||||
Services.obs.removeObserver(this, "oop-frameloader-crashed");
|
||||
Services.obs.removeObserver(this, "ipc:content-shutdown");
|
||||
}
|
||||
|
||||
// Bundle event handler.
|
||||
@ -197,38 +195,17 @@ class GeckoViewContent extends GeckoViewModule {
|
||||
// nsIObserver event handler
|
||||
observe(aSubject, aTopic, aData) {
|
||||
debug`observe: ${aTopic}`;
|
||||
this._contentCrashed = false;
|
||||
const browser = aSubject.ownerElement;
|
||||
|
||||
switch (aTopic) {
|
||||
case "oop-frameloader-crashed": {
|
||||
const browser = aSubject.ownerElement;
|
||||
if (!browser || browser != this.browser) {
|
||||
return;
|
||||
}
|
||||
this.window.setTimeout(() => {
|
||||
if (this._contentCrashed) {
|
||||
this.eventDispatcher.sendRequest({
|
||||
type: "GeckoView:ContentCrash",
|
||||
});
|
||||
} else {
|
||||
this.eventDispatcher.sendRequest({
|
||||
type: "GeckoView:ContentKill",
|
||||
});
|
||||
}
|
||||
}, 250);
|
||||
break;
|
||||
}
|
||||
case "ipc:content-shutdown": {
|
||||
aSubject.QueryInterface(Ci.nsIPropertyBag2);
|
||||
if (aSubject.get("dumpID")) {
|
||||
if (
|
||||
browser &&
|
||||
aSubject.get("childID") != browser.frameLoader.childID
|
||||
) {
|
||||
return;
|
||||
}
|
||||
this._contentCrashed = true;
|
||||
}
|
||||
|
||||
this.eventDispatcher.sendRequest({
|
||||
type: "GeckoView:ContentCrash",
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -160,10 +160,13 @@ interface nsISiteSecurityService : nsISupports
|
||||
[optional] out uint32_t aFailureResult);
|
||||
|
||||
/**
|
||||
* Given a header type, removes state relating to that header of a host,
|
||||
* Given a header type, resets state relating to that header of a host,
|
||||
* including the includeSubdomains state that would affect subdomains.
|
||||
* This essentially removes the state for the domain tree rooted at this
|
||||
* host.
|
||||
* host. If any preloaded information is present for that host, that
|
||||
* information will then be used instead of any other previously existing
|
||||
* state.
|
||||
*
|
||||
* @param aType the type of security state in question
|
||||
* @param aURI the URI of the target host
|
||||
* @param aFlags options for this request as defined in nsISocketProvider:
|
||||
@ -175,10 +178,10 @@ interface nsISiteSecurityService : nsISupports
|
||||
* happens).
|
||||
*/
|
||||
[implicit_jscontext, optional_argc, must_use]
|
||||
void removeState(in uint32_t aType,
|
||||
in nsIURI aURI,
|
||||
in uint32_t aFlags,
|
||||
[optional] in jsval aOriginAttributes);
|
||||
void resetState(in uint32_t aType,
|
||||
in nsIURI aURI,
|
||||
in uint32_t aFlags,
|
||||
[optional] in jsval aOriginAttributes);
|
||||
|
||||
/**
|
||||
* Checks whether or not the URI's hostname has a given security state set.
|
||||
|
@ -557,11 +557,12 @@ nsresult nsSiteSecurityService::SetHSTSState(
|
||||
SecurityPropertySource aSource, const OriginAttributes& aOriginAttributes) {
|
||||
nsAutoCString hostname(aHost);
|
||||
bool isPreload = (aSource == SourcePreload);
|
||||
// If max-age is zero, that's an indication to immediately remove the
|
||||
// security state, so here's a shortcut.
|
||||
if (!maxage) {
|
||||
return RemoveStateInternal(aType, hostname, flags, isPreload,
|
||||
aOriginAttributes);
|
||||
// If max-age is zero, the host is no longer considered HSTS. If the host was
|
||||
// preloaded, we store an entry indicating that this host is not HSTS, causing
|
||||
// the preloaded information to be ignored.
|
||||
if (maxage == 0) {
|
||||
return MarkHostAsNotHSTS(aType, hostname, flags, isPreload,
|
||||
aOriginAttributes);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(
|
||||
@ -608,28 +609,17 @@ nsresult nsSiteSecurityService::SetHSTSState(
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsSiteSecurityService::RemoveStateInternal(
|
||||
uint32_t aType, nsIURI* aURI, uint32_t aFlags,
|
||||
const OriginAttributes& aOriginAttributes) {
|
||||
nsAutoCString hostname;
|
||||
GetHost(aURI, hostname);
|
||||
return RemoveStateInternal(aType, hostname, aFlags, false, aOriginAttributes);
|
||||
}
|
||||
|
||||
nsresult nsSiteSecurityService::RemoveStateInternal(
|
||||
// Helper function to mark a host as not HSTS. In the general case, we can just
|
||||
// remove the HSTS state. However, for preloaded entries, we have to store an
|
||||
// entry that indicates this host is not HSTS to prevent the implementation
|
||||
// using the preloaded information.
|
||||
nsresult nsSiteSecurityService::MarkHostAsNotHSTS(
|
||||
uint32_t aType, const nsAutoCString& aHost, uint32_t aFlags,
|
||||
bool aIsPreload, const OriginAttributes& aOriginAttributes) {
|
||||
// Child processes are not allowed direct access to this.
|
||||
if (!XRE_IsParentProcess()) {
|
||||
MOZ_CRASH(
|
||||
"Child process: no direct access to "
|
||||
"nsISiteSecurityService::RemoveStateInternal");
|
||||
// This only applies to HSTS.
|
||||
if (aType != nsISiteSecurityService::HEADER_HSTS) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
// Only HSTS is supported at the moment.
|
||||
NS_ENSURE_TRUE(aType == nsISiteSecurityService::HEADER_HSTS ||
|
||||
aType == nsISiteSecurityService::HEADER_HPKP,
|
||||
NS_ERROR_NOT_IMPLEMENTED);
|
||||
if (aIsPreload && aOriginAttributes != OriginAttributes()) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
@ -638,7 +628,6 @@ nsresult nsSiteSecurityService::RemoveStateInternal(
|
||||
mozilla::DataStorageType storageType = isPrivate
|
||||
? mozilla::DataStorage_Private
|
||||
: mozilla::DataStorage_Persistent;
|
||||
// If this host is in the preload list, we have to store a knockout entry.
|
||||
nsAutoCString storageKey;
|
||||
SetStorageKey(aHost, aType, aOriginAttributes, storageKey);
|
||||
|
||||
@ -675,10 +664,18 @@ nsresult nsSiteSecurityService::RemoveStateInternal(
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSiteSecurityService::RemoveState(uint32_t aType, nsIURI* aURI,
|
||||
uint32_t aFlags,
|
||||
JS::HandleValue aOriginAttributes,
|
||||
JSContext* aCx, uint8_t aArgc) {
|
||||
nsSiteSecurityService::ResetState(uint32_t aType, nsIURI* aURI, uint32_t aFlags,
|
||||
JS::HandleValue aOriginAttributes,
|
||||
JSContext* aCx, uint8_t aArgc) {
|
||||
if (!XRE_IsParentProcess()) {
|
||||
MOZ_CRASH(
|
||||
"Child process: no direct access to "
|
||||
"nsISiteSecurityService::ResetState");
|
||||
}
|
||||
if (!aURI) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
OriginAttributes originAttributes;
|
||||
if (aArgc > 0) {
|
||||
// OriginAttributes were passed in.
|
||||
@ -687,7 +684,39 @@ nsSiteSecurityService::RemoveState(uint32_t aType, nsIURI* aURI,
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
}
|
||||
return RemoveStateInternal(aType, aURI, aFlags, originAttributes);
|
||||
|
||||
return ResetStateInternal(aType, aURI, aFlags, originAttributes);
|
||||
}
|
||||
|
||||
// Helper function to reset stored state of the given type for the host
|
||||
// identified by the given URI. If there is preloaded information for the host,
|
||||
// that information will be used for future queries. C.f. MarkHostAsNotHSTS,
|
||||
// which will store a knockout entry for preloaded HSTS hosts that have sent a
|
||||
// header with max-age=0 (meaning preloaded information will then not be used
|
||||
// for that host).
|
||||
nsresult nsSiteSecurityService::ResetStateInternal(
|
||||
uint32_t aType, nsIURI* aURI, uint32_t aFlags,
|
||||
const OriginAttributes& aOriginAttributes) {
|
||||
if (!aURI) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
if (aType != nsISiteSecurityService::HEADER_HSTS &&
|
||||
aType != nsISiteSecurityService::HEADER_HPKP) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
nsAutoCString hostname;
|
||||
nsresult rv = GetHost(aURI, hostname);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
nsAutoCString storageKey;
|
||||
SetStorageKey(hostname, aType, aOriginAttributes, storageKey);
|
||||
bool isPrivate = aFlags & nsISocketProvider::NO_PERMANENT_STORAGE;
|
||||
mozilla::DataStorageType storageType = isPrivate
|
||||
? mozilla::DataStorage_Private
|
||||
: mozilla::DataStorage_Persistent;
|
||||
mSiteStateStorage->Remove(storageKey, storageType);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static bool HostIsIPAddress(const nsCString& hostname) {
|
||||
@ -1062,9 +1091,12 @@ nsresult nsSiteSecurityService::ProcessPKPHeader(
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// if maxAge == 0 we must delete all state, for now no hole-punching
|
||||
// If maxAge == 0, we remove dynamic HPKP state for this host. Due to
|
||||
// architectural constraints, if this host was preloaded, any future lookups
|
||||
// will use the preloaded state (i.e. we can't store a "this host is not HPKP"
|
||||
// entry like we can for HSTS).
|
||||
if (maxAge == 0) {
|
||||
return RemoveStateInternal(aType, aSourceURI, aFlags, aOriginAttributes);
|
||||
return ResetStateInternal(aType, aSourceURI, aFlags, aOriginAttributes);
|
||||
}
|
||||
|
||||
// clamp maxAge to the maximum set by pref
|
||||
|
@ -191,11 +191,11 @@ class nsSiteSecurityService : public nsISiteSecurityService,
|
||||
nsresult SetHPKPState(const char* aHost, SiteHPKPState& entry, uint32_t flags,
|
||||
bool aIsPreload,
|
||||
const OriginAttributes& aOriginAttributes);
|
||||
nsresult RemoveStateInternal(uint32_t aType, nsIURI* aURI, uint32_t aFlags,
|
||||
const OriginAttributes& aOriginAttributes);
|
||||
nsresult RemoveStateInternal(uint32_t aType, const nsAutoCString& aHost,
|
||||
uint32_t aFlags, bool aIsPreload,
|
||||
const OriginAttributes& aOriginAttributes);
|
||||
nsresult MarkHostAsNotHSTS(uint32_t aType, const nsAutoCString& aHost,
|
||||
uint32_t aFlags, bool aIsPreload,
|
||||
const OriginAttributes& aOriginAttributes);
|
||||
nsresult ResetStateInternal(uint32_t aType, nsIURI* aURI, uint32_t aFlags,
|
||||
const OriginAttributes& aOriginAttributes);
|
||||
bool HostHasHSTSEntry(const nsAutoCString& aHost,
|
||||
bool aRequireIncludeSubdomains, uint32_t aFlags,
|
||||
const OriginAttributes& aOriginAttributes,
|
||||
|
@ -93,7 +93,7 @@ function test() {
|
||||
aWin.close();
|
||||
});
|
||||
uri = Services.io.newURI("http://localhost");
|
||||
gSSService.removeState(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0);
|
||||
gSSService.resetState(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0);
|
||||
});
|
||||
|
||||
// test first when on private mode
|
||||
|
@ -69,7 +69,7 @@ function add_tests() {
|
||||
);
|
||||
|
||||
// Clear accumulated state.
|
||||
ssservice.removeState(Ci.nsISiteSecurityService.HEADER_HPKP, uri, 0);
|
||||
ssservice.resetState(Ci.nsISiteSecurityService.HEADER_HPKP, uri, 0);
|
||||
Services.prefs.clearUserPref(
|
||||
"security.cert_pinning.process_headers_from_non_builtin_roots"
|
||||
);
|
||||
|
@ -55,7 +55,7 @@ function checkPassValidPin(pinValue, settingPin, expectedMaxAge) {
|
||||
// setup preconditions for the test, if setting ensure there is no previous
|
||||
// state, if removing ensure there is a valid pin in place.
|
||||
if (settingPin) {
|
||||
gSSService.removeState(Ci.nsISiteSecurityService.HEADER_HPKP, uri, 0);
|
||||
gSSService.resetState(Ci.nsISiteSecurityService.HEADER_HPKP, uri, 0);
|
||||
} else {
|
||||
// add a known valid pin!
|
||||
let validPinValue = "max-age=5000;" + VALID_PIN1 + BACKUP_PIN1;
|
||||
|
@ -83,7 +83,7 @@ function doTest(originAttributes1, originAttributes2, shouldShare) {
|
||||
|
||||
if (!shouldShare) {
|
||||
// Remove originAttributes2 from the storage.
|
||||
sss.removeState(type, uri, 0, originAttributes2);
|
||||
sss.resetState(type, uri, 0, originAttributes2);
|
||||
ok(
|
||||
sss.isSecureURI(type, uri, 0, originAttributes1),
|
||||
"URI should still be secure given original origin attributes"
|
||||
@ -91,7 +91,7 @@ function doTest(originAttributes1, originAttributes2, shouldShare) {
|
||||
}
|
||||
|
||||
// Remove originAttributes1 from the storage.
|
||||
sss.removeState(type, uri, 0, originAttributes1);
|
||||
sss.resetState(type, uri, 0, originAttributes1);
|
||||
ok(
|
||||
!sss.isSecureURI(type, uri, 0, originAttributes1),
|
||||
"URI should be not be secure after removeState"
|
||||
@ -161,7 +161,7 @@ function testInvalidOriginAttributes(originAttributes) {
|
||||
originAttributes
|
||||
),
|
||||
() => sss.isSecureURI(type, uri, 0, originAttributes),
|
||||
() => sss.removeState(type, uri, 0, originAttributes),
|
||||
() => sss.resetState(type, uri, 0, originAttributes),
|
||||
];
|
||||
|
||||
for (let callback of callbacks) {
|
||||
|
126
security/manager/ssl/tests/unit/test_sss_resetState.js
Normal file
126
security/manager/ssl/tests/unit/test_sss_resetState.js
Normal file
@ -0,0 +1,126 @@
|
||||
// -*- indent-tabs-mode: nil; js-indent-level: 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/.
|
||||
|
||||
"use strict";
|
||||
|
||||
// Tests that resetting HSTS/HPKP state in the way the "forget about this site"
|
||||
// functionality does works as expected for preloaded and non-preloaded sites.
|
||||
|
||||
do_get_profile();
|
||||
|
||||
var gCertDB = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
const ROOT_CERT = addCertFromFile(gCertDB, "bad_certs/test-ca.pem", "CTu,,");
|
||||
|
||||
var gSSService = Cc["@mozilla.org/ssservice;1"].getService(
|
||||
Ci.nsISiteSecurityService
|
||||
);
|
||||
|
||||
function run_test() {
|
||||
Services.prefs.setBoolPref(
|
||||
"security.cert_pinning.process_headers_from_non_builtin_roots",
|
||||
true
|
||||
);
|
||||
test_removeState(Ci.nsISiteSecurityService.HEADER_HSTS, 0);
|
||||
test_removeState(
|
||||
Ci.nsISiteSecurityService.HEADER_HSTS,
|
||||
Ci.nsISocketProvider.NO_PERMANENT_STORAGE
|
||||
);
|
||||
test_removeState(Ci.nsISiteSecurityService.HEADER_HPKP, 0);
|
||||
test_removeState(
|
||||
Ci.nsISiteSecurityService.HEADER_HPKP,
|
||||
Ci.nsISocketProvider.NO_PERMANENT_STORAGE
|
||||
);
|
||||
}
|
||||
|
||||
function test_removeState(type, flags) {
|
||||
info(`running test_removeState(type=${type}, flags=${flags})`);
|
||||
const NON_ISSUED_KEY_HASH = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
|
||||
const PINNING_ROOT_KEY_HASH = "VCIlmPM9NkgFQtrs4Oa5TeFcDu6MWRTKSNdePEhOgD8=";
|
||||
const PINNING_HEADERS = `pin-sha256="${NON_ISSUED_KEY_HASH}"; pin-sha256="${PINNING_ROOT_KEY_HASH}"`;
|
||||
let headerAddendum =
|
||||
type == Ci.nsISiteSecurityService.HEADER_HPKP ? PINNING_HEADERS : "";
|
||||
let secInfo = new FakeTransportSecurityInfo(
|
||||
constructCertFromFile("bad_certs/default-ee.pem")
|
||||
);
|
||||
// Simulate visiting a non-preloaded site by processing an HSTS or HPKP header
|
||||
// (depending on which type we were given), check that the HSTS/HPKP bit gets
|
||||
// set, simulate "forget about this site" (call removeState), and then check
|
||||
// that the HSTS/HPKP bit isn't set.
|
||||
let notPreloadedURI = Services.io.newURI("https://not-preloaded.example.com");
|
||||
ok(!gSSService.isSecureURI(type, notPreloadedURI, flags));
|
||||
gSSService.processHeader(
|
||||
type,
|
||||
notPreloadedURI,
|
||||
"max-age=1000;" + headerAddendum,
|
||||
secInfo,
|
||||
flags,
|
||||
Ci.nsISiteSecurityService.SOURCE_ORGANIC_REQUEST
|
||||
);
|
||||
ok(gSSService.isSecureURI(type, notPreloadedURI, flags));
|
||||
gSSService.resetState(type, notPreloadedURI, flags);
|
||||
ok(!gSSService.isSecureURI(type, notPreloadedURI, flags));
|
||||
|
||||
// Simulate visiting a non-preloaded site that unsets HSTS/HPKP by processing
|
||||
// an HSTS/HPKP header with "max-age=0", check that the HSTS/HPKP bit isn't
|
||||
// set, simulate "forget about this site" (call removeState), and then check
|
||||
// that the HSTS/HPKP bit isn't set.
|
||||
gSSService.processHeader(
|
||||
type,
|
||||
notPreloadedURI,
|
||||
"max-age=0;" + headerAddendum,
|
||||
secInfo,
|
||||
flags,
|
||||
Ci.nsISiteSecurityService.SOURCE_ORGANIC_REQUEST
|
||||
);
|
||||
ok(!gSSService.isSecureURI(type, notPreloadedURI, flags));
|
||||
gSSService.resetState(type, notPreloadedURI, flags);
|
||||
ok(!gSSService.isSecureURI(type, notPreloadedURI, flags));
|
||||
|
||||
// Simulate visiting a preloaded site by processing an HSTS/HPKP header, check
|
||||
// that the HSTS/HPKP bit is still set, simulate "forget about this site"
|
||||
// (call removeState), and then check that the HSTS/HPKP bit is still set.
|
||||
let preloadedHost =
|
||||
type == Ci.nsISiteSecurityService.HEADER_HPKP
|
||||
? "include-subdomains.pinning.example.com"
|
||||
: "includesubdomains.preloaded.test";
|
||||
let preloadedURI = Services.io.newURI(`https://${preloadedHost}`);
|
||||
ok(gSSService.isSecureURI(type, preloadedURI, flags));
|
||||
gSSService.processHeader(
|
||||
type,
|
||||
preloadedURI,
|
||||
"max-age=1000;" + headerAddendum,
|
||||
secInfo,
|
||||
flags,
|
||||
Ci.nsISiteSecurityService.SOURCE_ORGANIC_REQUEST
|
||||
);
|
||||
ok(gSSService.isSecureURI(type, preloadedURI, flags));
|
||||
gSSService.resetState(type, preloadedURI, flags);
|
||||
ok(gSSService.isSecureURI(type, preloadedURI, flags));
|
||||
|
||||
// Simulate visiting a preloaded site that unsets HSTS/HPKP by processing an
|
||||
// HSTS/HPKP header with "max-age=0", check that the HSTS/HPKP bit is what we
|
||||
// expect (see below), simulate "forget about this site" (call removeState),
|
||||
// and then check that the HSTS/HPKP bit is set.
|
||||
gSSService.processHeader(
|
||||
type,
|
||||
preloadedURI,
|
||||
"max-age=0;" + headerAddendum,
|
||||
secInfo,
|
||||
flags,
|
||||
Ci.nsISiteSecurityService.SOURCE_ORGANIC_REQUEST
|
||||
);
|
||||
// Due to architectural constraints, encountering a "max-age=0" header for a
|
||||
// preloaded HPKP site does not mark that site as not HPKP (whereas with HSTS,
|
||||
// it does).
|
||||
if (type == Ci.nsISiteSecurityService.HEADER_HPKP) {
|
||||
ok(gSSService.isSecureURI(type, preloadedURI, flags));
|
||||
} else {
|
||||
ok(!gSSService.isSecureURI(type, preloadedURI, flags));
|
||||
}
|
||||
gSSService.resetState(type, preloadedURI, flags);
|
||||
ok(gSSService.isSecureURI(type, preloadedURI, flags));
|
||||
}
|
@ -29,7 +29,7 @@ function run_test() {
|
||||
ok(SSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri1, 0));
|
||||
ok(SSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri2, 0));
|
||||
|
||||
SSService.removeState(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0);
|
||||
SSService.resetState(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0);
|
||||
ok(!SSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0));
|
||||
ok(!SSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri1, 0));
|
||||
ok(!SSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri2, 0));
|
||||
|
@ -199,6 +199,7 @@ skip-if = toolkit == 'android'
|
||||
[test_sss_readstate_empty.js]
|
||||
[test_sss_readstate_garbage.js]
|
||||
[test_sss_readstate_huge.js]
|
||||
[test_sss_resetState.js]
|
||||
[test_sss_savestate.js]
|
||||
[test_sss_sanitizeOnShutdown.js]
|
||||
firefox-appdir = browser
|
||||
|
@ -705,7 +705,7 @@ class SpecialPowersAPIParent extends JSWindowActorParent {
|
||||
let sss = Cc["@mozilla.org/ssservice;1"].getService(
|
||||
Ci.nsISiteSecurityService
|
||||
);
|
||||
sss.removeState(Ci.nsISiteSecurityService.HEADER_HSTS, uri, flags);
|
||||
sss.resetState(Ci.nsISiteSecurityService.HEADER_HSTS, uri, flags);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
@ -920,14 +920,14 @@ const SecuritySettingsCleaner = {
|
||||
Ci.nsISiteSecurityService.HEADER_HSTS,
|
||||
Ci.nsISiteSecurityService.HEADER_HPKP,
|
||||
]) {
|
||||
// Also remove HSTS/HPKP/OMS information for subdomains by enumerating
|
||||
// Also remove HSTS/HPKP information for subdomains by enumerating
|
||||
// the information in the site security service.
|
||||
for (let entry of sss.enumerate(type)) {
|
||||
let hostname = entry.hostname;
|
||||
if (Services.eTLD.hasRootDomain(hostname, aHost)) {
|
||||
// This uri is used as a key to remove the state.
|
||||
// This uri is used as a key to reset the state.
|
||||
let uri = Services.io.newURI("https://" + hostname);
|
||||
sss.removeState(type, uri, 0, entry.originAttributes);
|
||||
sss.resetState(type, uri, 0, entry.originAttributes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user