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 | 53 |
54 namespace { | |
55 | |
56 // The list of possible values for |sessionType|. | |
57 const char* kTemporary = "temporary"; | |
58 const char* kPersistent = "persistent"; | |
59 | |
60 // Minimum and maximum length for session ids. | |
61 enum { | |
62 MinSessionIdLength = 1, | |
63 MaxSessionIdLength = 512 | |
64 }; | |
65 | |
66 } // namespace | |
67 | |
53 namespace blink { | 68 namespace blink { |
54 | 69 |
55 static bool isKeySystemSupportedWithInitDataType(const String& keySystem, const String& initDataType) | 70 static bool isKeySystemSupportedWithInitDataType(const String& keySystem, const String& initDataType) |
56 { | 71 { |
57 ASSERT(!keySystem.isEmpty()); | 72 ASSERT(!keySystem.isEmpty()); |
58 | 73 |
59 // FIXME: initDataType != contentType. Implement this properly. | 74 // FIXME: initDataType != contentType. Implement this properly. |
60 // http://crbug.com/385874. | 75 // http://crbug.com/385874. |
61 String contentType = initDataType; | 76 String contentType = initDataType; |
62 if (initDataType == "webm") { | 77 if (initDataType == "webm") { |
63 contentType = "video/webm"; | 78 contentType = "video/webm"; |
64 } else if (initDataType == "cenc") { | 79 } else if (initDataType == "cenc") { |
65 contentType = "video/mp4"; | 80 contentType = "video/mp4"; |
66 } | 81 } |
67 | 82 |
68 ContentType type(contentType); | 83 ContentType type(contentType); |
69 return MIMETypeRegistry::isSupportedEncryptedMediaMIMEType(keySystem, type.t ype(), type.parameter("codecs")); | 84 return MIMETypeRegistry::isSupportedEncryptedMediaMIMEType(keySystem, type.t ype(), type.parameter("codecs")); |
70 } | 85 } |
71 | 86 |
87 // Returns whether |sessionId| looks correct. Returns true if all tests pass, | |
ddorwin
2014/10/08 23:08:49
Checks that |sessionId| looks correct and returns
jrummell
2014/10/08 23:52:53
Done.
| |
88 // false otherwise. | |
89 static bool isValidSessionId(const String& sessionId) | |
90 { | |
91 if ((sessionId.length() < MinSessionIdLength) || (sessionId.length() > MaxSe ssionIdLength)) | |
92 return false; | |
93 | |
94 if (!sessionId.containsOnlyASCII()) | |
95 return false; | |
96 | |
97 // Check that the sessionId only contains alphanumeric characters. | |
98 for (unsigned i = 0; i < sessionId.length(); ++i) { | |
99 if (!isASCIIAlphanumeric(sessionId[i])) | |
100 return false; | |
101 } | |
102 | |
103 return true; | |
104 } | |
105 | |
72 // A class holding a pending action. | 106 // A class holding a pending action. |
73 class MediaKeySession::PendingAction : public GarbageCollectedFinalized<MediaKey Session::PendingAction> { | 107 class MediaKeySession::PendingAction : public GarbageCollectedFinalized<MediaKey Session::PendingAction> { |
74 public: | 108 public: |
75 enum Type { | 109 enum Type { |
76 GenerateRequest, | 110 GenerateRequest, |
111 Load, | |
77 Update, | 112 Update, |
78 Release | 113 Release |
79 }; | 114 }; |
80 | 115 |
81 Type type() const { return m_type; } | 116 Type type() const { return m_type; } |
82 | 117 |
83 const Persistent<ContentDecryptionModuleResult> result() const | 118 const Persistent<ContentDecryptionModuleResult> result() const |
84 { | 119 { |
85 return m_result; | 120 return m_result; |
86 } | 121 } |
87 | 122 |
88 const RefPtr<ArrayBuffer> data() const | 123 const RefPtr<ArrayBuffer> data() const |
89 { | 124 { |
90 ASSERT(m_type == GenerateRequest || m_type == Update); | 125 ASSERT(m_type == GenerateRequest || m_type == Update); |
91 return m_data; | 126 return m_data; |
92 } | 127 } |
93 | 128 |
94 const String& initDataType() const | 129 const String& initDataType() const |
95 { | 130 { |
96 ASSERT(m_type == GenerateRequest); | 131 ASSERT(m_type == GenerateRequest); |
97 return m_initDataType; | 132 return m_stringData; |
133 } | |
134 | |
135 const String& sessionId() const | |
136 { | |
137 ASSERT(m_type == Load); | |
138 return m_stringData; | |
98 } | 139 } |
99 | 140 |
100 static PendingAction* CreatePendingGenerateRequest(ContentDecryptionModuleRe sult* result, const String& initDataType, PassRefPtr<ArrayBuffer> initData) | 141 static PendingAction* CreatePendingGenerateRequest(ContentDecryptionModuleRe sult* result, const String& initDataType, PassRefPtr<ArrayBuffer> initData) |
101 { | 142 { |
102 ASSERT(result); | 143 ASSERT(result); |
103 ASSERT(initData); | 144 ASSERT(initData); |
104 return new PendingAction(GenerateRequest, result, initDataType, initData ); | 145 return new PendingAction(GenerateRequest, result, initDataType, initData ); |
105 } | 146 } |
106 | 147 |
148 static PendingAction* CreatePendingLoadRequest(ContentDecryptionModuleResult * result, const String& sessionId) | |
149 { | |
150 ASSERT(result); | |
151 return new PendingAction(Load, result, sessionId, PassRefPtr<ArrayBuffer >()); | |
152 } | |
153 | |
107 static PendingAction* CreatePendingUpdate(ContentDecryptionModuleResult* res ult, PassRefPtr<ArrayBuffer> data) | 154 static PendingAction* CreatePendingUpdate(ContentDecryptionModuleResult* res ult, PassRefPtr<ArrayBuffer> data) |
108 { | 155 { |
109 ASSERT(result); | 156 ASSERT(result); |
110 ASSERT(data); | 157 ASSERT(data); |
111 return new PendingAction(Update, result, String(), data); | 158 return new PendingAction(Update, result, String(), data); |
112 } | 159 } |
113 | 160 |
114 static PendingAction* CreatePendingRelease(ContentDecryptionModuleResult* re sult) | 161 static PendingAction* CreatePendingRelease(ContentDecryptionModuleResult* re sult) |
115 { | 162 { |
116 ASSERT(result); | 163 ASSERT(result); |
117 return new PendingAction(Release, result, String(), PassRefPtr<ArrayBuff er>()); | 164 return new PendingAction(Release, result, String(), PassRefPtr<ArrayBuff er>()); |
118 } | 165 } |
119 | 166 |
120 ~PendingAction() | 167 ~PendingAction() |
121 { | 168 { |
122 } | 169 } |
123 | 170 |
124 void trace(Visitor* visitor) | 171 void trace(Visitor* visitor) |
125 { | 172 { |
126 visitor->trace(m_result); | 173 visitor->trace(m_result); |
127 } | 174 } |
128 | 175 |
129 private: | 176 private: |
130 PendingAction(Type type, ContentDecryptionModuleResult* result, const String & initDataType, PassRefPtr<ArrayBuffer> data) | 177 PendingAction(Type type, ContentDecryptionModuleResult* result, const String & stringData, PassRefPtr<ArrayBuffer> data) |
131 : m_type(type) | 178 : m_type(type) |
132 , m_result(result) | 179 , m_result(result) |
133 , m_initDataType(initDataType) | 180 , m_stringData(stringData) |
134 , m_data(data) | 181 , m_data(data) |
135 { | 182 { |
136 } | 183 } |
137 | 184 |
138 const Type m_type; | 185 const Type m_type; |
139 const Member<ContentDecryptionModuleResult> m_result; | 186 const Member<ContentDecryptionModuleResult> m_result; |
140 const String m_initDataType; | 187 const String m_stringData; |
141 const RefPtr<ArrayBuffer> m_data; | 188 const RefPtr<ArrayBuffer> m_data; |
142 }; | 189 }; |
143 | 190 |
144 // This class wraps the promise resolver used when initializing a new session | 191 // This class wraps the promise resolver used when initializing a new session |
145 // and is passed to Chromium to fullfill the promise. This implementation of | 192 // and is passed to Chromium to fullfill the promise. This implementation of |
146 // completeWithSession() will resolve the promise with void, while | 193 // completeWithSession() will resolve the promise with void, while |
147 // completeWithError() will reject the promise with an exception. complete() | 194 // completeWithError() will reject the promise with an exception. complete() |
148 // is not expected to be called, and will reject the promise. | 195 // is not expected to be called, and will reject the promise. |
149 class NewSessionResult : public ContentDecryptionModuleResult { | 196 class NewSessionResult : public ContentDecryptionModuleResult { |
150 public: | 197 public: |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
198 void completeWithDOMException(ExceptionCode code, const String& errorMessage ) | 245 void completeWithDOMException(ExceptionCode code, const String& errorMessage ) |
199 { | 246 { |
200 m_resolver->reject(DOMException::create(code, errorMessage)); | 247 m_resolver->reject(DOMException::create(code, errorMessage)); |
201 m_resolver.clear(); | 248 m_resolver.clear(); |
202 } | 249 } |
203 | 250 |
204 RefPtr<ScriptPromiseResolver> m_resolver; | 251 RefPtr<ScriptPromiseResolver> m_resolver; |
205 Member<MediaKeySession> m_session; | 252 Member<MediaKeySession> m_session; |
206 }; | 253 }; |
207 | 254 |
255 // This class wraps the promise resolver used when loading a session | |
256 // and is passed to Chromium to fullfill the promise. This implementation of | |
257 // completeWithSession() will resolve the promise with true/false, while | |
258 // completeWithError() will reject the promise with an exception. complete() | |
259 // is not expected to be called, and will reject the promise. | |
260 class LoadSessionResult : public ContentDecryptionModuleResult { | |
261 public: | |
262 LoadSessionResult(ScriptState* scriptState, MediaKeySession* session) | |
263 : m_resolver(ScriptPromiseResolver::create(scriptState)) | |
264 , m_session(session) | |
265 { | |
266 WTF_LOG(Media, "LoadSessionResult(%p)", this); | |
267 } | |
268 | |
269 virtual ~LoadSessionResult() | |
270 { | |
271 WTF_LOG(Media, "~LoadSessionResult(%p)", this); | |
272 } | |
273 | |
274 // ContentDecryptionModuleResult implementation. | |
275 virtual void complete() OVERRIDE | |
276 { | |
277 ASSERT_NOT_REACHED(); | |
278 completeWithDOMException(InvalidStateError, "Unexpected completion."); | |
279 } | |
280 | |
281 virtual void completeWithSession(WebContentDecryptionModuleResult::SessionSt atus status) OVERRIDE | |
282 { | |
283 bool result; | |
284 switch (status) { | |
285 case WebContentDecryptionModuleResult::NewSession: | |
286 result = true; | |
287 break; | |
288 | |
289 case WebContentDecryptionModuleResult::SessionNotFound: | |
290 result = false; | |
291 break; | |
292 | |
293 case WebContentDecryptionModuleResult::SessionAlreadyExists: | |
294 ASSERT_NOT_REACHED(); | |
295 completeWithDOMException(InvalidStateError, "Unexpected completion." ); | |
296 return; | |
297 } | |
298 | |
299 m_session->finishLoad(); | |
300 m_resolver->resolve(result); | |
301 m_resolver.clear(); | |
302 } | |
303 | |
304 virtual void completeWithError(WebContentDecryptionModuleException exception Code, unsigned long systemCode, const WebString& errorMessage) OVERRIDE | |
305 { | |
306 completeWithDOMException(WebCdmExceptionToExceptionCode(exceptionCode), errorMessage); | |
307 } | |
308 | |
309 // It is only valid to call this before completion. | |
310 ScriptPromise promise() { return m_resolver->promise(); } | |
311 | |
312 void trace(Visitor* visitor) | |
313 { | |
314 visitor->trace(m_session); | |
315 ContentDecryptionModuleResult::trace(visitor); | |
316 } | |
317 | |
318 private: | |
319 // Reject the promise with a DOMException. | |
320 void completeWithDOMException(ExceptionCode code, const String& errorMessage ) | |
321 { | |
322 m_resolver->reject(DOMException::create(code, errorMessage)); | |
323 m_resolver.clear(); | |
324 } | |
325 | |
326 RefPtr<ScriptPromiseResolver> m_resolver; | |
327 Member<MediaKeySession> m_session; | |
328 }; | |
329 | |
208 MediaKeySession* MediaKeySession::create(ScriptState* scriptState, MediaKeys* me diaKeys, const String& sessionType) | 330 MediaKeySession* MediaKeySession::create(ScriptState* scriptState, MediaKeys* me diaKeys, const String& sessionType) |
209 { | 331 { |
210 RefPtrWillBeRawPtr<MediaKeySession> session = adoptRefCountedGarbageCollecte dWillBeNoop(new MediaKeySession(scriptState, mediaKeys, sessionType)); | 332 RefPtrWillBeRawPtr<MediaKeySession> session = adoptRefCountedGarbageCollecte dWillBeNoop(new MediaKeySession(scriptState, mediaKeys, sessionType)); |
211 session->suspendIfNeeded(); | 333 session->suspendIfNeeded(); |
212 return session.get(); | 334 return session.get(); |
213 } | 335 } |
214 | 336 |
215 MediaKeySession::MediaKeySession(ScriptState* scriptState, MediaKeys* mediaKeys, const String& sessionType) | 337 MediaKeySession::MediaKeySession(ScriptState* scriptState, MediaKeys* mediaKeys, const String& sessionType) |
216 : ActiveDOMObject(scriptState->executionContext()) | 338 : ActiveDOMObject(scriptState->executionContext()) |
217 , m_keySystem(mediaKeys->keySystem()) | 339 , m_keySystem(mediaKeys->keySystem()) |
(...skipping 19 matching lines...) Expand all Loading... | |
237 // 2.1 Let the sessionId attribute be the empty string. | 359 // 2.1 Let the sessionId attribute be the empty string. |
238 ASSERT(sessionId().isEmpty()); | 360 ASSERT(sessionId().isEmpty()); |
239 | 361 |
240 // 2.2 Let the expiration attribute be NaN. | 362 // 2.2 Let the expiration attribute be NaN. |
241 // FIXME: Add expiration property. | 363 // FIXME: Add expiration property. |
242 | 364 |
243 // 2.3 Let the closed attribute be a new promise. | 365 // 2.3 Let the closed attribute be a new promise. |
244 ASSERT(!closed(scriptState).isUndefinedOrNull()); | 366 ASSERT(!closed(scriptState).isUndefinedOrNull()); |
245 | 367 |
246 // 2.4 Let the session type be sessionType. | 368 // 2.4 Let the session type be sessionType. |
247 ASSERT(sessionType == m_sessionType); | 369 ASSERT(isValidSessionType(sessionType)); |
248 | 370 |
249 // 2.5 Let uninitialized be true. | 371 // 2.5 Let uninitialized be true. |
250 ASSERT(m_isUninitialized); | 372 ASSERT(m_isUninitialized); |
251 | 373 |
252 // 2.6 Let callable be false. | 374 // 2.6 Let callable be false. |
253 ASSERT(!m_isCallable); | 375 ASSERT(!m_isCallable); |
254 } | 376 } |
255 | 377 |
256 MediaKeySession::~MediaKeySession() | 378 MediaKeySession::~MediaKeySession() |
257 { | 379 { |
258 WTF_LOG(Media, "MediaKeySession(%p)::~MediaKeySession", this); | 380 WTF_LOG(Media, "MediaKeySession(%p)::~MediaKeySession", this); |
259 m_session.clear(); | 381 m_session.clear(); |
260 #if !ENABLE(OILPAN) | 382 #if !ENABLE(OILPAN) |
261 // MediaKeySession and m_asyncEventQueue always become unreachable | 383 // MediaKeySession and m_asyncEventQueue always become unreachable |
262 // together. So MediaKeySession and m_asyncEventQueue are destructed in the | 384 // together. So MediaKeySession and m_asyncEventQueue are destructed in the |
263 // same GC. We don't need to call cancelAllEvents explicitly in Oilpan. | 385 // same GC. We don't need to call cancelAllEvents explicitly in Oilpan. |
264 m_asyncEventQueue->cancelAllEvents(); | 386 m_asyncEventQueue->cancelAllEvents(); |
265 #endif | 387 #endif |
266 } | 388 } |
267 | 389 |
390 bool MediaKeySession::isValidSessionType(const String& sessionType) | |
391 { | |
392 return (sessionType == kTemporary || sessionType == kPersistent); | |
393 } | |
394 | |
268 void MediaKeySession::setError(MediaKeyError* error) | 395 void MediaKeySession::setError(MediaKeyError* error) |
269 { | 396 { |
270 m_error = error; | 397 m_error = error; |
271 } | 398 } |
272 | 399 |
273 String MediaKeySession::sessionId() const | 400 String MediaKeySession::sessionId() const |
274 { | 401 { |
275 return m_session->sessionId(); | 402 return m_session->sessionId(); |
276 } | 403 } |
277 | 404 |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
349 // 10. Run the following steps asynchronously (documented in | 476 // 10. Run the following steps asynchronously (documented in |
350 // actionTimerFired()) | 477 // actionTimerFired()) |
351 m_pendingActions.append(PendingAction::CreatePendingGenerateRequest(result, initDataType, initData)); | 478 m_pendingActions.append(PendingAction::CreatePendingGenerateRequest(result, initDataType, initData)); |
352 ASSERT(!m_actionTimer.isActive()); | 479 ASSERT(!m_actionTimer.isActive()); |
353 m_actionTimer.startOneShot(0, FROM_HERE); | 480 m_actionTimer.startOneShot(0, FROM_HERE); |
354 | 481 |
355 // 11. Return promise. | 482 // 11. Return promise. |
356 return promise; | 483 return promise; |
357 } | 484 } |
358 | 485 |
486 ScriptPromise MediaKeySession::load(ScriptState* scriptState, const String& sess ionId) | |
487 { | |
488 WTF_LOG(Media, "MediaKeySession(%p)::load %s", this, sessionId.ascii().data( )); | |
489 | |
490 // From https://dvcs.w3.org/hg/html-media/raw-file/default/encrypted-media/e ncrypted-media.html#dom-load: | |
491 // The load(sessionId) method loads the data stored for the sessionId into | |
492 // the session represented by the object. It must run the following steps: | |
493 | |
494 // 1. If this object's uninitialized value is false, return a promise | |
495 // rejected with a new DOMException whose name is "InvalidStateError". | |
496 if (!m_isUninitialized) { | |
497 return ScriptPromise::rejectWithDOMException( | |
498 scriptState, DOMException::create(InvalidStateError, "The session is already initialized.")); | |
499 } | |
500 | |
501 // 2. Let this object's uninitialized be false. | |
502 m_isUninitialized = false; | |
503 | |
504 // 3. If sessionId is an empty string, return a promise rejected with a | |
505 // new DOMException whose name is "InvalidAccessError". | |
506 if (sessionId.isEmpty()) { | |
507 return ScriptPromise::rejectWithDOMException( | |
508 scriptState, DOMException::create(InvalidAccessError, "The sessionId parameter is empty.")); | |
509 } | |
510 | |
511 // 4. If this object's session type is not "persistent", return a promise | |
512 // rejected with a new DOMException whose name is "InvalidAccessError". | |
513 if (m_sessionType != kPersistent) { | |
514 return ScriptPromise::rejectWithDOMException( | |
515 scriptState, DOMException::create(InvalidAccessError, "The session t ype is not 'persistent'.")); | |
516 } | |
517 | |
518 // 5. Let media keys be the MediaKeys object that created this object. | |
519 // (Done in constructor.) | |
520 ASSERT(m_mediaKeys); | |
521 | |
522 // 6. If the content decryption module corresponding to media keys's | |
523 // keySystem attribute does not support loading previous sessions, | |
524 // return a promise rejected with a new DOMException whose name is | |
525 // "NotSupportedError". | |
526 // (Done by CDM.) | |
527 | |
528 // 7. Let promise be a new promise. | |
529 LoadSessionResult* result = new LoadSessionResult(scriptState, this); | |
530 ScriptPromise promise = result->promise(); | |
531 | |
532 // 8. Run the following steps asynchronously (documented in | |
533 // actionTimerFired()) | |
534 m_pendingActions.append(PendingAction::CreatePendingLoadRequest(result, sess ionId)); | |
535 ASSERT(!m_actionTimer.isActive()); | |
536 m_actionTimer.startOneShot(0, FROM_HERE); | |
537 | |
538 // 9. Return promise. | |
539 return promise; | |
540 } | |
541 | |
359 ScriptPromise MediaKeySession::update(ScriptState* scriptState, ArrayBuffer* res ponse) | 542 ScriptPromise MediaKeySession::update(ScriptState* scriptState, ArrayBuffer* res ponse) |
360 { | 543 { |
361 RefPtr<ArrayBuffer> responseCopy = ArrayBuffer::create(response->data(), res ponse->byteLength()); | 544 RefPtr<ArrayBuffer> responseCopy = ArrayBuffer::create(response->data(), res ponse->byteLength()); |
362 return updateInternal(scriptState, responseCopy.release()); | 545 return updateInternal(scriptState, responseCopy.release()); |
363 } | 546 } |
364 | 547 |
365 ScriptPromise MediaKeySession::update(ScriptState* scriptState, ArrayBufferView* response) | 548 ScriptPromise MediaKeySession::update(ScriptState* scriptState, ArrayBufferView* response) |
366 { | 549 { |
367 RefPtr<ArrayBuffer> responseCopy = ArrayBuffer::create(response->baseAddress (), response->byteLength()); | 550 RefPtr<ArrayBuffer> responseCopy = ArrayBuffer::create(response->baseAddress (), response->byteLength()); |
368 return updateInternal(scriptState, responseCopy.release()); | 551 return updateInternal(scriptState, responseCopy.release()); |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
464 // "NotSupportedError". | 647 // "NotSupportedError". |
465 // 10.3.3 Let request be a request (e.g. a license request) | 648 // 10.3.3 Let request be a request (e.g. a license request) |
466 // generated based on the init data, which is interpreted | 649 // generated based on the init data, which is interpreted |
467 // per initDataType, and session type. | 650 // per initDataType, and session type. |
468 m_session->initializeNewSession(action->initDataType(), static_cast< unsigned char*>(action->data()->data()), action->data()->byteLength(), m_session Type, action->result()->result()); | 651 m_session->initializeNewSession(action->initDataType(), static_cast< unsigned char*>(action->data()->data()), action->data()->byteLength(), m_session Type, action->result()->result()); |
469 | 652 |
470 // Remainder of steps executed in finishGenerateRequest(), called | 653 // Remainder of steps executed in finishGenerateRequest(), called |
471 // when |result| is resolved. | 654 // when |result| is resolved. |
472 break; | 655 break; |
473 | 656 |
657 case PendingAction::Load: | |
658 // NOTE: Continue step 8 of MediaKeySession::load(). | |
659 | |
660 // 8.1 Let sanitized session ID be a validated and/or sanitized | |
661 // version of sessionId. The user agent should thoroughly | |
662 // validate the sessionId value before passing it to the CDM. | |
663 // At a minimum, this should include checking that the length | |
664 // and value (e.g. alphanumeric) are reasonable. | |
665 // 8.2 If the previous step failed, reject promise with a new | |
666 // DOMException whose name is "InvalidAccessError". | |
667 if (!isValidSessionId(action->sessionId())) { | |
668 action->result()->completeWithError(WebContentDecryptionModuleEx ceptionInvalidAccessError, 0, "Invalid sessionId"); | |
669 return; | |
670 } | |
671 | |
672 // 8.3 Let expiration time be NaN. | |
673 // FIXME: Implement expiration attribute. | |
674 | |
675 // 8.4 Let message be null. | |
676 // 8.5 Let message type be null. | |
677 // (Will be provided by the CDM if needed.) | |
678 | |
679 // 8.6 Let origin be the origin of this object's Document. | |
680 // (Obtained previously when CDM created.) | |
681 | |
682 // 8.7 Let cdm be the CDM loaded during the initialization of media | |
683 // keys. | |
684 // 8.8 Use the cdm to execute the following steps: | |
685 // 8.8.1 If there is no data stored for the sanitized session ID in | |
686 // the origin, resolve promise with false. | |
687 // 8.8.2 Let session data be the data stored for the sanitized | |
688 // session ID in the origin. This must not include data from | |
689 // other origin(s) or that is not associated with an origin. | |
690 // 8.8.3 If there is an unclosed "persistent" session in any | |
691 // Document representing the session data, reject promise | |
692 // with a new DOMException whose name is "QuotaExceededError". | |
693 // 8.8.4 In other words, do not create a session if a non-closed | |
694 // persistent session already exists for this sanitized | |
695 // session ID in any browsing context. | |
696 // 8.8.5 Load the session data. | |
697 // 8.8.6 If the session data indicates an expiration time for the | |
698 // session, let expiration time be the expiration time | |
699 // in milliseconds since 01 January 1970 UTC. | |
700 // 8.8.6 If the CDM needs to send a message: | |
701 // 8.8.6.1 Let message be a message generated by the CDM based on | |
702 // the session data. | |
703 // 8.8.6.2 Let message type be the appropriate MediaKeyMessageType | |
704 // for the message. | |
705 // 8.9 If any of the preceding steps failed, reject promise with a | |
706 // new DOMException whose name is the appropriate error name. | |
707 m_session->load(action->sessionId(), action->result()->result()); | |
708 | |
709 // Remainder of steps executed in finishLoad(), called | |
710 // when |result| is resolved. | |
711 break; | |
712 | |
474 case PendingAction::Update: | 713 case PendingAction::Update: |
475 WTF_LOG(Media, "MediaKeySession(%p)::actionTimerFired: Update", this ); | 714 WTF_LOG(Media, "MediaKeySession(%p)::actionTimerFired: Update", this ); |
476 // NOTE: Continued from step 4 of MediaKeySession::update(). | 715 // NOTE: Continued from step 4 of MediaKeySession::update(). |
477 // Continue the update call by passing message to the cdm. Once | 716 // Continue the update call by passing message to the cdm. Once |
478 // completed, it will resolve/reject the promise. | 717 // completed, it will resolve/reject the promise. |
479 m_session->update(static_cast<unsigned char*>(action->data()->data() ), action->data()->byteLength(), action->result()->result()); | 718 m_session->update(static_cast<unsigned char*>(action->data()->data() ), action->data()->byteLength(), action->result()->result()); |
480 break; | 719 break; |
481 | 720 |
482 case PendingAction::Release: | 721 case PendingAction::Release: |
483 WTF_LOG(Media, "MediaKeySession(%p)::actionTimerFired: Release", thi s); | 722 WTF_LOG(Media, "MediaKeySession(%p)::actionTimerFired: Release", thi s); |
(...skipping 26 matching lines...) Expand all Loading... | |
510 // https://www.w3.org/Bugs/Public/show_bug.cgi?id=26758 | 749 // https://www.w3.org/Bugs/Public/show_bug.cgi?id=26758 |
511 | 750 |
512 // 10.7 Run the Queue a "message" Event algorithm on the session, | 751 // 10.7 Run the Queue a "message" Event algorithm on the session, |
513 // providing request and null. | 752 // providing request and null. |
514 // (Done by the CDM). | 753 // (Done by the CDM). |
515 | 754 |
516 // 10.8 Let this object's callable be true. | 755 // 10.8 Let this object's callable be true. |
517 m_isCallable = true; | 756 m_isCallable = true; |
518 } | 757 } |
519 | 758 |
759 void MediaKeySession::finishLoad() | |
760 { | |
761 // 8.10 Set the sessionId attribute to sanitized session ID. | |
762 ASSERT(!sessionId().isEmpty()); | |
763 | |
764 // 8.11 Let this object's callable be true. | |
765 m_isCallable = true; | |
766 | |
767 // 8.12 If the loaded session contains usable keys, run the Usable | |
768 // Keys Changed algorithm on the session. The algorithm may | |
769 // also be run later should additional processing be necessary | |
770 // to determine with certainty whether one or more keys is | |
771 // usable. | |
772 // (Done by the CDM.) | |
773 | |
774 // 8.13 Run the Update Expiration algorithm on the session, | |
775 // providing expiration time. | |
776 // (Done by the CDM.) | |
777 | |
778 // 8.14 If message is not null, run the Queue a "message" Event | |
779 // algorithm on the session, providing message type and | |
780 // message. | |
781 // (Done by the CDM.) | |
782 } | |
783 | |
520 // Queue a task to fire a simple event named keymessage at the new object. | 784 // Queue a task to fire a simple event named keymessage at the new object. |
521 void MediaKeySession::message(const unsigned char* message, size_t messageLength , const WebURL& destinationURL) | 785 void MediaKeySession::message(const unsigned char* message, size_t messageLength , const WebURL& destinationURL) |
522 { | 786 { |
523 WTF_LOG(Media, "MediaKeySession(%p)::message", this); | 787 WTF_LOG(Media, "MediaKeySession(%p)::message", this); |
524 | 788 |
525 // Verify that 'message' not fired before session initialization is complete . | 789 // Verify that 'message' not fired before session initialization is complete . |
526 ASSERT(m_isCallable); | 790 ASSERT(m_isCallable); |
527 | 791 |
528 MediaKeyMessageEventInit init; | 792 MediaKeyMessageEventInit init; |
529 init.bubbles = false; | 793 init.bubbles = false; |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
647 { | 911 { |
648 visitor->trace(m_error); | 912 visitor->trace(m_error); |
649 visitor->trace(m_asyncEventQueue); | 913 visitor->trace(m_asyncEventQueue); |
650 visitor->trace(m_pendingActions); | 914 visitor->trace(m_pendingActions); |
651 visitor->trace(m_mediaKeys); | 915 visitor->trace(m_mediaKeys); |
652 visitor->trace(m_closedPromise); | 916 visitor->trace(m_closedPromise); |
653 EventTargetWithInlineData::trace(visitor); | 917 EventTargetWithInlineData::trace(visitor); |
654 } | 918 } |
655 | 919 |
656 } // namespace blink | 920 } // namespace blink |
OLD | NEW |