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