Title: [211550] trunk
Revision
211550
Author
zandober...@gmail.com
Date
2017-02-01 22:28:03 -0800 (Wed, 01 Feb 2017)

Log Message

[EME] Implement MediaKeySession::update()
https://bugs.webkit.org/show_bug.cgi?id=167636

Reviewed by Xabier Rodriguez-Calvar.

Source/WebCore:

Implement the MediaKeySession::update() method by following the steps as
they are described in the specification.

In order to sanitize the passed-in response data, CDM::sanitizeResponse()
is added. It passes the SharedBuffer object by reference to the CDMPrivate
interface implementor, which returns a SharedBuffer object containing
sanitized response data.

CDMInstance::updateLicense() virtual method is added to perform the license
update for some specific CDMInstance object. After the update the CDMInstance
invokes the callback that's passed to updateLicense(), providing information
about session being closed, changed keys or expiration value, any message
that has to be enqueued, and whether the update was successful.

After that callback is invoked, MediaKeySession::update() goes on to handle
all the provided information in a future task, finally resolving the promise
(or rejecting it beforehand in case of any failure during response handling
or license update).

Three algorithms that can be invoked from MediaKeySession::update() (key
status update, expiration update and session closure) will be implemented
separately. Placeholder methods are provided until then.

MockCDM::sanitizeResponse() and MockCDMInstance::updateLicense() are
implemented for testing purposes. For now only the response sanitization
and sanitized response format are checked there. Key status update,
expiration update and session closure should be tested once the
implementations for those algorithms are added.

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

* Modules/encryptedmedia/CDM.cpp:
(WebCore::CDM::sanitizeResponse):
* Modules/encryptedmedia/CDM.h:
* Modules/encryptedmedia/CDMInstance.h:
* Modules/encryptedmedia/CDMPrivate.h:
* Modules/encryptedmedia/MediaKeySession.cpp:
(WebCore::MediaKeySession::update):
(WebCore::MediaKeySession::updateKeyStatuses):
(WebCore::MediaKeySession::updateExpiration):
(WebCore::MediaKeySession::sessionClosed):
* Modules/encryptedmedia/MediaKeySession.h:
* testing/MockCDMFactory.cpp:
(WebCore::MockCDM::sanitizeResponse):
(WebCore::MockCDMInstance::updateLicense):
* testing/MockCDMFactory.h:

LayoutTests:

Add the mock-MediaKeySession-update.html test, cotaining a few cases that check
the basic operations of MediaKeySession::update(), focusing on proper promise
resolution and rejection based on the state of the object and the passed-in
response argument. Skip the test on all platforms for now.

* media/encrypted-media/mock-MediaKeySession-update-expected.txt: Added.
* media/encrypted-media/mock-MediaKeySession-update.html: Added.
* platform/efl/TestExpectations:
* platform/mac/TestExpectations:

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (211549 => 211550)


--- trunk/LayoutTests/ChangeLog	2017-02-02 03:10:58 UTC (rev 211549)
+++ trunk/LayoutTests/ChangeLog	2017-02-02 06:28:03 UTC (rev 211550)
@@ -1,3 +1,20 @@
+2017-02-01  Zan Dobersek  <zdober...@igalia.com>
+
+        [EME] Implement MediaKeySession::update()
+        https://bugs.webkit.org/show_bug.cgi?id=167636
+
+        Reviewed by Xabier Rodriguez-Calvar.
+
+        Add the mock-MediaKeySession-update.html test, cotaining a few cases that check
+        the basic operations of MediaKeySession::update(), focusing on proper promise
+        resolution and rejection based on the state of the object and the passed-in
+        response argument. Skip the test on all platforms for now.
+
+        * media/encrypted-media/mock-MediaKeySession-update-expected.txt: Added.
+        * media/encrypted-media/mock-MediaKeySession-update.html: Added.
+        * platform/efl/TestExpectations:
+        * platform/mac/TestExpectations:
+
 2017-02-01  Ryan Haddad  <ryanhad...@apple.com>
 
         Rebaseline compositing/geometry/fixed-in-composited.html for ios-simulator.

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


