Title: [210555] trunk
Revision
210555
Author
jer.no...@apple.com
Date
2017-01-10 12:09:21 -0800 (Tue, 10 Jan 2017)

Log Message

Add support for MediaKeys.generateRequest().
https://bugs.webkit.org/show_bug.cgi?id=166880

Reviewed by Xabier Rodriguez-Calvar.

Source/WebCore:

Test: media/encrypted-media/mock-MediaKeySession-generateRequest.html

Implement MediaKeySession::generateRequest(). This requires some additions
to CDM, CDMPrivate, and CDMInstance to support platform adoption and to
implement mock support for testing. Additionally, add an InitDataRegistry
object which can sanitize and extract key data from various initData types.
(At the moment, only the "keyids" initData type is implemented.)

Drive-by fixes: Change all instances of initDataType from String -> AtomicString.
Add "const" flags to all CDMPrivate methods that might be called from a const
reference.

* CMakeLists.txt:
* Modules/encryptedmedia/CDM.cpp:
(WebCore::CDM::supportsInitDataType):
(WebCore::CDM::sanitizeInitData):
(WebCore::CDM::supportsInitData):
* Modules/encryptedmedia/CDM.h:
* Modules/encryptedmedia/CDMInstance.h:
* Modules/encryptedmedia/CDMPrivate.h:
* Modules/encryptedmedia/InitDataRegistry.cpp: Added.
(WebCore::extractKeyIDsKeyids):
(WebCore::sanitizeKeyids):
(WebCore::sanitizeCenc):
(WebCore::extractKeyIDsCenc):
(WebCore::sanitizeWebM):
(WebCore::extractKeyIDsWebM):
(WebCore::InitDataRegistry::shared):
(WebCore::InitDataRegistry::InitDataRegistry):
(WebCore::InitDataRegistry::sanitizeInitData):
(WebCore::InitDataRegistry::extractKeyIDs):
(WebCore::InitDataRegistry::registerInitDataType):
* Modules/encryptedmedia/InitDataRegistry.h:
* Modules/encryptedmedia/MediaKeySession.cpp:
(WebCore::messageEventName):
(WebCore::MediaKeySession::MediaKeySession):
(WebCore::MediaKeySession::generateRequest):
(WebCore::MediaKeySession::enqueueMessage):
* Modules/encryptedmedia/MediaKeySession.h:
* Modules/encryptedmedia/MediaKeys.cpp:
(WebCore::MediaKeys::setServerCertificate):
* WebCore.xcodeproj/project.pbxproj:
* testing/MockCDMFactory.cpp:
(WebCore::MockCDMFactory::addKeysToSessionWithID):
(WebCore::MockCDMFactory::setSupportedDataTypes):
(WebCore::MockCDM::supportsInitDataType):
(WebCore::MockCDM::supportsConfiguration):
(WebCore::MockCDM::supportsConfigurationWithRestrictions):
(WebCore::MockCDM::supportsSessionTypeWithConfiguration):
(WebCore::MockCDM::supportsRobustness):
(WebCore::MockCDM::distinctiveIdentifiersRequirement):
(WebCore::MockCDM::persistentStateRequirement):
(WebCore::MockCDM::distinctiveIdentifiersAreUniquePerOriginAndClearable):
(WebCore::MockCDM::supportsInitData):
(WebCore::MockCDMInstance::setServerCertificate):
(WebCore::MockCDMInstance::requestLicense):
* testing/MockCDMFactory.h:
(WebCore::MockCDMFactory::supportedDataTypes):
(WebCore::MockCDMFactory::hasSessionWithID):
(WebCore::MockCDMFactory::removeSessionWithID):
(WebCore::MockCDMFactory::setSupportedDataTypes): Deleted.

LayoutTests:

Add shouldResolve() and shouldReject() to video-test.js and update existing
tests to use these new functions.

* media/encrypted-media/mock-MediaKeys-createSession-expected.txt: Added.
* media/encrypted-media/mock-MediaKeys-createSession.html: Added.
* media/encrypted-media/mock-MediaKeys-setServerCertificate.html:
* media/encrypted-media/mock-MediaKeySession-generateRequest.html:
* media/encrypted-media/mock-MediaKeySystemAccess.html:
* media/encrypted-media/mock-navigator-requestMediaKeySystemAccess.html:
* media/video-test.js:
(shouldResolve):
(shouldReject):
* platform/mac/TestExpectations:

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (210554 => 210555)


--- trunk/LayoutTests/ChangeLog	2017-01-10 19:13:06 UTC (rev 210554)
+++ trunk/LayoutTests/ChangeLog	2017-01-10 20:09:21 UTC (rev 210555)
@@ -1,5 +1,26 @@
 2017-01-10  Jer Noble  <jer.no...@apple.com>
 
+        Add support for MediaKeys.generateRequest().
+        https://bugs.webkit.org/show_bug.cgi?id=166880
+
+        Reviewed by Xabier Rodriguez-Calvar.
+
+        Add shouldResolve() and shouldReject() to video-test.js and update existing
+        tests to use these new functions.
+
+        * media/encrypted-media/mock-MediaKeys-createSession-expected.txt: Added.
+        * media/encrypted-media/mock-MediaKeys-createSession.html: Added.
+        * media/encrypted-media/mock-MediaKeys-setServerCertificate.html:
+        * media/encrypted-media/mock-MediaKeySession-generateRequest.html:
+        * media/encrypted-media/mock-MediaKeySystemAccess.html:
+        * media/encrypted-media/mock-navigator-requestMediaKeySystemAccess.html:
+        * media/video-test.js:
+        (shouldResolve):
+        (shouldReject):
+        * platform/mac/TestExpectations:
+
+2017-01-10  Jer Noble  <jer.no...@apple.com>
+
         Add support for MediaKeys.createSession().
         https://bugs.webkit.org/show_bug.cgi?id=166796
 

Added: trunk/LayoutTests/media/encrypted-media/mock-MediaKeySession-generateRequest-expected.txt (0 => 210555)


--- trunk/LayoutTests/media/encrypted-media/mock-MediaKeySession-generateRequest-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/media/encrypted-media/mock-MediaKeySession-generateRequest-expected.txt	2017-01-10 20:09:21 UTC (rev 210555)
@@ -0,0 +1,41 @@
+RUN(internals.initializeMockMediaSource())
+RUN(mock = internals.registerMockCDM())
+RUN(mock.supportedDataTypes = ["keyids"])
+RUN(capabilities.initDataTypes = ["keyids"])
+RUN(capabilities.videoCapabilities = [{ contentType: 'video/mock; codecs="mock"' }] )
+RUN(promise = navigator.requestMediaKeySystemAccess("org.webkit.mock", [capabilities]))
+Promise resolved OK
+
+RUN(promise = mediaKeySystemAccess.createMediaKeys())
+Promise resolved OK
+
+Using an invalid initDataType string should reject.
+RUN(mediaKeySession = mediaKeys.createSession("temporary"))
+EXPECTED (typeof mediaKeySession == 'object') OK
+RUN(promise = mediaKeySession.generateRequest("invalid", stringToUInt8Array("invalid")))
+Promise rejected correctly OK
+
+Re-using a failed mediaKeySession should reject.
+RUN(kids = JSON.stringify({ kids: [ "MTIzNDU=" ] }))
+RUN(promise = mediaKeySession.generateRequest("keyids", stringToUInt8Array(kids)))
+Promise rejected correctly OK
+
+Using a new mediaKeySession should resolve.
+RUN(kids = JSON.stringify({ kids: [ "MTIzNDU=" ] }))
+RUN(mediaKeySession = mediaKeys.createSession("temporary"))
+RUN(promise = mediaKeySession.generateRequest("keyids", stringToUInt8Array(kids)))
+Promise resolved OK
+
+Using invalid initData should reject.
+RUN(kids = JSON.stringify({ invalid: "invalid" }))
+RUN(mediaKeySession = mediaKeys.createSession("temporary"))
+RUN(promise = mediaKeySession.generateRequest("keyids", stringToUInt8Array(kids)))
+Promise rejected correctly OK
+
+Using initData with extraneous information should resolve.
+RUN(kids = JSON.stringify({ kids: [ "MTIzNDU="], invalid: "invalid" }))
+RUN(mediaKeySession = mediaKeys.createSession("temporary"))
+RUN(promise = mediaKeySession.generateRequest("keyids", stringToUInt8Array(kids)))
+Promise resolved OK
+END OF TEST
+

Added: trunk/LayoutTests/media/encrypted-media/mock-MediaKeySession-generateRequest.html (0 => 210555)


