Add initial support for [Unforgeable] IDL extended attribute
authorcdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 16 Sep 2015 17:46:24 +0000 (17:46 +0000)
committercdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 16 Sep 2015 17:46:24 +0000 (17:46 +0000)
https://bugs.webkit.org/show_bug.cgi?id=149147

Reviewed by Darin Adler.

Source/WebCore:

Add initial support for [Unforgeable] IDL extended attribute:
https://heycam.github.io/webidl/#Unforgeable

In particular, attributes marked as unforgeable are now:
- on the instance rather than the prototype
- non-configurable. WebKit does not match the Web IDL specification
  and most properties are currently non-configurable already. However,
  I added an extra check for [Unforgeable] so that unforgeable
  attributes stay unconfigurable if we later decide to match the spec
  and mark properties as configurable.

Operation marked as unforgeable are now non-configurable. However, this
patch does not move them from the prototype to the instance yet. This
needs to be addressed in a follow-up patch as this is a larger change.

This patch also drops support for the undocumented
[OperationsNotDeletable] IDL extended attribute. It is no longer needed
now that we support [Unforgeable] and still support [NotDeletable] for
operations.

Test: fast/dom/unforgeable-attributes.html

* Modules/plugins/QuickTimePluginReplacement.idl:
Drop [OperationsNotDeletable] on the interface and mark the only
operation on this interface as [NotDeletable]. There is no behavior
change but this allows us to drop support for a non-standard and
undocumented IDL extended attribute.

* bindings/scripts/CodeGeneratorJS.pm:
(AttributeShouldBeOnInstance):
(GenerateAttributesHashTable):
(GenerateImplementation):
Add initial support for [Unforgeable] IDL extended attribute.

* bindings/scripts/IDLAttributes.txt:
Add [Unforgeable]. Drop [OperationsNotDeletable].

* crypto/CryptoKeyPair.idl:
Drop [OperationsNotDeletable] on the interface as this interface has
no operations.

* dom/Document.idl:
* page/DOMWindow.idl:
* page/Location.idl:
Mark attributes / interfaces as [Unforgeable] as per the latest HTML
specification:
https://html.spec.whatwg.org/multipage/dom.html#document
https://html.spec.whatwg.org/multipage/browsers.html#window
https://html.spec.whatwg.org/multipage/browsers.html#the-location-interface

LayoutTests:

New test that verifies that well-known [Unforgeable] attributes
are on the instance rather than the prototype and that they are
non-configurable.

* fast/dom/unforgeable-attributes-expected.txt: Added.
* fast/dom/unforgeable-attributes.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@189873 268f45cc-cd09-0410-ab3c-d52691b4dbfc

12 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/dom/unforgeable-attributes-expected.txt [new file with mode: 0644]
LayoutTests/fast/dom/unforgeable-attributes.html [new file with mode: 0644]
LayoutTests/http/tests/security/cross-frame-access-enumeration-expected.txt
Source/WebCore/ChangeLog
Source/WebCore/Modules/plugins/QuickTimePluginReplacement.idl
Source/WebCore/bindings/scripts/CodeGeneratorJS.pm
Source/WebCore/bindings/scripts/IDLAttributes.txt
Source/WebCore/crypto/CryptoKeyPair.idl
Source/WebCore/dom/Document.idl
Source/WebCore/page/DOMWindow.idl
Source/WebCore/page/Location.idl

index 9d74a96..ffa925b 100644 (file)
@@ -1,3 +1,17 @@
+2015-09-16  Chris Dumez  <cdumez@apple.com>
+
+        Add initial support for [Unforgeable] IDL extended attribute
+        https://bugs.webkit.org/show_bug.cgi?id=149147
+
+        Reviewed by Darin Adler.
+
+        New test that verifies that well-known [Unforgeable] attributes
+        are on the instance rather than the prototype and that they are
+        non-configurable.
+
+        * fast/dom/unforgeable-attributes-expected.txt: Added.
+        * fast/dom/unforgeable-attributes.html: Added.
+
 2015-09-16  Zalan Bujtas  <zalan@apple.com>
 
         Simple line layout: Glitch selecting long text.