--- trunk/LayoutTests/media/encrypted-media/mock-MediaKeySession-update-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/media/encrypted-media/mock-MediaKeySession-update-expected.txt	2017-02-02 06:28:03 UTC (rev 211550)
@@ -0,0 +1,50 @@
+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 a non-callable MediaKeySession should reject.
+RUN(mediaKeySession = mediaKeys.createSession("temporary"))
+EXPECTED (typeof mediaKeySession == 'object') OK
+RUN(promise = mediaKeySession.update(stringToUInt8Array("invalid-state")))
+Promise rejected correctly OK
+
+Using a zero-length response should reject.
+RUN(kids = JSON.stringify({ kids: [ "MTIzNDU=" ] }))
+RUN(mediaKeySession = mediaKeys.createSession("temporary"))
+RUN(promise = mediaKeySession.generateRequest("keyids", stringToUInt8Array(kids)))
+Promise resolved OK
+RUN(promise = mediaKeySession.update(new Uint8Array(0)))
+Promise rejected correctly OK
+
+Using a non-sanitizable response should reject.
+RUN(kids = JSON.stringify({ kids: [ "MTIzNDU=" ] }))
+RUN(mediaKeySession = mediaKeys.createSession("temporary"))
+RUN(promise = mediaKeySession.generateRequest("keyids", stringToUInt8Array(kids)))
+Promise resolved OK
+RUN(promise = mediaKeySession.update(stringToUInt8Array("invalid-response")))
+Promise rejected correctly OK
+
+Using a sanitizable response should resolve.
+RUN(kids = JSON.stringify({ kids: [ "MTIzNDU=" ] }))
+RUN(mediaKeySession = mediaKeys.createSession("temporary"))
+RUN(promise = mediaKeySession.generateRequest("keyids", stringToUInt8Array(kids)))
+Promise resolved OK
+RUN(promise = mediaKeySession.update(stringToUInt8Array("valid-response")))
+Promise resolved OK
+
+Using a sanitizable response with invalid format should resolve.
+RUN(kids = JSON.stringify({ kids: [ "MTIzNDU=" ] }))
+RUN(mediaKeySession = mediaKeys.createSession("temporary"))
+RUN(promise = mediaKeySession.generateRequest("keyids", stringToUInt8Array(kids)))
+Promise resolved OK
+RUN(promise = mediaKeySession.update(stringToUInt8Array("valid-response invalid-format")))
+Promise rejected correctly OK
+END OF TEST
+

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