--- trunk/LayoutTests/media/encrypted-media/mock-MediaKeySession-generateRequest.html	                        (rev 0)
+++ trunk/LayoutTests/media/encrypted-media/mock-MediaKeySession-generateRequest.html	2017-01-10 20:09:21 UTC (rev 210555)
@@ -0,0 +1,109 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script src=""
+    <script type="text/_javascript_">
+    var mock;
+    var promise;
+    var mediaKeySystemAccess;
+    var mediaKeys;
+    var mediaKeySession;
+    var capabilities = {};
+    var kids;
+
+    function doTest()
+    {
+        if (!window.internals) {
+            failTest("Internals is required for this test.")
+            return;
+        }
+
+        run('internals.initializeMockMediaSource()');
+        run('mock = internals.registerMockCDM()');
+        run('mock.supportedDataTypes = ["keyids"]');
+        run('capabilities.initDataTypes = ["keyids"]');
+        run(`capabilities.videoCapabilities = [{ contentType: 'video/mock; codecs="mock"' }] `);
+        run('promise = navigator.requestMediaKeySystemAccess("org.webkit.mock", [capabilities])');
+        shouldResolve(promise).then(gotMediaKeySystemAccess, failTest);
+    }
+
+    function next() {
+        if (!tests.length) {
+            mock.unregister();
+            endTest()
+            return;
+        }
+
+        var nextTest = tests.shift();
+        consoleWrite('');
+        nextTest();
+    }
+
+    function gotMediaKeySystemAccess(result) {
+        mediaKeySystemAccess = result;
+        next();
+    }
+
+    function gotMediaKeys(result) {
+        mediaKeys = result;
+        next();
+    }
+
+    function stringToUInt8Array(str)
+    {
+       var array = new Uint8Array(str.length);
+       for (var i=0; i<str.length; i++)
+            array[i] = str.charCodeAt(i);
+       return array;
+    }
+
+    tests = [
+        function() {
+            run('promise = mediaKeySystemAccess.createMediaKeys()');
+            shouldResolve(promise).then(gotMediaKeys, failTest);
+        },
+
+        function() {
+            consoleWrite('Using an invalid initDataType string should reject.')
+            run('mediaKeySession = mediaKeys.createSession("temporary")');
+            testExpected('typeof mediaKeySession', 'object')
+            run('promise = mediaKeySession.generateRequest("invalid", stringToUInt8Array("invalid"))');
+            shouldReject(promise).then(next, next);
+        },
+
+        function() {
+            consoleWrite('Re-using a failed mediaKeySession should reject.')
+            run('kids = JSON.stringify({ kids: [ "MTIzNDU=" ] })');
+            run('promise = mediaKeySession.generateRequest("keyids", stringToUInt8Array(kids))');
+            shouldReject(promise).then(next, next);
+        },
+
+        function() {
+            consoleWrite('Using a new mediaKeySession should resolve.')
+            run('kids = JSON.stringify({ kids: [ "MTIzNDU=" ] })');
+            run('mediaKeySession = mediaKeys.createSession("temporary")');
+            run('promise = mediaKeySession.generateRequest("keyids", stringToUInt8Array(kids))');
+            shouldResolve(promise).then(next, next);
+        },
+
+        function() {
+            consoleWrite('Using invalid initData should reject.')
+            run('kids = JSON.stringify({ invalid: "invalid" })');
+            run('mediaKeySession = mediaKeys.createSession("temporary")');
+            run('promise = mediaKeySession.generateRequest("keyids", stringToUInt8Array(kids))');
+            shouldReject(promise).then(next, next);
+        },
+
+        function() {
+            consoleWrite('Using initData with extraneous information should resolve.')
+            run('kids = JSON.stringify({ kids: [ "MTIzNDU="], invalid: "invalid" })');
+            run('mediaKeySession = mediaKeys.createSession("temporary")');
+            run('promise = mediaKeySession.generateRequest("keyids", stringToUInt8Array(kids))');
+            shouldResolve(promise).then(next, next);
+        },
+    ];
+    </script>
+</head>
+<body _onload_="doTest()">
+</body>
+</html>

Modified: trunk/LayoutTests/media/encrypted-media/mock-MediaKeySystemAccess.html (210554 => 210555)


--- trunk/LayoutTests/media/encrypted-media/mock-MediaKeySystemAccess.html	2017-01-10 19:13:06 UTC (rev 210554)
+++ trunk/LayoutTests/media/encrypted-media/mock-MediaKeySystemAccess.html	2017-01-10 20:09:21 UTC (rev 210555)
@@ -34,28 +34,7 @@
         nextTest();
     }
 
-    function shouldResolve(promise) {
-        promise.then(mediaKeySystemAccess => {
-            logResult(Success, 'Promise resolved');
-            next();
-        }, () => {
-            logResult(Failed, 'Promise rejected');
-            next();
-        });
-    }
-
-    function shouldReject(promise) {
-        promise.then(() => {
-            logResult(Failed, 'Promise resolved incorrectly');
-            next();
-        }, exceptionCode => {
-            logResult(Success, 'Promise rejected correctly');
-            next();
-        });
-    }
-
     function gotMediaKeySystemAccess(result) {
-        logResult(Success, 'Promise resolved');
         mediaKeySystemAccess = result;
         next();
     }
@@ -65,18 +44,18 @@
             run('capabilities.initDataTypes = ["mock"]');
             run(`capabilities.videoCapabilities = [{ contentType: 'video/mock; codecs="mock"' }] `);
             run('promise = navigator.requestMediaKeySystemAccess("org.webkit.mock", [capabilities])');
-            promise.then(gotMediaKeySystemAccess).catch(failTest);
+            shouldResolve(promise).then(gotMediaKeySystemAccess, failTest);
         },
 
         function() {
             run('promise = mediaKeySystemAccess.createMediaKeys()');
-            shouldResolve(promise);
+            shouldResolve(promise).then(next, next);
         },
 
         function() {
             run('mock.canCreateInstances = false');
             run('promise = mediaKeySystemAccess.createMediaKeys()');
-            shouldReject(promise);
+            shouldReject(promise).then(next, next);
         },
 
         function() {
@@ -83,18 +62,18 @@
             run('mock.canCreateInstances = true');
             run('capabilities.distinctiveIdentifier = "not-allowed"');
             run('promise = navigator.requestMediaKeySystemAccess("org.webkit.mock", [capabilities])');
-            promise.then(gotMediaKeySystemAccess).catch(failTest);
+            shouldResolve(promise).then(gotMediaKeySystemAccess, failTest);
         },
 
         function() {
             run('promise = mediaKeySystemAccess.createMediaKeys()');
-            shouldResolve(promise);
+            shouldResolve(promise).then(next, next);
         },
 
         function() {
             run('mock.distinctiveIdentifiersRequirement = "required"');
             run('promise = mediaKeySystemAccess.createMediaKeys()');
-            shouldReject(promise);
+            shouldReject(promise).then(next, next);
         },
 
         function() {
@@ -101,18 +80,18 @@
             run('mock.distinctiveIdentifiersRequirement = "optional"');
             run('capabilities.persistentState = "not-allowed"');
             run('promise = navigator.requestMediaKeySystemAccess("org.webkit.mock", [capabilities])');
-            promise.then(gotMediaKeySystemAccess).catch(failTest);
+            shouldResolve(promise).then(gotMediaKeySystemAccess, failTest);
         },
 
         function() {
             run('promise = mediaKeySystemAccess.createMediaKeys()');
-            shouldResolve(promise);
+            shouldResolve(promise).then(next, next);
         },
 
         function() {
             run('mock.persistentStateRequirement = "required"');
             run('promise = mediaKeySystemAccess.createMediaKeys()');
-            shouldReject(promise);
+            shouldReject(promise).then(next, next);
         },
     ];
     </script>

Modified: trunk/LayoutTests/media/encrypted-media/mock-MediaKeys-createSession.html (210554 => 210555)


--- trunk/LayoutTests/media/encrypted-media/mock-MediaKeys-createSession.html	2017-01-10 19:13:06 UTC (rev 210554)
+++ trunk/LayoutTests/media/encrypted-media/mock-MediaKeys-createSession.html	2017-01-10 20:09:21 UTC (rev 210555)
@@ -23,7 +23,7 @@
         run('capabilities.initDataTypes = ["mock"]');
         run(`capabilities.videoCapabilities = [{ contentType: 'video/mock; codecs="mock"' }] `);
         run('promise = navigator.requestMediaKeySystemAccess("org.webkit.mock", [capabilities])');
-        promise.then(gotMediaKeySystemAccess).catch(failTest);
+        shouldResolve(promise).then(gotMediaKeySystemAccess, failTest);
     }
 
     function next() {
@@ -38,34 +38,12 @@
         nextTest();
     }
 
-    function shouldResolve(promise) {
-        promise.then(mediaKeySystemAccess => {
-            logResult(Success, 'Promise resolved');
-            next();
-        }, () => {
-            logResult(Failed, 'Promise rejected');
-            next();
-        });
-    }
-
-    function shouldReject(promise) {
-        promise.then(() => {
-            logResult(Failed, 'Promise resolved incorrectly');
-            next();
-        }, exceptionCode => {
-            logResult(Success, 'Promise rejected correctly');
-            next();
-        });
-    }
-
     function gotMediaKeySystemAccess(result) {
-        logResult(Success, 'Promise resolved');
         mediaKeySystemAccess = result;
         next();
     }
 
     function gotMediaKeys(result) {
-        logResult(Success, 'Promise resolved');
         mediaKeys = result;
         next();
     }
