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 29 matching lines...) Expand all Loading... |
40 #include "platform/ContentDecryptionModuleResult.h" | 40 #include "platform/ContentDecryptionModuleResult.h" |
41 #include "platform/ContentType.h" | 41 #include "platform/ContentType.h" |
42 #include "platform/Logging.h" | 42 #include "platform/Logging.h" |
43 #include "platform/MIMETypeRegistry.h" | 43 #include "platform/MIMETypeRegistry.h" |
44 #include "platform/Timer.h" | 44 #include "platform/Timer.h" |
45 #include "public/platform/WebContentDecryptionModule.h" | 45 #include "public/platform/WebContentDecryptionModule.h" |
46 #include "public/platform/WebContentDecryptionModuleException.h" | 46 #include "public/platform/WebContentDecryptionModuleException.h" |
47 #include "public/platform/WebContentDecryptionModuleSession.h" | 47 #include "public/platform/WebContentDecryptionModuleSession.h" |
48 #include "public/platform/WebString.h" | 48 #include "public/platform/WebString.h" |
49 #include "public/platform/WebURL.h" | 49 #include "public/platform/WebURL.h" |
| 50 #include "wtf/ASCIICType.h" |
50 #include "wtf/ArrayBuffer.h" | 51 #include "wtf/ArrayBuffer.h" |
51 #include "wtf/ArrayBufferView.h" | 52 #include "wtf/ArrayBufferView.h" |
52 #include <cmath> | 53 #include <cmath> |
53 #include <limits> | 54 #include <limits> |
54 | 55 |
55 namespace { | 56 namespace { |
56 | 57 |
57 // The list of possible values for |sessionType| passed to createSession(). | 58 // The list of possible values for |sessionType|. |
58 #if ENABLE(ASSERT) | |
59 const char* kTemporary = "temporary"; | 59 const char* kTemporary = "temporary"; |
60 #endif | |
61 const char* kPersistent = "persistent"; | 60 const char* kPersistent = "persistent"; |
62 | 61 |
| 62 // Minimum and maximum length for session ids. |
| 63 enum { |
| 64 MinSessionIdLength = 1, |
| 65 MaxSessionIdLength = 512 |
| 66 }; |
| 67 |
63 } // namespace | 68 } // namespace |
64 | 69 |
65 namespace blink { | 70 namespace blink { |
66 | 71 |
67 static bool isKeySystemSupportedWithInitDataType(const String& keySystem, const
String& initDataType) | 72 static bool isKeySystemSupportedWithInitDataType(const String& keySystem, const
String& initDataType) |
68 { | 73 { |
69 ASSERT(!keySystem.isEmpty()); | 74 ASSERT(!keySystem.isEmpty()); |
70 | 75 |
71 // FIXME: initDataType != contentType. Implement this properly. | 76 // FIXME: initDataType != contentType. Implement this properly. |
72 // http://crbug.com/385874. | 77 // http://crbug.com/385874. |
73 String contentType = initDataType; | 78 String contentType = initDataType; |
74 if (initDataType == "webm") { | 79 if (initDataType == "webm") { |
75 contentType = "video/webm"; | 80 contentType = "video/webm"; |
76 } else if (initDataType == "cenc") { | 81 } else if (initDataType == "cenc") { |
77 contentType = "video/mp4"; | 82 contentType = "video/mp4"; |
78 } | 83 } |
79 | 84 |
80 ContentType type(contentType); | 85 ContentType type(contentType); |
81 return MIMETypeRegistry::isSupportedEncryptedMediaMIMEType(keySystem, type.t
ype(), type.parameter("codecs")); | 86 return MIMETypeRegistry::isSupportedEncryptedMediaMIMEType(keySystem, type.t
ype(), type.parameter("codecs")); |
82 } | 87 } |
83 | 88 |
| 89 // Checks that |sessionId| looks correct and returns whether all checks pass. |
| 90 static bool isValidSessionId(const String& sessionId) |
| 91 { |
| 92 if ((sessionId.length() < MinSessionIdLength) || (sessionId.length() > MaxSe
ssionIdLength)) |
| 93 return false; |
| 94 |
| 95 if (!sessionId.containsOnlyASCII()) |
| 96 return false; |
| 97 |
| 98 // Check that the sessionId only contains alphanumeric characters. |
| 99 for (unsigned i = 0; i < sessionId.length(); ++i) { |
| 100 if (!isASCIIAlphanumeric(sessionId[i])) |
| 101 return false; |
| 102 } |
| 103 |
| 104 return true; |
| 105 } |
| 106 |
84 // A class holding a pending action. | 107 // A class holding a pending action. |
85 class MediaKeySession::PendingAction : public GarbageCollectedFinalized<MediaKey
Session::PendingAction> { | 108 class MediaKeySession::PendingAction : public GarbageCollectedFinalized<MediaKey
Session::PendingAction> { |
86 public: | 109 public: |
87 enum Type { | 110 enum Type { |
88 GenerateRequest, | 111 GenerateRequest, |
| 112 Load, |
89 Update, | 113 Update, |
90 Close, | 114 Close, |
91 Remove | 115 Remove |
92 }; | 116 }; |
93 | 117 |
94 Type type() const { return m_type; } | 118 Type type() const { return m_type; } |
95 | 119 |
96 const Persistent<ContentDecryptionModuleResult> result() const | 120 const Persistent<ContentDecryptionModuleResult> result() const |
97 { | 121 { |
98 return m_result; | 122 return m_result; |
99 } | 123 } |
100 | 124 |
101 const RefPtr<ArrayBuffer> data() const | 125 const RefPtr<ArrayBuffer> data() const |
102 { | 126 { |
103 ASSERT(m_type == GenerateRequest || m_type == Update); | 127 ASSERT(m_type == GenerateRequest || m_type == Update); |
104 return m_data; | 128 return m_data; |
105 } | 129 } |
106 | 130 |
107 const String& initDataType() const | 131 const String& initDataType() const |
108 { | 132 { |
109 ASSERT(m_type == GenerateRequest); | 133 ASSERT(m_type == GenerateRequest); |
110 return m_initDataType; | 134 return m_stringData; |
| 135 } |
| 136 |
| 137 const String& sessionId() const |
| 138 { |
| 139 ASSERT(m_type == Load); |
| 140 return m_stringData; |
111 } | 141 } |
112 | 142 |
113 static PendingAction* CreatePendingGenerateRequest(ContentDecryptionModuleRe
sult* result, const String& initDataType, PassRefPtr<ArrayBuffer> initData) | 143 static PendingAction* CreatePendingGenerateRequest(ContentDecryptionModuleRe
sult* result, const String& initDataType, PassRefPtr<ArrayBuffer> initData) |
114 { | 144 { |
115 ASSERT(result); | 145 ASSERT(result); |
116 ASSERT(initData); | 146 ASSERT(initData); |
117 return new PendingAction(GenerateRequest, result, initDataType, initData
); | 147 return new PendingAction(GenerateRequest, result, initDataType, initData
); |
118 } | 148 } |
119 | 149 |
| 150 static PendingAction* CreatePendingLoadRequest(ContentDecryptionModuleResult
* result, const String& sessionId) |
| 151 { |
| 152 ASSERT(result); |
| 153 return new PendingAction(Load, result, sessionId, PassRefPtr<ArrayBuffer
>()); |
| 154 } |
| 155 |
120 static PendingAction* CreatePendingUpdate(ContentDecryptionModuleResult* res
ult, PassRefPtr<ArrayBuffer> data) | 156 static PendingAction* CreatePendingUpdate(ContentDecryptionModuleResult* res
ult, PassRefPtr<ArrayBuffer> data) |
121 { | 157 { |
122 ASSERT(result); | 158 ASSERT(result); |
123 ASSERT(data); | 159 ASSERT(data); |
124 return new PendingAction(Update, result, String(), data); | 160 return new PendingAction(Update, result, String(), data); |
125 } | 161 } |
126 | 162 |
127 static PendingAction* CreatePendingClose(ContentDecryptionModuleResult* resu
lt) | 163 static PendingAction* CreatePendingClose(ContentDecryptionModuleResult* resu
lt) |
128 { | 164 { |
129 ASSERT(result); | 165 ASSERT(result); |
130 return new PendingAction(Close, result, String(), PassRefPtr<ArrayBuffer
>()); | 166 return new PendingAction(Close, result, String(), PassRefPtr<ArrayBuffer
>()); |
131 } | 167 } |
132 | 168 |
133 static PendingAction* CreatePendingRemove(ContentDecryptionModuleResult* res
ult) | 169 static PendingAction* CreatePendingRemove(ContentDecryptionModuleResult* res
ult) |
134 { | 170 { |
135 ASSERT(result); | 171 ASSERT(result); |
136 return new PendingAction(Remove, result, String(), PassRefPtr<ArrayBuffe
r>()); | 172 return new PendingAction(Remove, result, String(), PassRefPtr<ArrayBuffe
r>()); |
137 } | 173 } |
138 | 174 |
139 ~PendingAction() | 175 ~PendingAction() |
140 { | 176 { |
141 } | 177 } |
142 | 178 |
143 void trace(Visitor* visitor) | 179 void trace(Visitor* visitor) |
144 { | 180 { |
145 visitor->trace(m_result); | 181 visitor->trace(m_result); |
146 } | 182 } |
147 | 183 |
148 private: | 184 private: |
149 PendingAction(Type type, ContentDecryptionModuleResult* result, const String
& initDataType, PassRefPtr<ArrayBuffer> data) | 185 PendingAction(Type type, ContentDecryptionModuleResult* result, const String
& stringData, PassRefPtr<ArrayBuffer> data) |
150 : m_type(type) | 186 : m_type(type) |
151 , m_result(result) | 187 , m_result(result) |
152 , m_initDataType(initDataType) | 188 , m_stringData(stringData) |
153 , m_data(data) | 189 , m_data(data) |
154 { | 190 { |
155 } | 191 } |
156 | 192 |
157 const Type m_type; | 193 const Type m_type; |
158 const Member<ContentDecryptionModuleResult> m_result; | 194 const Member<ContentDecryptionModuleResult> m_result; |
159 const String m_initDataType; | 195 const String m_stringData; |
160 const RefPtr<ArrayBuffer> m_data; | 196 const RefPtr<ArrayBuffer> m_data; |
161 }; | 197 }; |
162 | 198 |
163 // This class wraps the promise resolver used when initializing a new session | 199 // This class wraps the promise resolver used when initializing a new session |
164 // and is passed to Chromium to fullfill the promise. This implementation of | 200 // and is passed to Chromium to fullfill the promise. This implementation of |
165 // completeWithSession() will resolve the promise with void, while | 201 // completeWithSession() will resolve the promise with void, while |
166 // completeWithError() will reject the promise with an exception. complete() | 202 // completeWithError() will reject the promise with an exception. complete() |
167 // is not expected to be called, and will reject the promise. | 203 // is not expected to be called, and will reject the promise. |
168 class NewSessionResult : public ContentDecryptionModuleResult { | 204 class NewSessionResult : public ContentDecryptionModuleResult { |
169 public: | 205 public: |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
217 void completeWithDOMException(ExceptionCode code, const String& errorMessage
) | 253 void completeWithDOMException(ExceptionCode code, const String& errorMessage
) |
218 { | 254 { |
219 m_resolver->reject(DOMException::create(code, errorMessage)); | 255 m_resolver->reject(DOMException::create(code, errorMessage)); |
220 m_resolver.clear(); | 256 m_resolver.clear(); |
221 } | 257 } |
222 | 258 |
223 RefPtr<ScriptPromiseResolver> m_resolver; | 259 RefPtr<ScriptPromiseResolver> m_resolver; |
224 Member<MediaKeySession> m_session; | 260 Member<MediaKeySession> m_session; |
225 }; | 261 }; |
226 | 262 |
| 263 // This class wraps the promise resolver used when loading a session |
| 264 // and is passed to Chromium to fullfill the promise. This implementation of |
| 265 // completeWithSession() will resolve the promise with true/false, while |
| 266 // completeWithError() will reject the promise with an exception. complete() |
| 267 // is not expected to be called, and will reject the promise. |
| 268 class LoadSessionResult : public ContentDecryptionModuleResult { |
| 269 public: |
| 270 LoadSessionResult(ScriptState* scriptState, MediaKeySession* session) |
| 271 : m_resolver(ScriptPromiseResolver::create(scriptState)) |
| 272 , m_session(session) |
| 273 { |
| 274 WTF_LOG(Media, "LoadSessionResult(%p)", this); |
| 275 } |
| 276 |
| 277 virtual ~LoadSessionResult() |
| 278 { |
| 279 WTF_LOG(Media, "~LoadSessionResult(%p)", this); |
| 280 } |
| 281 |
| 282 // ContentDecryptionModuleResult implementation. |
| 283 virtual void complete() override |
| 284 { |
| 285 ASSERT_NOT_REACHED(); |
| 286 completeWithDOMException(InvalidStateError, "Unexpected completion."); |
| 287 } |
| 288 |
| 289 virtual void completeWithSession(WebContentDecryptionModuleResult::SessionSt
atus status) override |
| 290 { |
| 291 bool result = false; |
| 292 switch (status) { |
| 293 case WebContentDecryptionModuleResult::NewSession: |
| 294 result = true; |
| 295 break; |
| 296 |
| 297 case WebContentDecryptionModuleResult::SessionNotFound: |
| 298 result = false; |
| 299 break; |
| 300 |
| 301 case WebContentDecryptionModuleResult::SessionAlreadyExists: |
| 302 ASSERT_NOT_REACHED(); |
| 303 completeWithDOMException(InvalidStateError, "Unexpected completion."
); |
| 304 return; |
| 305 } |
| 306 |
| 307 m_session->finishLoad(); |
| 308 m_resolver->resolve(result); |
| 309 m_resolver.clear(); |
| 310 } |
| 311 |
| 312 virtual void completeWithError(WebContentDecryptionModuleException exception
Code, unsigned long systemCode, const WebString& errorMessage) override |
| 313 { |
| 314 completeWithDOMException(WebCdmExceptionToExceptionCode(exceptionCode),
errorMessage); |
| 315 } |
| 316 |
| 317 // It is only valid to call this before completion. |
| 318 ScriptPromise promise() { return m_resolver->promise(); } |
| 319 |
| 320 void trace(Visitor* visitor) |
| 321 { |
| 322 visitor->trace(m_session); |
| 323 ContentDecryptionModuleResult::trace(visitor); |
| 324 } |
| 325 |
| 326 private: |
| 327 // Reject the promise with a DOMException. |
| 328 void completeWithDOMException(ExceptionCode code, const String& errorMessage
) |
| 329 { |
| 330 m_resolver->reject(DOMException::create(code, errorMessage)); |
| 331 m_resolver.clear(); |
| 332 } |
| 333 |
| 334 RefPtr<ScriptPromiseResolver> m_resolver; |
| 335 Member<MediaKeySession> m_session; |
| 336 }; |
| 337 |
227 MediaKeySession* MediaKeySession::create(ScriptState* scriptState, MediaKeys* me
diaKeys, const String& sessionType) | 338 MediaKeySession* MediaKeySession::create(ScriptState* scriptState, MediaKeys* me
diaKeys, const String& sessionType) |
228 { | 339 { |
229 ASSERT(sessionType == kTemporary || sessionType == kPersistent); | 340 ASSERT(sessionType == kTemporary || sessionType == kPersistent); |
230 RefPtrWillBeRawPtr<MediaKeySession> session = new MediaKeySession(scriptStat
e, mediaKeys, sessionType); | 341 RefPtrWillBeRawPtr<MediaKeySession> session = new MediaKeySession(scriptStat
e, mediaKeys, sessionType); |
231 session->suspendIfNeeded(); | 342 session->suspendIfNeeded(); |
232 return session.get(); | 343 return session.get(); |
233 } | 344 } |
234 | 345 |
| 346 bool MediaKeySession::isValidSessionType(const String& sessionType) |
| 347 { |
| 348 return (sessionType == kTemporary || sessionType == kPersistent); |
| 349 } |
| 350 |
235 MediaKeySession::MediaKeySession(ScriptState* scriptState, MediaKeys* mediaKeys,
const String& sessionType) | 351 MediaKeySession::MediaKeySession(ScriptState* scriptState, MediaKeys* mediaKeys,
const String& sessionType) |
236 : ActiveDOMObject(scriptState->executionContext()) | 352 : ActiveDOMObject(scriptState->executionContext()) |
237 , m_keySystem(mediaKeys->keySystem()) | 353 , m_keySystem(mediaKeys->keySystem()) |
238 , m_asyncEventQueue(GenericEventQueue::create(this)) | 354 , m_asyncEventQueue(GenericEventQueue::create(this)) |
239 , m_mediaKeys(mediaKeys) | 355 , m_mediaKeys(mediaKeys) |
240 , m_sessionType(sessionType) | 356 , m_sessionType(sessionType) |
241 , m_expiration(std::numeric_limits<double>::quiet_NaN()) | 357 , m_expiration(std::numeric_limits<double>::quiet_NaN()) |
242 , m_isUninitialized(true) | 358 , m_isUninitialized(true) |
243 , m_isCallable(false) | 359 , m_isCallable(false) |
244 , m_isClosed(false) | 360 , m_isClosed(false) |
(...skipping 13 matching lines...) Expand all Loading... |
258 // 2.1 Let the sessionId attribute be the empty string. | 374 // 2.1 Let the sessionId attribute be the empty string. |
259 ASSERT(sessionId().isEmpty()); | 375 ASSERT(sessionId().isEmpty()); |
260 | 376 |
261 // 2.2 Let the expiration attribute be NaN. | 377 // 2.2 Let the expiration attribute be NaN. |
262 ASSERT(std::isnan(m_expiration)); | 378 ASSERT(std::isnan(m_expiration)); |
263 | 379 |
264 // 2.3 Let the closed attribute be a new promise. | 380 // 2.3 Let the closed attribute be a new promise. |
265 ASSERT(!closed(scriptState).isUndefinedOrNull()); | 381 ASSERT(!closed(scriptState).isUndefinedOrNull()); |
266 | 382 |
267 // 2.4 Let the session type be sessionType. | 383 // 2.4 Let the session type be sessionType. |
268 ASSERT(sessionType == m_sessionType); | 384 ASSERT(isValidSessionType(sessionType)); |
269 | 385 |
270 // 2.5 Let uninitialized be true. | 386 // 2.5 Let uninitialized be true. |
271 ASSERT(m_isUninitialized); | 387 ASSERT(m_isUninitialized); |
272 | 388 |
273 // 2.6 Let callable be false. | 389 // 2.6 Let callable be false. |
274 ASSERT(!m_isCallable); | 390 ASSERT(!m_isCallable); |
275 } | 391 } |
276 | 392 |
277 MediaKeySession::~MediaKeySession() | 393 MediaKeySession::~MediaKeySession() |
278 { | 394 { |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
370 // 10. Run the following steps asynchronously (documented in | 486 // 10. Run the following steps asynchronously (documented in |
371 // actionTimerFired()) | 487 // actionTimerFired()) |
372 m_pendingActions.append(PendingAction::CreatePendingGenerateRequest(result,
initDataType, initData)); | 488 m_pendingActions.append(PendingAction::CreatePendingGenerateRequest(result,
initDataType, initData)); |
373 ASSERT(!m_actionTimer.isActive()); | 489 ASSERT(!m_actionTimer.isActive()); |
374 m_actionTimer.startOneShot(0, FROM_HERE); | 490 m_actionTimer.startOneShot(0, FROM_HERE); |
375 | 491 |
376 // 11. Return promise. | 492 // 11. Return promise. |
377 return promise; | 493 return promise; |
378 } | 494 } |
379 | 495 |
| 496 ScriptPromise MediaKeySession::load(ScriptState* scriptState, const String& sess
ionId) |
| 497 { |
| 498 WTF_LOG(Media, "MediaKeySession(%p)::load %s", this, sessionId.ascii().data(
)); |
| 499 |
| 500 // From https://dvcs.w3.org/hg/html-media/raw-file/default/encrypted-media/e
ncrypted-media.html#dom-load: |
| 501 // The load(sessionId) method loads the data stored for the sessionId into |
| 502 // the session represented by the object. It must run the following steps: |
| 503 |
| 504 // 1. If this object's uninitialized value is false, return a promise |
| 505 // rejected with a new DOMException whose name is "InvalidStateError". |
| 506 if (!m_isUninitialized) { |
| 507 return ScriptPromise::rejectWithDOMException( |
| 508 scriptState, DOMException::create(InvalidStateError, "The session is
already initialized.")); |
| 509 } |
| 510 |
| 511 // 2. Let this object's uninitialized be false. |
| 512 m_isUninitialized = false; |
| 513 |
| 514 // 3. If sessionId is an empty string, return a promise rejected with a |
| 515 // new DOMException whose name is "InvalidAccessError". |
| 516 if (sessionId.isEmpty()) { |
| 517 return ScriptPromise::rejectWithDOMException( |
| 518 scriptState, DOMException::create(InvalidAccessError, "The sessionId
parameter is empty.")); |
| 519 } |
| 520 |
| 521 // 4. If this object's session type is not "persistent", return a promise |
| 522 // rejected with a new DOMException whose name is "InvalidAccessError". |
| 523 if (m_sessionType != kPersistent) { |
| 524 return ScriptPromise::rejectWithDOMException( |
| 525 scriptState, DOMException::create(InvalidAccessError, "The session t
ype is not 'persistent'.")); |
| 526 } |
| 527 |
| 528 // 5. Let media keys be the MediaKeys object that created this object. |
| 529 // (Done in constructor.) |
| 530 ASSERT(m_mediaKeys); |
| 531 |
| 532 // 6. If the content decryption module corresponding to media keys's |
| 533 // keySystem attribute does not support loading previous sessions, |
| 534 // return a promise rejected with a new DOMException whose name is |
| 535 // "NotSupportedError". |
| 536 // (Done by CDM.) |
| 537 |
| 538 // 7. Let promise be a new promise. |
| 539 LoadSessionResult* result = new LoadSessionResult(scriptState, this); |
| 540 ScriptPromise promise = result->promise(); |
| 541 |
| 542 // 8. Run the following steps asynchronously (documented in |
| 543 // actionTimerFired()) |
| 544 m_pendingActions.append(PendingAction::CreatePendingLoadRequest(result, sess
ionId)); |
| 545 ASSERT(!m_actionTimer.isActive()); |
| 546 m_actionTimer.startOneShot(0, FROM_HERE); |
| 547 |
| 548 // 9. Return promise. |
| 549 return promise; |
| 550 } |
| 551 |
380 ScriptPromise MediaKeySession::update(ScriptState* scriptState, ArrayBuffer* res
ponse) | 552 ScriptPromise MediaKeySession::update(ScriptState* scriptState, ArrayBuffer* res
ponse) |
381 { | 553 { |
382 RefPtr<ArrayBuffer> responseCopy = ArrayBuffer::create(response->data(), res
ponse->byteLength()); | 554 RefPtr<ArrayBuffer> responseCopy = ArrayBuffer::create(response->data(), res
ponse->byteLength()); |
383 return updateInternal(scriptState, responseCopy.release()); | 555 return updateInternal(scriptState, responseCopy.release()); |
384 } | 556 } |
385 | 557 |
386 ScriptPromise MediaKeySession::update(ScriptState* scriptState, ArrayBufferView*
response) | 558 ScriptPromise MediaKeySession::update(ScriptState* scriptState, ArrayBufferView*
response) |
387 { | 559 { |
388 RefPtr<ArrayBuffer> responseCopy = ArrayBuffer::create(response->baseAddress
(), response->byteLength()); | 560 RefPtr<ArrayBuffer> responseCopy = ArrayBuffer::create(response->baseAddress
(), response->byteLength()); |
389 return updateInternal(scriptState, responseCopy.release()); | 561 return updateInternal(scriptState, responseCopy.release()); |
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
533 // "NotSupportedError". | 705 // "NotSupportedError". |
534 // 10.3.3 Let request be a request (e.g. a license request) | 706 // 10.3.3 Let request be a request (e.g. a license request) |
535 // generated based on the init data, which is interpreted | 707 // generated based on the init data, which is interpreted |
536 // per initDataType, and session type. | 708 // per initDataType, and session type. |
537 m_session->initializeNewSession(action->initDataType(), static_cast<
unsigned char*>(action->data()->data()), action->data()->byteLength(), m_session
Type, action->result()->result()); | 709 m_session->initializeNewSession(action->initDataType(), static_cast<
unsigned char*>(action->data()->data()), action->data()->byteLength(), m_session
Type, action->result()->result()); |
538 | 710 |
539 // Remainder of steps executed in finishGenerateRequest(), called | 711 // Remainder of steps executed in finishGenerateRequest(), called |
540 // when |result| is resolved. | 712 // when |result| is resolved. |
541 break; | 713 break; |
542 | 714 |
| 715 case PendingAction::Load: |
| 716 // NOTE: Continue step 8 of MediaKeySession::load(). |
| 717 |
| 718 // 8.1 Let sanitized session ID be a validated and/or sanitized |
| 719 // version of sessionId. The user agent should thoroughly |
| 720 // validate the sessionId value before passing it to the CDM. |
| 721 // At a minimum, this should include checking that the length |
| 722 // and value (e.g. alphanumeric) are reasonable. |
| 723 // 8.2 If the previous step failed, reject promise with a new |
| 724 // DOMException whose name is "InvalidAccessError". |
| 725 if (!isValidSessionId(action->sessionId())) { |
| 726 action->result()->completeWithError(WebContentDecryptionModuleEx
ceptionInvalidAccessError, 0, "Invalid sessionId"); |
| 727 return; |
| 728 } |
| 729 |
| 730 // 8.3 Let expiration time be NaN. |
| 731 // (Done in the constructor.) |
| 732 ASSERT(std::isnan(m_expiration)); |
| 733 |
| 734 // 8.4 Let message be null. |
| 735 // 8.5 Let message type be null. |
| 736 // (Will be provided by the CDM if needed.) |
| 737 |
| 738 // 8.6 Let origin be the origin of this object's Document. |
| 739 // (Obtained previously when CDM created.) |
| 740 |
| 741 // 8.7 Let cdm be the CDM loaded during the initialization of media |
| 742 // keys. |
| 743 // 8.8 Use the cdm to execute the following steps: |
| 744 // 8.8.1 If there is no data stored for the sanitized session ID in |
| 745 // the origin, resolve promise with false. |
| 746 // 8.8.2 Let session data be the data stored for the sanitized |
| 747 // session ID in the origin. This must not include data from |
| 748 // other origin(s) or that is not associated with an origin. |
| 749 // 8.8.3 If there is an unclosed "persistent" session in any |
| 750 // Document representing the session data, reject promise |
| 751 // with a new DOMException whose name is "QuotaExceededError". |
| 752 // 8.8.4 In other words, do not create a session if a non-closed |
| 753 // persistent session already exists for this sanitized |
| 754 // session ID in any browsing context. |
| 755 // 8.8.5 Load the session data. |
| 756 // 8.8.6 If the session data indicates an expiration time for the |
| 757 // session, let expiration time be the expiration time |
| 758 // in milliseconds since 01 January 1970 UTC. |
| 759 // 8.8.6 If the CDM needs to send a message: |
| 760 // 8.8.6.1 Let message be a message generated by the CDM based on |
| 761 // the session data. |
| 762 // 8.8.6.2 Let message type be the appropriate MediaKeyMessageType |
| 763 // for the message. |
| 764 // 8.9 If any of the preceding steps failed, reject promise with a |
| 765 // new DOMException whose name is the appropriate error name. |
| 766 m_session->load(action->sessionId(), action->result()->result()); |
| 767 |
| 768 // Remainder of steps executed in finishLoad(), called |
| 769 // when |result| is resolved. |
| 770 break; |
| 771 |
543 case PendingAction::Update: | 772 case PendingAction::Update: |
544 WTF_LOG(Media, "MediaKeySession(%p)::actionTimerFired: Update", this
); | 773 WTF_LOG(Media, "MediaKeySession(%p)::actionTimerFired: Update", this
); |
545 // NOTE: Continued from step 4 of MediaKeySession::update(). | 774 // NOTE: Continued from step 4 of MediaKeySession::update(). |
546 // Continue the update call by passing message to the cdm. Once | 775 // Continue the update call by passing message to the cdm. Once |
547 // completed, it will resolve/reject the promise. | 776 // completed, it will resolve/reject the promise. |
548 m_session->update(static_cast<unsigned char*>(action->data()->data()
), action->data()->byteLength(), action->result()->result()); | 777 m_session->update(static_cast<unsigned char*>(action->data()->data()
), action->data()->byteLength(), action->result()->result()); |
549 break; | 778 break; |
550 | 779 |
551 case PendingAction::Close: | 780 case PendingAction::Close: |
552 WTF_LOG(Media, "MediaKeySession(%p)::actionTimerFired: Close", this)
; | 781 WTF_LOG(Media, "MediaKeySession(%p)::actionTimerFired: Close", this)
; |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
606 // https://www.w3.org/Bugs/Public/show_bug.cgi?id=26758 | 835 // https://www.w3.org/Bugs/Public/show_bug.cgi?id=26758 |
607 | 836 |
608 // 10.7 Run the Queue a "message" Event algorithm on the session, | 837 // 10.7 Run the Queue a "message" Event algorithm on the session, |
609 // providing request and null. | 838 // providing request and null. |
610 // (Done by the CDM). | 839 // (Done by the CDM). |
611 | 840 |
612 // 10.8 Let this object's callable be true. | 841 // 10.8 Let this object's callable be true. |
613 m_isCallable = true; | 842 m_isCallable = true; |
614 } | 843 } |
615 | 844 |
| 845 void MediaKeySession::finishLoad() |
| 846 { |
| 847 // 8.10 Set the sessionId attribute to sanitized session ID. |
| 848 ASSERT(!sessionId().isEmpty()); |
| 849 |
| 850 // 8.11 Let this object's callable be true. |
| 851 m_isCallable = true; |
| 852 |
| 853 // 8.12 If the loaded session contains usable keys, run the Usable |
| 854 // Keys Changed algorithm on the session. The algorithm may |
| 855 // also be run later should additional processing be necessary |
| 856 // to determine with certainty whether one or more keys is |
| 857 // usable. |
| 858 // (Done by the CDM.) |
| 859 |
| 860 // 8.13 Run the Update Expiration algorithm on the session, |
| 861 // providing expiration time. |
| 862 // (Done by the CDM.) |
| 863 |
| 864 // 8.14 If message is not null, run the Queue a "message" Event |
| 865 // algorithm on the session, providing message type and |
| 866 // message. |
| 867 // (Done by the CDM.) |
| 868 } |
| 869 |
616 // Queue a task to fire a simple event named keymessage at the new object. | 870 // Queue a task to fire a simple event named keymessage at the new object. |
617 void MediaKeySession::message(const unsigned char* message, size_t messageLength
, const WebURL& destinationURL) | 871 void MediaKeySession::message(const unsigned char* message, size_t messageLength
, const WebURL& destinationURL) |
618 { | 872 { |
619 WTF_LOG(Media, "MediaKeySession(%p)::message", this); | 873 WTF_LOG(Media, "MediaKeySession(%p)::message", this); |
620 | 874 |
621 // Verify that 'message' not fired before session initialization is complete
. | 875 // Verify that 'message' not fired before session initialization is complete
. |
622 ASSERT(m_isCallable); | 876 ASSERT(m_isCallable); |
623 | 877 |
624 MediaKeyMessageEventInit init; | 878 MediaKeyMessageEventInit init; |
625 init.bubbles = false; | 879 init.bubbles = false; |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
748 { | 1002 { |
749 visitor->trace(m_error); | 1003 visitor->trace(m_error); |
750 visitor->trace(m_asyncEventQueue); | 1004 visitor->trace(m_asyncEventQueue); |
751 visitor->trace(m_pendingActions); | 1005 visitor->trace(m_pendingActions); |
752 visitor->trace(m_mediaKeys); | 1006 visitor->trace(m_mediaKeys); |
753 visitor->trace(m_closedPromise); | 1007 visitor->trace(m_closedPromise); |
754 EventTargetWithInlineData::trace(visitor); | 1008 EventTargetWithInlineData::trace(visitor); |
755 } | 1009 } |
756 | 1010 |
757 } // namespace blink | 1011 } // namespace blink |
OLD | NEW |