--- trunk/LayoutTests/media/encrypted-media/mock-MediaKeySession-update.html	                        (rev 0)
+++ trunk/LayoutTests/media/encrypted-media/mock-MediaKeySession-update.html	2017-02-02 06:28:03 UTC (rev 211550)
@@ -0,0 +1,122 @@
+<!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 a non-callable MediaKeySession should reject.');
+            run('mediaKeySession = mediaKeys.createSession("temporary")');
+            testExpected('typeof mediaKeySession', 'object');
+            run('promise = mediaKeySession.update(stringToUInt8Array("invalid-state"))');
+            shouldReject(promise).then(next, next);
+        },
+
+        function() {
+            consoleWrite('Using a zero-length response should reject.');
+            run('kids = JSON.stringify({ kids: [ "MTIzNDU=" ] })');
+            run('mediaKeySession = mediaKeys.createSession("temporary")');
+            run('promise = mediaKeySession.generateRequest("keyids", stringToUInt8Array(kids))');
+            shouldResolve(promise).then(function() {
+                run('promise = mediaKeySession.update(new Uint8Array(0))');
+                shouldReject(promise).then(next, next);
+            }, next);
+        },
+
+        function() {
+            consoleWrite('Using a non-sanitizable response should reject.');
+            run('kids = JSON.stringify({ kids: [ "MTIzNDU=" ] })');
+            run('mediaKeySession = mediaKeys.createSession("temporary")');
+            run('promise = mediaKeySession.generateRequest("keyids", stringToUInt8Array(kids))');
+            shouldResolve(promise).then(function() {
+                run('promise = mediaKeySession.update(stringToUInt8Array("invalid-response"))');
+                shouldReject(promise).then(next, next);
+            }, next);
+        },
+
+        function() {
+            consoleWrite('Using a sanitizable response should resolve.');
+            run('kids = JSON.stringify({ kids: [ "MTIzNDU=" ] })');
+            run('mediaKeySession = mediaKeys.createSession("temporary")');
+            run('promise = mediaKeySession.generateRequest("keyids", stringToUInt8Array(kids))');
+            shouldResolve(promise).then(function() {
+                run('promise = mediaKeySession.update(stringToUInt8Array("valid-response"))');
+                shouldResolve(promise).then(next, next);
+            }, next);
+        },
+
+        function() {
+            consoleWrite('Using a sanitizable response with invalid format should resolve.');
+            run('kids = JSON.stringify({ kids: [ "MTIzNDU=" ] })');
+            run('mediaKeySession = mediaKeys.createSession("temporary")');
+            run('promise = mediaKeySession.generateRequest("keyids", stringToUInt8Array(kids))');
+            shouldResolve(promise).then(function() {
+                run('promise = mediaKeySession.update(stringToUInt8Array("valid-response invalid-format"))');
+                shouldReject(promise).then(next, next);
+            }, next);
+        },
+    ];
+    </script>
+</head>
+<body _onload_="doTest()">
+</body>
+</html>

Modified: trunk/LayoutTests/platform/efl/TestExpectations (211549 => 211550)


--- trunk/LayoutTests/platform/efl/TestExpectations	2017-02-02 03:10:58 UTC (rev 211549)
+++ trunk/LayoutTests/platform/efl/TestExpectations	2017-02-02 06:28:03 UTC (rev 211550)
@@ -2982,6 +2982,7 @@
 Bug(EFL) media/encrypted-media/encrypted-media-not-loaded.html [ Failure ]
 Bug(EFL) media/encrypted-media/encrypted-media-syntax.html [ Failure ]
 Bug(EFL) media/encrypted-media/mock-MediaKeySession-generateRequest.html [ Failure ]
+Bug(EFL) media/encrypted-media/mock-MediaKeySession-update.html [ Failure ]
 Bug(EFL) media/encrypted-media/mock-MediaKeySystemAccess.html [ Failure ]
 Bug(EFL) media/encrypted-media/mock-MediaKeys-createSession.html [ Failure ]
 Bug(EFL) media/encrypted-media/mock-MediaKeys-setServerCertificate.html [ Failure ]

Modified: trunk/LayoutTests/platform/mac/TestExpectations (211549 => 211550)


--- trunk/LayoutTests/platform/mac/TestExpectations	2017-02-02 03:10:58 UTC (rev 211549)
+++ trunk/LayoutTests/platform/mac/TestExpectations	2017-02-02 06:28:03 UTC (rev 211550)
@@ -1496,6 +1496,7 @@
 media/encrypted-media/mock-MediaKeys-setServerCertificate.html [ Skip ]
 media/encrypted-media/mock-MediaKeys-createSession.html [ Skip ]
 media/encrypted-media/mock-MediaKeySession-generateRequest.html [ Skip ]
+media/encrypted-media/mock-MediaKeySession-update.html [ Skip ]
 
 webkit.org/b/166025 http/tests/fetch/fetching-same-resource-with-diffferent-options.html [ Pass Failure ]
 

Modified: trunk/Source/WebCore/ChangeLog (211549 => 211550)