@@ -81,7 +59,7 @@
     tests = [
         function() {
             run('promise = mediaKeySystemAccess.createMediaKeys()');
-            promise.then(gotMediaKeys).catch(failTest);
+            shouldResolve(promise).then(gotMediaKeys, failTest);
         },
 
         function() {

Modified: trunk/LayoutTests/media/encrypted-media/mock-MediaKeys-setServerCertificate.html (210554 => 210555)


--- trunk/LayoutTests/media/encrypted-media/mock-MediaKeys-setServerCertificate.html	2017-01-10 19:13:06 UTC (rev 210554)
+++ trunk/LayoutTests/media/encrypted-media/mock-MediaKeys-setServerCertificate.html	2017-01-10 20:09:21 UTC (rev 210555)
@@ -22,7 +22,7 @@
         run('capabilities.initDataTypes = ["mock"]');
         run(`capabilities.videoCapabilities = [{ contentType: 'video/mock; codecs="mock"' }] `);
         run('promise = navigator.requestMediaKeySystemAccess("org.webkit.mock", [capabilities])');
-        promise.then(gotMediaKeySystemAccess).catch(failTest);
+        shouldResolve(promise).then(gotMediaKeySystemAccess, failTest);
     }
 
     function next() {
@@ -37,34 +37,12 @@
         nextTest();
     }
 
-    function shouldResolve(promise) {
-        promise.then(mediaKeySystemAccess => {
-            logResult(Success, 'Promise resolved');
-            next();
-        }, () => {
-            logResult(Failed, 'Promise rejected');
-            next();
-        });
-    }
-
-    function shouldReject(promise) {
-        promise.then(() => {
-            logResult(Failed, 'Promise resolved incorrectly');
-            next();
-        }, exceptionCode => {
-            logResult(Success, 'Promise rejected correctly');
-            next();
-        });
-    }
-
     function gotMediaKeySystemAccess(result) {
-        logResult(Success, 'Promise resolved');
         mediaKeySystemAccess = result;
         next();
     }
 
     function gotMediaKeys(result) {
-        logResult(Success, 'Promise resolved');
         mediaKeys = result;
         next();
     }
@@ -80,28 +58,28 @@
     tests = [
         function() {
             run('promise = mediaKeySystemAccess.createMediaKeys()');
-            promise.then(gotMediaKeys).catch(failTest);
+            shouldResolve(promise).then(gotMediaKeys, failTest);
         },
 
         function() {
             run('promise = mediaKeys.setServerCertificate(new ArrayBuffer())');
-            shouldReject(promise);
+            shouldReject(promise).then(next, next);
         },
 
         function() {
             run('promise = mediaKeys.setServerCertificate(stringToUInt8Array("invalid"))');
-            shouldReject(promise);
+            shouldReject(promise).then(next, next);
         },
 
         function() {
             run('promise = mediaKeys.setServerCertificate(stringToUInt8Array("valid"))');
-            shouldResolve(promise);
+            shouldResolve(promise).then(next, next);
         },
 
         function() {
             run('mock.supportsServerCertificates = false');
             run('promise = mediaKeys.setServerCertificate(stringToUInt8Array("valid"))');
-            shouldReject(promise);
+            shouldReject(promise).then(next, next);
         },
     ];
     </script>

Modified: trunk/LayoutTests/media/encrypted-media/mock-navigator-requestMediaKeySystemAccess.html (210554 => 210555)


--- trunk/LayoutTests/media/encrypted-media/mock-navigator-requestMediaKeySystemAccess.html	2017-01-10 19:13:06 UTC (rev 210554)
+++ trunk/LayoutTests/media/encrypted-media/mock-navigator-requestMediaKeySystemAccess.html	2017-01-10 20:09:21 UTC (rev 210555)
@@ -34,27 +34,11 @@
     }
 
     function passingTestWithCapabilities(capabilities, success) {
-        testWithCapabilities(capabilities);
-        promise.then(mediaKeySystemAccess => {
-            logResult(Success, 'Promise resolved');
-            success(mediaKeySystemAccess);
-            next();
-        }, () => {
-            logResult(Failed, 'Promise rejected');
-            next();
-        });
+        shouldResolve(testWithCapabilities(capabilities)).then(success).then(next, next);
     }
 
     function failingTestWithCapabilities(capabilities, failure) {
-        testWithCapabilities(capabilities);
-        promise.then(() => {
-            logResult(Failed, 'Promise resolved incorrectly');
-            next();
-        }, exceptionCode => {
-            logResult(Success, 'Promise rejected correctly');
-            failure(exceptionCode)
-            next();
-        });
+        shouldReject(testWithCapabilities(capabilities)).then(failure).then(next, next);
     }
 
     function testWithCapabilities(capabilities) {
@@ -61,6 +45,7 @@
         window.capabilities = capabilities;
         consoleWrite(`SET capabilities = '${ JSON.stringify(capabilities, null, 1) }'`);
         run('promise  = navigator.requestMediaKeySystemAccess("org.webkit.mock", capabilities)');
+        return promise;
     }
 
     tests = [

Modified: trunk/LayoutTests/media/video-test.js (210554 => 210555)


--- trunk/LayoutTests/media/video-test.js	2017-01-10 19:13:06 UTC (rev 210554)
+++ trunk/LayoutTests/media/video-test.js	2017-01-10 20:09:21 UTC (rev 210555)
@@ -416,3 +416,28 @@
             eventSender.mouseDown();
     }
 }
+
+function shouldResolve(promise) {
+    return new Promise((resolve, reject) => {
+        promise.then(result => {
+            logResult(Success, 'Promise resolved');
+            resolve(result);
+        }).catch((error) => {
+            logResult(Failed, 'Promise rejected');
+            reject(error);
+        });
+    });
+}
+
+function shouldReject(promise) {
+    return new Promise((resolve, reject) => {
+        promise.then(result => {
+            logResult(Failed, 'Promise resolved incorrectly');
+            reject(result);
+        }).catch((error) => {
+            logResult(Success, 'Promise rejected correctly');
+            resolve(error);
+        });
+    });
+
+}

Modified: trunk/LayoutTests/platform/mac/TestExpectations (210554 => 210555)


--- trunk/LayoutTests/platform/mac/TestExpectations	2017-01-10 19:13:06 UTC (rev 210554)
+++ trunk/LayoutTests/platform/mac/TestExpectations	2017-01-10 20:09:21 UTC (rev 210555)
@@ -1469,6 +1469,7 @@
 media/encrypted-media/mock-MediaKeySystemAccess.html [ Skip ]
 media/encrypted-media/mock-MediaKeys-setServerCertificate.html [ Skip ]
 media/encrypted-media/mock-MediaKeys-createSession.html [ Skip ]
+media/encrypted-media/mock-MediaKeySession-generateRequest.html [ Skip ]
 
 webkit.org/b/166025 http/tests/fetch/fetching-same-resource-with-diffferent-options.html [ Pass Failure ]
 

Modified: trunk/Source/WebCore/CMakeLists.txt (210554 => 210555)


--- trunk/Source/WebCore/CMakeLists.txt	2017-01-10 19:13:06 UTC (rev 210554)
+++ trunk/Source/WebCore/CMakeLists.txt	2017-01-10 20:09:21 UTC (rev 210555)
@@ -2982,6 +2982,7 @@
 if (ENABLE_ENCRYPTED_MEDIA)
     list(APPEND WebCore_SOURCES
         Modules/encryptedmedia/CDM.cpp
+        Modules/encryptedmedia/InitDataRegistry.cpp
         Modules/encryptedmedia/MediaKeyMessageEvent.cpp
         Modules/encryptedmedia/MediaKeySession.cpp
         Modules/encryptedmedia/MediaKeyStatusMap.cpp

Modified: trunk/Source/WebCore/ChangeLog (210554 => 210555)


--- trunk/Source/WebCore/ChangeLog	2017-01-10 19:13:06 UTC (rev 210554)
+++ trunk/Source/WebCore/ChangeLog	2017-01-10 20:09:21 UTC (rev 210555)
@@ -1,5 +1,74 @@
 2017-01-10  Jer Noble  <jer.no...@apple.com>
 
+        Add support for MediaKeys.generateRequest().
+        https://bugs.webkit.org/show_bug.cgi?id=166880
+
+        Reviewed by Xabier Rodriguez-Calvar.
+
+        Test: media/encrypted-media/mock-MediaKeySession-generateRequest.html
+
+        Implement MediaKeySession::generateRequest(). This requires some additions
+        to CDM, CDMPrivate, and CDMInstance to support platform adoption and to
+        implement mock support for testing. Additionally, add an InitDataRegistry
+        object which can sanitize and extract key data from various initData types.
+        (At the moment, only the "keyids" initData type is implemented.)
+
+        Drive-by fixes: Change all instances of initDataType from String -> AtomicString.
+        Add "const" flags to all CDMPrivate methods that might be called from a const
+        reference.
+
+        * CMakeLists.txt:
+        * Modules/encryptedmedia/CDM.cpp:
+        (WebCore::CDM::supportsInitDataType):
+        (WebCore::CDM::sanitizeInitData):
+        (WebCore::CDM::supportsInitData):
+        * Modules/encryptedmedia/CDM.h:
+        * Modules/encryptedmedia/CDMInstance.h:
+        * Modules/encryptedmedia/CDMPrivate.h:
+        * Modules/encryptedmedia/InitDataRegistry.cpp: Added.
+        (WebCore::extractKeyIDsKeyids):
+        (WebCore::sanitizeKeyids):
+        (WebCore::sanitizeCenc):
+        (WebCore::extractKeyIDsCenc):
+        (WebCore::sanitizeWebM):
+        (WebCore::extractKeyIDsWebM):
+        (WebCore::InitDataRegistry::shared):
+        (WebCore::InitDataRegistry::InitDataRegistry):
+        (WebCore::InitDataRegistry::sanitizeInitData):
+        (WebCore::InitDataRegistry::extractKeyIDs):
+        (WebCore::InitDataRegistry::registerInitDataType):
+        * Modules/encryptedmedia/InitDataRegistry.h:
+        * Modules/encryptedmedia/MediaKeySession.cpp:
+        (WebCore::messageEventName):
+        (WebCore::MediaKeySession::MediaKeySession):
+        (WebCore::MediaKeySession::generateRequest):
+        (WebCore::MediaKeySession::enqueueMessage):
+        * Modules/encryptedmedia/MediaKeySession.h:
+        * Modules/encryptedmedia/MediaKeys.cpp:
+        (WebCore::MediaKeys::setServerCertificate):
+        * WebCore.xcodeproj/project.pbxproj:
+        * testing/MockCDMFactory.cpp:
+        (WebCore::MockCDMFactory::addKeysToSessionWithID):
+        (WebCore::MockCDMFactory::setSupportedDataTypes):
+        (WebCore::MockCDM::supportsInitDataType):
+        (WebCore::MockCDM::supportsConfiguration):
+        (WebCore::MockCDM::supportsConfigurationWithRestrictions):
+        (WebCore::MockCDM::supportsSessionTypeWithConfiguration):
+        (WebCore::MockCDM::supportsRobustness):
+        (WebCore::MockCDM::distinctiveIdentifiersRequirement):
+        (WebCore::MockCDM::persistentStateRequirement):
+        (WebCore::MockCDM::distinctiveIdentifiersAreUniquePerOriginAndClearable):
+        (WebCore::MockCDM::supportsInitData):
+        (WebCore::MockCDMInstance::setServerCertificate):
+        (WebCore::MockCDMInstance::requestLicense):
+        * testing/MockCDMFactory.h:
+        (WebCore::MockCDMFactory::supportedDataTypes):
+        (WebCore::MockCDMFactory::hasSessionWithID):
+        (WebCore::MockCDMFactory::removeSessionWithID):
+        (WebCore::MockCDMFactory::setSupportedDataTypes): Deleted.
+
+2017-01-10  Jer Noble  <jer.no...@apple.com>
+
         Add support for MediaKeys.createSession().
         https://bugs.webkit.org/show_bug.cgi?id=166796
 

Modified: trunk/Source/WebCore/Modules/encryptedmedia/CDM.cpp (210554 => 210555)


--- trunk/Source/WebCore/Modules/encryptedmedia/CDM.cpp	2017-01-10 19:13:06 UTC (rev 210554)
+++ trunk/Source/WebCore/Modules/encryptedmedia/CDM.cpp	2017-01-10 20:09:21 UTC (rev 210555)
@@ -30,6 +30,7 @@
 
 #include "CDMPrivate.h"
 #include "Document.h"
+#include "InitDataRegistry.h"
 #include "MediaKeysRestrictions.h"
 #include "MediaPlayer.h"
 #include "NotImplemented.h"
@@ -634,6 +635,21 @@
     return m_private && m_private->supportsSessions();
 }
 
