Skip to content

Commit

Permalink
Auto merge of #8963 - Aesthetikx:unforgeable-istrusted, r=jdm
Browse files Browse the repository at this point in the history
Make Event's isTrusted attribute unforgeable

Three failure expectations were able to be removed from `tests/wpt/web-platform-tests/dom/interfaces.html`. This is my first commit to servo and my first time with rust, hopefully I didn't overlook anything.

Fixes #8956.

<!-- Reviewable:start -->
[<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/8963)
<!-- Reviewable:end -->
  • Loading branch information
bors-servo authored and jxs committed Dec 15, 2015
2 parents 201b5c9 + f244a70 commit 6da1680
Show file tree
Hide file tree
Showing 16 changed files with 164 additions and 39 deletions.
6 changes: 6 additions & 0 deletions components/script/dom/closeevent.rs
Expand Up @@ -4,6 +4,7 @@

use dom::bindings::codegen::Bindings::CloseEventBinding;
use dom::bindings::codegen::Bindings::CloseEventBinding::CloseEventMethods;
use dom::bindings::codegen::Bindings::EventBinding::EventMethods;
use dom::bindings::error::Fallible;
use dom::bindings::global::GlobalRef;
use dom::bindings::inheritance::Castable;
Expand Down Expand Up @@ -90,4 +91,9 @@ impl CloseEventMethods for CloseEvent {
fn Reason(&self) -> DOMString {
self.reason.clone()
}

// https://dom.spec.whatwg.org/#dom-event-istrusted
fn IsTrusted(&self) -> bool {
self.event.IsTrusted()
}
}
6 changes: 6 additions & 0 deletions components/script/dom/customevent.rs
Expand Up @@ -4,6 +4,7 @@

use dom::bindings::codegen::Bindings::CustomEventBinding;
use dom::bindings::codegen::Bindings::CustomEventBinding::CustomEventMethods;
use dom::bindings::codegen::Bindings::EventBinding::EventMethods;
use dom::bindings::error::Fallible;
use dom::bindings::global::GlobalRef;
use dom::bindings::inheritance::Castable;
Expand Down Expand Up @@ -89,4 +90,9 @@ impl CustomEventMethods for CustomEvent {
detail: HandleValue) {
self.init_custom_event(_cx, Atom::from(&*type_), can_bubble, cancelable, detail)
}

// https://dom.spec.whatwg.org/#dom-event-istrusted
fn IsTrusted(&self) -> bool {
self.event.IsTrusted()
}
}
5 changes: 5 additions & 0 deletions components/script/dom/errorevent.rs
Expand Up @@ -5,6 +5,7 @@
use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::ErrorEventBinding;
use dom::bindings::codegen::Bindings::ErrorEventBinding::ErrorEventMethods;
use dom::bindings::codegen::Bindings::EventBinding::EventMethods;
use dom::bindings::error::Fallible;
use dom::bindings::global::GlobalRef;
use dom::bindings::inheritance::Castable;
Expand Down Expand Up @@ -134,4 +135,8 @@ impl ErrorEventMethods for ErrorEvent {
self.error.get()
}