--- trunk/Source/WebCore/ChangeLog	2017-02-02 03:10:58 UTC (rev 211549)
+++ trunk/Source/WebCore/ChangeLog	2017-02-02 06:28:03 UTC (rev 211550)
@@ -1,3 +1,57 @@
+2017-02-01  Zan Dobersek  <zdober...@igalia.com>
+
+        [EME] Implement MediaKeySession::update()
+        https://bugs.webkit.org/show_bug.cgi?id=167636
+
+        Reviewed by Xabier Rodriguez-Calvar.
+
+        Implement the MediaKeySession::update() method by following the steps as
+        they are described in the specification.
+
+        In order to sanitize the passed-in response data, CDM::sanitizeResponse()
+        is added. It passes the SharedBuffer object by reference to the CDMPrivate
+        interface implementor, which returns a SharedBuffer object containing
+        sanitized response data.
+
+        CDMInstance::updateLicense() virtual method is added to perform the license
+        update for some specific CDMInstance object. After the update the CDMInstance
+        invokes the callback that's passed to updateLicense(), providing information
+        about session being closed, changed keys or expiration value, any message
+        that has to be enqueued, and whether the update was successful.
+
+        After that callback is invoked, MediaKeySession::update() goes on to handle
+        all the provided information in a future task, finally resolving the promise
+        (or rejecting it beforehand in case of any failure during response handling
+        or license update).
+
+        Three algorithms that can be invoked from MediaKeySession::update() (key
+        status update, expiration update and session closure) will be implemented
+        separately. Placeholder methods are provided until then.
+
+        MockCDM::sanitizeResponse() and MockCDMInstance::updateLicense() are
+        implemented for testing purposes. For now only the response sanitization
+        and sanitized response format are checked there. Key status update,
+        expiration update and session closure should be tested once the
+        implementations for those algorithms are added.
+
+        Test: media/encrypted-media/mock-MediaKeySession-update.html
+
+        * Modules/encryptedmedia/CDM.cpp:
+        (WebCore::CDM::sanitizeResponse):
+        * Modules/encryptedmedia/CDM.h:
+        * Modules/encryptedmedia/CDMInstance.h:
+        * Modules/encryptedmedia/CDMPrivate.h:
+        * Modules/encryptedmedia/MediaKeySession.cpp:
+        (WebCore::MediaKeySession::update):
+        (WebCore::MediaKeySession::updateKeyStatuses):
+        (WebCore::MediaKeySession::updateExpiration):
+        (WebCore::MediaKeySession::sessionClosed):
+        * Modules/encryptedmedia/MediaKeySession.h:
+        * testing/MockCDMFactory.cpp:
+        (WebCore::MockCDM::sanitizeResponse):
+        (WebCore::MockCDMInstance::updateLicense):
+        * testing/MockCDMFactory.h:
+
 2017-02-01  Eric Carlson  <eric.carl...@apple.com>
 
         [Mac] Update CARingBuffer class

Modified: trunk/Source/WebCore/Modules/encryptedmedia/CDM.cpp (211549 => 211550)


--- trunk/Source/WebCore/Modules/encryptedmedia/CDM.cpp	2017-02-02 03:10:58 UTC (rev 211549)
+++ trunk/Source/WebCore/Modules/encryptedmedia/CDM.cpp	2017-02-02 06:28:03 UTC (rev 211550)
@@ -644,6 +644,13 @@
     return m_private && m_private->supportsInitData(initDataType, initData);
 }
 
+RefPtr<SharedBuffer> CDM::sanitizeResponse(const SharedBuffer& response)
+{
+    if (!m_private)
+        return nullptr;
+    return m_private->sanitizeResponse(response);
 }
 
+}
+
 #endif

Modified: trunk/Source/WebCore/Modules/encryptedmedia/CDM.h (211549 => 211550)


--- trunk/Source/WebCore/Modules/encryptedmedia/CDM.h	2017-02-02 03:10:58 UTC (rev 211549)
+++ trunk/Source/WebCore/Modules/encryptedmedia/CDM.h	2017-02-02 06:28:03 UTC (rev 211550)
@@ -80,6 +80,8 @@
     RefPtr<SharedBuffer> sanitizeInitData(const AtomicString& initDataType, const SharedBuffer&);
     bool supportsInitData(const AtomicString& initDataType, const SharedBuffer&);
 
