| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "webcontentdecryptionmodulesession_impl.h" | 5 #include "webcontentdecryptionmodulesession_impl.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/callback_helpers.h" | 8 #include "base/callback_helpers.h" |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/numerics/safe_conversions.h" | 10 #include "base/numerics/safe_conversions.h" |
| (...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 249 blink::WebEncryptedMediaInitDataType init_data_type, | 249 blink::WebEncryptedMediaInitDataType init_data_type, |
| 250 const unsigned char* init_data, | 250 const unsigned char* init_data, |
| 251 size_t init_data_length, | 251 size_t init_data_length, |
| 252 blink::WebEncryptedMediaSessionType session_type, | 252 blink::WebEncryptedMediaSessionType session_type, |
| 253 blink::WebContentDecryptionModuleResult result) { | 253 blink::WebContentDecryptionModuleResult result) { |
| 254 DCHECK(init_data); | 254 DCHECK(init_data); |
| 255 DCHECK(session_id_.empty()); | 255 DCHECK(session_id_.empty()); |
| 256 DCHECK(thread_checker_.CalledOnValidThread()); | 256 DCHECK(thread_checker_.CalledOnValidThread()); |
| 257 | 257 |
| 258 // From https://w3c.github.io/encrypted-media/#generateRequest. | 258 // From https://w3c.github.io/encrypted-media/#generateRequest. |
| 259 // 5. If the Key System implementation represented by this object's cdm | 259 // 6. If the Key System implementation represented by this object's cdm |
| 260 // implementation value does not support initDataType as an Initialization | 260 // implementation value does not support initDataType as an Initialization |
| 261 // Data Type, return a promise rejected with a new DOMException whose name | 261 // Data Type, return a promise rejected with a NotSupportedError. |
| 262 // is NotSupportedError. String comparison is case-sensitive. | 262 // String comparison is case-sensitive. |
| 263 EmeInitDataType eme_init_data_type = ConvertToEmeInitDataType(init_data_type); | 263 EmeInitDataType eme_init_data_type = ConvertToEmeInitDataType(init_data_type); |
| 264 if (!IsSupportedKeySystemWithInitDataType(adapter_->GetKeySystem(), | 264 if (!IsSupportedKeySystemWithInitDataType(adapter_->GetKeySystem(), |
| 265 eme_init_data_type)) { | 265 eme_init_data_type)) { |
| 266 std::string message = | 266 std::string message = |
| 267 "The initialization data type is not supported by the key system."; | 267 "The initialization data type is not supported by the key system."; |
| 268 result.completeWithError( | 268 result.completeWithError( |
| 269 blink::WebContentDecryptionModuleExceptionNotSupportedError, 0, | 269 blink::WebContentDecryptionModuleExceptionNotSupportedError, 0, |
| 270 blink::WebString::fromUTF8(message)); | 270 blink::WebString::fromUTF8(message)); |
| 271 return; | 271 return; |
| 272 } | 272 } |
| 273 | 273 |
| 274 // 9.1 If the init data is not valid for initDataType, reject promise with a | 274 // 10.1 If the init data is not valid for initDataType, reject promise with |
| 275 // new DOMException whose name is InvalidAccessError. | 275 // a newly created TypeError. |
| 276 // 9.2 Let sanitized init data be a validated and sanitized version of init | 276 // 10.2 Let sanitized init data be a validated and sanitized version of init |
| 277 // data. The user agent must thoroughly validate the Initialization Data | 277 // data. The user agent must thoroughly validate the Initialization Data |
| 278 // before passing it to the CDM. This includes verifying that the length | 278 // before passing it to the CDM. This includes verifying that the length |
| 279 // and values of fields are reasonable, verifying that values are within | 279 // and values of fields are reasonable, verifying that values are within |
| 280 // reasonable limits, and stripping irrelevant, unsupported, or unknown | 280 // reasonable limits, and stripping irrelevant, unsupported, or unknown |
| 281 // data or fields. It is recommended that user agents pre-parse, sanitize, | 281 // data or fields. It is recommended that user agents pre-parse, |
| 282 // and/or generate a fully sanitized version of the Initialization Data. | 282 // sanitize, and/or generate a fully sanitized version of the |
| 283 // If the Initialization Data format specified by initDataType support | 283 // Initialization Data. If the Initialization Data format specified by |
| 284 // multiple entries, the user agent should remove entries that are not | 284 // initDataType supports multiple entries, the user agent should remove |
| 285 // needed by the CDM. | 285 // entries that are not needed by the CDM. The user agent must not |
| 286 // 9.3 If the previous step failed, reject promise with a new DOMException | 286 // re-order entries within the Initialization Data. |
| 287 // whose name is InvalidAccessError. | 287 // 10.3 If the preceding step failed, reject promise with a newly created |
| 288 // TypeError. |
| 288 std::vector<uint8_t> sanitized_init_data; | 289 std::vector<uint8_t> sanitized_init_data; |
| 289 std::string message; | 290 std::string message; |
| 290 if (!SanitizeInitData(eme_init_data_type, init_data, init_data_length, | 291 if (!SanitizeInitData(eme_init_data_type, init_data, init_data_length, |
| 291 &sanitized_init_data, &message)) { | 292 &sanitized_init_data, &message)) { |
| 292 result.completeWithError( | 293 result.completeWithError( |
| 293 blink::WebContentDecryptionModuleExceptionInvalidAccessError, 0, | 294 blink::WebContentDecryptionModuleExceptionTypeError, 0, |
| 294 blink::WebString::fromUTF8(message)); | 295 blink::WebString::fromUTF8(message)); |
| 295 return; | 296 return; |
| 296 } | 297 } |
| 297 | 298 |
| 298 // 9.4 Let session id be the empty string. | 299 // 10.4 If sanitized init data is empty, reject promise with a |
| 299 // (Done in constructor.) | 300 // NotSupportedError. |
| 301 if (sanitized_init_data.empty()) { |
| 302 result.completeWithError( |
| 303 blink::WebContentDecryptionModuleExceptionNotSupportedError, 0, |
| 304 "No initialization data provided."); |
| 305 return; |
| 306 } |
| 300 | 307 |
| 301 // 9.5 Let message be null. | 308 // 10.5 Let session id be the empty string. |
| 302 // (Done by CDM.) | 309 // (Done in constructor.) |
| 303 | 310 |
| 304 // 9.6 Let cdm be the CDM instance represented by this object's cdm | 311 // 10.6 Let message be null. |
| 305 // instance value. | 312 // 10.7 Let message type be null. |
| 306 // 9.7 Use the cdm to execute the following steps: | 313 // (Done by CDM.) |
| 314 |
| 315 // 10.8 Let cdm be the CDM instance represented by this object's cdm |
| 316 // instance value. |
| 317 // 10.9 Use the cdm to execute the following steps: |
| 307 adapter_->InitializeNewSession( | 318 adapter_->InitializeNewSession( |
| 308 eme_init_data_type, sanitized_init_data, convertSessionType(session_type), | 319 eme_init_data_type, sanitized_init_data, convertSessionType(session_type), |
| 309 std::unique_ptr<NewSessionCdmPromise>(new NewSessionCdmResultPromise( | 320 std::unique_ptr<NewSessionCdmPromise>(new NewSessionCdmResultPromise( |
| 310 result, adapter_->GetKeySystemUMAPrefix() + kGenerateRequestUMAName, | 321 result, adapter_->GetKeySystemUMAPrefix() + kGenerateRequestUMAName, |
| 311 base::Bind( | 322 base::Bind( |
| 312 &WebContentDecryptionModuleSessionImpl::OnSessionInitialized, | 323 &WebContentDecryptionModuleSessionImpl::OnSessionInitialized, |
| 313 weak_ptr_factory_.GetWeakPtr())))); | 324 weak_ptr_factory_.GetWeakPtr())))); |
| 314 } | 325 } |
| 315 | 326 |
| 316 void WebContentDecryptionModuleSessionImpl::load( | 327 void WebContentDecryptionModuleSessionImpl::load( |
| 317 const blink::WebString& session_id, | 328 const blink::WebString& session_id, |
| 318 blink::WebContentDecryptionModuleResult result) { | 329 blink::WebContentDecryptionModuleResult result) { |
| 319 DCHECK(!session_id.isEmpty()); | 330 DCHECK(!session_id.isEmpty()); |
| 320 DCHECK(session_id_.empty()); | 331 DCHECK(session_id_.empty()); |
| 321 DCHECK(thread_checker_.CalledOnValidThread()); | 332 DCHECK(thread_checker_.CalledOnValidThread()); |
| 322 | 333 |
| 334 // From https://w3c.github.io/encrypted-media/#load. |
| 335 // 8.1 Let sanitized session ID be a validated and/or sanitized version of |
| 336 // sessionId. The user agent should thoroughly validate the sessionId |
| 337 // value before passing it to the CDM. At a minimum, this should include |
| 338 // checking that the length and value (e.g. alphanumeric) are reasonable. |
| 339 // 8.2 If the preceding step failed, or if sanitized session ID is empty, |
| 340 // reject promise with a newly created TypeError. |
| 323 std::string sanitized_session_id; | 341 std::string sanitized_session_id; |
| 324 if (!SanitizeSessionId(session_id, &sanitized_session_id)) { | 342 if (!SanitizeSessionId(session_id, &sanitized_session_id)) { |
| 325 result.completeWithError( | 343 result.completeWithError( |
| 326 blink::WebContentDecryptionModuleExceptionInvalidAccessError, 0, | 344 blink::WebContentDecryptionModuleExceptionTypeError, 0, |
| 327 "Invalid session ID."); | 345 "Invalid session ID."); |
| 328 return; | 346 return; |
| 329 } | 347 } |
| 330 | 348 |
| 331 // TODO(jrummell): Now that there are 2 types of persistent sessions, the | 349 // TODO(jrummell): Now that there are 2 types of persistent sessions, the |
| 332 // session type should be passed from blink. Type should also be passed in the | 350 // session type should be passed from blink. Type should also be passed in the |
| 333 // constructor (and removed from initializeNewSession()). | 351 // constructor (and removed from initializeNewSession()). |
| 334 adapter_->LoadSession( | 352 adapter_->LoadSession( |
| 335 MediaKeys::PERSISTENT_LICENSE_SESSION, sanitized_session_id, | 353 MediaKeys::PERSISTENT_LICENSE_SESSION, sanitized_session_id, |
| 336 std::unique_ptr<NewSessionCdmPromise>(new NewSessionCdmResultPromise( | 354 std::unique_ptr<NewSessionCdmPromise>(new NewSessionCdmResultPromise( |
| 337 result, adapter_->GetKeySystemUMAPrefix() + kLoadSessionUMAName, | 355 result, adapter_->GetKeySystemUMAPrefix() + kLoadSessionUMAName, |
| 338 base::Bind( | 356 base::Bind( |
| 339 &WebContentDecryptionModuleSessionImpl::OnSessionInitialized, | 357 &WebContentDecryptionModuleSessionImpl::OnSessionInitialized, |
| 340 weak_ptr_factory_.GetWeakPtr())))); | 358 weak_ptr_factory_.GetWeakPtr())))); |
| 341 } | 359 } |
| 342 | 360 |
| 343 void WebContentDecryptionModuleSessionImpl::update( | 361 void WebContentDecryptionModuleSessionImpl::update( |
| 344 const uint8_t* response, | 362 const uint8_t* response, |
| 345 size_t response_length, | 363 size_t response_length, |
| 346 blink::WebContentDecryptionModuleResult result) { | 364 blink::WebContentDecryptionModuleResult result) { |
| 347 DCHECK(response); | 365 DCHECK(response); |
| 348 DCHECK(!session_id_.empty()); | 366 DCHECK(!session_id_.empty()); |
| 349 DCHECK(thread_checker_.CalledOnValidThread()); | 367 DCHECK(thread_checker_.CalledOnValidThread()); |
| 350 | 368 |
| 369 // From https://w3c.github.io/encrypted-media/#update. |
| 370 // 6.1 Let sanitized response be a validated and/or sanitized version of |
| 371 // response copy. The user agent should thoroughly validate the response |
| 372 // before passing it to the CDM. This may include verifying values are |
| 373 // within reasonable limits, stripping irrelevant data or fields, |
| 374 // pre-parsing it, sanitizing it, and/or generating a fully sanitized |
| 375 // version. The user agent should check that the length and values of |
| 376 // fields are reasonable. Unknown fields should be rejected or removed. |
| 377 // 6.2 If the preceding step failed, or if sanitized response is empty, |
| 378 // reject promise with a newly created TypeError. |
| 351 std::vector<uint8_t> sanitized_response; | 379 std::vector<uint8_t> sanitized_response; |
| 352 if (!SanitizeResponse(adapter_->GetKeySystem(), response, response_length, | 380 if (!SanitizeResponse(adapter_->GetKeySystem(), response, response_length, |
| 353 &sanitized_response)) { | 381 &sanitized_response)) { |
| 354 result.completeWithError( | 382 result.completeWithError( |
| 355 blink::WebContentDecryptionModuleExceptionInvalidAccessError, 0, | 383 blink::WebContentDecryptionModuleExceptionTypeError, 0, |
| 356 "Invalid response."); | 384 "Invalid response."); |
| 357 return; | 385 return; |
| 358 } | 386 } |
| 359 | 387 |
| 360 adapter_->UpdateSession( | 388 adapter_->UpdateSession( |
| 361 session_id_, sanitized_response, | 389 session_id_, sanitized_response, |
| 362 std::unique_ptr<SimpleCdmPromise>(new CdmResultPromise<>( | 390 std::unique_ptr<SimpleCdmPromise>(new CdmResultPromise<>( |
| 363 result, adapter_->GetKeySystemUMAPrefix() + kUpdateSessionUMAName))); | 391 result, adapter_->GetKeySystemUMAPrefix() + kUpdateSessionUMAName))); |
| 364 } | 392 } |
| 365 | 393 |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 437 | 465 |
| 438 DCHECK(session_id_.empty()) << "Session ID may not be changed once set."; | 466 DCHECK(session_id_.empty()) << "Session ID may not be changed once set."; |
| 439 session_id_ = session_id; | 467 session_id_ = session_id; |
| 440 *status = | 468 *status = |
| 441 adapter_->RegisterSession(session_id_, weak_ptr_factory_.GetWeakPtr()) | 469 adapter_->RegisterSession(session_id_, weak_ptr_factory_.GetWeakPtr()) |
| 442 ? SessionInitStatus::NEW_SESSION | 470 ? SessionInitStatus::NEW_SESSION |
| 443 : SessionInitStatus::SESSION_ALREADY_EXISTS; | 471 : SessionInitStatus::SESSION_ALREADY_EXISTS; |
| 444 } | 472 } |
| 445 | 473 |
| 446 } // namespace media | 474 } // namespace media |
| OLD | NEW |