Bug 918780 - Add new PopupControlState for permitting file/color picker popup regardless of dom_allowed_events. r=smaug

MozReview-Commit-ID: 1GbjQ6IkMsv

--HG--
extra : rebase_source : 4ea11b78007d9ab67a932536843b3e12175732b3
This commit is contained in:
Kestrel 2016-04-24 04:49:00 +01:00
parent c86980aa3c
commit 91cfa95229
7 changed files with 37 additions and 15 deletions

View File

@ -567,7 +567,7 @@ TimeoutManager::SetTimeout(nsITimeoutHandler* aHandler,
}
if (gRunningTimeoutDepth == 0 &&
mWindow.GetPopupControlState() < openAbused) {
mWindow.GetPopupControlState() < openBlocked) {
// This timeout is *not* set from another timeout and it's set
// while popups are enabled. Propagate the state to the timeout if
// its delay (interval) is equal to or less than what

View File

@ -7865,7 +7865,7 @@ nsGlobalWindow::FocusOuter(ErrorResult& aError)
// (bugs 355482 and 369306).
bool canFocus = CanSetProperty("dom.disable_window_flip") ||
(opener == callerOuter &&
RevisePopupAbuseLevel(gPopupControlState) < openAbused);
RevisePopupAbuseLevel(gPopupControlState) < openBlocked);
nsCOMPtr<mozIDOMWindowProxy> activeDOMWindow;
fm->GetActiveWindow(getter_AddRefs(activeDOMWindow));
@ -8860,18 +8860,25 @@ nsGlobalWindow::RevisePopupAbuseLevel(PopupControlState aControl)
PopupControlState abuse = aControl;
switch (abuse) {
case openControlled:
case openAbused:
case openBlocked:
case openOverridden:
if (PopupWhitelisted())
abuse = PopupControlState(abuse - 1);
break;
case openAbused:
if (PopupWhitelisted())
//Skip openBlocked
abuse = openControlled;
break;
case openAllowed: break;
default:
NS_WARNING("Strange PopupControlState!");
}
// limit the number of simultaneously open popups
if (abuse == openAbused || abuse == openControlled) {
if (abuse == openAbused ||
abuse == openBlocked ||
abuse == openControlled) {
int32_t popupMax = Preferences::GetInt("dom.popup_maximum", -1);
if (popupMax >= 0 && gOpenPopupSpamCount >= popupMax)
abuse = openOverridden;
@ -12993,7 +13000,7 @@ nsGlobalWindow::OpenInternal(const nsAString& aUrl, const nsAString& aName,
PopupControlState abuseLevel = gPopupControlState;
if (checkForPopup) {
abuseLevel = RevisePopupAbuseLevel(abuseLevel);
if (abuseLevel >= openAbused) {
if (abuseLevel >= openBlocked) {
if (!aCalledNoScript) {
// If script in some other window is doing a window.open on us and
// it's being blocked, then it's OK to close us afterwards, probably.
@ -13031,9 +13038,9 @@ nsGlobalWindow::OpenInternal(const nsAString& aUrl, const nsAString& aName,
nsCOMPtr<nsPIWindowWatcher> pwwatch(do_QueryInterface(wwatch));
NS_ENSURE_STATE(pwwatch);
MOZ_ASSERT_IF(checkForPopup, abuseLevel < openAbused);
MOZ_ASSERT_IF(checkForPopup, abuseLevel < openBlocked);
// At this point we should know for a fact that if checkForPopup then
// abuseLevel < openAbused, so we could just check for abuseLevel ==
// abuseLevel < openBlocked, so we could just check for abuseLevel ==
// openControlled. But let's be defensive just in case and treat anything
// that fails the above assert as a spam popup too, if it ever happens.
bool isPopupSpamWindow = checkForPopup && (abuseLevel >= openControlled);

View File

@ -65,6 +65,7 @@ enum class CallerType : uint32_t;
enum PopupControlState {
openAllowed = 0, // open that window without worries
openControlled, // it's a popup, but allow it
openBlocked, // it's a popup, but not from an allowed event
openAbused, // it's a popup. disallow it, but allow domain override.
openOverridden // disallow window open
};

View File

@ -713,6 +713,7 @@ Event::GetEventPopupControlState(WidgetEvent* aEvent, nsIDOMEvent* aDOMEvent)
// triggered while handling user input. See
// nsPresShell::HandleEventInternal() for details.
if (EventStateManager::IsHandlingUserInput()) {
abuse = openBlocked;
switch(aEvent->mMessage) {
case eFormSelect:
if (PopupAllowedForEvent("select")) {
@ -734,6 +735,7 @@ Event::GetEventPopupControlState(WidgetEvent* aEvent, nsIDOMEvent* aDOMEvent)
// while handling user input. See
// nsPresShell::HandleEventInternal() for details.
if (EventStateManager::IsHandlingUserInput()) {
abuse = openBlocked;
switch(aEvent->mMessage) {
case eEditorInput:
if (PopupAllowedForEvent("input")) {
@ -750,6 +752,7 @@ Event::GetEventPopupControlState(WidgetEvent* aEvent, nsIDOMEvent* aDOMEvent)
// while handling user input. See
// nsPresShell::HandleEventInternal() for details.
if (EventStateManager::IsHandlingUserInput()) {
abuse = openBlocked;
switch(aEvent->mMessage) {
case eFormChange:
if (PopupAllowedForEvent("change")) {
@ -766,6 +769,7 @@ Event::GetEventPopupControlState(WidgetEvent* aEvent, nsIDOMEvent* aDOMEvent)
break;
case eKeyboardEventClass:
if (aEvent->IsTrusted()) {
abuse = openBlocked;
uint32_t key = aEvent->AsKeyboardEvent()->mKeyCode;
switch(aEvent->mMessage) {
case eKeyPress:
@ -796,6 +800,7 @@ Event::GetEventPopupControlState(WidgetEvent* aEvent, nsIDOMEvent* aDOMEvent)
break;
case eTouchEventClass:
if (aEvent->IsTrusted()) {
abuse = openBlocked;
switch (aEvent->mMessage) {
case eTouchStart:
if (PopupAllowedForEvent("touchstart")) {
@ -815,6 +820,7 @@ Event::GetEventPopupControlState(WidgetEvent* aEvent, nsIDOMEvent* aDOMEvent)
case eMouseEventClass:
if (aEvent->IsTrusted() &&
aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton) {
abuse = openBlocked;
switch(aEvent->mMessage) {
case eMouseUp:
if (PopupAllowedForEvent("mouseup")) {
@ -869,6 +875,7 @@ Event::GetEventPopupControlState(WidgetEvent* aEvent, nsIDOMEvent* aDOMEvent)
// triggered while handling user input. See
// nsPresShell::HandleEventInternal() for details.
if (EventStateManager::IsHandlingUserInput()) {
abuse = openBlocked;
switch(aEvent->mMessage) {
case eFormSubmit:
if (PopupAllowedForEvent("submit")) {

View File

@ -818,8 +818,8 @@ HTMLInputElement::IsPopupBlocked() const
return true;
}
// Check if page is allowed to open the popup
if (win->GetPopupControlState() <= openControlled) {
// Check if page can open a popup without abuse regardless of allowed events
if (win->GetPopupControlState() <= openBlocked) {
return false;
}

View File

@ -60,6 +60,8 @@
<button id='button-up' onclick="document.getElementById('by-button').click();">foo</button>
<div id='div-click' onclick="document.getElementById('by-button').click();" tabindex='1'>foo</div>
<div id='div-click-on-demand' onclick="var i=document.createElement('input'); i.type='file'; i.click();" tabindex='1'>foo</div>
<div id='div-keydown' onkeydown="document.getElementById('by-button').click();" tabindex='1'>foo</div>
<a id='link-click' href="javascript:document.getElementById('by-button').click();" tabindex='1'>foo</a>
</div>
<pre id="test">
<script type="application/javascript">
@ -129,6 +131,8 @@ var testData = [["a", 1, MockFilePicker.filterImages, 1],
["button-up", 0, undefined, 0],
["div-click", 0, undefined, 0],
["div-click-on-demand", 0, undefined, 0],
["div-keydown", 0, undefined, 0],
["link-click", 0, undefined, 0],
];
var currentTest = 0;
@ -137,9 +141,8 @@ var filters;
var filterIndex;
var mixRefExtensionList;
// disable popups to make sure that the popup blocker does not interfere
// with manually opened file pickers.
SpecialPowers.pushPrefEnv({'set': [["dom.disable_open_during_load", false]]}, runTests);
// Make sure picker works with popup blocker enabled and no allowed events
SpecialPowers.pushPrefEnv({'set': [["dom.popup_allowed_events", ""]]}, runTests);
function launchNextTest() {
MockFilePicker.shown = false;
@ -192,8 +195,11 @@ function launchNextTest() {
testData[currentTest][0] == 'button-down' ||
testData[currentTest][0] == 'button-up' ||
testData[currentTest][0] == 'div-click' ||
testData[currentTest][0] == 'div-click-on-demand') {
testData[currentTest][0] == 'div-click-on-demand' ||
testData[currentTest][0] == 'link-click') {
synthesizeMouseAtCenter(document.getElementById(testData[currentTest][0]), {});
} else if (testData[currentTest][0] == 'div-keydown') {
synthesizeKey("a", {});
} else {
document.getElementById(testData[currentTest][0]).click();
}

View File

@ -1380,8 +1380,9 @@ pref("content.sink.pending_event_mode", 0);
// Disable popups from plugins by default
// 0 = openAllowed
// 1 = openControlled
// 2 = openAbused
pref("privacy.popups.disable_from_plugins", 2);
// 2 = openBlocked
// 3 = openAbused
pref("privacy.popups.disable_from_plugins", 3);
// send "do not track" HTTP header, disabled by default
pref("privacy.donottrackheader.enabled", false);