+    RefPtr<SharedBuffer> sanitizeResponse(const SharedBuffer&);
+
 private:
     CDM(Document&, const String& keySystem);
 

Modified: trunk/Source/WebCore/Modules/encryptedmedia/CDMInstance.h (211549 => 211550)


--- trunk/Source/WebCore/Modules/encryptedmedia/CDMInstance.h	2017-02-02 03:10:58 UTC (rev 211549)
+++ trunk/Source/WebCore/Modules/encryptedmedia/CDMInstance.h	2017-02-02 06:28:03 UTC (rev 211550)
@@ -27,8 +27,11 @@
 
 #if ENABLE(ENCRYPTED_MEDIA)
 
+#include <utility>
 #include <wtf/Forward.h>
+#include <wtf/Optional.h>
 #include <wtf/RefCounted.h>
+#include <wtf/Vector.h>
 
 namespace WebCore {
 
@@ -57,6 +60,28 @@
 
     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;
+
+    enum class KeyStatus {
+        Usable,
+        Expired,
+        Released,
+        OutputRestricted,
+        OutputDownscaled,
+        StatusPending,
+        InternalError,
+    };
+
+    enum class MessageType {
+        LicenseRequest,
+        LicenseRenewal,
+        LicenseRelease,
+        IndividualizationRequest,
+    };
+
+    using KeyStatusVector = Vector<std::pair<Ref<SharedBuffer>, KeyStatus>>;
+    using Message = std::pair<MessageType, Ref<SharedBuffer>>;
+    using LicenseUpdateCallback = Function<void(bool sessionWasClosed, std::optional<KeyStatusVector>&& changedKeys, std::optional<double>&& changedExpiration, std::optional<Message>&& message, SuccessValue succeeded)>;
+    virtual void updateLicense(LicenseType, const SharedBuffer& response, LicenseUpdateCallback) = 0;
 };
 
 }

Modified: trunk/Source/WebCore/Modules/encryptedmedia/CDMPrivate.h (211549 => 211550)


--- trunk/Source/WebCore/Modules/encryptedmedia/CDMPrivate.h	2017-02-02 03:10:58 UTC (rev 211549)
+++ trunk/Source/WebCore/Modules/encryptedmedia/CDMPrivate.h	2017-02-02 06:28:03 UTC (rev 211550)
@@ -54,6 +54,7 @@
     virtual bool supportsServerCertificates() const = 0;
     virtual bool supportsSessions() const = 0;
     virtual bool supportsInitData(const AtomicString&, const SharedBuffer&) const = 0;
+    virtual RefPtr<SharedBuffer> sanitizeResponse(const SharedBuffer&) const = 0;
 };
 
 }

Modified: trunk/Source/WebCore/Modules/encryptedmedia/MediaKeySession.cpp (211549 => 211550)


--- trunk/Source/WebCore/Modules/encryptedmedia/MediaKeySession.cpp	2017-02-02 03:10:58 UTC (rev 211549)
+++ trunk/Source/WebCore/Modules/encryptedmedia/MediaKeySession.cpp	2017-02-02 06:28:03 UTC (rev 211550)
@@ -245,9 +245,143 @@
     notImplemented();
 }
 
