| Index: Source/modules/encryptedmedia/MediaKeys.cpp
|
| diff --git a/Source/modules/encryptedmedia/MediaKeys.cpp b/Source/modules/encryptedmedia/MediaKeys.cpp
|
| index 462eef5c603456349d44dba35b48696ece90ca1c..1a863bf419c282d6cdf44e76f1391354b38570bc 100644
|
| --- a/Source/modules/encryptedmedia/MediaKeys.cpp
|
| +++ b/Source/modules/encryptedmedia/MediaKeys.cpp
|
| @@ -35,6 +35,7 @@
|
| #include "modules/encryptedmedia/MediaKeyMessageEvent.h"
|
| #include "modules/encryptedmedia/MediaKeySession.h"
|
| #include "modules/encryptedmedia/MediaKeysController.h"
|
| +#include "modules/encryptedmedia/SimpleContentDecryptionModuleResult.h"
|
| #include "platform/ContentType.h"
|
| #include "platform/Logging.h"
|
| #include "platform/MIMETypeRegistry.h"
|
| @@ -72,6 +73,46 @@ static ScriptPromise createRejectedPromise(ScriptState* scriptState, ExceptionCo
|
| return ScriptPromise::rejectWithDOMException(scriptState, DOMException::create(error, errorMessage));
|
| }
|
|
|
| +// A class holding a pending action.
|
| +class MediaKeys::PendingAction : public GarbageCollectedFinalized<MediaKeys::PendingAction> {
|
| +public:
|
| + const Persistent<ContentDecryptionModuleResult> result() const
|
| + {
|
| + return m_result;
|
| + }
|
| +
|
| + const RefPtr<ArrayBuffer> data() const
|
| + {
|
| + return m_data;
|
| + }
|
| +
|
| + static PendingAction* CreatePendingSetServerCertificate(ContentDecryptionModuleResult* result, PassRefPtr<ArrayBuffer> serverCertificate)
|
| + {
|
| + ASSERT(result);
|
| + ASSERT(serverCertificate);
|
| + return new PendingAction(result, serverCertificate);
|
| + }
|
| +
|
| + ~PendingAction()
|
| + {
|
| + }
|
| +
|
| + void trace(Visitor* visitor)
|
| + {
|
| + visitor->trace(m_result);
|
| + }
|
| +
|
| +private:
|
| + PendingAction(ContentDecryptionModuleResult* result, PassRefPtr<ArrayBuffer> data)
|
| + : m_result(result)
|
| + , m_data(data)
|
| + {
|
| + }
|
| +
|
| + const Member<ContentDecryptionModuleResult> m_result;
|
| + const RefPtr<ArrayBuffer> m_data;
|
| +};
|
| +
|
| // This class allows a MediaKeys object to be created asynchronously.
|
| class MediaKeysInitializer : public ScriptPromiseResolver {
|
| WTF_MAKE_NONCOPYABLE(MediaKeysInitializer);
|
| @@ -177,6 +218,7 @@ MediaKeys::MediaKeys(ExecutionContext* context, const String& keySystem, PassOwn
|
| : ContextLifecycleObserver(context)
|
| , m_keySystem(keySystem)
|
| , m_cdm(cdm)
|
| + , m_timer(this, &MediaKeys::timerFired)
|
| {
|
| WTF_LOG(Media, "MediaKeys(%p)::MediaKeys", this);
|
|
|
| @@ -210,6 +252,53 @@ MediaKeySession* MediaKeys::createSession(ScriptState* scriptState, const String
|
| return MediaKeySession::create(scriptState, this, sessionType);
|
| }
|
|
|
| +ScriptPromise MediaKeys::setServerCertificate(ScriptState* scriptState, ArrayBuffer* serverCertificate)
|
| +{
|
| + RefPtr<ArrayBuffer> serverCertificateCopy = ArrayBuffer::create(serverCertificate->data(), serverCertificate->byteLength());
|
| + return setServerCertificateInternal(scriptState, serverCertificateCopy.release());
|
| +}
|
| +
|
| +ScriptPromise MediaKeys::setServerCertificate(ScriptState* scriptState, ArrayBufferView* serverCertificate)
|
| +{
|
| + RefPtr<ArrayBuffer> serverCertificateCopy = ArrayBuffer::create(serverCertificate->baseAddress(), serverCertificate->byteLength());
|
| + return setServerCertificateInternal(scriptState, serverCertificateCopy.release());
|
| +}
|
| +
|
| +ScriptPromise MediaKeys::setServerCertificateInternal(ScriptState* scriptState, PassRefPtr<ArrayBuffer> serverCertificate)
|
| +{
|
| + // From https://dvcs.w3.org/hg/html-media/raw-file/default/encrypted-media/encrypted-media.html#dom-setservercertificate:
|
| + // The setServerCertificate(serverCertificate) method provides a server
|
| + // certificate to be used to encrypt messages to the license server.
|
| + // It must run the following steps:
|
| + // 1. If serverCertificate is an empty array, return a promise rejected
|
| + // with a new DOMException whose name is "InvalidAccessError".
|
| + if (!serverCertificate->byteLength()) {
|
| + return ScriptPromise::rejectWithDOMException(
|
| + scriptState, DOMException::create(InvalidAccessError, "The serverCertificate parameter is empty."));
|
| + }
|
| +
|
| + // 2. If the keySystem does not support server certificates, return a
|
| + // promise rejected with a new DOMException whose name is
|
| + // "NotSupportedError".
|
| + // (Let the CDM decide whether to support this or not.)
|
| +
|
| + // 3. Let certificate be a copy of the contents of the serverCertificate
|
| + // parameter.
|
| + // (Done in caller.)
|
| +
|
| + // 4. Let promise be a new promise.
|
| + SimpleContentDecryptionModuleResult* result = new SimpleContentDecryptionModuleResult(scriptState);
|
| + ScriptPromise promise = result->promise();
|
| +
|
| + // 5. Run the following steps asynchronously (documented in timerFired()).
|
| + m_pendingActions.append(PendingAction::CreatePendingSetServerCertificate(result, serverCertificate));
|
| + if (!m_timer.isActive())
|
| + m_timer.startOneShot(0, FROM_HERE);
|
| +
|
| + // 6. Return promise.
|
| + return promise;
|
| +}
|
| +
|
| bool MediaKeys::isTypeSupported(const String& keySystem, const String& contentType)
|
| {
|
| WTF_LOG(Media, "MediaKeys::isTypeSupported(%s, %s)", keySystem.ascii().data(), contentType.ascii().data());
|
| @@ -232,6 +321,31 @@ bool MediaKeys::isTypeSupported(const String& keySystem, const String& contentTy
|
| return isKeySystemSupportedWithContentType(keySystem, contentType);
|
| }
|
|
|
| +void MediaKeys::timerFired(Timer<MediaKeys>*)
|
| +{
|
| + ASSERT(m_pendingActions.size());
|
| +
|
| + // Swap the queue to a local copy to avoid problems if resolving promises
|
| + // run synchronously.
|
| + HeapDeque<Member<PendingAction> > pendingActions;
|
| + pendingActions.swap(m_pendingActions);
|
| +
|
| + while (!pendingActions.isEmpty()) {
|
| + PendingAction* action = pendingActions.takeFirst();
|
| + WTF_LOG(Media, "MediaKeys(%p)::timerFired: Certificate", this);
|
| +
|
| + // 5.1 Let cdm be the cdm during the initialization of this object.
|
| + WebContentDecryptionModule* cdm = contentDecryptionModule();
|
| +
|
| + // 5.2 Use the cdm to process certificate.
|
| + cdm->setServerCertificate(static_cast<unsigned char*>(action->data()->data()), action->data()->byteLength(), action->result()->result());
|
| + // 5.3 If any of the preceding steps failed, reject promise with a
|
| + // new DOMException whose name is the appropriate error name.
|
| + // 5.4 Resolve promise.
|
| + // (These are handled by Chromium and the CDM.)
|
| + }
|
| +}
|
| +
|
| WebContentDecryptionModule* MediaKeys::contentDecryptionModule()
|
| {
|
| return m_cdm.get();
|
| @@ -239,6 +353,7 @@ WebContentDecryptionModule* MediaKeys::contentDecryptionModule()
|
|
|
| void MediaKeys::trace(Visitor* visitor)
|
| {
|
| + visitor->trace(m_pendingActions);
|
| }
|
|
|
| void MediaKeys::contextDestroyed()
|
|
|