diff --git a/LayoutTests/fast/dom/unforgeable-attributes-expected.txt b/LayoutTests/fast/dom/unforgeable-attributes-expected.txt
new file mode 100644 (file)
index 0000000..0c07986
--- /dev/null
@@ -0,0 +1,107 @@
+Checks that [Unforgeable] attributes are non-configurable and on the instance rather than the prototype.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Event.isTrusted
+FAIL Unsupported property.
+
+Document.location
+PASS testObject.hasOwnProperty(testPropertyName) is true
+PASS testObject.__proto__.hasOwnProperty(testPropertyName) is false
+PASS Object.defineProperty(testObject, testPropertyName, { value: 'test' }) threw exception TypeError: Attempting to change access mechanism for an unconfigurable property..
+PASS Object.getOwnPropertyDescriptor(testObject, testPropertyName).configurable is false
+
+Window.window
+PASS testObject.hasOwnProperty(testPropertyName) is true
+PASS testObject.__proto__.hasOwnProperty(testPropertyName) is false
+PASS Object.defineProperty(testObject, testPropertyName, { value: 'test' }) threw exception TypeError: Attempting to change value of a readonly property..
+PASS Object.getOwnPropertyDescriptor(testObject, testPropertyName).configurable is false
+
+Window.document
+PASS testObject.hasOwnProperty(testPropertyName) is true
+PASS testObject.__proto__.hasOwnProperty(testPropertyName) is false
+PASS Object.defineProperty(testObject, testPropertyName, { value: 'test' }) threw exception TypeError: Attempting to change value of a readonly property..
+PASS Object.getOwnPropertyDescriptor(testObject, testPropertyName).configurable is false
+
+Window.location
+PASS testObject.hasOwnProperty(testPropertyName) is true
+PASS testObject.__proto__.hasOwnProperty(testPropertyName) is false
+PASS Object.defineProperty(testObject, testPropertyName, { value: 'test' }) threw exception TypeError: Attempting to change access mechanism for an unconfigurable property..
+PASS Object.getOwnPropertyDescriptor(testObject, testPropertyName).configurable is false
+
+Window.top
+PASS testObject.hasOwnProperty(testPropertyName) is true
+PASS testObject.__proto__.hasOwnProperty(testPropertyName) is false
+PASS Object.defineProperty(testObject, testPropertyName, { value: 'test' }) threw exception TypeError: Attempting to change access mechanism for an unconfigurable property..
+PASS Object.getOwnPropertyDescriptor(testObject, testPropertyName).configurable is false
+
+Location.ancestorOrigins
+PASS testObject.hasOwnProperty(testPropertyName) is true
+PASS testObject.__proto__.hasOwnProperty(testPropertyName) is false
+PASS Object.defineProperty(testObject, testPropertyName, { value: 'test' }) threw exception TypeError: Attempting to change access mechanism for an unconfigurable property..
+PASS Object.getOwnPropertyDescriptor(testObject, testPropertyName).configurable is false
+
+Location.href
+PASS testObject.hasOwnProperty(testPropertyName) is true
+PASS testObject.__proto__.hasOwnProperty(testPropertyName) is false
+PASS Object.defineProperty(testObject, testPropertyName, { value: 'test' }) threw exception TypeError: Attempting to change access mechanism for an unconfigurable property..
+PASS Object.getOwnPropertyDescriptor(testObject, testPropertyName).configurable is false
+
+Location.origin
+PASS testObject.hasOwnProperty(testPropertyName) is true
+PASS testObject.__proto__.hasOwnProperty(testPropertyName) is false
+PASS Object.defineProperty(testObject, testPropertyName, { value: 'test' }) threw exception TypeError: Attempting to change access mechanism for an unconfigurable property..
+PASS Object.getOwnPropertyDescriptor(testObject, testPropertyName).configurable is false
+
+Location.protocol
+PASS testObject.hasOwnProperty(testPropertyName) is true
+PASS testObject.__proto__.hasOwnProperty(testPropertyName) is false
+PASS Object.defineProperty(testObject, testPropertyName, { value: 'test' }) threw exception TypeError: Attempting to change access mechanism for an unconfigurable property..
+PASS Object.getOwnPropertyDescriptor(testObject, testPropertyName).configurable is false
+
+Location.username
+FAIL Unsupported property.
+
+Location.password
+FAIL Unsupported property.
+
+Location.host
+PASS testObject.hasOwnProperty(testPropertyName) is true
+PASS testObject.__proto__.hasOwnProperty(testPropertyName) is false
+PASS Object.defineProperty(testObject, testPropertyName, { value: 'test' }) threw exception TypeError: Attempting to change access mechanism for an unconfigurable property..
+PASS Object.getOwnPropertyDescriptor(testObject, testPropertyName).configurable is false
+
+Location.hostname
+PASS testObject.hasOwnProperty(testPropertyName) is true
+PASS testObject.__proto__.hasOwnProperty(testPropertyName) is false
+PASS Object.defineProperty(testObject, testPropertyName, { value: 'test' }) threw exception TypeError: Attempting to change access mechanism for an unconfigurable property..
+PASS Object.getOwnPropertyDescriptor(testObject, testPropertyName).configurable is false
+
+Location.port
+PASS testObject.hasOwnProperty(testPropertyName) is true
+PASS testObject.__proto__.hasOwnProperty(testPropertyName) is false
+PASS Object.defineProperty(testObject, testPropertyName, { value: 'test' }) threw exception TypeError: Attempting to change access mechanism for an unconfigurable property..
+PASS Object.getOwnPropertyDescriptor(testObject, testPropertyName).configurable is false
+
+Location.pathname
+PASS testObject.hasOwnProperty(testPropertyName) is true
+PASS testObject.__proto__.hasOwnProperty(testPropertyName) is false
+PASS Object.defineProperty(testObject, testPropertyName, { value: 'test' }) threw exception TypeError: Attempting to change access mechanism for an unconfigurable property..
+PASS Object.getOwnPropertyDescriptor(testObject, testPropertyName).configurable is false
+
+Location.search
+PASS testObject.hasOwnProperty(testPropertyName) is true
+PASS testObject.__proto__.hasOwnProperty(testPropertyName) is false
+PASS Object.defineProperty(testObject, testPropertyName, { value: 'test' }) threw exception TypeError: Attempting to change access mechanism for an unconfigurable property..
+PASS Object.getOwnPropertyDescriptor(testObject, testPropertyName).configurable is false
+
+Location.hash
+PASS testObject.hasOwnProperty(testPropertyName) is true
+PASS testObject.__proto__.hasOwnProperty(testPropertyName) is false
+PASS Object.defineProperty(testObject, testPropertyName, { value: 'test' }) threw exception TypeError: Attempting to change access mechanism for an unconfigurable property..
+PASS Object.getOwnPropertyDescriptor(testObject, testPropertyName).configurable is false
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/dom/unforgeable-attributes.html b/LayoutTests/fast/dom/unforgeable-attributes.html
new file mode 100644 (file)
index 0000000..d56187b
--- /dev/null
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src="../../resources/js-test-pre.js"></script>
+<script>
+description("Checks that [Unforgeable] attributes are non-configurable and on the instance rather than the prototype.");
+
+function testProperty(object, propertyName)
+{
+    testObject = object;
+    testPropertyName = propertyName;
+
+    if (testObject[propertyName] === undefined) {
+        testFailed("Unsupported property.");
+        return;
+    }
+
+    shouldBeTrue("testObject.hasOwnProperty(testPropertyName)");
+    shouldBeFalse("testObject.__proto__.hasOwnProperty(testPropertyName)");
+    shouldThrow("Object.defineProperty(testObject, testPropertyName, { value: 'test' })");
+    shouldBeFalse("Object.getOwnPropertyDescriptor(testObject, testPropertyName).configurable");
+}
+
+// DOM specification.
+debug("Event.isTrusted");
+var event = new Event("test");
+testProperty(event, "isTrusted");
+
+// HTML specification.
+debug("");
+debug("Document.location");
+testProperty(document, "location");
+
+for (var property of ["window", "document", "location", "top"]) {
+    debug("");
+    debug("Window." + property);
+    testProperty(window, property);
+}
+
+for (var property of ["ancestorOrigins", "href", "origin", "protocol", "username", "password", "host", "hostname", "port", "pathname", "search", "hash"]) {
+    debug("");
+    debug("Location." + property);
+    testProperty(window.location, property);
+}
+
+</script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
index a3c57ba..416d0f9 100644 (file)
@@ -8,8 +8,6 @@ CONSOLE MESSAGE: line 29: Blocked a frame with origin "http://127.0.0.1:8000" fr
 CONSOLE MESSAGE: line 75: 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 82: 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 29: 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 29: 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 29: 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 102: 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 109: 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.
 This tests that variable names can't be enumerated cross domain (see http://bugs.webkit.org/show_bug.cgi?id=16387)