-void MediaKeySession::update(const BufferSource&, Ref<DeferredPromise>&&)
+void MediaKeySession::update(const BufferSource& response, Ref<DeferredPromise>&& promise)
 {
-    notImplemented();
+    // https://w3c.github.io/encrypted-media/#dom-mediakeysession-update
+    // 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 callable value is false, return a promise rejected with an InvalidStateError.
+    if (m_closed || !m_callable) {
+        promise->reject(INVALID_STATE_ERR);
+        return;
+    }
+
+    // 3. If response is an empty array, return a promise rejected with a newly created TypeError.
+    if (!response.length()) {
+        promise->reject(TypeError);
+        return;
+    }
+
+    // 4. Let response copy be a copy of the contents of the response parameter.
+    // 5. Let promise be a new promise.
+    // 6. Run the following steps in parallel:
+    m_taskQueue.enqueueTask([this, response = SharedBuffer::create(response.data(), response.length()), promise = WTFMove(promise)] () mutable {
+        // 6.1. Let sanitized response be a validated and/or sanitized version of response copy.
+        RefPtr<SharedBuffer> sanitizedResponse = m_implementation->sanitizeResponse(response);
+
+        // 6.2. If the preceding step failed, or if sanitized response is empty, reject promise with a newly created TypeError.
+        if (!sanitizedResponse || sanitizedResponse->isEmpty()) {
+            promise->reject(TypeError);
+            return;
+        }
+
+        CDMInstance::LicenseType licenseType;
+        switch (m_sessionType) {
+        case MediaKeySessionType::Temporary:
+            licenseType = CDMInstance::LicenseType::Temporary;
+            break;
+        case MediaKeySessionType::PersistentLicense:
+            licenseType = CDMInstance::LicenseType::Persistable;
+            break;
+        case MediaKeySessionType::PersistentUsageRecord:
+            licenseType = CDMInstance::LicenseType::UsageRecord;
+            break;
+        };
+
+        // 6.3. Let message be null.
+        // 6.4. Let message type be null.
+        // 6.5. Let session closed be false.
+        // 6.6. Let cdm be the CDM instance represented by this object's cdm instance value.
+        // 6.7. Use the cdm to execute the following steps:
+        m_instance->updateLicense(licenseType, *sanitizedResponse, [this, weakThis = m_weakPtrFactory.createWeakPtr(), promise = WTFMove(promise)] (bool sessionWasClosed, std::optional<CDMInstance::KeyStatusVector>&& changedKeys, std::optional<double>&& changedExpiration, std::optional<CDMInstance::Message>&& message, CDMInstance::SuccessValue succeeded) mutable {
+            if (!weakThis)
+                return;
+
+            // 6.7.1. If the format of sanitized response is invalid in any way, reject promise with a newly created TypeError.
+            // 6.7.2. Process sanitized response, following the stipulation for the first matching condition from the following list:
+            //   ↳ If sanitized response contains a license or key(s)
+            //     Process sanitized response, following the stipulation for the first matching condition from the following list:
+            //     ↳ If sessionType is "temporary" and sanitized response does not specify that session data, including any license, key(s), or similar session data it contains, should be stored
+            //       Process sanitized response, not storing any session data.
+            //     ↳ If sessionType is "persistent-license" and sanitized response contains a persistable license
+            //       Process sanitized response, storing the license/key(s) and related session data contained in sanitized response. Such data must be stored such that only the origin of this object's Document can access it.
+            //     ↳ If sessionType is "persistent-usage-record" and sanitized response contains a non-persistable license
+            //       Run the following steps:
+            //         6.7.2.3.1. Process sanitized response, not storing any session data.
+            //         6.7.2.3.2. If processing sanitized response results in the addition of keys to the set of known keys, add the key IDs of these keys to this object's record of key usage.
+            //     ↳ Otherwise
+            //       Reject promise with a newly created TypeError.
+            //   ↳ If sanitized response contains a record of license destruction acknowledgement and sessionType is "persistent-license"
+            //     Run the following steps:
+            //       6.7.2.1. Close the key session and clear all stored session data associated with this object, including the sessionId and record of license destruction.
+            //       6.7.2.2. Set session closed to true.
+            //   ↳ Otherwise
+            //     Process sanitized response, not storing any session data.
+            // NOTE: Steps 6.7.1. and 6.7.2. should be implemented in CDMInstance.
+
+            if (succeeded == CDMInstance::SuccessValue::Failed) {
+                promise->reject(TypeError);
+                return;
+            }
+
+            // 6.7.3. If a message needs to be sent to the server, execute the following steps:
+            //   6.7.3.1. Let message be that message.
+            //   6.7.3.2. Let message type be the appropriate MediaKeyMessageType for the message.
+            // 6.8. Queue a task to run the following steps:
+            m_taskQueue.enqueueTask([this, sessionWasClosed, changedKeys = WTFMove(changedKeys), changedExpiration = WTFMove(changedExpiration), message = WTFMove(message), promise = WTFMove(promise)] () mutable {
+                // 6.8.1.
+                if (sessionWasClosed) {
+                    // ↳ If session closed is true:
+                    //   Run the Session Closed algorithm on this object.
+                    sessionClosed();
+                } else {
+                    // ↳ Otherwise:
+                    //   Run the following steps:
+                    //     6.8.1.1. If the set of keys known to the CDM for this object changed or the status of any key(s) changed, run the Update Key Statuses
+                    //              algorithm on the session, providing each known key's key ID along with the appropriate MediaKeyStatus. Should additional
+                    //              processing be necessary to determine with certainty the status of a key, use "status-pending". Once the additional processing
+                    //              for one or more keys has completed, run the Update Key Statuses algorithm again with the actual status(es).
+                    if (changedKeys)
+                        updateKeyStatuses(WTFMove(*changedKeys));
+
+                    //     6.8.1.2. If the expiration time for the session changed, run the Update Expiration algorithm on the session, providing the new expiration time.
+                    if (changedExpiration)
+                        updateExpiration(*changedExpiration);
+
+                    //     6.8.1.3. If any of the preceding steps failed, reject promise with a new DOMException whose name is the appropriate error name.
+                    // FIXME: At this point the implementations of preceding steps can't fail.
+
+                    //     6.8.1.4. If message is not null, run the Queue a "message" Event algorithm on the session, providing message type and message.
+                    if (message) {
+                        MediaKeyMessageType messageType;
+                        switch (message->first) {
+                        case CDMInstance::MessageType::LicenseRequest:
+                            messageType = MediaKeyMessageType::LicenseRequest;
+                            break;
+                        case CDMInstance::MessageType::LicenseRenewal:
+                            messageType = MediaKeyMessageType::LicenseRenewal;
+                            break;
+                        case CDMInstance::MessageType::LicenseRelease:
+                            messageType = MediaKeyMessageType::LicenseRelease;
+                            break;
+                        case CDMInstance::MessageType::IndividualizationRequest:
+                            messageType = MediaKeyMessageType::IndividualizationRequest;
+                            break;
+                        }
+
+                        enqueueMessage(messageType, WTFMove(message->second));
+                    }
+                }
+
+                // 6.8.2. Resolve promise.
+                promise->resolve();
+            });
+        });
+    });
+
+    // 7. Return promise.
 }
 
 void MediaKeySession::close(Ref<DeferredPromise>&&)