+bool CDM::supportsInitDataType(const AtomicString& initDataType) const
+{
+    return m_private && m_private->supportsInitDataType(initDataType);
 }
 
+RefPtr<SharedBuffer> CDM::sanitizeInitData(const AtomicString& initDataType, const SharedBuffer& initData)
+{
+    return InitDataRegistry::shared().sanitizeInitData(initDataType, initData);
+}
+
+bool CDM::supportsInitData(const AtomicString& initDataType, const SharedBuffer& initData)
+{
+    return m_private && m_private->supportsInitData(initDataType, initData);
+}
+
+}
+
 #endif

Modified: trunk/Source/WebCore/Modules/encryptedmedia/CDM.h (210554 => 210555)


--- trunk/Source/WebCore/Modules/encryptedmedia/CDM.h	2017-01-10 19:13:06 UTC (rev 210554)
+++ trunk/Source/WebCore/Modules/encryptedmedia/CDM.h	2017-01-10 20:09:21 UTC (rev 210555)
@@ -29,6 +29,7 @@
 
 #include "ContextDestructionObserver.h"
 #include "MediaKeySystemConfiguration.h"
+#include "SharedBuffer.h"
 #include <functional>
 #include <wtf/HashSet.h>
 #include <wtf/Ref.h>
@@ -43,6 +44,7 @@
 class CDMPrivate;
 class Document;
 class ScriptExecutionContext;
+class SharedBuffer;
 
 struct MediaKeysRestrictions;
 
@@ -73,7 +75,11 @@
     RefPtr<CDMInstance> createInstance();
     bool supportsServerCertificates() const;
     bool supportsSessions() const;
+    bool supportsInitDataType(const AtomicString&) const;
 
+    RefPtr<SharedBuffer> sanitizeInitData(const AtomicString& initDataType, const SharedBuffer&);
+    bool supportsInitData(const AtomicString& initDataType, const SharedBuffer&);
+
 private:
     CDM(Document&, const String& keySystem);
 

Modified: trunk/Source/WebCore/Modules/encryptedmedia/CDMInstance.h (210554 => 210555)


--- trunk/Source/WebCore/Modules/encryptedmedia/CDMInstance.h	2017-01-10 19:13:06 UTC (rev 210554)
+++ trunk/Source/WebCore/Modules/encryptedmedia/CDMInstance.h	2017-01-10 20:09:21 UTC (rev 210555)
@@ -30,13 +30,10 @@
 #include <wtf/Forward.h>
 #include <wtf/RefCounted.h>
 
-namespace JSC {
-class ArrayBuffer;
-}
-
 namespace WebCore {
 
 struct MediaKeySystemConfiguration;
+class SharedBuffer;
 
 class CDMInstance : public RefCounted<CDMInstance> {
 public:
@@ -50,7 +47,16 @@
     virtual SuccessValue initializeWithConfiguration(const MediaKeySystemConfiguration&) = 0;
     virtual SuccessValue setDistinctiveIdentifiersAllowed(bool) = 0;
     virtual SuccessValue setPersistentStateAllowed(bool) = 0;
-    virtual SuccessValue setServerCertificate(JSC::ArrayBuffer&) = 0;
+    virtual SuccessValue setServerCertificate(Ref<SharedBuffer>&&) = 0;
+
+    enum class LicenseType {
+        Temporary,
+        Persistable,
+        UsageRecord,
+    };
+
+    using LicenseCallback = Function<void(Ref<SharedBuffer>&& message, const String& sessionId, bool needsIndividualization, SuccessValue succeeded)>;
+    virtual void requestLicense(LicenseType, const AtomicString& initDataType, Ref<SharedBuffer>&& initData, LicenseCallback) = 0;
 };
 
 }

Modified: trunk/Source/WebCore/Modules/encryptedmedia/CDMPrivate.h (210554 => 210555)


--- trunk/Source/WebCore/Modules/encryptedmedia/CDMPrivate.h	2017-01-10 19:13:06 UTC (rev 210554)
+++ trunk/Source/WebCore/Modules/encryptedmedia/CDMPrivate.h	2017-01-10 20:09:21 UTC (rev 210555)
@@ -41,18 +41,19 @@
 public:
     virtual ~CDMPrivate() { }
 
-    virtual bool supportsInitDataType(const String&) = 0;
-    virtual bool supportsConfiguration(const MediaKeySystemConfiguration&) = 0;
-    virtual bool supportsConfigurationWithRestrictions(const MediaKeySystemConfiguration&, const MediaKeysRestrictions&) = 0;
-    virtual bool supportsSessionTypeWithConfiguration(MediaKeySessionType&, const MediaKeySystemConfiguration&) = 0;
-    virtual bool supportsRobustness(const String&) = 0;
-    virtual MediaKeysRequirement distinctiveIdentifiersRequirement(const MediaKeySystemConfiguration&, const MediaKeysRestrictions&) = 0;
-    virtual MediaKeysRequirement persistentStateRequirement(const MediaKeySystemConfiguration&, const MediaKeysRestrictions&) = 0;
-    virtual bool distinctiveIdentifiersAreUniquePerOriginAndClearable(const MediaKeySystemConfiguration&) = 0;
+    virtual bool supportsInitDataType(const AtomicString&) const = 0;
+    virtual bool supportsConfiguration(const MediaKeySystemConfiguration&) const = 0;
+    virtual bool supportsConfigurationWithRestrictions(const MediaKeySystemConfiguration&, const MediaKeysRestrictions&) const = 0;
+    virtual bool supportsSessionTypeWithConfiguration(MediaKeySessionType&, const MediaKeySystemConfiguration&) const = 0;
+    virtual bool supportsRobustness(const String&) const = 0;
+    virtual MediaKeysRequirement distinctiveIdentifiersRequirement(const MediaKeySystemConfiguration&, const MediaKeysRestrictions&) const = 0;
+    virtual MediaKeysRequirement persistentStateRequirement(const MediaKeySystemConfiguration&, const MediaKeysRestrictions&) const = 0;
+    virtual bool distinctiveIdentifiersAreUniquePerOriginAndClearable(const MediaKeySystemConfiguration&) const = 0;
     virtual RefPtr<CDMInstance> createInstance() = 0;
     virtual void loadAndInitialize() = 0;
     virtual bool supportsServerCertificates() const = 0;
     virtual bool supportsSessions() const = 0;
+    virtual bool supportsInitData(const AtomicString&, const SharedBuffer&) const = 0;
 };
 
 }

Added: trunk/Source/WebCore/Modules/encryptedmedia/InitDataRegistry.cpp (0 => 210555)