index 8f4e4a6..3d705a5 100644 (file)
@@ -1,3 +1,60 @@
+2015-09-16  Chris Dumez  <cdumez@apple.com>
+
+        Add initial support for [Unforgeable] IDL extended attribute
+        https://bugs.webkit.org/show_bug.cgi?id=149147
+
+        Reviewed by Darin Adler.
+
+        Add initial support for [Unforgeable] IDL extended attribute:
+        https://heycam.github.io/webidl/#Unforgeable
+
+        In particular, attributes marked as unforgeable are now:
+        - on the instance rather than the prototype
+        - non-configurable. WebKit does not match the Web IDL specification
+          and most properties are currently non-configurable already. However,
+          I added an extra check for [Unforgeable] so that unforgeable
+          attributes stay unconfigurable if we later decide to match the spec
+          and mark properties as configurable.
+
+        Operation marked as unforgeable are now non-configurable. However, this
+        patch does not move them from the prototype to the instance yet. This
+        needs to be addressed in a follow-up patch as this is a larger change.
+
+        This patch also drops support for the undocumented
+        [OperationsNotDeletable] IDL extended attribute. It is no longer needed
+        now that we support [Unforgeable] and still support [NotDeletable] for
+        operations.
+
+        Test: fast/dom/unforgeable-attributes.html
+
+        * Modules/plugins/QuickTimePluginReplacement.idl:
+        Drop [OperationsNotDeletable] on the interface and mark the only
+        operation on this interface as [NotDeletable]. There is no behavior
+        change but this allows us to drop support for a non-standard and
+        undocumented IDL extended attribute.
+
+        * bindings/scripts/CodeGeneratorJS.pm:
+        (AttributeShouldBeOnInstance):
+        (GenerateAttributesHashTable):
+        (GenerateImplementation):
+        Add initial support for [Unforgeable] IDL extended attribute.
+
+        * bindings/scripts/IDLAttributes.txt:
+        Add [Unforgeable]. Drop [OperationsNotDeletable].
+
+        * crypto/CryptoKeyPair.idl:
+        Drop [OperationsNotDeletable] on the interface as this interface has
+        no operations.
+
+        * dom/Document.idl:
+        * page/DOMWindow.idl:
+        * page/Location.idl:
+        Mark attributes / interfaces as [Unforgeable] as per the latest HTML
+        specification:
+        https://html.spec.whatwg.org/multipage/dom.html#document
+        https://html.spec.whatwg.org/multipage/browsers.html#window
+        https://html.spec.whatwg.org/multipage/browsers.html#the-location-interface
+
 2015-09-16  Zalan Bujtas  <zalan@apple.com>
 
         Simple line layout: Glitch selecting long text.
