Diff
Modified: trunk/LayoutTests/ChangeLog (196689 => 196690)
--- trunk/LayoutTests/ChangeLog 2016-02-17 07:18:34 UTC (rev 196689)
+++ trunk/LayoutTests/ChangeLog 2016-02-17 08:38:27 UTC (rev 196690)
@@ -1,3 +1,21 @@
+2016-02-17 Chris Dumez <[email protected]>
+
+ Window should have its 'constructor' property on the prototype
+ https://bugs.webkit.org/show_bug.cgi?id=154037
+ <rdar://problem/24689078>
+
+ Reviewed by Gavin Barraclough.
+
+ * http/tests/security/cross-origin-window-property-access-expected.txt:
+ * http/tests/security/cross-origin-window-property-access.html:
+ Add checks to make sure it still is not possible to access
+ window.constructor cross-origin.
+
+ * js/getOwnPropertyDescriptor-window-attributes-expected.txt:
+ * js/getOwnPropertyDescriptor-window-attributes.html:
+ Update test now that window has it's "constructor" attribute
+ on the prototype.
+
2016-02-16 Carlos Garcia Campos <[email protected]>
Add a way to test ScrollAnimator
Modified: trunk/LayoutTests/http/tests/security/cross-origin-window-property-access-expected.txt (196689 => 196690)
--- trunk/LayoutTests/http/tests/security/cross-origin-window-property-access-expected.txt 2016-02-17 07:18:34 UTC (rev 196689)
+++ trunk/LayoutTests/http/tests/security/cross-origin-window-property-access-expected.txt 2016-02-17 08:38:27 UTC (rev 196690)
@@ -3,6 +3,8 @@
CONSOLE MESSAGE: line 1: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
CONSOLE MESSAGE: line 1: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
CONSOLE MESSAGE: line 1: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
+CONSOLE MESSAGE: line 15: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
+CONSOLE MESSAGE: line 15: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
Tests that using another window's property getter does not bypass cross-origin checks.
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
@@ -14,6 +16,10 @@
PASS Object.getOwnPropertyDescriptor(window, "scrollbars").get.call(crossOriginWindow) returned undefined.
PASS Object.getOwnPropertyDescriptor(window, "navigator").get.call(crossOriginWindow) returned undefined.
PASS Object.getOwnPropertyDescriptor(window, "screenX").get.call(crossOriginWindow) returned undefined.
+PASS Object.getOwnPropertyDescriptor(window.__proto__, "constructor").get.call(crossOriginWindow) threw exception TypeError: undefined is not an object (evaluating 'Object.getOwnPropertyDescriptor(window.__proto__, "constructor").get.call').
+PASS Object.getOwnPropertyDescriptor(window.__proto__, "constructor").get.call(crossOriginWindow.__proto__) threw exception TypeError: undefined is not an object (evaluating 'Object.getOwnPropertyDescriptor(window.__proto__, "constructor").get.call').
+PASS crossOriginWindow.constructor returned undefined.
+PASS Object.getOwnPropertyDescriptor(crossOriginWindow.__proto__, "constructor").value threw exception TypeError: undefined is not an object (evaluating 'Object.getOwnPropertyDescriptor(crossOriginWindow.__proto__, "constructor")').
PASS Object.getOwnPropertyDescriptor(window, "location").get.call(crossOriginWindow) === crossOriginWindow.location is true
PASS successfullyParsed is true
Modified: trunk/LayoutTests/http/tests/security/cross-origin-window-property-access.html (196689 => 196690)
--- trunk/LayoutTests/http/tests/security/cross-origin-window-property-access.html 2016-02-17 07:18:34 UTC (rev 196689)
+++ trunk/LayoutTests/http/tests/security/cross-origin-window-property-access.html 2016-02-17 08:38:27 UTC (rev 196690)
@@ -32,6 +32,10 @@
shouldThrowOrReturnUndefined('Object.getOwnPropertyDescriptor(window, "scrollbars").get.call(crossOriginWindow)');
shouldThrowOrReturnUndefined('Object.getOwnPropertyDescriptor(window, "navigator").get.call(crossOriginWindow)');
shouldThrowOrReturnUndefined('Object.getOwnPropertyDescriptor(window, "screenX").get.call(crossOriginWindow)');
+ shouldThrowOrReturnUndefined('Object.getOwnPropertyDescriptor(window.__proto__, "constructor").get.call(crossOriginWindow)');
+ shouldThrowOrReturnUndefined('Object.getOwnPropertyDescriptor(window.__proto__, "constructor").get.call(crossOriginWindow.__proto__)');
+ shouldThrowOrReturnUndefined('crossOriginWindow.constructor');
+ shouldThrowOrReturnUndefined('Object.getOwnPropertyDescriptor(crossOriginWindow.__proto__, "constructor").value');
shouldBeTrue('Object.getOwnPropertyDescriptor(window, "location").get.call(crossOriginWindow) === crossOriginWindow.location');
finishJSTest();
}
Modified: trunk/LayoutTests/imported/w3c/ChangeLog (196689 => 196690)
--- trunk/LayoutTests/imported/w3c/ChangeLog 2016-02-17 07:18:34 UTC (rev 196689)
+++ trunk/LayoutTests/imported/w3c/ChangeLog 2016-02-17 08:38:27 UTC (rev 196690)
@@ -1,3 +1,15 @@
+2016-02-17 Chris Dumez <[email protected]>
+
+ Window should have its 'constructor' property on the prototype
+ https://bugs.webkit.org/show_bug.cgi?id=154037
+ <rdar://problem/24689078>
+
+ Reviewed by Gavin Barraclough.
+
+ Rebaseline W3C test now that one more check is passing.
+
+ * web-platform-tests/html/dom/interfaces-expected.txt:
+
2016-02-16 Chris Dumez <[email protected]>
Navigator.geolocation should not be marked a [Replaceable] and should be on the prototype
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/html/dom/interfaces-expected.txt (196689 => 196690)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/html/dom/interfaces-expected.txt 2016-02-17 07:18:34 UTC (rev 196689)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/html/dom/interfaces-expected.txt 2016-02-17 08:38:27 UTC (rev 196690)
@@ -3811,7 +3811,7 @@
PASS Window interface object length
PASS Window interface object name
FAIL Window interface: existence and properties of interface prototype object assert_equals: Class name for prototype of Window.prototype is not "WindowProperties" expected "[object WindowProperties]" but got "[object EventTargetPrototype]"
-FAIL Window interface: existence and properties of interface prototype object's "constructor" property assert_own_property: Window.prototype does not have own property "constructor" expected property "constructor" missing
+PASS Window interface: existence and properties of interface prototype object's "constructor" property
PASS Window interface: attribute self
PASS Window interface: attribute name
FAIL Window interface: attribute history assert_equals: setter must be undefined for readonly attributes expected (undefined) undefined but got (function) function "function history() {
Modified: trunk/LayoutTests/js/getOwnPropertyDescriptor-window-attributes-expected.txt (196689 => 196690)
--- trunk/LayoutTests/js/getOwnPropertyDescriptor-window-attributes-expected.txt 2016-02-17 07:18:34 UTC (rev 196689)
+++ trunk/LayoutTests/js/getOwnPropertyDescriptor-window-attributes-expected.txt 2016-02-17 08:38:27 UTC (rev 196690)
@@ -54,7 +54,7 @@
PASS descriptor.configurable is true
PASS descriptor.value is window.Node
-* window.constructor
+* window.__proto__.constructor
PASS descriptor.enumerable is false
PASS descriptor.writable is true
PASS descriptor.configurable is true
Modified: trunk/LayoutTests/js/getOwnPropertyDescriptor-window-attributes.html (196689 => 196690)
--- trunk/LayoutTests/js/getOwnPropertyDescriptor-window-attributes.html 2016-02-17 07:18:34 UTC (rev 196689)
+++ trunk/LayoutTests/js/getOwnPropertyDescriptor-window-attributes.html 2016-02-17 08:38:27 UTC (rev 196690)
@@ -62,9 +62,8 @@
shouldBe("descriptor.value", "window.Node");
debug("");
-// FIXME: 'constructor' should be on the prototype.
-debug("* window.constructor");
-descriptor = Object.getOwnPropertyDescriptor(window, "constructor");
+debug("* window.__proto__.constructor");
+descriptor = Object.getOwnPropertyDescriptor(window.__proto__, "constructor");
shouldBeFalse("descriptor.enumerable");
shouldBeTrue("descriptor.writable");
shouldBeTrue("descriptor.configurable");
Modified: trunk/Source/WebCore/ChangeLog (196689 => 196690)
--- trunk/Source/WebCore/ChangeLog 2016-02-17 07:18:34 UTC (rev 196689)
+++ trunk/Source/WebCore/ChangeLog 2016-02-17 08:38:27 UTC (rev 196690)
@@ -1,3 +1,66 @@
+2016-02-17 Chris Dumez <[email protected]>
+
+ Window should have its 'constructor' property on the prototype
+ https://bugs.webkit.org/show_bug.cgi?id=154037
+ <rdar://problem/24689078>
+
+ Reviewed by Gavin Barraclough.
+
+ Window should have its 'constructor' property on the prototype as per
+ the Web IDL specification:
+ http://heycam.github.io/webidl/#interface-prototype-object
+
+ Firefox and Chrome already match the specification.
+
+ No new tests, covered by:
+ - fast/dom/Window/window-constructor-settable.html
+ - fast/dom/Window/window-constructor.html
+ - http/tests/security/cross-origin-window-property-access.html
+ - imported/w3c/web-platform-tests/html/dom/interfaces.html
+
+ * bindings/scripts/CodeGeneratorJS.pm:
+ (ConstructorShouldBeOnInstance): Deleted.
+ Drop this routine as all constructors are now on the prototype.
+
+ (InstancePropertyCount):
+ Do not account for constructor properties as these can only be
+ on the prototype now.
+
+ (PrototypePropertyCount):
+ Increment the property count by 1 if the interface has a constructor
+ property (e.g. [NoInterfaceObject] interfaces do not have one).
+
+ (GeneratePropertiesHashTable):
+ Stop calling ConstructorShouldBeOnInstance() as it no longer exists.
+ Always generated the "constructor" property if:
+ 1. We are generating the prototype hash table.
+ and
+ 2. The interface needs a constructor (i.e. not marked as
+ [NoInterfaceObject]).
+
+ (GenerateImplementation):
+ - Drop code handling the case where ConstructorShouldBeOnInstance()
+ returns true as constructors are not always on the prototype and
+ the ConstructorShouldBeOnInstance() routine has been dropped.
+ - Drop code handling [CustomProxyToJSObject]. Now that the constructor
+ is always on the prototype, we never need to cast thisValue to a
+ JSDOMWindow (by calling toJSDOMWindow). In the Window case, thisValue
+ is now casted to a JSDOMWindowPrototype*, similarly to other interfaces
+ so we don't need a special casting function anymore.
+ - Stop generating security checks. This only impacts Window as it is the
+ only interface marked as [CheckSecurity]. The cross-origin checking code
+ as it was would not work when "constructor" is on the prototype because
+ thisValue is a JSDOMWindowPrototype, not a JSDOMWindow and we have no
+ way of getting the wrapped window. Also, the security check is no longer
+ needed because:
+ 1. Accessing crossOriginWindow.constructor will not work now that
+ constructor is on the prototype because
+ JSDOMWindow::getOwnPropertySlot() already prevents access to the
+ prototype in the cross-origin case.
+ 2. "constructor" is a value property, not a getter/setter. Therefore,
+ it is no possible to use the getter/setter from a same origin window
+ instance and call it on a cross origin window.
+
2016-02-16 Carlos Garcia Campos <[email protected]>
Add a way to test ScrollAnimator
Modified: trunk/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm (196689 => 196690)
--- trunk/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm 2016-02-17 07:18:34 UTC (rev 196689)
+++ trunk/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm 2016-02-17 08:38:27 UTC (rev 196690)
@@ -681,16 +681,6 @@
return 0;
}
-sub ConstructorShouldBeOnInstance
-{
- my $interface = shift;
-
- # FIXME: constructor should always be on the prototype:
- # http://www.w3.org/TR/WebIDL/#interface-prototype-object
- return 1 if $interface->extendedAttributes->{"CheckSecurity"};
- return 0;
-}
-
sub AttributeShouldBeOnInstanceForCompatibility
{
my $interface = shift;
@@ -790,7 +780,6 @@
$count++ if AttributeShouldBeOnInstance($interface, $attribute);
}
$count += InstanceFunctionCount($interface);
- $count++ if ConstructorShouldBeOnInstance($interface);
return $count;
}
@@ -802,7 +791,7 @@
$count++ if !AttributeShouldBeOnInstance($interface, $attribute);
}
$count += PrototypeFunctionCount($interface);
- $count++ if !ConstructorShouldBeOnInstance($interface);
+ $count++ if NeedsConstructorProperty($interface);
return $count;
}
@@ -1388,18 +1377,15 @@
# - Add all properties in a hashtable definition
my $propertyCount = $isInstance ? InstancePropertyCount($interface) : PrototypePropertyCount($interface);
- if (ConstructorShouldBeOnInstance($interface) == $isInstance) {
+ if (!$isInstance && NeedsConstructorProperty($interface)) {
+ die if !$propertyCount;
+ push(@$hashKeys, "constructor");
+ my $getter = "js" . $interfaceName . "Constructor";
+ push(@$hashValue1, $getter);
- if (NeedsConstructorProperty($interface)) {
- die if !$propertyCount;
- push(@$hashKeys, "constructor");
- my $getter = "js" . $interfaceName . "Constructor";
- push(@$hashValue1, $getter);
-
- my $setter = "setJS" . $interfaceName . "Constructor";
- push(@$hashValue2, $setter);
- push(@$hashSpecials, "DontEnum");
- }
+ my $setter = "setJS" . $interfaceName . "Constructor";
+ push(@$hashValue2, $setter);
+ push(@$hashSpecials, "DontEnum");
}
return 0 if !$propertyCount;
@@ -2523,28 +2509,12 @@
if (NeedsConstructorProperty($interface)) {
my $constructorFunctionName = "js" . $interfaceName . "Constructor";
- if ($interface->extendedAttributes->{"CustomProxyToJSObject"}) {
- push(@implContent, "EncodedJSValue ${constructorFunctionName}(ExecState* state, EncodedJSValue thisValue, PropertyName)\n");
- push(@implContent, "{\n");
- push(@implContent, " ${className}* domObject = to${className}(JSValue::decode(thisValue));\n");
- } elsif (ConstructorShouldBeOnInstance($interface)) {
- push(@implContent, "EncodedJSValue ${constructorFunctionName}(ExecState* state, EncodedJSValue thisValue, PropertyName)\n");
- push(@implContent, "{\n");
- push(@implContent, " ${className}* domObject = " . GetCastingHelperForThisObject($interface) . "(JSValue::decode(thisValue));\n");
- } else {
- push(@implContent, "EncodedJSValue ${constructorFunctionName}(ExecState* state, EncodedJSValue thisValue, PropertyName)\n");
- push(@implContent, "{\n");
- push(@implContent, " ${className}Prototype* domObject = jsDynamicCast<${className}Prototype*>(JSValue::decode(thisValue));\n");
- }
+ push(@implContent, "EncodedJSValue ${constructorFunctionName}(ExecState* state, EncodedJSValue thisValue, PropertyName)\n");
+ push(@implContent, "{\n");
+ push(@implContent, " ${className}Prototype* domObject = jsDynamicCast<${className}Prototype*>(JSValue::decode(thisValue));\n");
push(@implContent, " if (!domObject)\n");
push(@implContent, " return throwVMTypeError(state);\n");
- if ($interface->extendedAttributes->{"CheckSecurity"}) {
- die if !ConstructorShouldBeOnInstance($interface);
- push(@implContent, " if (!BindingSecurity::shouldAllowAccessToDOMWindow(state, domObject->wrapped()))\n");
- push(@implContent, " return JSValue::encode(jsUndefined());\n");
- }
-
if (!$interface->extendedAttributes->{"NoInterfaceObject"}) {
push(@implContent, " return JSValue::encode(${className}::getConstructor(state->vm(), domObject->globalObject()));\n");
} else {
@@ -2561,25 +2531,11 @@
push(@implContent, "void ${constructorFunctionName}(ExecState* state, EncodedJSValue thisValue, EncodedJSValue encodedValue)\n");
push(@implContent, "{\n");
push(@implContent, " JSValue value = JSValue::decode(encodedValue);\n");
- if ($interface->extendedAttributes->{"CustomProxyToJSObject"}) {
- push(@implContent, " ${className}* domObject = to${className}(JSValue::decode(thisValue));\n");
- } elsif (ConstructorShouldBeOnInstance($interface)) {
- push(@implContent, " ${className}* domObject = " . GetCastingHelperForThisObject($interface) . "(JSValue::decode(thisValue));\n");
- } else {
- push(@implContent, " ${className}Prototype* domObject = jsDynamicCast<${className}Prototype*>(JSValue::decode(thisValue));\n");
- }
+ push(@implContent, " ${className}Prototype* domObject = jsDynamicCast<${className}Prototype*>(JSValue::decode(thisValue));\n");
push(@implContent, " if (UNLIKELY(!domObject)) {\n");
push(@implContent, " throwVMTypeError(state);\n");
push(@implContent, " return;\n");
push(@implContent, " }\n");
- if ($interface->extendedAttributes->{"CheckSecurity"}) {
- if ($interfaceName eq "DOMWindow") {
- push(@implContent, " if (!BindingSecurity::shouldAllowAccessToDOMWindow(state, domObject->wrapped()))\n");
- } else {
- push(@implContent, " if (!shouldAllowAccessToFrame(state, domObject->wrapped().frame()))\n");
- }
- push(@implContent, " return;\n");
- }
push(@implContent, " // Shadowing a built-in constructor\n");
Modified: trunk/Source/WebCore/bindings/scripts/test/JS/JSTestActiveDOMObject.cpp (196689 => 196690)
--- trunk/Source/WebCore/bindings/scripts/test/JS/JSTestActiveDOMObject.cpp 2016-02-17 07:18:34 UTC (rev 196689)
+++ trunk/Source/WebCore/bindings/scripts/test/JS/JSTestActiveDOMObject.cpp 2016-02-17 08:38:27 UTC (rev 196690)
@@ -73,21 +73,18 @@
/* Hash table */
-static const struct CompactHashIndex JSTestActiveDOMObjectTableIndex[4] = {
- { 1, -1 },
+static const struct CompactHashIndex JSTestActiveDOMObjectTableIndex[2] = {
{ 0, -1 },
{ -1, -1 },
- { -1, -1 },
};
static const HashTableValue JSTestActiveDOMObjectTableValues[] =
{
- { "constructor", DontEnum, NoIntrinsic, { (intptr_t)static_cast<PropertySlot::GetValueFunc>(jsTestActiveDOMObjectConstructor), (intptr_t) static_cast<PutPropertySlot::PutValueFunc>(setJSTestActiveDOMObjectConstructor) } },
{ "excitingAttr", ReadOnly | CustomAccessor, NoIntrinsic, { (intptr_t)static_cast<PropertySlot::GetValueFunc>(jsTestActiveDOMObjectExcitingAttr), (intptr_t) static_cast<PutPropertySlot::PutValueFunc>(0) } },
};
-static const HashTable JSTestActiveDOMObjectTable = { 2, 3, true, JSTestActiveDOMObjectTableValues, JSTestActiveDOMObjectTableIndex };
+static const HashTable JSTestActiveDOMObjectTable = { 1, 1, true, JSTestActiveDOMObjectTableValues, JSTestActiveDOMObjectTableIndex };
template<> JSValue JSTestActiveDOMObjectConstructor::prototypeForStructure(JSC::VM& vm, const JSDOMGlobalObject& globalObject)
{
UNUSED_PARAM(vm);
@@ -107,6 +104,7 @@
static const HashTableValue JSTestActiveDOMObjectPrototypeTableValues[] =
{
+ { "constructor", DontEnum, NoIntrinsic, { (intptr_t)static_cast<PropertySlot::GetValueFunc>(jsTestActiveDOMObjectConstructor), (intptr_t) static_cast<PutPropertySlot::PutValueFunc>(setJSTestActiveDOMObjectConstructor) } },
{ "excitingFunction", JSC::Function, NoIntrinsic, { (intptr_t)static_cast<NativeFunction>(jsTestActiveDOMObjectPrototypeFunctionExcitingFunction), (intptr_t) (1) } },
{ "postMessage", JSC::Function, NoIntrinsic, { (intptr_t)static_cast<NativeFunction>(jsTestActiveDOMObjectPrototypeFunctionPostMessage), (intptr_t) (1) } },
};
@@ -170,24 +168,20 @@
EncodedJSValue jsTestActiveDOMObjectConstructor(ExecState* state, EncodedJSValue thisValue, PropertyName)
{
- JSTestActiveDOMObject* domObject = jsDynamicCast<JSTestActiveDOMObject*>(JSValue::decode(thisValue));
+ JSTestActiveDOMObjectPrototype* domObject = jsDynamicCast<JSTestActiveDOMObjectPrototype*>(JSValue::decode(thisValue));
if (!domObject)
return throwVMTypeError(state);
- if (!BindingSecurity::shouldAllowAccessToDOMWindow(state, domObject->wrapped()))
- return JSValue::encode(jsUndefined());
return JSValue::encode(JSTestActiveDOMObject::getConstructor(state->vm(), domObject->globalObject()));
}
void setJSTestActiveDOMObjectConstructor(ExecState* state, EncodedJSValue thisValue, EncodedJSValue encodedValue)
{
JSValue value = JSValue::decode(encodedValue);
- JSTestActiveDOMObject* domObject = jsDynamicCast<JSTestActiveDOMObject*>(JSValue::decode(thisValue));
+ JSTestActiveDOMObjectPrototype* domObject = jsDynamicCast<JSTestActiveDOMObjectPrototype*>(JSValue::decode(thisValue));
if (UNLIKELY(!domObject)) {
throwVMTypeError(state);
return;
}
- if (!shouldAllowAccessToFrame(state, domObject->wrapped().frame()))
- return;
// Shadowing a built-in constructor
domObject->putDirect(state->vm(), state->propertyNames().constructor, value);
}