@@ -275,6 +409,21 @@
     m_eventQueue.enqueueEvent(WTFMove(messageEvent));
 }
 
+void MediaKeySession::updateKeyStatuses(CDMInstance::KeyStatusVector&&)
+{
+    notImplemented();
+}
+
+void MediaKeySession::updateExpiration(double)
+{
+    notImplemented();
+}
+
+void MediaKeySession::sessionClosed()
+{
+    notImplemented();
+}
+
 bool MediaKeySession::hasPendingActivity() const
 {
     notImplemented();

Modified: trunk/Source/WebCore/Modules/encryptedmedia/MediaKeySession.h (211549 => 211550)


--- trunk/Source/WebCore/Modules/encryptedmedia/MediaKeySession.h	2017-02-02 03:10:58 UTC (rev 211549)
+++ trunk/Source/WebCore/Modules/encryptedmedia/MediaKeySession.h	2017-02-02 06:28:03 UTC (rev 211550)
@@ -31,6 +31,7 @@
 #if ENABLE(ENCRYPTED_MEDIA)
 
 #include "ActiveDOMObject.h"
+#include "CDMInstance.h"
 #include "EventTarget.h"
 #include "GenericEventQueue.h"
 #include "GenericTaskQueue.h"
@@ -46,7 +47,6 @@
 
 class BufferSource;
 class CDM;
-class CDMInstance;
 class MediaKeyStatusMap;
 class MediaKeys;
 class SharedBuffer;
@@ -72,6 +72,9 @@
 private:
     MediaKeySession(ScriptExecutionContext&, MediaKeySessionType, bool useDistinctiveIdentifier, Ref<CDM>&&, Ref<CDMInstance>&&);
     void enqueueMessage(MediaKeyMessageType, const SharedBuffer&);
+    void updateKeyStatuses(CDMInstance::KeyStatusVector&&);
+    void updateExpiration(double);
+    void sessionClosed();
 
     // EventTarget
     EventTargetInterface eventTargetInterface() const override { return MediaKeySessionEventTargetInterfaceType; }

Modified: trunk/Source/WebCore/testing/MockCDMFactory.cpp (211549 => 211550)


--- trunk/Source/WebCore/testing/MockCDMFactory.cpp	2017-02-02 03:10:58 UTC (rev 211549)
+++ trunk/Source/WebCore/testing/MockCDMFactory.cpp	2017-02-02 06:28:03 UTC (rev 211550)
@@ -177,6 +177,20 @@
     return true;
 }
 