--- trunk/Source/WebCore/Modules/encryptedmedia/InitDataRegistry.cpp	                        (rev 0)
+++ trunk/Source/WebCore/Modules/encryptedmedia/InitDataRegistry.cpp	2017-01-10 20:09:21 UTC (rev 210555)
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "InitDataRegistry.h"
+
+#if ENABLE(ENCRYPTED_MEDIA)
+
+#include "NotImplemented.h"
+#include "SharedBuffer.h"
+#include "inspector/InspectorValues.h"
+#include <wtf/NeverDestroyed.h>
+#include <wtf/text/Base64.h>
+
+using namespace Inspector;
+
+namespace WebCore {
+
+static Vector<Ref<SharedBuffer>> extractKeyIDsKeyids(const SharedBuffer& buffer)
+{
+    // 1. Format
+    // https://w3c.github.io/encrypted-media/format-registry/initdata/keyids.html#format
+    String json { buffer.data(), buffer.size() };
+
+    RefPtr<InspectorValue> value;
+    if (!InspectorValue::parseJSON(json, value))
+        return { };
+
+    RefPtr<InspectorObject> object;
+    if (!value->asObject(object))
+        return { };
+
+    RefPtr<InspectorArray> kidsArray;
+    if (!object->getArray("kids", kidsArray))
+        return { };
+
+    Vector<Ref<SharedBuffer>> keyIDs;
+    for (auto& value : *kidsArray) {
+        String keyID;
+        if (!value->asString(keyID))
+            continue;
+
+        Vector<char> keyIDData;
+        if (!WTF::base64Decode(keyID, { keyIDData }))
+            continue;
+
+        Ref<SharedBuffer> keyIDBuffer = SharedBuffer::adoptVector(keyIDData);
+        keyIDs.append(WTFMove(keyIDBuffer));
+    }
+
+    return keyIDs;
+}
+
+static RefPtr<SharedBuffer> sanitizeKeyids(const SharedBuffer& buffer)
+{
+    // 1. Format
+    // https://w3c.github.io/encrypted-media/format-registry/initdata/keyids.html#format
+    Vector<Ref<SharedBuffer>> keyIDBuffer = extractKeyIDsKeyids(buffer);
+    if (keyIDBuffer.isEmpty())
+        return nullptr;
+
+    auto object = InspectorObject::create();
+    auto kidsArray = InspectorArray::create();
+    for (auto& buffer : keyIDBuffer)
+        kidsArray->pushString(base64Encode(buffer->data(), buffer->size()));
+    object->setArray("kids", WTFMove(kidsArray));
+
+    CString jsonData = object->toJSONString().utf8();
+    return SharedBuffer::create(jsonData.data(), jsonData.length());
+}
+
+static RefPtr<SharedBuffer> sanitizeCenc(const SharedBuffer& buffer)
+{
+    // 4. Common SystemID and PSSH Box Format
+    // https://w3c.github.io/encrypted-media/format-registry/initdata/cenc.html#common-system
+    notImplemented();
+    return buffer.copy();
+}
+
+static Vector<Ref<SharedBuffer>> extractKeyIDsCenc(const SharedBuffer&)
+{
+    // 4. Common SystemID and PSSH Box Format
+    // https://w3c.github.io/encrypted-media/format-registry/initdata/cenc.html#common-system
+    notImplemented();
+    return { };
+}
+
+static RefPtr<SharedBuffer> sanitizeWebM(const SharedBuffer& buffer)
+{
+    // 1. Format
+    // https://w3c.github.io/encrypted-media/format-registry/initdata/webm.html#format
+    notImplemented();
+    return buffer.copy();
+}
+
+static Vector<Ref<SharedBuffer>> extractKeyIDsWebM(const SharedBuffer&)
+{
+    // 1. Format
+    // https://w3c.github.io/encrypted-media/format-registry/initdata/webm.html#format
+    notImplemented();
+    return { };
+}
+
+InitDataRegistry& InitDataRegistry::shared()
+{
+    static NeverDestroyed<InitDataRegistry> registry;
+    return registry.get();
+}
+
+InitDataRegistry::InitDataRegistry()
+{
+    registerInitDataType("keyids", { &sanitizeKeyids, &extractKeyIDsKeyids });
+    registerInitDataType("cenc", { &sanitizeCenc, &extractKeyIDsCenc });
+    registerInitDataType("webm", { &sanitizeWebM, &extractKeyIDsWebM });
+}
+
+InitDataRegistry::~InitDataRegistry() = default;
+
+RefPtr<SharedBuffer> InitDataRegistry::sanitizeInitData(const AtomicString& initDataType, const SharedBuffer& buffer)
+{
+    auto iter = m_types.find(initDataType);
+    if (iter == m_types.end() || !iter->value.sanitizeInitData)
+        return nullptr;
+    return iter->value.sanitizeInitData(buffer);
+}
+
+Vector<Ref<SharedBuffer>> InitDataRegistry::extractKeyIDs(const AtomicString& initDataType, const SharedBuffer& buffer)
+{
+    auto iter = m_types.find(initDataType);
+    if (iter == m_types.end() || !iter->value.sanitizeInitData)
+        return { };
+    return iter->value.extractKeyIDs(buffer);
+}
+
+void InitDataRegistry::registerInitDataType(const AtomicString& initDataType, InitDataTypeCallbacks&& callbacks)
+{
+    ASSERT(!m_types.contains(initDataType));
+    m_types.set(initDataType, WTFMove(callbacks));
+}
+
+}
+
+#endif // ENABLE(ENCRYPTED_MEDIA)

Copied: trunk/Source/WebCore/Modules/encryptedmedia/InitDataRegistry.h (from rev 210554, trunk/Source/WebCore/Modules/encryptedmedia/CDMInstance.h) (0 => 210555)


--- trunk/Source/WebCore/Modules/encryptedmedia/InitDataRegistry.h	                        (rev 0)
+++ trunk/Source/WebCore/Modules/encryptedmedia/InitDataRegistry.h	2017-01-10 20:09:21 UTC (rev 210555)
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(ENCRYPTED_MEDIA)
+
+#include <wtf/Function.h>
+#include <wtf/HashMap.h>
+#include <wtf/Ref.h>
+#include <wtf/RefPtr.h>
+#include <wtf/Vector.h>
+#include <wtf/text/AtomicString.h>
+#include <wtf/text/AtomicStringHash.h>
+
+namespace WebCore {
+
+class SharedBuffer;
+
+class InitDataRegistry {
+public:
+    WEBCORE_EXPORT static InitDataRegistry& shared();
+    friend class NeverDestroyed<InitDataRegistry>;
+
+    RefPtr<SharedBuffer> sanitizeInitData(const AtomicString& initDataType, const SharedBuffer&);
+    WEBCORE_EXPORT Vector<Ref<SharedBuffer>> extractKeyIDs(const AtomicString& initDataType, const SharedBuffer&);
+
+    struct InitDataTypeCallbacks {
+        using SanitizeInitDataCallback = Function<RefPtr<SharedBuffer>(const SharedBuffer&)>;
+        using ExtractKeyIDsCallback = Function<Vector<Ref<SharedBuffer>>(const SharedBuffer&)>;
+
+        SanitizeInitDataCallback sanitizeInitData;
+        ExtractKeyIDsCallback extractKeyIDs;
+    };
+    void registerInitDataType(const AtomicString& initDataType, InitDataTypeCallbacks&&);
+
+private:
+    InitDataRegistry();
+    ~InitDataRegistry();
+
+    HashMap<AtomicString, InitDataTypeCallbacks> m_types;
+};
+
+}
+
+#endif // ENABLE(ENCRYPTED_MEDIA)

Modified: trunk/Source/WebCore/Modules/encryptedmedia/MediaKeySession.cpp (210554 => 210555)


--- trunk/Source/WebCore/Modules/encryptedmedia/MediaKeySession.cpp	2017-01-10 19:13:06 UTC (rev 210554)
+++ trunk/Source/WebCore/Modules/encryptedmedia/MediaKeySession.cpp	2017-01-10 20:09:21 UTC (rev 210555)
@@ -33,11 +33,21 @@
 
 #include "CDM.h"
 #include "CDMInstance.h"
+#include "MediaKeyMessageEvent.h"
+#include "MediaKeyMessageType.h"
 #include "MediaKeyStatusMap.h"
 #include "NotImplemented.h"
