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 17 matching lines...) Expand all Loading... |
28 | 28 |
29 #include "bindings/core/v8/ScriptPromiseResolver.h" | 29 #include "bindings/core/v8/ScriptPromiseResolver.h" |
30 #include "bindings/core/v8/ScriptState.h" | 30 #include "bindings/core/v8/ScriptState.h" |
31 #include "core/dom/DOMException.h" | 31 #include "core/dom/DOMException.h" |
32 #include "core/dom/Document.h" | 32 #include "core/dom/Document.h" |
33 #include "core/dom/ExceptionCode.h" | 33 #include "core/dom/ExceptionCode.h" |
34 #include "core/dom/ExecutionContext.h" | 34 #include "core/dom/ExecutionContext.h" |
35 #include "modules/encryptedmedia/MediaKeyMessageEvent.h" | 35 #include "modules/encryptedmedia/MediaKeyMessageEvent.h" |
36 #include "modules/encryptedmedia/MediaKeySession.h" | 36 #include "modules/encryptedmedia/MediaKeySession.h" |
37 #include "modules/encryptedmedia/MediaKeysController.h" | 37 #include "modules/encryptedmedia/MediaKeysController.h" |
| 38 #include "modules/encryptedmedia/SimpleContentDecryptionModuleResult.h" |
38 #include "platform/ContentType.h" | 39 #include "platform/ContentType.h" |
39 #include "platform/Logging.h" | 40 #include "platform/Logging.h" |
40 #include "platform/MIMETypeRegistry.h" | 41 #include "platform/MIMETypeRegistry.h" |
41 #include "platform/Timer.h" | 42 #include "platform/Timer.h" |
42 #include "platform/UUID.h" | 43 #include "platform/UUID.h" |
43 #include "public/platform/Platform.h" | 44 #include "public/platform/Platform.h" |
44 #include "public/platform/WebContentDecryptionModule.h" | 45 #include "public/platform/WebContentDecryptionModule.h" |
45 #include "wtf/ArrayBuffer.h" | 46 #include "wtf/ArrayBuffer.h" |
46 #include "wtf/ArrayBufferView.h" | 47 #include "wtf/ArrayBufferView.h" |
47 #include "wtf/RefPtr.h" | 48 #include "wtf/RefPtr.h" |
(...skipping 17 matching lines...) Expand all Loading... |
65 ContentType type(contentType); | 66 ContentType type(contentType); |
66 String codecs = type.parameter("codecs"); | 67 String codecs = type.parameter("codecs"); |
67 return MIMETypeRegistry::isSupportedEncryptedMediaMIMEType(keySystem, type.t
ype(), codecs); | 68 return MIMETypeRegistry::isSupportedEncryptedMediaMIMEType(keySystem, type.t
ype(), codecs); |
68 } | 69 } |
69 | 70 |
70 static ScriptPromise createRejectedPromise(ScriptState* scriptState, ExceptionCo
de error, const String& errorMessage) | 71 static ScriptPromise createRejectedPromise(ScriptState* scriptState, ExceptionCo
de error, const String& errorMessage) |
71 { | 72 { |
72 return ScriptPromise::rejectWithDOMException(scriptState, DOMException::crea
te(error, errorMessage)); | 73 return ScriptPromise::rejectWithDOMException(scriptState, DOMException::crea
te(error, errorMessage)); |
73 } | 74 } |
74 | 75 |
| 76 // A class holding a pending action. |
| 77 class MediaKeys::PendingAction : public GarbageCollectedFinalized<MediaKeys::Pen
dingAction> { |
| 78 public: |
| 79 const Persistent<ContentDecryptionModuleResult> result() const |
| 80 { |
| 81 return m_result; |
| 82 } |
| 83 |
| 84 const RefPtr<ArrayBuffer> data() const |
| 85 { |
| 86 return m_data; |
| 87 } |
| 88 |
| 89 static PendingAction* CreatePendingSetServerCertificate(ContentDecryptionMod
uleResult* result, PassRefPtr<ArrayBuffer> serverCertificate) |
| 90 { |
| 91 ASSERT(result); |
| 92 ASSERT(serverCertificate); |
| 93 return new PendingAction(result, serverCertificate); |
| 94 } |
| 95 |
| 96 ~PendingAction() |
| 97 { |
| 98 } |
| 99 |
| 100 void trace(Visitor* visitor) |
| 101 { |
| 102 visitor->trace(m_result); |
| 103 } |
| 104 |
| 105 private: |
| 106 PendingAction(ContentDecryptionModuleResult* result, PassRefPtr<ArrayBuffer>
data) |
| 107 : m_result(result) |
| 108 , m_data(data) |
| 109 { |
| 110 } |
| 111 |
| 112 const Member<ContentDecryptionModuleResult> m_result; |
| 113 const RefPtr<ArrayBuffer> m_data; |
| 114 }; |
| 115 |
75 // This class allows a MediaKeys object to be created asynchronously. | 116 // This class allows a MediaKeys object to be created asynchronously. |
76 class MediaKeysInitializer : public ScriptPromiseResolver { | 117 class MediaKeysInitializer : public ScriptPromiseResolver { |
77 WTF_MAKE_NONCOPYABLE(MediaKeysInitializer); | 118 WTF_MAKE_NONCOPYABLE(MediaKeysInitializer); |
78 | 119 |
79 public: | 120 public: |
80 static ScriptPromise create(ScriptState*, const String& keySystem); | 121 static ScriptPromise create(ScriptState*, const String& keySystem); |
81 virtual ~MediaKeysInitializer(); | 122 virtual ~MediaKeysInitializer(); |
82 | 123 |
83 private: | 124 private: |
84 MediaKeysInitializer(ScriptState*, const String& keySystem); | 125 MediaKeysInitializer(ScriptState*, const String& keySystem); |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
170 // 3. Let promise be a new promise. | 211 // 3. Let promise be a new promise. |
171 // 4. Asynchronously create and initialize the MediaKeys. | 212 // 4. Asynchronously create and initialize the MediaKeys. |
172 // 5. Return promise. | 213 // 5. Return promise. |
173 return MediaKeysInitializer::create(scriptState, keySystem); | 214 return MediaKeysInitializer::create(scriptState, keySystem); |
174 } | 215 } |
175 | 216 |
176 MediaKeys::MediaKeys(ExecutionContext* context, const String& keySystem, PassOwn
Ptr<WebContentDecryptionModule> cdm) | 217 MediaKeys::MediaKeys(ExecutionContext* context, const String& keySystem, PassOwn
Ptr<WebContentDecryptionModule> cdm) |
177 : ContextLifecycleObserver(context) | 218 : ContextLifecycleObserver(context) |
178 , m_keySystem(keySystem) | 219 , m_keySystem(keySystem) |
179 , m_cdm(cdm) | 220 , m_cdm(cdm) |
| 221 , m_timer(this, &MediaKeys::timerFired) |
180 { | 222 { |
181 WTF_LOG(Media, "MediaKeys(%p)::MediaKeys", this); | 223 WTF_LOG(Media, "MediaKeys(%p)::MediaKeys", this); |
182 | 224 |
183 // Step 4.4 of MediaKeys::create(): | 225 // Step 4.4 of MediaKeys::create(): |
184 // 4.4.1 Set the keySystem attribute to keySystem. | 226 // 4.4.1 Set the keySystem attribute to keySystem. |
185 ASSERT(!m_keySystem.isEmpty()); | 227 ASSERT(!m_keySystem.isEmpty()); |
186 } | 228 } |
187 | 229 |
188 MediaKeys::~MediaKeys() | 230 MediaKeys::~MediaKeys() |
189 { | 231 { |
(...skipping 13 matching lines...) Expand all Loading... |
203 // FIXME: Check whether sessionType is actually supported by the CDM. | 245 // FIXME: Check whether sessionType is actually supported by the CDM. |
204 ASSERT(sessionType == kTemporary || sessionType == kPersistent); | 246 ASSERT(sessionType == kTemporary || sessionType == kPersistent); |
205 | 247 |
206 // 2. Let session be a new MediaKeySession object, and initialize it as | 248 // 2. Let session be a new MediaKeySession object, and initialize it as |
207 // follows: | 249 // follows: |
208 // (Initialization is performed in the constructor.) | 250 // (Initialization is performed in the constructor.) |
209 // 3. Return session. | 251 // 3. Return session. |
210 return MediaKeySession::create(scriptState, this, sessionType); | 252 return MediaKeySession::create(scriptState, this, sessionType); |
211 } | 253 } |
212 | 254 |
| 255 ScriptPromise MediaKeys::setServerCertificate(ScriptState* scriptState, ArrayBuf
fer* serverCertificate) |
| 256 { |
| 257 RefPtr<ArrayBuffer> serverCertificateCopy = ArrayBuffer::create(serverCertif
icate->data(), serverCertificate->byteLength()); |
| 258 return setServerCertificateInternal(scriptState, serverCertificateCopy.relea
se()); |
| 259 } |
| 260 |
| 261 ScriptPromise MediaKeys::setServerCertificate(ScriptState* scriptState, ArrayBuf
ferView* serverCertificate) |
| 262 { |
| 263 RefPtr<ArrayBuffer> serverCertificateCopy = ArrayBuffer::create(serverCertif
icate->baseAddress(), serverCertificate->byteLength()); |
| 264 return setServerCertificateInternal(scriptState, serverCertificateCopy.relea
se()); |
| 265 } |
| 266 |
| 267 ScriptPromise MediaKeys::setServerCertificateInternal(ScriptState* scriptState,
PassRefPtr<ArrayBuffer> serverCertificate) |
| 268 { |
| 269 // From https://dvcs.w3.org/hg/html-media/raw-file/default/encrypted-media/e
ncrypted-media.html#dom-setservercertificate: |
| 270 // The setServerCertificate(serverCertificate) method provides a server |
| 271 // certificate to be used to encrypt messages to the license server. |
| 272 // It must run the following steps: |
| 273 // 1. If serverCertificate is an empty array, return a promise rejected |
| 274 // with a new DOMException whose name is "InvalidAccessError". |
| 275 if (!serverCertificate->byteLength()) { |
| 276 return ScriptPromise::rejectWithDOMException( |
| 277 scriptState, DOMException::create(InvalidAccessError, "The serverCer
tificate parameter is empty.")); |
| 278 } |
| 279 |
| 280 // 2. If the keySystem does not support server certificates, return a |
| 281 // promise rejected with a new DOMException whose name is |
| 282 // "NotSupportedError". |
| 283 // (Let the CDM decide whether to support this or not.) |
| 284 |
| 285 // 3. Let certificate be a copy of the contents of the serverCertificate |
| 286 // parameter. |
| 287 // (Done in caller.) |
| 288 |
| 289 // 4. Let promise be a new promise. |
| 290 SimpleContentDecryptionModuleResult* result = new SimpleContentDecryptionMod
uleResult(scriptState); |
| 291 ScriptPromise promise = result->promise(); |
| 292 |
| 293 // 5. Run the following steps asynchronously (documented in timerFired()). |
| 294 m_pendingActions.append(PendingAction::CreatePendingSetServerCertificate(res
ult, serverCertificate)); |
| 295 if (!m_timer.isActive()) |
| 296 m_timer.startOneShot(0, FROM_HERE); |
| 297 |
| 298 // 6. Return promise. |
| 299 return promise; |
| 300 } |
| 301 |
213 bool MediaKeys::isTypeSupported(const String& keySystem, const String& contentTy
pe) | 302 bool MediaKeys::isTypeSupported(const String& keySystem, const String& contentTy
pe) |
214 { | 303 { |
215 WTF_LOG(Media, "MediaKeys::isTypeSupported(%s, %s)", keySystem.ascii().data(
), contentType.ascii().data()); | 304 WTF_LOG(Media, "MediaKeys::isTypeSupported(%s, %s)", keySystem.ascii().data(
), contentType.ascii().data()); |
216 | 305 |
217 // 1. If keySystem is an empty string, return false and abort these steps. | 306 // 1. If keySystem is an empty string, return false and abort these steps. |
218 if (keySystem.isEmpty()) | 307 if (keySystem.isEmpty()) |
219 return false; | 308 return false; |
220 | 309 |
221 // 2. If keySystem contains an unrecognized or unsupported Key System, retur
n false and abort | 310 // 2. If keySystem contains an unrecognized or unsupported Key System, retur
n false and abort |
222 // these steps. Key system string comparison is case-sensitive. | 311 // these steps. Key system string comparison is case-sensitive. |
223 if (!isKeySystemSupportedWithContentType(keySystem, "")) | 312 if (!isKeySystemSupportedWithContentType(keySystem, "")) |
224 return false; | 313 return false; |
225 | 314 |
226 // 3. If contentType is an empty string, return true and abort these steps. | 315 // 3. If contentType is an empty string, return true and abort these steps. |
227 if (contentType.isEmpty()) | 316 if (contentType.isEmpty()) |
228 return true; | 317 return true; |
229 | 318 |
230 // 4. If the Key System specified by keySystem does not support decrypting t
he container and/or | 319 // 4. If the Key System specified by keySystem does not support decrypting t
he container and/or |
231 // codec specified by contentType, return false and abort these steps. | 320 // codec specified by contentType, return false and abort these steps. |
232 return isKeySystemSupportedWithContentType(keySystem, contentType); | 321 return isKeySystemSupportedWithContentType(keySystem, contentType); |
233 } | 322 } |
234 | 323 |
| 324 void MediaKeys::timerFired(Timer<MediaKeys>*) |
| 325 { |
| 326 ASSERT(m_pendingActions.size()); |
| 327 |
| 328 // Swap the queue to a local copy to avoid problems if resolving promises |
| 329 // run synchronously. |
| 330 HeapDeque<Member<PendingAction> > pendingActions; |
| 331 pendingActions.swap(m_pendingActions); |
| 332 |
| 333 while (!pendingActions.isEmpty()) { |
| 334 PendingAction* action = pendingActions.takeFirst(); |
| 335 WTF_LOG(Media, "MediaKeys(%p)::timerFired: Certificate", this); |
| 336 |
| 337 // 5.1 Let cdm be the cdm during the initialization of this object. |
| 338 WebContentDecryptionModule* cdm = contentDecryptionModule(); |
| 339 |
| 340 // 5.2 Use the cdm to process certificate. |
| 341 cdm->setServerCertificate(static_cast<unsigned char*>(action->data()->da
ta()), action->data()->byteLength(), action->result()->result()); |
| 342 // 5.3 If any of the preceding steps failed, reject promise with a |
| 343 // new DOMException whose name is the appropriate error name. |
| 344 // 5.4 Resolve promise. |
| 345 // (These are handled by Chromium and the CDM.) |
| 346 } |
| 347 } |
| 348 |
235 WebContentDecryptionModule* MediaKeys::contentDecryptionModule() | 349 WebContentDecryptionModule* MediaKeys::contentDecryptionModule() |
236 { | 350 { |
237 return m_cdm.get(); | 351 return m_cdm.get(); |
238 } | 352 } |
239 | 353 |
240 void MediaKeys::trace(Visitor* visitor) | 354 void MediaKeys::trace(Visitor* visitor) |
241 { | 355 { |
| 356 visitor->trace(m_pendingActions); |
242 } | 357 } |
243 | 358 |
244 void MediaKeys::contextDestroyed() | 359 void MediaKeys::contextDestroyed() |
245 { | 360 { |
246 ContextLifecycleObserver::contextDestroyed(); | 361 ContextLifecycleObserver::contextDestroyed(); |
247 | 362 |
248 // We don't need the CDM anymore. | 363 // We don't need the CDM anymore. |
249 m_cdm.clear(); | 364 m_cdm.clear(); |
250 } | 365 } |
251 | 366 |
252 } // namespace blink | 367 } // namespace blink |
OLD | NEW |