+RefPtr<SharedBuffer> MockCDM::sanitizeResponse(const SharedBuffer& response) const
+{
+    if (!charactersAreAllASCII(reinterpret_cast<const LChar*>(response.data()), response.size()))
+        return nullptr;
+
+    Vector<String> responseArray;
+    String(response.data(), response.size()).split(ASCIILiteral(" "), responseArray);
+
+    if (!responseArray.contains(String(ASCIILiteral("valid-response"))))
+        return nullptr;
+
+    return response.copy();
+}
+
 MockCDMInstance::MockCDMInstance(WeakPtr<MockCDM> cdm)
     : m_cdm(cdm)
 {
@@ -256,6 +270,28 @@
     callback(SharedBuffer::create(license.data(), license.length()), sessionID, false, SuccessValue::Succeeded);
 }
 
+void MockCDMInstance::updateLicense(LicenseType, const SharedBuffer& response, LicenseUpdateCallback callback)
+{
+    MockCDMFactory* factory = m_cdm ? m_cdm->factory() : nullptr;
+    if (!factory) {
+        callback(false, std::nullopt, std::nullopt, std::nullopt, SuccessValue::Failed);
+        return;
+    }
+
+    Vector<String> responseVector;
+    String(response.data(), response.size()).split(ASCIILiteral(" "), responseVector);
+
+    if (responseVector.contains(String(ASCIILiteral("invalid-format")))) {
+        callback(false, std::nullopt, std::nullopt, std::nullopt, SuccessValue::Failed);
+        return;
+    }
+
+    // FIXME: Session closure, key status, expiration and message handling should be implemented
+    // once the relevant algorithms are supported.
+
+    callback(false, std::nullopt, std::nullopt, std::nullopt, SuccessValue::Succeeded);
 }
 
+}
+
 #endif

Modified: trunk/Source/WebCore/testing/MockCDMFactory.h (211549 => 211550)


--- trunk/Source/WebCore/testing/MockCDMFactory.h	2017-02-02 03:10:58 UTC (rev 211549)
+++ trunk/Source/WebCore/testing/MockCDMFactory.h	2017-02-02 06:28:03 UTC (rev 211550)
@@ -113,6 +113,7 @@
     bool supportsServerCertificates() const final;
     bool supportsSessions() const final;
     bool supportsInitData(const AtomicString&, const SharedBuffer&) const final;
+    RefPtr<SharedBuffer> sanitizeResponse(const SharedBuffer&) const final;
 
     WeakPtr<MockCDMFactory> m_factory;
     WeakPtrFactory<MockCDM> m_weakPtrFactory;
@@ -128,6 +129,7 @@
     SuccessValue setPersistentStateAllowed(bool) final;
     SuccessValue setServerCertificate(Ref<SharedBuffer>&&) final;
     void requestLicense(LicenseType, const AtomicString& initDataType, Ref<SharedBuffer>&& initData, LicenseCallback) final;
+    void updateLicense(LicenseType, const SharedBuffer&, LicenseUpdateCallback) 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