index d1e9fcb..70e7159 100644 (file)
 
 [
     NoInterfaceObject,
-    OperationsNotDeletable,
     JSGenerateToJSObject,
 ] interface QuickTimePluginReplacement {
     readonly attribute unsigned long long movieSize;
     [CustomGetter] readonly attribute any timedMetaData;
     [CustomGetter] readonly attribute any accessLog;
     [CustomGetter] readonly attribute any errorLog;
-    void postEvent(DOMString eventName);
+    [NotDeletable] void postEvent(DOMString eventName);
 };
index 6463cca..a836209 100644 (file)
@@ -673,6 +673,10 @@ sub AttributeShouldBeOnInstance
     return 1 if HasCustomGetter($attribute->signature->extendedAttributes);
     return 1 if HasCustomSetter($attribute->signature->extendedAttributes);
 
+    # [Unforgeable] attributes should be on the instance.
+    # https://heycam.github.io/webidl/#Unforgeable
+    return 1 if $attribute->signature->extendedAttributes->{"Unforgeable"} || $interface->extendedAttributes->{"Unforgeable"};
+
     # FIXME: Length is a tricky attribute to handle correctly as it is frequently tied to
     # objects which also have magic named attributes that can end up being named "length"
     # and so interfere with lookup ordering.  I'm not sure what the correct solution is
@@ -1335,7 +1339,13 @@ sub GenerateAttributesHashTable
         # As per Web IDL specification, constructor properties on the ECMAScript global object should be
         # configurable and should not be enumerable.
         my $is_global_constructor = $attribute->signature->type =~ /Constructor$/;
-        push(@specials, "DontDelete") unless ($attribute->signature->extendedAttributes->{"Deletable"} || $is_global_constructor);
+
+        # FIXME: Attributes should be configurable unless [Unforgeable] is specified.
+        # https://heycam.github.io/webidl/#es-attributes
+        push(@specials, "DontDelete") if (!$attribute->signature->extendedAttributes->{"Deletable"} && !$is_global_constructor)
+            || $attribute->signature->extendedAttributes->{"Unforgeable"}
+            || $interface->extendedAttributes->{"Unforgeable"};
+
         push(@specials, "DontEnum") if ($attribute->signature->extendedAttributes->{"NotEnumerable"} || $is_global_constructor);
         push(@specials, "ReadOnly") if IsReadonly($attribute);
         push(@specials, "CustomAccessor") unless $is_global_constructor;
@@ -1911,8 +1921,7 @@ sub GenerateImplementation
             push(@hashValue2, $functionLength);
 
             my @specials = ();