// https://dom.spec.whatwg.org/#dom-event-istrusted
fn IsTrusted(&self) -> bool {
self.event.IsTrusted()
}
}
78 changes: 48 additions & 30 deletions components/script/dom/eventtarget.rs
Expand Up @@ -5,6 +5,7 @@
use dom::bindings::callback::{CallbackContainer, ExceptionHandling, CallbackFunction};
use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::ErrorEventBinding::ErrorEventMethods;
use dom::bindings::codegen::Bindings::EventBinding::EventMethods;
use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
use dom::bindings::codegen::Bindings::EventHandlerBinding::OnErrorEventHandlerNonNull;
use dom::bindings::codegen::Bindings::EventListenerBinding::EventListener;
Expand Down Expand Up @@ -122,35 +123,52 @@ impl EventListenerType {
EventListenerType::Inline(ref handler) => {
match *handler {
CommonEventHandler::ErrorEventHandler(ref handler) => {
if let Some(event) = event.downcast::<ErrorEvent>() {
if let Some(error_event) = event.downcast::<ErrorEvent>() {
let global = global_root_from_reflector(object);
let cx = global.r().get_cx();
let error = RootedValue::new(cx, event.Error(cx));
let _ = handler.Call_(object,
EventOrString::eString(event.Message()),
Some(event.Filename()),
Some(event.Lineno()),
Some(event.Colno()),
Some(error.handle()),
exception_handle);
let error = RootedValue::new(cx, error_event.Error(cx));
let return_value = handler.Call_(object,
EventOrString::eString(error_event.Message()),
Some(error_event.Filename()),
Some(error_event.Lineno()),
Some(error_event.Colno()),
Some(error.handle()),
exception_handle);
if let Ok(return_value) = return_value {
let return_value = RootedValue::new(cx, return_value);
if return_value.handle().is_boolean() && return_value.handle().to_boolean() == true {
event.PreventDefault();
}
}
return;
}

let _ = handler.Call_(object, EventOrString::eEvent(Root::from_ref(event)),
None, None, None, None, exception_handle);
}

CommonEventHandler::EventHandler(ref handler) => {
let _ = handler.Call_(object, event, exception_handle);
if let Ok(value) = handler.Call_(object, event, exception_handle) {
let global = global_root_from_reflector(object);
let cx = global.r().get_cx();
let value = RootedValue::new(cx, value);
let value = value.handle();

//Step 4
let should_cancel = match event.type_() {
atom!("mouseover") => value.is_boolean() && value.to_boolean() == true,
atom!("beforeunload") => value.is_null(),
_ => value.is_boolean() && value.to_boolean() == false
};
if should_cancel {
event.PreventDefault();
}
}
}
}
},
}
}

// TODO(#8490): step 4 (cancel event based on return value)
}
}