+#include "SharedBuffer.h"
+#include <wtf/NeverDestroyed.h>
 
 namespace WebCore {
 
+static AtomicString& messageEventName()
+{
+    NeverDestroyed<AtomicString> message { "message" };
+    return message.get();
+}
+
 Ref<MediaKeySession> MediaKeySession::create(ScriptExecutionContext& context, MediaKeySessionType sessionType, bool useDistinctiveIdentifier, Ref<CDM>&& implementation, Ref<CDMInstance>&& instance)
 {
     auto session = adoptRef(*new MediaKeySession(context, sessionType, useDistinctiveIdentifier, WTFMove(implementation), WTFMove(instance)));
@@ -53,6 +63,8 @@
     , m_sessionType(sessionType)
     , m_implementation(WTFMove(implementation))
     , m_instance(WTFMove(instance))
+    , m_eventQueue(*this)
+    , m_weakPtrFactory(this)
 {
     // https://w3c.github.io/encrypted-media/#dom-mediakeys-setservercertificate
     // W3C Editor's Draft 09 November 2016
@@ -94,9 +106,143 @@
     return m_keyStatuses.copyRef();
 }
 
-void MediaKeySession::generateRequest(const String&, const BufferSource&, Ref<DeferredPromise>&&)
+void MediaKeySession::generateRequest(const AtomicString& initDataType, const BufferSource& initData, Ref<DeferredPromise>&& promise)
 {
-    notImplemented();
+    // https://w3c.github.io/encrypted-media/#dom-mediakeysession-generaterequest
+    // W3C Editor's Draft 09 November 2016
+
+    // When this method is invoked, the user agent must run the following steps:
+    // 1. If this object is closed, return a promise rejected with an InvalidStateError.
+    // 2. If this object's uninitialized value is false, return a promise rejected with an InvalidStateError.
+    if (m_closed || !m_uninitialized) {
+        promise->reject(INVALID_STATE_ERR);
+        return;
+    }
+
+    // 3. Let this object's uninitialized value be false.
+    m_uninitialized = false;
+
+    // 4. If initDataType is the empty string, return a promise rejected with a newly created TypeError.
+    // 5. If initData is an empty array, return a promise rejected with a newly created TypeError.
+    if (initDataType.isEmpty() || !initData.length()) {
+        promise->reject(TypeError);
+        return;
+    }
+
+    // 6. If the Key System implementation represented by this object's cdm implementation value does not support
+    //    initDataType as an Initialization Data Type, return a promise rejected with a NotSupportedError. String
+    //    comparison is case-sensitive.
+    if (!m_implementation->supportsInitDataType(initDataType)) {
+        promise->reject(NOT_SUPPORTED_ERR);
+        return;
+    }
+
+    // 7. Let init data be a copy of the contents of the initData parameter.
+    // 8. Let session type be this object's session type.
+    // 9. Let promise be a new promise.
+    // 10. Run the following steps in parallel:
+    m_taskQueue.enqueueTask([this, initData = SharedBuffer::create(initData.data(), initData.length()), initDataType, promise = WTFMove(promise)] () mutable {
+        // 10.1. If the init data is not valid for initDataType, reject promise with a newly created TypeError.
+        // 10.2. Let sanitized init data be a validated and sanitized version of init data.
+        RefPtr<SharedBuffer> sanitizedInitData = m_implementation->sanitizeInitData(initDataType, initData);
+
+        // 10.3. If the preceding step failed, reject promise with a newly created TypeError.
+        if (!sanitizedInitData) {
+            promise->reject(TypeError);
+            return;
+        }
+
+        // 10.4. If sanitized init data is empty, reject promise with a NotSupportedError.
+        if (sanitizedInitData->isEmpty()) {
+            promise->reject(NOT_SUPPORTED_ERR);
+            return;
+        }
+
+        // 10.5. Let session id be the empty string.
+        // 10.6. Let message be null.
+        // 10.7. Let message type be null.
+        // 10.8. Let cdm be the CDM instance represented by this object's cdm instance value.
+        // 10.9. Use the cdm to execute the following steps:
+        // 10.9.1. If the sanitized init data is not supported by the cdm, reject promise with a NotSupportedError.
+        if (!m_implementation->supportsInitData(initDataType, *sanitizedInitData)) {
+            promise->reject(NOT_SUPPORTED_ERR);
+            return;
+        }
+
+        // 10.9.2 Follow the steps for the value of session type from the following list:
+        CDMInstance::LicenseType requestedLicenseType;
+        switch (m_sessionType) {
+        case MediaKeySessionType::Temporary:
+            // ↳ "temporary"
+            // Let requested license type be a temporary non-persistable license.
+            requestedLicenseType = CDMInstance::LicenseType::Temporary;
+            break;
+        case MediaKeySessionType::PersistentLicense:
+            // ↳ "persistent-license"
+            // Let requested license type be a persistable license.
+            requestedLicenseType = CDMInstance::LicenseType::Persistable;
+            break;
+        case MediaKeySessionType::PersistentUsageRecord:
+            // ↳ "persistent-usage-record"
+            // 1. Initialize this object's record of key usage as follows.
+            //    Set the list of key IDs known to the session to an empty list.
+            m_recordOfKeyUsage.clear();
+
+            //    Set the first decrypt time to null.
+            m_firstDecryptTime = 0;
+
+            //    Set the latest decrypt time to null.
+            m_latestDecryptTime = 0;
+
+            // 2. Let requested license type be a non-persistable license that will
+            //    persist a record of key usage.
+            requestedLicenseType = CDMInstance::LicenseType::UsageRecord;
+            break;
+        }
+
+        m_instance->requestLicense(requestedLicenseType, initDataType, WTFMove(initData), [this, weakThis = m_weakPtrFactory.createWeakPtr(), promise = WTFMove(promise)] (Ref<SharedBuffer>&& message, const String& sessionId, bool needsIndividualization, CDMInstance::SuccessValue succeeded) mutable {
+            if (!weakThis)
+                return;
+
+            // 10.9.3. Let session id be a unique Session ID string.
+
+            MediaKeyMessageType messageType;
+            if (!needsIndividualization) {
+                // 10.9.4. If a license request for the requested license type can be generated based on the sanitized init data:
+                // 10.9.4.1. Let message be a license request for the requested license type generated based on the sanitized init data interpreted per initDataType.
+                // 10.9.4.2. Let message type be "license-request".
+                messageType = MediaKeyMessageType::LicenseRequest;
+            } else {
+                // 10.9.5. Otherwise:
+                // 10.9.5.1. Let message be the request that needs to be processed before a license request request for the requested license
+                //           type can be generated based on the sanitized init data.
+                // 10.9.5.2. Let message type reflect the type of message, either "license-request" or "individualization-request".
+                messageType = MediaKeyMessageType::IndividualizationRequest;
+            }
+
+            // 10.10. Queue a task to run the following steps:
+            m_taskQueue.enqueueTask([this, promise = WTFMove(promise), message = WTFMove(message), messageType, sessionId, succeeded] () mutable {
+                // 10.10.1. If any of the preceding steps failed, reject promise with a new DOMException whose name is the appropriate error name.
+                if (succeeded == CDMInstance::SuccessValue::Failed) {
+                    promise->reject(NOT_SUPPORTED_ERR);
+                    return;
+                }
+                // 10.10.2. Set the sessionId attribute to session id.
+                m_sessionId = sessionId;
+
+                // 10.9.3. Let this object's callable value be true.
+                m_callable = true;
+
+                // 10.9.3. Run the Queue a "message" Event algorithm on the session, providing message type and message.
+                enqueueMessage(messageType, message);
+
+                // 10.9.3. Resolve promise.
+                promise->resolve();
+            });
+        });
+    });
+
+    // 11. Return promise.
 }
 
 void MediaKeySession::load(const String&, Ref<DeferredPromise>&&)
@@ -119,6 +265,21 @@
     notImplemented();
 }
 
+void MediaKeySession::enqueueMessage(MediaKeyMessageType messageType, const SharedBuffer& message)
+{
+    // 6.4.1 Queue a "message" Event
+    // https://w3c.github.io/encrypted-media/#queue-message
+    // W3C Editor's Draft 09 November 2016
+
+    // The following steps are run:
+    // 1. Let the session be the specified MediaKeySession object.
+    // 2. Queue a task to create an event named message that does not bubble and is not cancellable using the MediaKeyMessageEvent
+    //    interface with its type attribute set to message and its isTrusted attribute initialized to true, and dispatch it at the
+    //    session.
+    auto messageEvent = MediaKeyMessageEvent::create(messageEventName(), {messageType, message.createArrayBuffer()}, Event::IsTrusted::Yes);
+    m_eventQueue.enqueueEvent(WTFMove(messageEvent));
+}
+
 bool MediaKeySession::hasPendingActivity() const
 {
     notImplemented();

Modified: trunk/Source/WebCore/Modules/encryptedmedia/MediaKeySession.h (210554 => 210555)


--- trunk/Source/WebCore/Modules/encryptedmedia/MediaKeySession.h	2017-01-10 19:13:06 UTC (rev 210554)
+++ trunk/Source/WebCore/Modules/encryptedmedia/MediaKeySession.h	2017-01-10 20:09:21 UTC (rev 210555)
@@ -33,9 +33,13 @@
 #include "ActiveDOMObject.h"
 #include "EventTarget.h"
 #include "GenericEventQueue.h"
+#include "GenericTaskQueue.h"
 #include "JSDOMPromise.h"
+#include "MediaKeyMessageType.h"
 #include "MediaKeySessionType.h"
 #include <wtf/RefCounted.h>
+#include <wtf/Vector.h>
+#include <wtf/WeakPtr.h>
 #include <wtf/text/WTFString.h>
 
 namespace WebCore {
@@ -45,6 +49,7 @@
 class CDMInstance;
 class MediaKeyStatusMap;
 class MediaKeys;
+class SharedBuffer;
 
 class MediaKeySession final : public RefCounted<MediaKeySession>, public EventTargetWithInlineData, public ActiveDOMObject {
 public:
@@ -58,7 +63,7 @@
     double expiration() const;
     Ref<MediaKeyStatusMap> keyStatuses() const;
 
-    void generateRequest(const String&, const BufferSource&, Ref<DeferredPromise>&&);
+    void generateRequest(const AtomicString&, const BufferSource&, Ref<DeferredPromise>&&);
     void load(const String&, Ref<DeferredPromise>&&);
     void update(const BufferSource&, Ref<DeferredPromise>&&);
     void close(Ref<DeferredPromise>&&);
@@ -66,6 +71,7 @@
 
 private:
     MediaKeySession(ScriptExecutionContext&, MediaKeySessionType, bool useDistinctiveIdentifier, Ref<CDM>&&, Ref<CDMInstance>&&);
+    void enqueueMessage(MediaKeyMessageType, const SharedBuffer&);
 
     // EventTarget
     EventTargetInterface eventTargetInterface() const override { return MediaKeySessionEventTargetInterfaceType; }
@@ -89,6 +95,12 @@
     MediaKeySessionType m_sessionType;
     Ref<CDM> m_implementation;
     Ref<CDMInstance> m_instance;
+    GenericEventQueue m_eventQueue;
+    GenericTaskQueue<Timer> m_taskQueue;
+    Vector<Ref<SharedBuffer>> m_recordOfKeyUsage;
+    double m_firstDecryptTime { 0 };
+    double m_latestDecryptTime { 0 };
+    WeakPtrFactory<MediaKeySession> m_weakPtrFactory;
 };
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/Modules/encryptedmedia/MediaKeys.cpp (210554 => 210555)


--- trunk/Source/WebCore/Modules/encryptedmedia/MediaKeys.cpp	2017-01-10 19:13:06 UTC (rev 210554)
+++ trunk/Source/WebCore/Modules/encryptedmedia/MediaKeys.cpp	2017-01-10 20:09:21 UTC (rev 210555)
@@ -35,7 +35,7 @@
 #include "CDMInstance.h"
 #include "MediaKeySession.h"
 #include "NotImplemented.h"
-#include <runtime/ArrayBuffer.h>
+#include "SharedBuffer.h"
 
 namespace WebCore {
 
@@ -90,7 +90,7 @@
     }
 
     // 3. Let certificate be a copy of the contents of the serverCertificate parameter.
-    auto certificate = ArrayBuffer::create(serverCertificate.data(), serverCertificate.length());
+    auto certificate = SharedBuffer::create(serverCertificate.data(), serverCertificate.length());
 
     // 4. Let promise be a new promise.
     // 5. Run the following steps in parallel:
@@ -97,7 +97,7 @@
 
     m_taskQueue.enqueueTask([this, certificate = WTFMove(certificate), promise = WTFMove(promise)] () mutable {
         // 5.1. Use this object's cdm instance to process certificate.
-        if (m_instance->setServerCertificate(certificate) == CDMInstance::Failed) {
+        if (m_instance->setServerCertificate(WTFMove(certificate)) == CDMInstance::Failed) {
             // 5.2. If the preceding step failed, resolve promise with a new DOMException whose name is the appropriate error name.
             promise->reject(INVALID_STATE_ERR);
             return;

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (210554 => 210555)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2017-01-10 19:13:06 UTC (rev 210554)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2017-01-10 20:09:21 UTC (rev 210555)
@@ -5717,6 +5717,8 @@
 		CCC2B51415F613060048CDD6 /* DeviceClient.h in Headers */ = {isa = PBXBuildFile; fileRef = CCC2B51015F613060048CDD6 /* DeviceClient.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		CCC2B51515F613060048CDD6 /* DeviceController.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CCC2B51115F613060048CDD6 /* DeviceController.cpp */; };
 		CCC2B51615F613060048CDD6 /* DeviceController.h in Headers */ = {isa = PBXBuildFile; fileRef = CCC2B51215F613060048CDD6 /* DeviceController.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		CD063F821E23FA8900812BE3 /* InitDataRegistry.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CD063F801E23FA8900812BE3 /* InitDataRegistry.cpp */; };
+		CD063F831E23FA8900812BE3 /* InitDataRegistry.h in Headers */ = {isa = PBXBuildFile; fileRef = CD063F811E23FA8900812BE3 /* InitDataRegistry.h */; };
 		CD0EEE0E14743F39003EAFA2 /* AudioDestinationIOS.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CD0EEE0B14743E35003EAFA2 /* AudioDestinationIOS.cpp */; };
 		CD127DED14F3097D00E84779 /* WebCoreFullScreenWindow.mm in Sources */ = {isa = PBXBuildFile; fileRef = CD127DEB14F3097900E84779 /* WebCoreFullScreenWindow.mm */; };
 		CD127DEE14F3098400E84779 /* WebCoreFullScreenWindow.h in Headers */ = {isa = PBXBuildFile; fileRef = CD127DEA14F3097900E84779 /* WebCoreFullScreenWindow.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -13643,6 +13645,8 @@
 		CCC2B51015F613060048CDD6 /* DeviceClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DeviceClient.h; sourceTree = "<group>"; };
 		CCC2B51115F613060048CDD6 /* DeviceController.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DeviceController.cpp; sourceTree = "<group>"; };
 		CCC2B51215F613060048CDD6 /* DeviceController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DeviceController.h; sourceTree = "<group>"; };
+		CD063F801E23FA8900812BE3 /* InitDataRegistry.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InitDataRegistry.cpp; sourceTree = "<group>"; };
+		CD063F811E23FA8900812BE3 /* InitDataRegistry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InitDataRegistry.h; sourceTree = "<group>"; };
 		CD0EEE0A14743E34003EAFA2 /* AudioDestinationIOS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AudioDestinationIOS.h; sourceTree = "<group>"; };
 		CD0EEE0B14743E35003EAFA2 /* AudioDestinationIOS.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AudioDestinationIOS.cpp; sourceTree = "<group>"; };
 		CD127DEA14F3097900E84779 /* WebCoreFullScreenWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebCoreFullScreenWindow.h; sourceTree = "<group>"; };
@@ -22773,6 +22777,8 @@
 				CDF4B7141E00B7E500E235A2 /* CDM.h */,
 				CD9D05421E1EFA12003B4C4F /* CDMInstance.h */,
 				CDF4B7251E03C15B00E235A2 /* CDMPrivate.h */,
+				CD063F801E23FA8900812BE3 /* InitDataRegistry.cpp */,
+				CD063F811E23FA8900812BE3 /* InitDataRegistry.h */,
 				2D9BF72F1DBFDC0F007A7D99 /* MediaKeyMessageEvent.cpp */,
 				2D9BF7301DBFDC0F007A7D99 /* MediaKeyMessageEvent.h */,
 				2D9BF6F51DBFB71F007A7D99 /* MediaKeyMessageEvent.idl */,
@@ -27867,6 +27873,7 @@
 				7CE58D501DD69A1E00128552 /* SVGNumber.h in Headers */,
 				B2227A510D00BF220071B782 /* SVGNumberList.h in Headers */,
 				B2227A570D00BF220071B782 /* SVGParserUtilities.h in Headers */,
+				CD063F831E23FA8900812BE3 /* InitDataRegistry.h in Headers */,
 				2D3A0E3613A7D76100E85AF0 /* SVGParsingError.h in Headers */,
 				84C6784D1214814700A92902 /* SVGPathBlender.h in Headers */,
 				8476C9EB11DF6A2900555B02 /* SVGPathBuilder.h in Headers */,
@@ -30820,6 +30827,7 @@
 				B27535630B053814002CE64F /* PathCG.cpp in Sources */,
 				A88DD4890B4629B000C02990 /* PathTraversalState.cpp in Sources */,
 				2D5002FB1B56D7990020AAF7 /* PathUtilities.cpp in Sources */,
+				CD063F821E23FA8900812BE3 /* InitDataRegistry.cpp in Sources */,
 				A8FA6E5E0E4CFDED00D5CF49 /* Pattern.cpp in Sources */,
 				A80A38FE0E50CC8200A25EBC /* PatternCG.cpp in Sources */,
 				1A8A646C1D19FF8700D0E00F /* PaymentCocoa.mm in Sources */,

Modified: trunk/Source/WebCore/testing/MockCDMFactory.cpp (210554 => 210555)


--- trunk/Source/WebCore/testing/MockCDMFactory.cpp	2017-01-10 19:13:06 UTC (rev 210554)
+++ trunk/Source/WebCore/testing/MockCDMFactory.cpp	2017-01-10 20:09:21 UTC (rev 210555)
@@ -28,7 +28,10 @@
 
 #if ENABLE(ENCRYPTED_MEDIA)
 
+#include "InitDataRegistry.h"
+#include "UUID.h"
 #include <runtime/ArrayBuffer.h>
+#include <wtf/text/StringHash.h>
 #include <wtf/text/StringView.h>
 
 namespace WebCore {
@@ -58,6 +61,24 @@
     return equalIgnoringASCIICase(keySystem, "org.webkit.mock");
 }
 
+void MockCDMFactory::addKeysToSessionWithID(const String& id, Vector<Ref<SharedBuffer>>&& keys)
+{
+    auto addResult = m_sessions.add(id, WTFMove(keys));
+    if (addResult.isNewEntry)
+        return;
+
+    auto& value = addResult.iterator->value;
+    for (auto& key : keys)
+        value.append(WTFMove(key));
+}
+
+void MockCDMFactory::setSupportedDataTypes(Vector<String>&& types)
+{
+    m_supportedDataTypes.clear();
+    for (auto& type : types)
+        m_supportedDataTypes.append(type);
+}
+
 std::unique_ptr<CDMPrivate> MockCDMFactory::createCDM(CDM&)
 {
     return std::make_unique<MockCDM>(m_weakPtrFactory.createWeakPtr());
@@ -69,7 +90,7 @@
 {
 }
 
-bool MockCDM::supportsInitDataType(const String& initDataType)
+bool MockCDM::supportsInitDataType(const AtomicString& initDataType) const
 {
     if (m_factory)
         return m_factory->supportedDataTypes().contains(initDataType);
@@ -76,7 +97,7 @@
     return false;
 }
 
-bool MockCDM::supportsConfiguration(const MediaKeySystemConfiguration&)
+bool MockCDM::supportsConfiguration(const MediaKeySystemConfiguration&) const
 {
     // NOTE: Implement;
     return true;
@@ -83,13 +104,13 @@
 
 }
 
-bool MockCDM::supportsConfigurationWithRestrictions(const MediaKeySystemConfiguration&, const MediaKeysRestrictions&)
+bool MockCDM::supportsConfigurationWithRestrictions(const MediaKeySystemConfiguration&, const MediaKeysRestrictions&) const
 {
     // NOTE: Implement;
     return true;
 }
 
-bool MockCDM::supportsSessionTypeWithConfiguration(MediaKeySessionType& sessionType, const MediaKeySystemConfiguration&)
+bool MockCDM::supportsSessionTypeWithConfiguration(MediaKeySessionType& sessionType, const MediaKeySystemConfiguration&) const
 {
     if (!m_factory || !m_factory->supportedSessionTypes().contains(sessionType))
         return false;
@@ -98,7 +119,7 @@
     return true;
 }
 
-bool MockCDM::supportsRobustness(const String& robustness)
+bool MockCDM::supportsRobustness(const String& robustness) const
 {
     if (m_factory)
         return m_factory->supportedRobustness().contains(robustness);
@@ -105,7 +126,7 @@
     return false;
 }
 
-MediaKeysRequirement MockCDM::distinctiveIdentifiersRequirement(const MediaKeySystemConfiguration&, const MediaKeysRestrictions&)
+MediaKeysRequirement MockCDM::distinctiveIdentifiersRequirement(const MediaKeySystemConfiguration&, const MediaKeysRestrictions&) const
 {
     if (m_factory)
         return m_factory->distinctiveIdentifiersRequirement();
@@ -112,7 +133,7 @@
     return MediaKeysRequirement::Optional;
 }
 
-MediaKeysRequirement MockCDM::persistentStateRequirement(const MediaKeySystemConfiguration&, const MediaKeysRestrictions&)
+MediaKeysRequirement MockCDM::persistentStateRequirement(const MediaKeySystemConfiguration&, const MediaKeysRestrictions&) const
 {
     if (m_factory)
         return m_factory->persistentStateRequirement();
@@ -119,7 +140,7 @@
     return MediaKeysRequirement::Optional;
 }
 
-bool MockCDM::distinctiveIdentifiersAreUniquePerOriginAndClearable(const MediaKeySystemConfiguration&)
+bool MockCDM::distinctiveIdentifiersAreUniquePerOriginAndClearable(const MediaKeySystemConfiguration&) const
 {
     // NOTE: Implement;
     return true;
@@ -147,6 +168,15 @@
     return m_factory && m_factory->supportsSessions();
 }
 
+bool MockCDM::supportsInitData(const AtomicString& initDataType, const SharedBuffer& initData) const
+{
+    if (!supportsInitDataType(initDataType))
+        return false;
+
+    UNUSED_PARAM(initData);
+    return true;
+}
+
 MockCDMInstance::MockCDMInstance(WeakPtr<MockCDM> cdm)
     : m_cdm(cdm)
 {
@@ -188,9 +218,9 @@
     return Succeeded;
 }
 
-CDMInstance::SuccessValue MockCDMInstance::setServerCertificate(ArrayBuffer& certificate)
+CDMInstance::SuccessValue MockCDMInstance::setServerCertificate(Ref<SharedBuffer>&& certificate)
 {
-    StringView certificateStringView(static_cast<const LChar*>(certificate.data()), certificate.byteLength());
+    StringView certificateStringView(reinterpret_cast<const LChar*>(certificate->data()), certificate->size());
 
     if (equalIgnoringASCIICase(certificateStringView, "valid"))
         return Succeeded;
@@ -197,6 +227,35 @@
     return Failed;
 }
 
+void MockCDMInstance::requestLicense(LicenseType licenseType, const AtomicString& initDataType, Ref<SharedBuffer>&& initData, LicenseCallback callback)
+{
+    MockCDMFactory* factory = m_cdm ? m_cdm->factory() : nullptr;
+    if (!factory) {
+        callback(SharedBuffer::create(), emptyAtom, false, SuccessValue::Failed);
+        return;
+    }
+
+    if ((licenseType == LicenseType::Temporary && !factory->supportedSessionTypes().contains(MediaKeySessionType::Temporary))
+        || (licenseType == LicenseType::Persistable && !factory->supportedSessionTypes().contains(MediaKeySessionType::PersistentLicense))
+        || (licenseType == LicenseType::UsageRecord && !factory->supportedSessionTypes().contains(MediaKeySessionType::PersistentUsageRecord))
+        || !factory->supportedDataTypes().contains(initDataType)) {
+        callback(SharedBuffer::create(), emptyString(), false, SuccessValue::Failed);
+        return;
+    }
+
+    auto keyIDs = InitDataRegistry::shared().extractKeyIDs(initDataType, initData);
+    if (keyIDs.isEmpty()) {
+        callback(SharedBuffer::create(), emptyString(), false, SuccessValue::Failed);
+        return;
+    }
+
+    String sessionID = createCanonicalUUIDString();
+    factory->addKeysToSessionWithID(sessionID, WTFMove(keyIDs));
+
+    CString license { "license" };
+    callback(SharedBuffer::create(license.data(), license.length()), sessionID, false, SuccessValue::Succeeded);
 }
 
+}
+
 #endif

Modified: trunk/Source/WebCore/testing/MockCDMFactory.h (210554 => 210555)


--- trunk/Source/WebCore/testing/MockCDMFactory.h	2017-01-10 19:13:06 UTC (rev 210554)
+++ trunk/Source/WebCore/testing/MockCDMFactory.h	2017-01-10 20:09:21 UTC (rev 210555)
@@ -31,6 +31,7 @@
 #include "CDMInstance.h"
 #include "CDMPrivate.h"
 #include "MediaKeysRequirement.h"
+#include <wtf/HashMap.h>
 #include <wtf/RefCounted.h>
 #include <wtf/Vector.h>
 #include <wtf/WeakPtr.h>
@@ -42,8 +43,8 @@
     static Ref<MockCDMFactory> create() { return adoptRef(*new MockCDMFactory); }
     ~MockCDMFactory();
 
-    const Vector<String>& supportedDataTypes() const { return m_supportedDataTypes; }
-    void setSupportedDataTypes(Vector<String>&& types) { m_supportedDataTypes = WTFMove(types); }
+    const Vector<AtomicString>& supportedDataTypes() const { return m_supportedDataTypes; }
+    void setSupportedDataTypes(Vector<String>&&);
 
     const Vector<MediaKeySessionType>& supportedSessionTypes() const { return m_supportedSessionTypes; }
     void setSupportedSessionTypes(Vector<MediaKeySessionType>&& types) { m_supportedSessionTypes = WTFMove(types); }
@@ -68,6 +69,10 @@
 
     void unregister();
 
+    bool hasSessionWithID(const String& id) { return m_sessions.contains(id); }
+    void removeSessionWithID(const String& id) { m_sessions.remove(id); }
+    void addKeysToSessionWithID(const String& id, Vector<Ref<SharedBuffer>>&&);
+
 private:
     MockCDMFactory();
     std::unique_ptr<CDMPrivate> createCDM(CDM&) final;
@@ -75,7 +80,7 @@
 
     MediaKeysRequirement m_distinctiveIdentifiersRequirement { MediaKeysRequirement::Optional };
     MediaKeysRequirement m_persistentStateRequirement { MediaKeysRequirement::Optional };
-    Vector<String> m_supportedDataTypes;
+    Vector<AtomicString> m_supportedDataTypes;
     Vector<MediaKeySessionType> m_supportedSessionTypes;
     Vector<String> m_supportedRobustness;
     bool m_registered { true };
@@ -83,6 +88,7 @@
     bool m_supportsServerCertificates { true };
     bool m_supportsSessions { true };
     WeakPtrFactory<MockCDMFactory> m_weakPtrFactory;
+    HashMap<String, Vector<Ref<SharedBuffer>>> m_sessions;
 };
 
 class MockCDM : public CDMPrivate {
@@ -94,18 +100,19 @@
 private:
     friend class MockCDMInstance;
 
-    bool supportsInitDataType(const String&) final;
-    bool supportsConfiguration(const MediaKeySystemConfiguration&) final;
-    bool supportsConfigurationWithRestrictions(const MediaKeySystemConfiguration&, const MediaKeysRestrictions&) final;
-    bool supportsSessionTypeWithConfiguration(MediaKeySessionType&, const MediaKeySystemConfiguration&) final;
-    bool supportsRobustness(const String&) final;
-    MediaKeysRequirement distinctiveIdentifiersRequirement(const MediaKeySystemConfiguration&, const MediaKeysRestrictions&) final;
-    MediaKeysRequirement persistentStateRequirement(const MediaKeySystemConfiguration&, const MediaKeysRestrictions&) final;
-    bool distinctiveIdentifiersAreUniquePerOriginAndClearable(const MediaKeySystemConfiguration&) final;
+    bool supportsInitDataType(const AtomicString&) const final;
+    bool supportsConfiguration(const MediaKeySystemConfiguration&) const final;
+    bool supportsConfigurationWithRestrictions(const MediaKeySystemConfiguration&, const MediaKeysRestrictions&) const final;
+    bool supportsSessionTypeWithConfiguration(MediaKeySessionType&, const MediaKeySystemConfiguration&) const final;
+    bool supportsRobustness(const String&) const final;
+    MediaKeysRequirement distinctiveIdentifiersRequirement(const MediaKeySystemConfiguration&, const MediaKeysRestrictions&) const final;
+    MediaKeysRequirement persistentStateRequirement(const MediaKeySystemConfiguration&, const MediaKeysRestrictions&) const final;
+    bool distinctiveIdentifiersAreUniquePerOriginAndClearable(const MediaKeySystemConfiguration&) const final;
     RefPtr<CDMInstance> createInstance() final;
     void loadAndInitialize() final;
     bool supportsServerCertificates() const final;
     bool supportsSessions() const final;
+    bool supportsInitData(const AtomicString&, const SharedBuffer&) const final;
 
     WeakPtr<MockCDMFactory> m_factory;
     WeakPtrFactory<MockCDM> m_weakPtrFactory;
@@ -119,7 +126,8 @@
     SuccessValue initializeWithConfiguration(const MediaKeySystemConfiguration&) final;
     SuccessValue setDistinctiveIdentifiersAllowed(bool) final;
     SuccessValue setPersistentStateAllowed(bool) final;
-    SuccessValue setServerCertificate(JSC::ArrayBuffer&) final;
+    SuccessValue setServerCertificate(Ref<SharedBuffer>&&) final;
+    void requestLicense(LicenseType, const AtomicString& initDataType, Ref<SharedBuffer>&& initData, LicenseCallback) final;
 
     WeakPtr<MockCDM> m_cdm;
     bool m_distinctiveIdentifiersAllowed { true };
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to