| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2013 Apple Inc. All rights reserved. | 2 * Copyright (C) 2013 Apple Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
| 6 * are met: | 6 * are met: |
| 7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
| 8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
| 9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
| 10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
| (...skipping 11 matching lines...) Expand all Loading... |
| 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
| 23 * THE POSSIBILITY OF SUCH DAMAGE. | 23 * THE POSSIBILITY OF SUCH DAMAGE. |
| 24 */ | 24 */ |
| 25 | 25 |
| 26 #include "modules/encryptedmedia/MediaKeySession.h" | 26 #include "modules/encryptedmedia/MediaKeySession.h" |
| 27 | 27 |
| 28 #include "bindings/core/v8/DOMWrapperWorld.h" | 28 #include "bindings/core/v8/DOMWrapperWorld.h" |
| 29 #include "bindings/core/v8/ScriptPromise.h" | 29 #include "bindings/core/v8/ScriptPromise.h" |
| 30 #include "bindings/core/v8/ScriptPromiseResolver.h" | 30 #include "bindings/core/v8/ScriptPromiseResolver.h" |
| 31 #include "bindings/core/v8/ScriptState.h" | 31 #include "bindings/core/v8/ScriptState.h" |
| 32 #include "bindings/core/v8/V8ThrowException.h" |
| 32 #include "core/dom/DOMArrayBuffer.h" | 33 #include "core/dom/DOMArrayBuffer.h" |
| 33 #include "core/dom/DOMException.h" | 34 #include "core/dom/DOMException.h" |
| 34 #include "core/dom/ExceptionCode.h" | 35 #include "core/dom/ExceptionCode.h" |
| 35 #include "core/events/Event.h" | 36 #include "core/events/Event.h" |
| 36 #include "core/events/GenericEventQueue.h" | 37 #include "core/events/GenericEventQueue.h" |
| 37 #include "modules/encryptedmedia/ContentDecryptionModuleResultPromise.h" | 38 #include "modules/encryptedmedia/ContentDecryptionModuleResultPromise.h" |
| 38 #include "modules/encryptedmedia/EncryptedMediaUtils.h" | 39 #include "modules/encryptedmedia/EncryptedMediaUtils.h" |
| 39 #include "modules/encryptedmedia/MediaKeyMessageEvent.h" | 40 #include "modules/encryptedmedia/MediaKeyMessageEvent.h" |
| 40 #include "modules/encryptedmedia/MediaKeys.h" | 41 #include "modules/encryptedmedia/MediaKeys.h" |
| 41 #include "platform/ContentDecryptionModuleResult.h" | 42 #include "platform/ContentDecryptionModuleResult.h" |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 74 | 75 |
| 75 // Check that the sessionId only contains alphanumeric characters. | 76 // Check that the sessionId only contains alphanumeric characters. |
| 76 for (unsigned i = 0; i < sessionId.length(); ++i) { | 77 for (unsigned i = 0; i < sessionId.length(); ++i) { |
| 77 if (!isASCIIAlphanumeric(sessionId[i])) | 78 if (!isASCIIAlphanumeric(sessionId[i])) |
| 78 return false; | 79 return false; |
| 79 } | 80 } |
| 80 | 81 |
| 81 return true; | 82 return true; |
| 82 } | 83 } |
| 83 | 84 |
| 85 static bool IsPersistentSessionType(WebEncryptedMediaSessionType sessionType) { |
| 86 // This implements section 5.1.1 Is persistent session type? from |
| 87 // https://w3c.github.io/encrypted-media/#is-persistent-session-type |
| 88 switch (sessionType) { |
| 89 case WebEncryptedMediaSessionType::Temporary: |
| 90 return false; |
| 91 case WebEncryptedMediaSessionType::PersistentLicense: |
| 92 return true; |
| 93 case WebEncryptedMediaSessionType::PersistentReleaseMessage: |
| 94 return true; |
| 95 case blink::WebEncryptedMediaSessionType::Unknown: |
| 96 break; |
| 97 } |
| 98 |
| 99 NOTREACHED(); |
| 100 return false; |
| 101 } |
| 102 |
| 84 static String ConvertKeyStatusToString( | 103 static String ConvertKeyStatusToString( |
| 85 const WebEncryptedMediaKeyInformation::KeyStatus status) { | 104 const WebEncryptedMediaKeyInformation::KeyStatus status) { |
| 86 switch (status) { | 105 switch (status) { |
| 87 case WebEncryptedMediaKeyInformation::KeyStatus::Usable: | 106 case WebEncryptedMediaKeyInformation::KeyStatus::Usable: |
| 88 return "usable"; | 107 return "usable"; |
| 89 case WebEncryptedMediaKeyInformation::KeyStatus::Expired: | 108 case WebEncryptedMediaKeyInformation::KeyStatus::Expired: |
| 90 return "expired"; | 109 return "expired"; |
| 91 case WebEncryptedMediaKeyInformation::KeyStatus::Released: | 110 case WebEncryptedMediaKeyInformation::KeyStatus::Released: |
| 92 return "released"; | 111 return "released"; |
| 93 case WebEncryptedMediaKeyInformation::KeyStatus::OutputRestricted: | 112 case WebEncryptedMediaKeyInformation::KeyStatus::OutputRestricted: |
| (...skipping 10 matching lines...) Expand all Loading... |
| 104 return "internal-error"; | 123 return "internal-error"; |
| 105 } | 124 } |
| 106 | 125 |
| 107 static ScriptPromise CreateRejectedPromiseNotCallable( | 126 static ScriptPromise CreateRejectedPromiseNotCallable( |
| 108 ScriptState* scriptState) { | 127 ScriptState* scriptState) { |
| 109 return ScriptPromise::rejectWithDOMException( | 128 return ScriptPromise::rejectWithDOMException( |
| 110 scriptState, | 129 scriptState, |
| 111 DOMException::create(InvalidStateError, "The session is not callable.")); | 130 DOMException::create(InvalidStateError, "The session is not callable.")); |
| 112 } | 131 } |
| 113 | 132 |
| 133 static ScriptPromise CreateRejectedPromiseAlreadyClosed( |
| 134 ScriptState* scriptState) { |
| 135 return ScriptPromise::rejectWithDOMException( |
| 136 scriptState, DOMException::create(InvalidStateError, |
| 137 "The session is already closed.")); |
| 138 } |
| 139 |
| 114 static ScriptPromise CreateRejectedPromiseAlreadyInitialized( | 140 static ScriptPromise CreateRejectedPromiseAlreadyInitialized( |
| 115 ScriptState* scriptState) { | 141 ScriptState* scriptState) { |
| 116 return ScriptPromise::rejectWithDOMException( | 142 return ScriptPromise::rejectWithDOMException( |
| 117 scriptState, DOMException::create(InvalidStateError, | 143 scriptState, DOMException::create(InvalidStateError, |
| 118 "The session is already initialized.")); | 144 "The session is already initialized.")); |
| 119 } | 145 } |
| 120 | 146 |
| 121 // A class holding a pending action. | 147 // A class holding a pending action. |
| 122 class MediaKeySession::PendingAction | 148 class MediaKeySession::PendingAction |
| 123 : public GarbageCollectedFinalized<MediaKeySession::PendingAction> { | 149 : public GarbageCollectedFinalized<MediaKeySession::PendingAction> { |
| (...skipping 296 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 420 ScriptPromise MediaKeySession::generateRequest(ScriptState* scriptState, | 446 ScriptPromise MediaKeySession::generateRequest(ScriptState* scriptState, |
| 421 const String& initDataTypeString, | 447 const String& initDataTypeString, |
| 422 const DOMArrayPiece& initData) { | 448 const DOMArrayPiece& initData) { |
| 423 DVLOG(MEDIA_KEY_SESSION_LOG_LEVEL) << __func__ << "(" << this << ") " | 449 DVLOG(MEDIA_KEY_SESSION_LOG_LEVEL) << __func__ << "(" << this << ") " |
| 424 << initDataTypeString; | 450 << initDataTypeString; |
| 425 | 451 |
| 426 // From https://w3c.github.io/encrypted-media/#generateRequest: | 452 // From https://w3c.github.io/encrypted-media/#generateRequest: |
| 427 // Generates a request based on the initData. When this method is invoked, | 453 // Generates a request based on the initData. When this method is invoked, |
| 428 // the user agent must run the following steps: | 454 // the user agent must run the following steps: |
| 429 | 455 |
| 430 // 1. If this object's uninitialized value is false, return a promise | 456 // 1. If this object is closed, return a promise rejected with an |
| 431 // rejected with a new DOMException whose name is "InvalidStateError". | 457 // InvalidStateError. |
| 458 if (m_isClosed) |
| 459 return CreateRejectedPromiseAlreadyClosed(scriptState); |
| 460 |
| 461 // 2. If this object's uninitialized value is false, return a promise |
| 462 // rejected with an InvalidStateError. |
| 432 if (!m_isUninitialized) | 463 if (!m_isUninitialized) |
| 433 return CreateRejectedPromiseAlreadyInitialized(scriptState); | 464 return CreateRejectedPromiseAlreadyInitialized(scriptState); |
| 434 | 465 |
| 435 // 2. Let this object's uninitialized be false. | 466 // 3. Let this object's uninitialized be false. |
| 436 m_isUninitialized = false; | 467 m_isUninitialized = false; |
| 437 | 468 |
| 438 // 3. If initDataType is an empty string, return a promise rejected with a | 469 // 4. If initDataType is the empty string, return a promise rejected |
| 439 // new DOMException whose name is "InvalidAccessError". | 470 // with a newly created TypeError. |
| 440 if (initDataTypeString.isEmpty()) { | 471 if (initDataTypeString.isEmpty()) { |
| 441 return ScriptPromise::rejectWithDOMException( | 472 return ScriptPromise::reject( |
| 442 scriptState, | 473 scriptState, |
| 443 DOMException::create(InvalidAccessError, | 474 V8ThrowException::createTypeError( |
| 444 "The initDataType parameter is empty.")); | 475 scriptState->isolate(), "The initDataType parameter is empty.")); |
| 445 } | 476 } |
| 446 | 477 |
| 447 // 4. If initData is an empty array, return a promise rejected with a new | 478 // 5. If initData is an empty array, return a promise rejected with a |
| 448 // DOMException whose name is"InvalidAccessError". | 479 // newly created TypeError. |
| 449 if (!initData.byteLength()) { | 480 if (!initData.byteLength()) { |
| 450 return ScriptPromise::rejectWithDOMException( | 481 return ScriptPromise::reject( |
| 451 scriptState, DOMException::create(InvalidAccessError, | 482 scriptState, |
| 483 V8ThrowException::createTypeError(scriptState->isolate(), |
| 452 "The initData parameter is empty.")); | 484 "The initData parameter is empty.")); |
| 453 } | 485 } |
| 454 | 486 |
| 455 // 5. If the Key System implementation represented by this object's cdm | 487 // 6. If the Key System implementation represented by this object's cdm |
| 456 // implementation value does not support initDataType as an | 488 // implementation value does not support initDataType as an |
| 457 // Initialization Data Type, return a promise rejected with a new | 489 // Initialization Data Type, return a promise rejected with a new |
| 458 // DOMException whose name is NotSupportedError. String comparison | 490 // DOMException whose name is NotSupportedError. String comparison |
| 459 // is case-sensitive. | 491 // is case-sensitive. |
| 460 // (blink side doesn't know what the CDM supports, so the proper check | 492 // (blink side doesn't know what the CDM supports, so the proper check |
| 461 // will be done on the Chromium side. However, we can verify that | 493 // will be done on the Chromium side. However, we can verify that |
| 462 // |initDataType| is one of the registered values.) | 494 // |initDataType| is one of the registered values.) |
| 463 WebEncryptedMediaInitDataType initDataType = | 495 WebEncryptedMediaInitDataType initDataType = |
| 464 EncryptedMediaUtils::convertToInitDataType(initDataTypeString); | 496 EncryptedMediaUtils::convertToInitDataType(initDataTypeString); |
| 465 if (initDataType == WebEncryptedMediaInitDataType::Unknown) { | 497 if (initDataType == WebEncryptedMediaInitDataType::Unknown) { |
| 466 return ScriptPromise::rejectWithDOMException( | 498 return ScriptPromise::rejectWithDOMException( |
| 467 scriptState, | 499 scriptState, |
| 468 DOMException::create(NotSupportedError, | 500 DOMException::create(NotSupportedError, |
| 469 "The initialization data type '" + | 501 "The initialization data type '" + |
| 470 initDataTypeString + "' is not supported.")); | 502 initDataTypeString + "' is not supported.")); |
| 471 } | 503 } |
| 472 | 504 |
| 473 // 6. Let init data be a copy of the contents of the initData parameter. | 505 // 7. Let init data be a copy of the contents of the initData parameter. |
| 474 DOMArrayBuffer* initDataBuffer = | 506 DOMArrayBuffer* initDataBuffer = |
| 475 DOMArrayBuffer::create(initData.data(), initData.byteLength()); | 507 DOMArrayBuffer::create(initData.data(), initData.byteLength()); |
| 476 | 508 |
| 477 // 7. Let session type be this object's session type. | 509 // 8. Let session type be this object's session type. |
| 478 // (Done in constructor.) | 510 // (Done in constructor.) |
| 479 | 511 |
| 480 // 8. Let promise be a new promise. | 512 // 9. Let promise be a new promise. |
| 481 NewSessionResultPromise* result = | 513 NewSessionResultPromise* result = |
| 482 new NewSessionResultPromise(scriptState, this); | 514 new NewSessionResultPromise(scriptState, this); |
| 483 ScriptPromise promise = result->promise(); | 515 ScriptPromise promise = result->promise(); |
| 484 | 516 |
| 485 // 9. Run the following steps asynchronously (documented in | 517 // 10. Run the following steps asynchronously (documented in |
| 486 // actionTimerFired()) | 518 // actionTimerFired()) |
| 487 m_pendingActions.append(PendingAction::CreatePendingGenerateRequest( | 519 m_pendingActions.append(PendingAction::CreatePendingGenerateRequest( |
| 488 result, initDataType, initDataBuffer)); | 520 result, initDataType, initDataBuffer)); |
| 489 DCHECK(!m_actionTimer.isActive()); | 521 DCHECK(!m_actionTimer.isActive()); |
| 490 m_actionTimer.startOneShot(0, BLINK_FROM_HERE); | 522 m_actionTimer.startOneShot(0, BLINK_FROM_HERE); |
| 491 | 523 |
| 492 // 10. Return promise. | 524 // 11. Return promise. |
| 493 return promise; | 525 return promise; |
| 494 } | 526 } |
| 495 | 527 |
| 496 ScriptPromise MediaKeySession::load(ScriptState* scriptState, | 528 ScriptPromise MediaKeySession::load(ScriptState* scriptState, |
| 497 const String& sessionId) { | 529 const String& sessionId) { |
| 498 DVLOG(MEDIA_KEY_SESSION_LOG_LEVEL) << __func__ << "(" << this << ") " | 530 DVLOG(MEDIA_KEY_SESSION_LOG_LEVEL) << __func__ << "(" << this << ") " |
| 499 << sessionId; | 531 << sessionId; |
| 500 | 532 |
| 501 // From https://w3c.github.io/encrypted-media/#load: | 533 // From https://w3c.github.io/encrypted-media/#load: |
| 502 // Loads the data stored for the specified session into this object. When | 534 // Loads the data stored for the specified session into this object. When |
| 503 // this method is invoked, the user agent must run the following steps: | 535 // this method is invoked, the user agent must run the following steps: |
| 504 | 536 |
| 505 // 1. If this object's uninitialized value is false, return a promise | 537 // 1. If this object is closed, return a promise rejected with an |
| 506 // rejected with a new DOMException whose name is "InvalidStateError". | 538 // InvalidStateError. |
| 539 if (m_isClosed) |
| 540 return CreateRejectedPromiseAlreadyClosed(scriptState); |
| 541 |
| 542 // 2. If this object's uninitialized value is false, return a promise |
| 543 // rejected with an InvalidStateError. |
| 507 if (!m_isUninitialized) | 544 if (!m_isUninitialized) |
| 508 return CreateRejectedPromiseAlreadyInitialized(scriptState); | 545 return CreateRejectedPromiseAlreadyInitialized(scriptState); |
| 509 | 546 |
| 510 // 2. Let this object's uninitialized be false. | 547 // 3. Let this object's uninitialized value be false. |
| 511 m_isUninitialized = false; | 548 m_isUninitialized = false; |
| 512 | 549 |
| 513 // 3. If sessionId is an empty string, return a promise rejected with a | 550 // 4. If sessionId is the empty string, return a promise rejected with |
| 514 // new DOMException whose name is "InvalidAccessError". | 551 // a newly created TypeError. |
| 515 if (sessionId.isEmpty()) { | 552 if (sessionId.isEmpty()) { |
| 516 return ScriptPromise::rejectWithDOMException( | 553 return ScriptPromise::reject( |
| 517 scriptState, DOMException::create(InvalidAccessError, | 554 scriptState, |
| 555 V8ThrowException::createTypeError(scriptState->isolate(), |
| 518 "The sessionId parameter is empty.")); | 556 "The sessionId parameter is empty.")); |
| 519 } | 557 } |
| 520 | 558 |
| 521 // 4. If this object's session type is not "persistent-license" or | 559 // 5. If the result of running the "Is persistent session type?" algorithm |
| 522 // "persistent-release-message", return a promise rejected with a | 560 // on this object's session type is false, return a promise rejected |
| 523 // new DOMException whose name is InvalidAccessError. | 561 // with a newly created TypeError. |
| 524 if (m_sessionType != WebEncryptedMediaSessionType::PersistentLicense && | 562 if (!IsPersistentSessionType(m_sessionType)) { |
| 525 m_sessionType != WebEncryptedMediaSessionType::PersistentReleaseMessage) { | 563 return ScriptPromise::reject( |
| 526 return ScriptPromise::rejectWithDOMException( | |
| 527 scriptState, | 564 scriptState, |
| 528 DOMException::create(InvalidAccessError, | 565 V8ThrowException::createTypeError( |
| 529 "The session type is not persistent.")); | 566 scriptState->isolate(), "The session type is not persistent.")); |
| 530 } | 567 } |
| 531 | 568 |
| 532 // 5. If the Key System implementation represented by this object's cdm | |
| 533 // implementation value does not support loading previous sessions, | |
| 534 // return a promise rejected with a new DOMException whose name is | |
| 535 // NotSupportedError. | |
| 536 // FIXME: Implement this (http://crbug.com/448922). | |
| 537 | |
| 538 // 6. Let origin be the origin of this object's Document. | 569 // 6. Let origin be the origin of this object's Document. |
| 539 // (Available as getExecutionContext()->getSecurityOrigin() anytime.) | 570 // (Available as getExecutionContext()->getSecurityOrigin() anytime.) |
| 540 | 571 |
| 541 // 7. Let promise be a new promise. | 572 // 7. Let promise be a new promise. |
| 542 LoadSessionResultPromise* result = | 573 LoadSessionResultPromise* result = |
| 543 new LoadSessionResultPromise(scriptState, this); | 574 new LoadSessionResultPromise(scriptState, this); |
| 544 ScriptPromise promise = result->promise(); | 575 ScriptPromise promise = result->promise(); |
| 545 | 576 |
| 546 // 8. Run the following steps asynchronously (documented in | 577 // 8. Run the following steps asynchronously (documented in |
| 547 // actionTimerFired()) | 578 // actionTimerFired()) |
| 548 m_pendingActions.append( | 579 m_pendingActions.append( |
| 549 PendingAction::CreatePendingLoadRequest(result, sessionId)); | 580 PendingAction::CreatePendingLoadRequest(result, sessionId)); |
| 550 DCHECK(!m_actionTimer.isActive()); | 581 DCHECK(!m_actionTimer.isActive()); |
| 551 m_actionTimer.startOneShot(0, BLINK_FROM_HERE); | 582 m_actionTimer.startOneShot(0, BLINK_FROM_HERE); |
| 552 | 583 |
| 553 // 9. Return promise. | 584 // 9. Return promise. |
| 554 return promise; | 585 return promise; |
| 555 } | 586 } |
| 556 | 587 |
| 557 ScriptPromise MediaKeySession::update(ScriptState* scriptState, | 588 ScriptPromise MediaKeySession::update(ScriptState* scriptState, |
| 558 const DOMArrayPiece& response) { | 589 const DOMArrayPiece& response) { |
| 559 DVLOG(MEDIA_KEY_SESSION_LOG_LEVEL) << __func__ << "(" << this << ")"; | 590 DVLOG(MEDIA_KEY_SESSION_LOG_LEVEL) << __func__ << "(" << this << ")"; |
| 560 DCHECK(!m_isClosed); | |
| 561 | 591 |
| 562 // From https://w3c.github.io/encrypted-media/#update: | 592 // From https://w3c.github.io/encrypted-media/#update: |
| 563 // Provides messages, including licenses, to the CDM. When this method is | 593 // Provides messages, including licenses, to the CDM. When this method is |
| 564 // invoked, the user agent must run the following steps: | 594 // invoked, the user agent must run the following steps: |
| 565 | 595 |
| 566 // 1. If this object's callable value is false, return a promise rejected | 596 // 1. If this object is closed, return a promise rejected with an |
| 567 // with a new DOMException whose name is InvalidStateError. | 597 // InvalidStateError. |
| 598 if (m_isClosed) |
| 599 return CreateRejectedPromiseAlreadyClosed(scriptState); |
| 600 |
| 601 // 2. If this object's callable value is false, return a promise |
| 602 // rejected with an InvalidStateError. |
| 568 if (!m_isCallable) | 603 if (!m_isCallable) |
| 569 return CreateRejectedPromiseNotCallable(scriptState); | 604 return CreateRejectedPromiseNotCallable(scriptState); |
| 570 | 605 |
| 571 // 2. If response is an empty array, return a promise rejected with a | 606 // 3. If response is an empty array, return a promise rejected with a |
| 572 // new DOMException whose name is InvalidAccessError. | 607 // newly created TypeError. |
| 573 if (!response.byteLength()) { | 608 if (!response.byteLength()) { |
| 574 return ScriptPromise::rejectWithDOMException( | 609 return ScriptPromise::reject( |
| 575 scriptState, DOMException::create(InvalidAccessError, | 610 scriptState, |
| 611 V8ThrowException::createTypeError(scriptState->isolate(), |
| 576 "The response parameter is empty.")); | 612 "The response parameter is empty.")); |
| 577 } | 613 } |
| 578 | 614 |
| 579 // 3. Let response copy be a copy of the contents of the response parameter. | 615 // 4. Let response copy be a copy of the contents of the response parameter. |
| 580 DOMArrayBuffer* responseCopy = | 616 DOMArrayBuffer* responseCopy = |
| 581 DOMArrayBuffer::create(response.data(), response.byteLength()); | 617 DOMArrayBuffer::create(response.data(), response.byteLength()); |
| 582 | 618 |
| 583 // 4. Let promise be a new promise. | 619 // 5. Let promise be a new promise. |
| 584 SimpleResultPromise* result = new SimpleResultPromise(scriptState, this); | 620 SimpleResultPromise* result = new SimpleResultPromise(scriptState, this); |
| 585 ScriptPromise promise = result->promise(); | 621 ScriptPromise promise = result->promise(); |
| 586 | 622 |
| 587 // 5. Run the following steps asynchronously (documented in | 623 // 6. Run the following steps asynchronously (documented in |
| 588 // actionTimerFired()) | 624 // actionTimerFired()) |
| 589 m_pendingActions.append( | 625 m_pendingActions.append( |
| 590 PendingAction::CreatePendingUpdate(result, responseCopy)); | 626 PendingAction::CreatePendingUpdate(result, responseCopy)); |
| 591 if (!m_actionTimer.isActive()) | 627 if (!m_actionTimer.isActive()) |
| 592 m_actionTimer.startOneShot(0, BLINK_FROM_HERE); | 628 m_actionTimer.startOneShot(0, BLINK_FROM_HERE); |
| 593 | 629 |
| 594 // 6. Return promise. | 630 // 7. Return promise. |
| 595 return promise; | 631 return promise; |
| 596 } | 632 } |
| 597 | 633 |
| 598 ScriptPromise MediaKeySession::close(ScriptState* scriptState) { | 634 ScriptPromise MediaKeySession::close(ScriptState* scriptState) { |
| 599 DVLOG(MEDIA_KEY_SESSION_LOG_LEVEL) << __func__ << "(" << this << ")"; | 635 DVLOG(MEDIA_KEY_SESSION_LOG_LEVEL) << __func__ << "(" << this << ")"; |
| 600 | 636 |
| 601 // From https://w3c.github.io/encrypted-media/#close: | 637 // From https://w3c.github.io/encrypted-media/#close: |
| 602 // Indicates that the application no longer needs the session and the CDM | 638 // Indicates that the application no longer needs the session and the CDM |
| 603 // should release any resources associated with this object and close it. | 639 // should release any resources associated with this object and close it. |
| 604 // When this method is invoked, the user agent must run the following steps: | 640 // When this method is invoked, the user agent must run the following steps: |
| (...skipping 22 matching lines...) Expand all Loading... |
| 627 return promise; | 663 return promise; |
| 628 } | 664 } |
| 629 | 665 |
| 630 ScriptPromise MediaKeySession::remove(ScriptState* scriptState) { | 666 ScriptPromise MediaKeySession::remove(ScriptState* scriptState) { |
| 631 DVLOG(MEDIA_KEY_SESSION_LOG_LEVEL) << __func__ << "(" << this << ")"; | 667 DVLOG(MEDIA_KEY_SESSION_LOG_LEVEL) << __func__ << "(" << this << ")"; |
| 632 | 668 |
| 633 // From https://w3c.github.io/encrypted-media/#remove: | 669 // From https://w3c.github.io/encrypted-media/#remove: |
| 634 // Removes stored session data associated with this object. When this | 670 // Removes stored session data associated with this object. When this |
| 635 // method is invoked, the user agent must run the following steps: | 671 // method is invoked, the user agent must run the following steps: |
| 636 | 672 |
| 637 // 1. If this object's callable value is false, return a promise rejected | 673 // 1. If this object is closed, return a promise rejected with an |
| 638 // with a new DOMException whose name is "InvalidStateError". | 674 // InvalidStateError. |
| 675 if (m_isClosed) |
| 676 return CreateRejectedPromiseAlreadyClosed(scriptState); |
| 677 |
| 678 // 2. If this object's callable value is false, return a promise rejected |
| 679 // with an InvalidStateError. |
| 639 if (!m_isCallable) | 680 if (!m_isCallable) |
| 640 return CreateRejectedPromiseNotCallable(scriptState); | 681 return CreateRejectedPromiseNotCallable(scriptState); |
| 641 | 682 |
| 642 // 2. If this object's session type is not "persistent-license" or | 683 // 3. If the result of running the "Is persistent session type?" algorithm |
| 643 // "persistent-release-message", return a promise rejected with a | 684 // on this object's session type is false, return a promise rejected |
| 644 // new DOMException whose name is InvalidAccessError. | 685 // with a newly created TypeError. |
| 645 if (m_sessionType != WebEncryptedMediaSessionType::PersistentLicense && | 686 if (!IsPersistentSessionType(m_sessionType)) { |
| 646 m_sessionType != WebEncryptedMediaSessionType::PersistentReleaseMessage) { | 687 return ScriptPromise::reject( |
| 647 return ScriptPromise::rejectWithDOMException( | |
| 648 scriptState, | 688 scriptState, |
| 649 DOMException::create(InvalidAccessError, | 689 V8ThrowException::createTypeError( |
| 650 "The session type is not persistent.")); | 690 scriptState->isolate(), "The session type is not persistent.")); |
| 651 } | |
| 652 | |
| 653 // 3. If the Session Close algorithm has been run on this object, return a | |
| 654 // promise rejected with a new DOMException whose name is | |
| 655 // "InvalidStateError". | |
| 656 if (m_isClosed) { | |
| 657 return ScriptPromise::rejectWithDOMException( | |
| 658 scriptState, DOMException::create(InvalidStateError, | |
| 659 "The session is already closed.")); | |
| 660 } | 691 } |
| 661 | 692 |
| 662 // 4. Let promise be a new promise. | 693 // 4. Let promise be a new promise. |
| 663 SimpleResultPromise* result = new SimpleResultPromise(scriptState, this); | 694 SimpleResultPromise* result = new SimpleResultPromise(scriptState, this); |
| 664 ScriptPromise promise = result->promise(); | 695 ScriptPromise promise = result->promise(); |
| 665 | 696 |
| 666 // 5. Run the following steps asynchronously (documented in | 697 // 5. Run the following steps asynchronously (documented in |
| 667 // actionTimerFired()). | 698 // actionTimerFired()). |
| 668 m_pendingActions.append(PendingAction::CreatePendingRemove(result)); | 699 m_pendingActions.append(PendingAction::CreatePendingRemove(result)); |
| 669 if (!m_actionTimer.isActive()) | 700 if (!m_actionTimer.isActive()) |
| (...skipping 10 matching lines...) Expand all Loading... |
| 680 // actions getting added to the queue. As a result, swap the queue to | 711 // actions getting added to the queue. As a result, swap the queue to |
| 681 // a local copy to avoid problems if this happens. | 712 // a local copy to avoid problems if this happens. |
| 682 HeapDeque<Member<PendingAction>> pendingActions; | 713 HeapDeque<Member<PendingAction>> pendingActions; |
| 683 pendingActions.swap(m_pendingActions); | 714 pendingActions.swap(m_pendingActions); |
| 684 | 715 |
| 685 while (!pendingActions.isEmpty()) { | 716 while (!pendingActions.isEmpty()) { |
| 686 PendingAction* action = pendingActions.takeFirst(); | 717 PendingAction* action = pendingActions.takeFirst(); |
| 687 | 718 |
| 688 switch (action->getType()) { | 719 switch (action->getType()) { |
| 689 case PendingAction::GenerateRequest: | 720 case PendingAction::GenerateRequest: |
| 690 // NOTE: Continue step 9 of MediaKeySession::generateRequest(). | 721 // NOTE: Continue step 10 of MediaKeySession::generateRequest(). |
| 691 DVLOG(MEDIA_KEY_SESSION_LOG_LEVEL) << __func__ << "(" << this | 722 DVLOG(MEDIA_KEY_SESSION_LOG_LEVEL) << __func__ << "(" << this |
| 692 << ") GenerateRequest"; | 723 << ") GenerateRequest"; |
| 693 | 724 |
| 694 // initializeNewSession() in Chromium will execute steps 9.1 to 9.7. | 725 // initializeNewSession() in Chromium will execute steps 10.1 to 10.9. |
| 695 m_session->initializeNewSession( | 726 m_session->initializeNewSession( |
| 696 action->initDataType(), | 727 action->initDataType(), |
| 697 static_cast<unsigned char*>(action->data()->data()), | 728 static_cast<unsigned char*>(action->data()->data()), |
| 698 action->data()->byteLength(), m_sessionType, | 729 action->data()->byteLength(), m_sessionType, |
| 699 action->result()->result()); | 730 action->result()->result()); |
| 700 | 731 |
| 701 // Remaining steps (from 9.8) executed in finishGenerateRequest(), | 732 // Remaining steps (from 10.10) executed in finishGenerateRequest(), |
| 702 // called when |result| is resolved. | 733 // called when |result| is resolved. |
| 703 break; | 734 break; |
| 704 | 735 |
| 705 case PendingAction::Load: | 736 case PendingAction::Load: |
| 706 // NOTE: Continue step 8 of MediaKeySession::load(). | 737 // NOTE: Continue step 8 of MediaKeySession::load(). |
| 707 DVLOG(MEDIA_KEY_SESSION_LOG_LEVEL) << __func__ << "(" << this | 738 DVLOG(MEDIA_KEY_SESSION_LOG_LEVEL) << __func__ << "(" << this |
| 708 << ") Load"; | 739 << ") Load"; |
| 709 | 740 |
| 710 // 8.1 Let sanitized session ID be a validated and/or sanitized | 741 // 8.1 Let sanitized session ID be a validated and/or sanitized |
| 711 // version of sessionId. The user agent should thoroughly | 742 // version of sessionId. The user agent should thoroughly |
| 712 // validate the sessionId value before passing it to the CDM. | 743 // validate the sessionId value before passing it to the CDM. |
| 713 // At a minimum, this should include checking that the length | 744 // At a minimum, this should include checking that the length |
| 714 // and value (e.g. alphanumeric) are reasonable. | 745 // and value (e.g. alphanumeric) are reasonable. |
| 715 // 8.2 If the previous step failed, reject promise with a new | 746 // 8.2 If the preceding step failed, or if sanitized session ID |
| 716 // DOMException whose name is "InvalidAccessError". | 747 // is empty, reject promise with a newly created TypeError. |
| 717 if (!isValidSessionId(action->sessionId())) { | 748 if (!isValidSessionId(action->sessionId())) { |
| 718 action->result()->completeWithError( | 749 action->result()->completeWithError( |
| 719 WebContentDecryptionModuleExceptionInvalidAccessError, 0, | 750 WebContentDecryptionModuleExceptionTypeError, 0, |
| 720 "Invalid sessionId"); | 751 "Invalid sessionId"); |
| 721 return; | 752 return; |
| 722 } | 753 } |
| 723 | 754 |
| 724 // 8.3 If there is an unclosed session in the object's Document | 755 // 8.3 If there is an unclosed session in the object's Document |
| 725 // whose sessionId attribute is sanitized session ID, reject | 756 // whose sessionId attribute is sanitized session ID, reject |
| 726 // promise with a new DOMException whose name is | 757 // promise with a new DOMException whose name is |
| 727 // QuotaExceededError. In other words, do not create a session | 758 // QuotaExceededError. In other words, do not create a session |
| 728 // if a non-closed session, regardless of type, already exists | 759 // if a non-closed session, regardless of type, already exists |
| 729 // for this sanitized session ID in this browsing context. | 760 // for this sanitized session ID in this browsing context. |
| (...skipping 272 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1002 visitor->trace(m_asyncEventQueue); | 1033 visitor->trace(m_asyncEventQueue); |
| 1003 visitor->trace(m_pendingActions); | 1034 visitor->trace(m_pendingActions); |
| 1004 visitor->trace(m_mediaKeys); | 1035 visitor->trace(m_mediaKeys); |
| 1005 visitor->trace(m_keyStatusesMap); | 1036 visitor->trace(m_keyStatusesMap); |
| 1006 visitor->trace(m_closedPromise); | 1037 visitor->trace(m_closedPromise); |
| 1007 EventTargetWithInlineData::trace(visitor); | 1038 EventTargetWithInlineData::trace(visitor); |
| 1008 ActiveDOMObject::trace(visitor); | 1039 ActiveDOMObject::trace(visitor); |
| 1009 } | 1040 } |
| 1010 | 1041 |
| 1011 } // namespace blink | 1042 } // namespace blink |
| OLD | NEW |