| Index: third_party/WebKit/Source/modules/encryptedmedia/MediaKeySession.cpp
|
| diff --git a/third_party/WebKit/Source/modules/encryptedmedia/MediaKeySession.cpp b/third_party/WebKit/Source/modules/encryptedmedia/MediaKeySession.cpp
|
| index b248dba590c4c12ab5a98bc0f81211dc2207e22d..4bff77a3e67dc8af8d0dfdefdb40018732168511 100644
|
| --- a/third_party/WebKit/Source/modules/encryptedmedia/MediaKeySession.cpp
|
| +++ b/third_party/WebKit/Source/modules/encryptedmedia/MediaKeySession.cpp
|
| @@ -152,9 +152,7 @@ class MediaKeySession::PendingAction
|
|
|
| Type getType() const { return m_type; }
|
|
|
| - const Persistent<ContentDecryptionModuleResult> result() const {
|
| - return m_result;
|
| - }
|
| + ContentDecryptionModuleResult* result() const { return m_result; }
|
|
|
| DOMArrayBuffer* data() const {
|
| DCHECK(m_type == GenerateRequest || m_type == Update);
|
| @@ -514,8 +512,7 @@ ScriptPromise MediaKeySession::generateRequest(ScriptState* scriptState,
|
| new NewSessionResultPromise(scriptState, this);
|
| ScriptPromise promise = result->promise();
|
|
|
| - // 10. Run the following steps asynchronously (documented in
|
| - // actionTimerFired())
|
| + // 10. Run the following steps asynchronously (done in generateRequestTask())
|
| m_pendingActions.append(PendingAction::CreatePendingGenerateRequest(
|
| result, initDataType, initDataBuffer));
|
| DCHECK(!m_actionTimer.isActive());
|
| @@ -525,6 +522,42 @@ ScriptPromise MediaKeySession::generateRequest(ScriptState* scriptState,
|
| return promise;
|
| }
|
|
|
| +void MediaKeySession::generateRequestTask(
|
| + ContentDecryptionModuleResult* result,
|
| + WebEncryptedMediaInitDataType initDataType,
|
| + DOMArrayBuffer* initDataBuffer) {
|
| + // NOTE: Continue step 10 of MediaKeySession::generateRequest().
|
| + DVLOG(MEDIA_KEY_SESSION_LOG_LEVEL) << __func__ << "(" << this << ")";
|
| +
|
| + // initializeNewSession() in Chromium will execute steps 10.1 to 10.9.
|
| + m_session->initializeNewSession(
|
| + initDataType, static_cast<unsigned char*>(initDataBuffer->data()),
|
| + initDataBuffer->byteLength(), m_sessionType, result->result());
|
| +
|
| + // Remaining steps (10.10) executed in finishGenerateRequest(),
|
| + // called when |result| is resolved.
|
| +}
|
| +
|
| +void MediaKeySession::finishGenerateRequest() {
|
| + // NOTE: Continue step 10.10 of MediaKeySession::generateRequest().
|
| + DVLOG(MEDIA_KEY_SESSION_LOG_LEVEL) << __func__ << "(" << this << ")";
|
| +
|
| + // 10.10.1 If any of the preceding steps failed, reject promise with a
|
| + // new DOMException whose name is the appropriate error name.
|
| + // (Done by CDM calling result.completeWithError() as appropriate.)
|
| + // 10.10.2 Set the sessionId attribute to session id.
|
| + DCHECK(!sessionId().isEmpty());
|
| +
|
| + // 10.10.3 Let this object's callable be true.
|
| + m_isCallable = true;
|
| +
|
| + // 10.10.4 Run the Queue a "message" Event algorithm on the session,
|
| + // providing message type and message.
|
| + // (Done by the CDM.)
|
| + // 10.10.5 Resolve promise.
|
| + // (Done by NewSessionResultPromise.)
|
| +}
|
| +
|
| ScriptPromise MediaKeySession::load(ScriptState* scriptState,
|
| const String& sessionId) {
|
| DVLOG(MEDIA_KEY_SESSION_LOG_LEVEL) << __func__ << "(" << this << ") "
|
| @@ -574,8 +607,7 @@ ScriptPromise MediaKeySession::load(ScriptState* scriptState,
|
| new LoadSessionResultPromise(scriptState, this);
|
| ScriptPromise promise = result->promise();
|
|
|
| - // 8. Run the following steps asynchronously (documented in
|
| - // actionTimerFired())
|
| + // 8. Run the following steps asynchronously (done in loadTask())
|
| m_pendingActions.append(
|
| PendingAction::CreatePendingLoadRequest(result, sessionId));
|
| DCHECK(!m_actionTimer.isActive());
|
| @@ -585,6 +617,80 @@ ScriptPromise MediaKeySession::load(ScriptState* scriptState,
|
| return promise;
|
| }
|
|
|
| +void MediaKeySession::loadTask(ContentDecryptionModuleResult* result,
|
| + const String& sessionId) {
|
| + // NOTE: Continue step 8 of MediaKeySession::load().
|
| + DVLOG(MEDIA_KEY_SESSION_LOG_LEVEL) << __func__ << "(" << this << ")";
|
| +
|
| + // 8.1 Let sanitized session ID be a validated and/or sanitized
|
| + // version of sessionId. The user agent should thoroughly
|
| + // validate the sessionId value before passing it to the CDM.
|
| + // At a minimum, this should include checking that the length
|
| + // and value (e.g. alphanumeric) are reasonable.
|
| + // 8.2 If the preceding step failed, or if sanitized session ID
|
| + // is empty, reject promise with a newly created TypeError.
|
| + if (!isValidSessionId(sessionId)) {
|
| + result->completeWithError(WebContentDecryptionModuleExceptionTypeError, 0,
|
| + "Invalid sessionId");
|
| + return;
|
| + }
|
| +
|
| + // 8.3 If there is an unclosed session in the object's Document
|
| + // whose sessionId attribute is sanitized session ID, reject
|
| + // promise with a new DOMException whose name is
|
| + // QuotaExceededError. In other words, do not create a session
|
| + // if a non-closed session, regardless of type, already exists
|
| + // for this sanitized session ID in this browsing context.
|
| + // (Done in the CDM.)
|
| +
|
| + // 8.4 Let expiration time be NaN.
|
| + // (Done in the constructor.)
|
| + DCHECK(std::isnan(m_expiration));
|
| +
|
| + // load() in Chromium will execute steps 8.5 through 8.8.
|
| + m_session->load(sessionId, result->result());
|
| +
|
| + // Remaining step (8.9) executed in finishLoad(), called when |result|
|
| + // is resolved.
|
| +}
|
| +
|
| +void MediaKeySession::finishLoad() {
|
| + // NOTE: Continue step 8.9 of MediaKeySession::load().
|
| + DVLOG(MEDIA_KEY_SESSION_LOG_LEVEL) << __func__ << "(" << this << ")";
|
| +
|
| + // 8.9.1 If any of the preceding steps failed, reject promise with a new
|
| + // DOMException whose name is the appropriate error name.
|
| + // (Done by CDM calling result.completeWithError() as appropriate.)
|
| +
|
| + // 8.9.2 Set the sessionId attribute to sanitized session ID.
|
| + DCHECK(!sessionId().isEmpty());
|
| +
|
| + // 8.9.3 Let this object's callable be true.
|
| + m_isCallable = true;
|
| +
|
| + // 8.9.4 If the loaded session contains information about any keys (there
|
| + // are known keys), run the update key statuses algorithm on the
|
| + // session, providing each key's key ID along with the appropriate
|
| + // MediaKeyStatus. Should additional processing be necessary to
|
| + // determine with certainty the status of a key, use the non-"usable"
|
| + // MediaKeyStatus value that corresponds to the reason for the
|
| + // additional processing. Once the additional processing for one or
|
| + // more keys has completed, run the update key statuses algorithm
|
| + // again if any of the statuses has changed.
|
| + // (Done by the CDM.)
|
| +
|
| + // 8.9.5 Run the Update Expiration algorithm on the session,
|
| + // providing expiration time.
|
| + // (Done by the CDM.)
|
| +
|
| + // 8.9.6 If message is not null, run the queue a "message" event algorithm
|
| + // on the session, providing message type and message.
|
| + // (Done by the CDM.)
|
| +
|
| + // 8.9.7 Resolve promise with true.
|
| + // (Done by LoadSessionResultPromise.)
|
| +}
|
| +
|
| ScriptPromise MediaKeySession::update(ScriptState* scriptState,
|
| const DOMArrayPiece& response) {
|
| DVLOG(MEDIA_KEY_SESSION_LOG_LEVEL) << __func__ << "(" << this << ")";
|
| @@ -620,8 +726,7 @@ ScriptPromise MediaKeySession::update(ScriptState* scriptState,
|
| SimpleResultPromise* result = new SimpleResultPromise(scriptState, this);
|
| ScriptPromise promise = result->promise();
|
|
|
| - // 6. Run the following steps asynchronously (documented in
|
| - // actionTimerFired())
|
| + // 6. Run the following steps asynchronously (done in updateTask())
|
| m_pendingActions.append(
|
| PendingAction::CreatePendingUpdate(result, responseCopy));
|
| if (!m_actionTimer.isActive())
|
| @@ -631,30 +736,42 @@ ScriptPromise MediaKeySession::update(ScriptState* scriptState,
|
| return promise;
|
| }
|
|
|
| +void MediaKeySession::updateTask(ContentDecryptionModuleResult* result,
|
| + DOMArrayBuffer* sanitizedResponse) {
|
| + // NOTE: Continue step 6 of MediaKeySession::update().
|
| + DVLOG(MEDIA_KEY_SESSION_LOG_LEVEL) << __func__ << "(" << this << ")";
|
| +
|
| + // update() in Chromium will execute steps 6.1 through 6.8.
|
| + m_session->update(static_cast<unsigned char*>(sanitizedResponse->data()),
|
| + sanitizedResponse->byteLength(), result->result());
|
| +
|
| + // Last step (6.8.2 Resolve promise) will be done when |result| is resolved.
|
| +}
|
| +
|
| ScriptPromise MediaKeySession::close(ScriptState* scriptState) {
|
| DVLOG(MEDIA_KEY_SESSION_LOG_LEVEL) << __func__ << "(" << this << ")";
|
|
|
| // From https://w3c.github.io/encrypted-media/#close:
|
| // Indicates that the application no longer needs the session and the CDM
|
| - // should release any resources associated with this object and close it.
|
| + // should release any resources associated with the session and close it.
|
| + // Persisted data should not be released or cleared.
|
| // When this method is invoked, the user agent must run the following steps:
|
|
|
| - // 1. If this object's callable value is false, return a promise rejected
|
| - // with a new DOMException whose name is "InvalidStateError".
|
| - if (!m_isCallable)
|
| - return CreateRejectedPromiseNotCallable(scriptState);
|
| -
|
| - // 2. If the Session Close algorithm has been run on this object,
|
| - // return a resolved promise.
|
| + // 1. Let session be the associated MediaKeySession object.
|
| + // 2. If session is closed, return a resolved promise.
|
| if (m_isClosed)
|
| return ScriptPromise::cast(scriptState, ScriptValue());
|
|
|
| - // 3. Let promise be a new promise.
|
| + // 3. If session's callable value is false, return a promise rejected with
|
| + // an InvalidStateError.
|
| + if (!m_isCallable)
|
| + return CreateRejectedPromiseNotCallable(scriptState);
|
| +
|
| + // 4. Let promise be a new promise.
|
| SimpleResultPromise* result = new SimpleResultPromise(scriptState, this);
|
| ScriptPromise promise = result->promise();
|
|
|
| - // 4. Run the following steps asynchronously (documented in
|
| - // actionTimerFired()).
|
| + // 4. Run the following steps in parallel (done in closeTask()).
|
| m_pendingActions.append(PendingAction::CreatePendingClose(result));
|
| if (!m_actionTimer.isActive())
|
| m_actionTimer.startOneShot(0, BLINK_FROM_HERE);
|
| @@ -663,6 +780,16 @@ ScriptPromise MediaKeySession::close(ScriptState* scriptState) {
|
| return promise;
|
| }
|
|
|
| +void MediaKeySession::closeTask(ContentDecryptionModuleResult* result) {
|
| + // NOTE: Continue step 4 of MediaKeySession::close().
|
| + DVLOG(MEDIA_KEY_SESSION_LOG_LEVEL) << __func__ << "(" << this << ")";
|
| +
|
| + // close() in Chromium will execute steps 5.1 through 5.3.
|
| + m_session->close(result->result());
|
| +
|
| + // Last step (5.3.2 Resolve promise) will be done when |result| is resolved.
|
| +}
|
| +
|
| ScriptPromise MediaKeySession::remove(ScriptState* scriptState) {
|
| DVLOG(MEDIA_KEY_SESSION_LOG_LEVEL) << __func__ << "(" << this << ")";
|
|
|
| @@ -694,8 +821,7 @@ ScriptPromise MediaKeySession::remove(ScriptState* scriptState) {
|
| SimpleResultPromise* result = new SimpleResultPromise(scriptState, this);
|
| ScriptPromise promise = result->promise();
|
|
|
| - // 5. Run the following steps asynchronously (documented in
|
| - // actionTimerFired()).
|
| + // 5. Run the following steps asynchronously (done in removeTask()).
|
| m_pendingActions.append(PendingAction::CreatePendingRemove(result));
|
| if (!m_actionTimer.isActive())
|
| m_actionTimer.startOneShot(0, BLINK_FROM_HERE);
|
| @@ -704,6 +830,16 @@ ScriptPromise MediaKeySession::remove(ScriptState* scriptState) {
|
| return promise;
|
| }
|
|
|
| +void MediaKeySession::removeTask(ContentDecryptionModuleResult* result) {
|
| + // NOTE: Continue step 5 of MediaKeySession::remove().
|
| + DVLOG(MEDIA_KEY_SESSION_LOG_LEVEL) << __func__ << "(" << this << ")";
|
| +
|
| + // remove() in Chromium will execute steps 5.1 through 5.3.
|
| + m_session->remove(result->result());
|
| +
|
| + // Last step (5.3.6 Resolve promise) will be done when |result| is resolved.
|
| +}
|
| +
|
| void MediaKeySession::actionTimerFired(TimerBase*) {
|
| DCHECK(m_pendingActions.size());
|
|
|
| @@ -718,153 +854,29 @@ void MediaKeySession::actionTimerFired(TimerBase*) {
|
|
|
| switch (action->getType()) {
|
| case PendingAction::GenerateRequest:
|
| - // NOTE: Continue step 10 of MediaKeySession::generateRequest().
|
| - DVLOG(MEDIA_KEY_SESSION_LOG_LEVEL) << __func__ << "(" << this
|
| - << ") GenerateRequest";
|
| -
|
| - // initializeNewSession() in Chromium will execute steps 10.1 to 10.9.
|
| - m_session->initializeNewSession(
|
| - action->initDataType(),
|
| - static_cast<unsigned char*>(action->data()->data()),
|
| - action->data()->byteLength(), m_sessionType,
|
| - action->result()->result());
|
| -
|
| - // Remaining steps (from 10.10) executed in finishGenerateRequest(),
|
| - // called when |result| is resolved.
|
| + generateRequestTask(action->result(), action->initDataType(),
|
| + action->data());
|
| break;
|
|
|
| case PendingAction::Load:
|
| - // NOTE: Continue step 8 of MediaKeySession::load().
|
| - DVLOG(MEDIA_KEY_SESSION_LOG_LEVEL) << __func__ << "(" << this
|
| - << ") Load";
|
| -
|
| - // 8.1 Let sanitized session ID be a validated and/or sanitized
|
| - // version of sessionId. The user agent should thoroughly
|
| - // validate the sessionId value before passing it to the CDM.
|
| - // At a minimum, this should include checking that the length
|
| - // and value (e.g. alphanumeric) are reasonable.
|
| - // 8.2 If the preceding step failed, or if sanitized session ID
|
| - // is empty, reject promise with a newly created TypeError.
|
| - if (!isValidSessionId(action->sessionId())) {
|
| - action->result()->completeWithError(
|
| - WebContentDecryptionModuleExceptionTypeError, 0,
|
| - "Invalid sessionId");
|
| - return;
|
| - }
|
| -
|
| - // 8.3 If there is an unclosed session in the object's Document
|
| - // whose sessionId attribute is sanitized session ID, reject
|
| - // promise with a new DOMException whose name is
|
| - // QuotaExceededError. In other words, do not create a session
|
| - // if a non-closed session, regardless of type, already exists
|
| - // for this sanitized session ID in this browsing context.
|
| - // (Done in the CDM.)
|
| -
|
| - // 8.4 Let expiration time be NaN.
|
| - // (Done in the constructor.)
|
| - DCHECK(std::isnan(m_expiration));
|
| -
|
| - // load() in Chromium will execute steps 8.5 through 8.8.
|
| - m_session->load(action->sessionId(), action->result()->result());
|
| -
|
| - // Remaining steps (from 8.9) executed in finishLoad(), called
|
| - // when |result| is resolved.
|
| + loadTask(action->result(), action->sessionId());
|
| break;
|
|
|
| case PendingAction::Update:
|
| - // NOTE: Continue step 5 of MediaKeySession::update().
|
| - DVLOG(MEDIA_KEY_SESSION_LOG_LEVEL) << __func__ << "(" << this
|
| - << ") Update";
|
| -
|
| - // update() in Chromium will execute steps 5.1 through 5.8.
|
| - m_session->update(static_cast<unsigned char*>(action->data()->data()),
|
| - action->data()->byteLength(),
|
| - action->result()->result());
|
| -
|
| - // Last step (5.9 Resolve promise) will be done when |result| is
|
| - // resolved.
|
| + updateTask(action->result(), action->data());
|
| break;
|
|
|
| case PendingAction::Close:
|
| - // NOTE: Continue step 4 of MediaKeySession::close().
|
| - DVLOG(MEDIA_KEY_SESSION_LOG_LEVEL) << __func__ << "(" << this
|
| - << ") Close";
|
| -
|
| - // close() in Chromium will execute steps 4.1 through 4.2.
|
| - m_session->close(action->result()->result());
|
| -
|
| - // Last step (4.3 Resolve promise) will be done when |result| is
|
| - // resolved.
|
| + closeTask(action->result());
|
| break;
|
|
|
| case PendingAction::Remove:
|
| - // NOTE: Continue step 5 of MediaKeySession::remove().
|
| - DVLOG(MEDIA_KEY_SESSION_LOG_LEVEL) << __func__ << "(" << this
|
| - << ") Remove";
|
| -
|
| - // remove() in Chromium will execute steps 5.1 through 5.3.
|
| - m_session->remove(action->result()->result());
|
| -
|
| - // Last step (5.3.3 Resolve promise) will be done when |result| is
|
| - // resolved.
|
| + removeTask(action->result());
|
| break;
|
| }
|
| }
|
| }
|
|
|
| -void MediaKeySession::finishGenerateRequest() {
|
| - // 9.8 If any of the preceding steps failed, reject promise with a
|
| - // new DOMException whose name is the appropriate error name.
|
| - // (Done by CDM calling result.completeWithError() as appropriate.)
|
| -
|
| - // 9.9 Set the sessionId attribute to session id.
|
| - DCHECK(!sessionId().isEmpty());
|
| -
|
| - // 9.10 Let this object's callable be true.
|
| - m_isCallable = true;
|
| -
|
| - // 9.11 Run the queue a "message" event algorithm on the session,
|
| - // providing "license-request" and message.
|
| - // (Done by the CDM.)
|
| -
|
| - // 9.12 Resolve promise.
|
| - // (Done by NewSessionResultPromise.)
|
| -}
|
| -
|
| -void MediaKeySession::finishLoad() {
|
| - // 8.9 If any of the preceding steps failed, reject promise with a new
|
| - // DOMException whose name is the appropriate error name.
|
| - // (Done by CDM calling result.completeWithError() as appropriate.)
|
| -
|
| - // 8.10 Set the sessionId attribute to sanitized session ID.
|
| - DCHECK(!sessionId().isEmpty());
|
| -
|
| - // 8.11 Let this object's callable be true.
|
| - m_isCallable = true;
|
| -
|
| - // 8.12 If the loaded session contains information about any keys (there
|
| - // are known keys), run the update key statuses algorithm on the
|
| - // session, providing each key's key ID along with the appropriate
|
| - // MediaKeyStatus. Should additional processing be necessary to
|
| - // determine with certainty the status of a key, use the non-"usable"
|
| - // MediaKeyStatus value that corresponds to the reason for the
|
| - // additional processing. Once the additional processing for one or
|
| - // more keys has completed, run the update key statuses algorithm
|
| - // again if any of the statuses has changed.
|
| - // (Done by the CDM.)
|
| -
|
| - // 8.13 Run the Update Expiration algorithm on the session,
|
| - // providing expiration time.
|
| - // (Done by the CDM.)
|
| -
|
| - // 8.14 If message is not null, run the queue a "message" event algorithm
|
| - // on the session, providing message type and message.
|
| - // (Done by the CDM.)
|
| -
|
| - // 8.15 Resolve promise with true.
|
| - // (Done by LoadSessionResultPromise.)
|
| -}
|
| -
|
| // Queue a task to fire a simple event named keymessage at the new object.
|
| void MediaKeySession::message(MessageType messageType,
|
| const unsigned char* message,
|
|
|