Adjust WidevineEncryptionKeySource to handle timeout

Change-Id: Iac4a86acae2e522c6cfc84ce02ae7ec1dd30c47e
This commit is contained in:
KongQun Yang 2014-06-18 12:23:34 -07:00
parent 419d463eaa
commit 1927109818
2 changed files with 53 additions and 37 deletions

View File

@ -40,6 +40,7 @@ const int kFirstRetryDelayMilliseconds = 1000;
// key rotation enabled request. // key rotation enabled request.
const int kDefaultCryptoPeriodCount = 10; const int kDefaultCryptoPeriodCount = 10;
const int kGetKeyTimeoutInSeconds = 5 * 60; // 5 minutes. const int kGetKeyTimeoutInSeconds = 5 * 60; // 5 minutes.
const int kHttpTimeoutInSeconds = 60; // 1 minute.
bool Base64StringToBytes(const std::string& base64_string, bool Base64StringToBytes(const std::string& base64_string,
std::vector<uint8>* bytes) { std::vector<uint8>* bytes) {
@ -129,7 +130,7 @@ WidevineEncryptionKeySource::WidevineEncryptionKeySource(
const std::string& policy, const std::string& policy,
scoped_ptr<RequestSigner> signer, scoped_ptr<RequestSigner> signer,
int first_crypto_period_index) int first_crypto_period_index)
: http_fetcher_(new SimpleHttpFetcher()), : http_fetcher_(new SimpleHttpFetcher(kHttpTimeoutInSeconds)),
server_url_(server_url), server_url_(server_url),
content_id_(content_id), content_id_(content_id),
policy_(policy), policy_(policy),
@ -243,24 +244,26 @@ Status WidevineEncryptionKeySource::FetchKeys(
// server limitation. // server limitation.
for (int i = 0; i < kNumTransientErrorRetries; ++i) { for (int i = 0; i < kNumTransientErrorRetries; ++i) {
status = http_fetcher_->Post(server_url_, message, &raw_response); status = http_fetcher_->Post(server_url_, message, &raw_response);
if (!status.ok()) if (status.ok()) {
VLOG(1) << "Retry [" << i << "] Response:" << raw_response;
std::string response;
if (!DecodeResponse(raw_response, &response)) {
return Status(error::SERVER_ERROR,
"Failed to decode response '" + raw_response + "'.");
}
bool transient_error = false;
if (ExtractEncryptionKey(response, &transient_error))
return Status::OK;
if (!transient_error) {
return Status(
error::SERVER_ERROR,
"Failed to extract encryption key from '" + response + "'.");
}
} else if (status.error_code() != error::TIME_OUT) {
return status; return status;
VLOG(1) << "Retry [" << i << "] Response:" << raw_response;
std::string response;
if (!DecodeResponse(raw_response, &response)) {
return Status(error::SERVER_ERROR,
"Failed to decode response '" + raw_response + "'.");
}
bool transient_error = false;
if (ExtractEncryptionKey(response, &transient_error))
return Status::OK;
if (!transient_error) {
return Status(
error::SERVER_ERROR,
"Failed to extract encryption key from '" + response + "'.");
} }
// Exponential backoff. // Exponential backoff.

View File

@ -143,6 +143,20 @@ class WidevineEncryptionKeySourceTest : public ::testing::Test {
mock_http_fetcher_.PassAs<HttpFetcher>()); mock_http_fetcher_.PassAs<HttpFetcher>());
} }
void VerifyKeys() {
EncryptionKey encryption_key;
const std::string kTrackTypes[] = {"SD", "HD", "AUDIO"};
for (size_t i = 0; i < arraysize(kTrackTypes); ++i) {
ASSERT_OK(widevine_encryption_key_source_->GetKey(
EncryptionKeySource::GetTrackTypeFromString(kTrackTypes[i]),
&encryption_key));
EXPECT_EQ(GetMockKeyId(kTrackTypes[i]), ToString(encryption_key.key_id));
EXPECT_EQ(GetMockKey(kTrackTypes[i]), ToString(encryption_key.key));
EXPECT_EQ(GetMockPsshData(kTrackTypes[i]),
GetPsshDataFromPsshBox(ToString(encryption_key.pssh)));
}
}
scoped_ptr<MockRequestSigner> mock_request_signer_; scoped_ptr<MockRequestSigner> mock_request_signer_;
scoped_ptr<MockHttpFetcher> mock_http_fetcher_; scoped_ptr<MockHttpFetcher> mock_http_fetcher_;
scoped_ptr<WidevineEncryptionKeySource> widevine_encryption_key_source_; scoped_ptr<WidevineEncryptionKeySource> widevine_encryption_key_source_;
@ -217,18 +231,24 @@ TEST_F(WidevineEncryptionKeySourceTest, LicenseStatusOK) {
CreateWidevineEncryptionKeySource(kDisableKeyRotation); CreateWidevineEncryptionKeySource(kDisableKeyRotation);
ASSERT_OK(widevine_encryption_key_source_->Initialize()); ASSERT_OK(widevine_encryption_key_source_->Initialize());
VerifyKeys();
}
EncryptionKey encryption_key; TEST_F(WidevineEncryptionKeySourceTest, RetryOnHttpTimeout) {
const std::string kTrackTypes[] = {"SD", "HD", "AUDIO"}; EXPECT_CALL(*mock_request_signer_, GenerateSignature(_, _))
for (size_t i = 0; i < 3; ++i) { .WillOnce(Return(true));
ASSERT_OK(widevine_encryption_key_source_->GetKey(
EncryptionKeySource::GetTrackTypeFromString(kTrackTypes[i]), std::string mock_response = base::StringPrintf(
&encryption_key)); kHttpResponseFormat, Base64Encode(GenerateMockLicenseResponse()).c_str());
EXPECT_EQ(GetMockKeyId(kTrackTypes[i]), ToString(encryption_key.key_id));
EXPECT_EQ(GetMockKey(kTrackTypes[i]), ToString(encryption_key.key)); // Retry is expected on HTTP timeout.
EXPECT_EQ(GetMockPsshData(kTrackTypes[i]), EXPECT_CALL(*mock_http_fetcher_, Post(_, _, _))
GetPsshDataFromPsshBox(ToString(encryption_key.pssh))); .WillOnce(Return(Status(error::TIME_OUT, "")))
} .WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK)));
CreateWidevineEncryptionKeySource(kDisableKeyRotation);
ASSERT_OK(widevine_encryption_key_source_->Initialize());
VerifyKeys();
} }
TEST_F(WidevineEncryptionKeySourceTest, RetryOnTransientError) { TEST_F(WidevineEncryptionKeySourceTest, RetryOnTransientError) {
@ -251,14 +271,7 @@ TEST_F(WidevineEncryptionKeySourceTest, RetryOnTransientError) {
CreateWidevineEncryptionKeySource(kDisableKeyRotation); CreateWidevineEncryptionKeySource(kDisableKeyRotation);
ASSERT_OK(widevine_encryption_key_source_->Initialize()); ASSERT_OK(widevine_encryption_key_source_->Initialize());
VerifyKeys();
EncryptionKey encryption_key;
ASSERT_OK(widevine_encryption_key_source_->GetKey(
EncryptionKeySource::TRACK_TYPE_SD, &encryption_key));
EXPECT_EQ(GetMockKeyId("SD"), ToString(encryption_key.key_id));
EXPECT_EQ(GetMockKey("SD"), ToString(encryption_key.key));
EXPECT_EQ(GetMockPsshData("SD"),
GetPsshDataFromPsshBox(ToString(encryption_key.pssh)));
} }
TEST_F(WidevineEncryptionKeySourceTest, NoRetryOnUnknownError) { TEST_F(WidevineEncryptionKeySourceTest, NoRetryOnUnknownError) {