#[derive(JSTraceable, Clone, PartialEq, HeapSizeOf)]
#[privatize]
pub struct EventListenerEntry {
Expand Down Expand Up @@ -179,16 +197,16 @@ impl EventTarget {
}

pub fn get_listeners_for(&self, type_: &Atom, desired_phase: ListenerPhase)
-> Option<Vec<EventListenerType>> {
-> Option<Vec<EventListenerType>> {
self.handlers.borrow().get(type_).map(|listeners| {
let filtered = listeners.iter().filter(|entry| entry.phase == desired_phase);
filtered.map(|entry| entry.listener.clone()).collect()
})
}

pub fn dispatch_event_with_target(&self,
target: &EventTarget,
event: &Event) -> bool {
target: &EventTarget,
event: &Event) -> bool {
dispatch_event(self, Some(target), event)
}

Expand All @@ -202,14 +220,14 @@ impl EventTarget {
let mut handlers = self.handlers.borrow_mut();
let entries = match handlers.entry(ty) {
Occupied(entry) => entry.into_mut(),
Vacant(entry) => entry.insert(vec!()),
};
Vacant(entry) => entry.insert(vec!()),
};

let idx = entries.iter().position(|ref entry| {
match entry.listener {
EventListenerType::Inline(_) => true,
_ => false,
}
let idx = entries.iter().position(|ref entry| {
match entry.listener {
EventListenerType::Inline(_) => true,
_ => false,
}
});

match idx {
Expand Down Expand Up @@ -246,11 +264,11 @@ impl EventTarget {
#[allow(unsafe_code)]
// https://html.spec.whatwg.org/multipage/#getting-the-current-value-of-the-event-handler
pub fn set_event_handler_uncompiled(&self,
cx: *mut JSContext,
url: Url,
scope: HandleObject,
ty: &str,
source: DOMString) {
cx: *mut JSContext,
url: Url,
scope: HandleObject,
ty: &str,
source: DOMString) {
let url = CString::new(url.serialize()).unwrap();
let name = CString::new(ty).unwrap();
let lineno = 0; //XXXjdm need to get a real number here
Expand Down
5 changes: 5 additions & 0 deletions components/script/dom/keyboardevent.rs
Expand Up @@ -841,4 +841,9 @@ impl KeyboardEventMethods for KeyboardEvent {
fn Which(&self) -> u32 {
self.char_code.get().unwrap_or(self.KeyCode())
}

// https://dom.spec.whatwg.org/#dom-event-istrusted
fn IsTrusted(&self) -> bool {
self.uievent.IsTrusted()
}
}
6 changes: 6 additions & 0 deletions components/script/dom/messageevent.rs
Expand Up @@ -2,6 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::codegen::Bindings::EventBinding::EventMethods;
use dom::bindings::codegen::Bindings::MessageEventBinding;
use dom::bindings::codegen::Bindings::MessageEventBinding::MessageEventMethods;
use dom::bindings::error::Fallible;
Expand Down Expand Up @@ -99,4 +100,9 @@ impl MessageEventMethods for MessageEvent {
fn LastEventId(&self) -> DOMString {
self.lastEventId.clone()
}

// https://dom.spec.whatwg.org/#dom-event-istrusted
fn IsTrusted(&self) -> bool {
self.event.IsTrusted()
}
}
5 changes: 5 additions & 0 deletions components/script/dom/mouseevent.rs
Expand Up @@ -206,4 +206,9 @@ impl MouseEventMethods for MouseEvent {
self.button.set(buttonArg);
self.related_target.set(relatedTargetArg);
}

// https://dom.spec.whatwg.org/#dom-event-istrusted
fn IsTrusted(&self) -> bool {
self.uievent.IsTrusted()
}
}
6 changes: 6 additions & 0 deletions components/script/dom/progressevent.rs
Expand Up @@ -2,6 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::codegen::Bindings::EventBinding::EventMethods;
use dom::bindings::codegen::Bindings::ProgressEventBinding;
use dom::bindings::codegen::Bindings::ProgressEventBinding::ProgressEventMethods;
use dom::bindings::error::Fallible;
Expand Down Expand Up @@ -70,4 +71,9 @@ impl ProgressEventMethods for ProgressEvent {
fn Total(&self) -> u64 {
self.total
}

// https://dom.spec.whatwg.org/#dom-event-istrusted
fn IsTrusted(&self) -> bool {
self.event.IsTrusted()
}
}
6 changes: 6 additions & 0 deletions components/script/dom/storageevent.rs
Expand Up @@ -2,6 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::codegen::Bindings::EventBinding::EventMethods;
use dom::bindings::codegen::Bindings::StorageEventBinding;
use dom::bindings::codegen::Bindings::StorageEventBinding::{StorageEventMethods};
use dom::bindings::error::Fallible;
Expand Down Expand Up @@ -108,4 +109,9 @@ impl StorageEventMethods for StorageEvent {
fn GetStorageArea(&self) -> Option<Root<Storage>> {
self.storageArea.get()
}

// https://dom.spec.whatwg.org/#dom-event-istrusted
fn IsTrusted(&self) -> bool {
self.event.IsTrusted()
}
}
5 changes: 5 additions & 0 deletions components/script/dom/touchevent.rs
Expand Up @@ -114,4 +114,9 @@ impl<'a> TouchEventMethods for &'a TouchEvent {
fn ChangedTouches(&self) -> Root<TouchList> {
self.changed_touches.get()
}

/// https://dom.spec.whatwg.org/#dom-event-istrusted
fn IsTrusted(&self) -> bool {
self.uievent.IsTrusted()
}
}
6 changes: 6 additions & 0 deletions components/script/dom/uievent.rs
Expand Up @@ -2,6 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::codegen::Bindings::EventBinding::EventMethods;
use dom::bindings::codegen::Bindings::UIEventBinding;
use dom::bindings::codegen::Bindings::UIEventBinding::UIEventMethods;
use dom::bindings::error::Fallible;
Expand Down Expand Up @@ -95,4 +96,9 @@ impl UIEventMethods for UIEvent {
self.view.set(view);
self.detail.set(detail);
}

// https://dom.spec.whatwg.org/#dom-event-istrusted
fn IsTrusted(&self) -> bool {
self.event.IsTrusted()
}
}
6 changes: 6 additions & 0 deletions components/script/dom/webglcontextevent.rs
Expand Up @@ -2,6 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::codegen::Bindings::EventBinding::EventMethods;
use dom::bindings::codegen::Bindings::WebGLContextEventBinding;
use dom::bindings::codegen::Bindings::WebGLContextEventBinding::WebGLContextEventInit;
use dom::bindings::codegen::Bindings::WebGLContextEventBinding::WebGLContextEventMethods;
Expand All @@ -25,6 +26,11 @@ impl WebGLContextEventMethods for WebGLContextEvent {
fn StatusMessage(&self) -> DOMString {
self.status_message.clone()
}

// https://dom.spec.whatwg.org/#dom-event-istrusted
fn IsTrusted(&self) -> bool {
self.event.IsTrusted()
}
}

impl WebGLContextEvent {
Expand Down
1 change: 1 addition & 0 deletions components/script/dom/webidls/Event.webidl
Expand Up @@ -34,6 +34,7 @@ interface Event {
[Pure]
readonly attribute boolean defaultPrevented;

[Unforgeable]
readonly attribute boolean isTrusted;
[Constant]
readonly attribute DOMTimeStamp timeStamp;
Expand Down
11 changes: 10 additions & 1 deletion tests/wpt/metadata/MANIFEST.json
Expand Up @@ -30149,7 +30149,16 @@
},
"local_changes": {
"deleted": [],
"items": {},
"items": {
"testharness": {
"html/webappapis/scripting/events/event-handler-processing-algorithm.html": [
{
"path": "html/webappapis/scripting/events/event-handler-processing-algorithm.html",
"url": "/html/webappapis/scripting/events/event-handler-processing-algorithm.html"
}
]
}
},
"reftest_nodes": {}
},
"reftest_nodes": {
Expand Down
8 changes: 0 additions & 8 deletions tests/wpt/metadata/dom/interfaces.html.ini
@@ -1,17 +1,9 @@
[interfaces.html]
type: testharness
[Event interface: document.createEvent("Event") must have own property "isTrusted"]
expected: FAIL

[Event interface: new Event("foo") must have own property "isTrusted"]
expected: FAIL

[CustomEvent interface: existence and properties of interface object]
expected: FAIL

[Event interface: new CustomEvent("foo") must have own property "isTrusted"]
expected: FAIL

[MutationObserver interface: existence and properties of interface object]
expected: FAIL

Expand Down
@@ -0,0 +1,43 @@
<!DOCTYPE html>
<title>Event handlers processing algorithm</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script
<body>
<div id="foo" style="width: 100px; height: 100px; background-color: black"></div>
<script>
test(function(){
document.getElementById("foo").onmouseover = function() { return true; };
document.getElementById("foo").addEventListener("mouseover", function(ev) { assert_equals(ev.defaultPrevented, true) }, false);
document.getElementById("foo").dispatchEvent(new Event('mouseover', {cancelable: true}));
}, "test Mouseover listener returning true cancels event");
test(function(){
document.getElementById("foo").onmouseover = function() { return true; };
document.getElementById("foo").addEventListener("mouseover", function(ev) { assert_equals(ev.defaultPrevented, false) }, false);
document.getElementById("foo").dispatchEvent(new Event('mouseover', {cancelable: true}));
}, "test Mouseover listener returning false doesn't cancel event");
test(function(){
window.onbeforeunload = function() {return null};
window.addEventListener("beforeunload", function(ev) { assert_equals(ev.defaultPrevented, true)});
window.dispatchEvent(new Event('beforeunload', {cancelable: true}));
}, "test beforeunload listener returning null cancels event");
test(function(){
window.onbeforeunload = function() {return true};
window.addEventListener("beforeunload", function(ev) { assert_equals(ev.defaultPrevented, false)});
window.dispatchEvent(new Event('beforeunload', {cancelable: true}));
}, "test beforeunload listener returning non null doesn't cancel event");
test(function(){
document.getElementById("foo").onclick = function() { return false; };
document.getElementById("foo").addEventListener("click", function(ev) { assert_equals(ev.defaultPrevented, true) }, false);
document.getElementById("foo").dispatchEvent(new Event("click", {cancelable: true}));
}, "click listener returning false cancels event");
test(function(){
document.getElementById("foo").onblur = function() { return false; };
document.getElementById("foo").addEventListener("blur", function(ev) { assert_equals(ev.defaultPrevented, true) }, false);
document.getElementById("foo").dispatchEvent(new Event("blur", {cancelable: true}));
}, "blur listener returning false cancels event");
test(function(){
document.getElementById("foo").ondblkclick = function() { return false; };
document.getElementById("foo").addEventListener("dblclick", function(ev) { assert_equals(ev.defaultPrevented, true) }, false);
document.getElementById("foo").dispatchEvent(new Event("dblclick", {cancelable: true}));
}, "dblclick listener returning false cancels event");
</script>

0 comments on commit 6da1680

Please sign in to comment.