-            push(@specials, "DontDelete") if $interface->extendedAttributes->{"OperationsNotDeletable"}
-                || $function->signature->extendedAttributes->{"NotDeletable"};
+            push(@specials, "DontDelete") if $function->signature->extendedAttributes->{"NotDeletable"};
             push(@specials, "DontEnum") if $function->signature->extendedAttributes->{"NotEnumerable"};
             push(@specials, "JSC::Function");
             my $special = (@specials > 0) ? join(" | ", @specials) : "0";
@@ -1988,8 +1997,9 @@ sub GenerateImplementation
         push(@hashValue2, $functionLength);
 
         my @specials = ();
-        push(@specials, "DontDelete") if $interface->extendedAttributes->{"OperationsNotDeletable"}
-            || $function->signature->extendedAttributes->{"NotDeletable"};
+        push(@specials, "DontDelete") if $function->signature->extendedAttributes->{"NotDeletable"}
+           || $function->signature->extendedAttributes->{"Unforgeable"}
+           || $interface->extendedAttributes->{"Unforgeable"};
         push(@specials, "DontEnum") if $function->signature->extendedAttributes->{"NotEnumerable"};
         push(@specials, "JSC::Function");
         my $special = (@specials > 0) ? join(" | ", @specials) : "0";
index b71cbd7..a040bda 100644 (file)
@@ -99,7 +99,6 @@ ObjCLegacyUnnamedParameters
 ObjCPolymorphic
 ObjCProtocol
 ObjCUseDefaultView
-OperationsNotDeletable
 OverrideBuiltins
 PassContext
 RaisesException
@@ -119,6 +118,7 @@ TreatReturnedNullStringAs=Null|Undefined
 TreatUndefinedAs=NullString
 TypedArray=*
 URL
+Unforgeable
 WindowEventHandler
 
 # PLATFORM(IOS)
index acc1482..1df4fba 100644 (file)
@@ -28,8 +28,7 @@
     ImplementationLacksVTable,
     InterfaceName=KeyPair,
     JSCustomMarkFunction,
-    NoInterfaceObject,
-    OperationsNotDeletable
+    NoInterfaceObject
 ] interface CryptoKeyPair {
     readonly attribute CryptoKey publicKey;
     readonly attribute CryptoKey privateKey;
index b72352a..45ece8c 100644 (file)
     NodeList getElementsByName([Default=Undefined,AtomicString] optional DOMString elementName);
 
 #if defined(LANGUAGE_JAVASCRIPT) && LANGUAGE_JAVASCRIPT
-             [Custom] attribute Location location;
+    [Custom, Unforgeable] attribute Location location;
 #endif
 
     // IE extensions
index 3505af9..ec5ec2d 100644 (file)
@@ -52,7 +52,7 @@
     [Replaceable] readonly attribute Navigator navigator;
     [Replaceable] readonly attribute Navigator clientInformation;
     readonly attribute Crypto crypto;
-    [DoNotCheckSecurity, CustomSetter] attribute Location location;
+    [DoNotCheckSecurity, CustomSetter, Unforgeable] attribute Location location;
     [Replaceable, CustomGetter] readonly attribute Event event;
 
     DOMSelection getSelection();
 
     // Self referential attributes
     [Replaceable, DoNotCheckSecurityOnGetter] readonly attribute DOMWindow self;
-    [DoNotCheckSecurity] readonly attribute DOMWindow window;
+    [DoNotCheckSecurity, Unforgeable] readonly attribute DOMWindow window;
     [Replaceable, DoNotCheckSecurityOnGetter] readonly attribute  DOMWindow frames;
 
     [Replaceable, DoNotCheckSecurityOnGetter] readonly attribute DOMWindow opener;
     [Replaceable, DoNotCheckSecurityOnGetter] readonly attribute DOMWindow parent;
-    [DoNotCheckSecurityOnGetter] readonly attribute DOMWindow top;
+    [DoNotCheckSecurityOnGetter, Unforgeable] readonly attribute DOMWindow top;
 
     // DOM Level 2 AbstractView Interface
-    readonly attribute Document document;
+    [Unforgeable] readonly attribute Document document;
 
     // CSSOM View Module
     MediaQueryList matchMedia(DOMString query);
index dc58129..1203bd7 100644 (file)
@@ -35,7 +35,7 @@
     JSCustomDefineOwnProperty,
     JSCustomNamedGetterOnPrototype,
     JSCustomDefineOwnPropertyOnPrototype,
-    OperationsNotDeletable
+    Unforgeable
 ] interface Location {
     [DoNotCheckSecurityOnSetter, CustomSetter] attribute DOMString href;