KeyFetcher interface and HTTP impl to retrieve keys from the Widevine
License Service. Change-Id: Icb1af3fd26a5243293dd089888d4b396539fd768
This commit is contained in:
parent
e7e86d684a
commit
8cc29520b0
|
@ -4,7 +4,7 @@
|
||||||
// license that can be found in the LICENSE file or at
|
// license that can be found in the LICENSE file or at
|
||||||
// https://developers.google.com/open-source/licenses/bsd
|
// https://developers.google.com/open-source/licenses/bsd
|
||||||
|
|
||||||
#include "packager/media/base/http_fetcher.h"
|
#include "packager/media/base/http_key_fetcher.h"
|
||||||
|
|
||||||
#include <curl/curl.h>
|
#include <curl/curl.h>
|
||||||
#include "packager/base/strings/stringprintf.h"
|
#include "packager/base/strings/stringprintf.h"
|
||||||
|
@ -40,36 +40,39 @@ size_t AppendToString(char* ptr, size_t size, size_t nmemb, std::string* respons
|
||||||
namespace edash_packager {
|
namespace edash_packager {
|
||||||
namespace media {
|
namespace media {
|
||||||
|
|
||||||
HttpFetcher::HttpFetcher() {}
|
HttpKeyFetcher::HttpKeyFetcher() : timeout_in_seconds_(0) {
|
||||||
HttpFetcher::~HttpFetcher() {}
|
|
||||||
|
|
||||||
SimpleHttpFetcher::SimpleHttpFetcher() : timeout_in_seconds_(0) {
|
|
||||||
curl_global_init(CURL_GLOBAL_DEFAULT);
|
curl_global_init(CURL_GLOBAL_DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
SimpleHttpFetcher::SimpleHttpFetcher(uint32_t timeout_in_seconds)
|
HttpKeyFetcher::HttpKeyFetcher(uint32_t timeout_in_seconds)
|
||||||
: timeout_in_seconds_(timeout_in_seconds) {
|
: timeout_in_seconds_(timeout_in_seconds) {
|
||||||
curl_global_init(CURL_GLOBAL_DEFAULT);
|
curl_global_init(CURL_GLOBAL_DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
SimpleHttpFetcher::~SimpleHttpFetcher() {
|
HttpKeyFetcher::~HttpKeyFetcher() {
|
||||||
curl_global_cleanup();
|
curl_global_cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
Status SimpleHttpFetcher::Get(const std::string& path, std::string* response) {
|
Status HttpKeyFetcher::FetchKeys(const std::string& url,
|
||||||
|
const std::string& request,
|
||||||
|
std::string* response) {
|
||||||
|
return Post(url, request, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
Status HttpKeyFetcher::Get(const std::string& path, std::string* response) {
|
||||||
return FetchInternal(GET, path, "", response);
|
return FetchInternal(GET, path, "", response);
|
||||||
}
|
}
|
||||||
|
|
||||||
Status SimpleHttpFetcher::Post(const std::string& path,
|
Status HttpKeyFetcher::Post(const std::string& path,
|
||||||
const std::string& data,
|
const std::string& data,
|
||||||
std::string* response) {
|
std::string* response) {
|
||||||
return FetchInternal(POST, path, data, response);
|
return FetchInternal(POST, path, data, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
Status SimpleHttpFetcher::FetchInternal(HttpMethod method,
|
Status HttpKeyFetcher::FetchInternal(HttpMethod method,
|
||||||
const std::string& path,
|
const std::string& path,
|
||||||
const std::string& data,
|
const std::string& data,
|
||||||
std::string* response) {
|
std::string* response) {
|
||||||
DCHECK(method == GET || method == POST);
|
DCHECK(method == GET || method == POST);
|
||||||
|
|
||||||
ScopedCurl scoped_curl;
|
ScopedCurl scoped_curl;
|
|
@ -4,27 +4,41 @@
|
||||||
// license that can be found in the LICENSE file or at
|
// license that can be found in the LICENSE file or at
|
||||||
// https://developers.google.com/open-source/licenses/bsd
|
// https://developers.google.com/open-source/licenses/bsd
|
||||||
|
|
||||||
#ifndef MEDIA_BASE_HTTP_FETCHER_H_
|
#ifndef MEDIA_BASE_HTTP_KEY_FETCHER_H_
|
||||||
#define MEDIA_BASE_HTTP_FETCHER_H_
|
#define MEDIA_BASE_HTTP_KEY_FETCHER_H_
|
||||||
|
|
||||||
#include "packager/base/compiler_specific.h"
|
#include "packager/base/compiler_specific.h"
|
||||||
|
#include "packager/media/base/key_fetcher.h"
|
||||||
#include "packager/media/base/status.h"
|
#include "packager/media/base/status.h"
|
||||||
|
|
||||||
namespace edash_packager {
|
namespace edash_packager {
|
||||||
namespace media {
|
namespace media {
|
||||||
|
|
||||||
/// Defines a generic http fetcher interface.
|
/// A KeyFetcher implementation that retrieves keys over HTTP(s).
|
||||||
class HttpFetcher {
|
/// This class is not fully thread safe. It can be used in multi-thread
|
||||||
|
/// environment once constructed, but it may not be safe to create a
|
||||||
|
/// HttpKeyFetcher object when any other thread is running due to use of
|
||||||
|
/// curl_global_init.
|
||||||
|
class HttpKeyFetcher : public KeyFetcher {
|
||||||
public:
|
public:
|
||||||
HttpFetcher();
|
/// Creates a fetcher with no timeout.
|
||||||
virtual ~HttpFetcher();
|
HttpKeyFetcher();
|
||||||
|
/// Create a fetcher with timeout.
|
||||||
|
/// @param timeout_in_seconds specifies the timeout in seconds.
|
||||||
|
HttpKeyFetcher(uint32_t timeout_in_seconds);
|
||||||
|
virtual ~HttpKeyFetcher();
|
||||||
|
|
||||||
|
/// @name KeyFetcher implementation overrides.
|
||||||
|
virtual Status FetchKeys(const std::string& url,
|
||||||
|
const std::string& request,
|
||||||
|
std::string* response) OVERRIDE;
|
||||||
|
|
||||||
/// Fetch content using HTTP GET.
|
/// Fetch content using HTTP GET.
|
||||||
/// @param url specifies the content URL.
|
/// @param url specifies the content URL.
|
||||||
/// @param[out] response will contain the body of the http response on
|
/// @param[out] response will contain the body of the http response on
|
||||||
/// success. It should not be NULL.
|
/// success. It should not be NULL.
|
||||||
/// @return OK on success.
|
/// @return OK on success.
|
||||||
virtual Status Get(const std::string& url, std::string* response) = 0;
|
virtual Status Get(const std::string& url, std::string* response);
|
||||||
|
|
||||||
/// Fetch content using HTTP POST.
|
/// Fetch content using HTTP POST.
|
||||||
/// @param url specifies the content URL.
|
/// @param url specifies the content URL.
|
||||||
|
@ -33,33 +47,7 @@ class HttpFetcher {
|
||||||
/// @return OK on success.
|
/// @return OK on success.
|
||||||
virtual Status Post(const std::string& url,
|
virtual Status Post(const std::string& url,
|
||||||
const std::string& data,
|
const std::string& data,
|
||||||
std::string* response) = 0;
|
std::string* response);
|
||||||
|
|
||||||
private:
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(HttpFetcher);
|
|
||||||
};
|
|
||||||
|
|
||||||
/// A simple HttpFetcher implementation.
|
|
||||||
/// This class is not fully thread safe. It can be used in multi-thread
|
|
||||||
/// environment once constructed, but it may not be safe to create a
|
|
||||||
/// SimpleHttpFetcher object when any other thread is running due to use of
|
|
||||||
/// curl_global_init.
|
|
||||||
class SimpleHttpFetcher : public HttpFetcher {
|
|
||||||
public:
|
|
||||||
/// Creates a fetcher with no timeout.
|
|
||||||
SimpleHttpFetcher();
|
|
||||||
/// Create a fetcher with timeout.
|
|
||||||
/// @param timeout_in_seconds specifies the timeout in seconds.
|
|
||||||
SimpleHttpFetcher(uint32_t timeout_in_seconds);
|
|
||||||
virtual ~SimpleHttpFetcher();
|
|
||||||
|
|
||||||
/// @name HttpFetcher implementation overrides.
|
|
||||||
/// @{
|
|
||||||
virtual Status Get(const std::string& url, std::string* response) OVERRIDE;
|
|
||||||
virtual Status Post(const std::string& url,
|
|
||||||
const std::string& data,
|
|
||||||
std::string* response) OVERRIDE;
|
|
||||||
/// @}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum HttpMethod {
|
enum HttpMethod {
|
||||||
|
@ -74,11 +62,11 @@ class SimpleHttpFetcher : public HttpFetcher {
|
||||||
|
|
||||||
const uint32_t timeout_in_seconds_;
|
const uint32_t timeout_in_seconds_;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(SimpleHttpFetcher);
|
DISALLOW_COPY_AND_ASSIGN(HttpKeyFetcher);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace media
|
} // namespace media
|
||||||
} // namespace edash_packager
|
} // namespace edash_packager
|
||||||
|
|
||||||
#endif // MEDIA_BASE_HTTP_FETCHER_H_
|
#endif // MEDIA_BASE_HTTP_KEY_FETCHER_H_
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
// license that can be found in the LICENSE file or at
|
// license that can be found in the LICENSE file or at
|
||||||
// https://developers.google.com/open-source/licenses/bsd
|
// https://developers.google.com/open-source/licenses/bsd
|
||||||
|
|
||||||
#include "packager/media/base/http_fetcher.h"
|
#include "packager/media/base/http_key_fetcher.h"
|
||||||
|
|
||||||
#include "packager/base/logging.h"
|
#include "packager/base/logging.h"
|
||||||
#include "packager/base/strings/string_number_conversions.h"
|
#include "packager/base/strings/string_number_conversions.h"
|
||||||
|
@ -29,7 +29,7 @@ namespace media {
|
||||||
|
|
||||||
static void CheckHttpGet(const std::string& url,
|
static void CheckHttpGet(const std::string& url,
|
||||||
const std::string& expected_response) {
|
const std::string& expected_response) {
|
||||||
SimpleHttpFetcher fetcher;
|
HttpKeyFetcher fetcher;
|
||||||
std::string response;
|
std::string response;
|
||||||
ASSERT_OK(fetcher.Get(url, &response));
|
ASSERT_OK(fetcher.Get(url, &response));
|
||||||
base::RemoveChars(response, "\r\n\t ", &response);
|
base::RemoveChars(response, "\r\n\t ", &response);
|
||||||
|
@ -38,14 +38,13 @@ static void CheckHttpGet(const std::string& url,
|
||||||
|
|
||||||
static void CheckHttpPost(const std::string& url, const std::string& data,
|
static void CheckHttpPost(const std::string& url, const std::string& data,
|
||||||
const std::string& expected_response) {
|
const std::string& expected_response) {
|
||||||
SimpleHttpFetcher fetcher;
|
HttpKeyFetcher fetcher;
|
||||||
std::string response;
|
std::string response;
|
||||||
ASSERT_OK(fetcher.Post(url, data, &response));
|
ASSERT_OK(fetcher.Post(url, data, &response));
|
||||||
base::RemoveChars(response, "\r\n\t ", &response);
|
base::RemoveChars(response, "\r\n\t ", &response);
|
||||||
EXPECT_EQ(expected_response, response);
|
EXPECT_EQ(expected_response, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TEST(DISABLED_HttpFetcherTest, HttpGet) {
|
TEST(DISABLED_HttpFetcherTest, HttpGet) {
|
||||||
CheckHttpGet(kTestUrl, kExpectedGetResponse);
|
CheckHttpGet(kTestUrl, kExpectedGetResponse);
|
||||||
}
|
}
|
||||||
|
@ -54,34 +53,45 @@ TEST(DISABLED_HttpFetcherTest, HttpPost) {
|
||||||
CheckHttpPost(kTestUrl, kPostData, kExpectedPostResponse);
|
CheckHttpPost(kTestUrl, kPostData, kExpectedPostResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(DISABLED_HttpFetcherTest, InvalidUrl) {
|
TEST(DISABLED_HttpKeyFetcherTest, HttpFetchKeys) {
|
||||||
const char kHttpNotFound[] = "404";
|
HttpKeyFetcher fetcher;
|
||||||
|
std::string response;
|
||||||
|
ASSERT_OK(fetcher.FetchKeys(kTestUrl, kPostData, &response));
|
||||||
|
base::RemoveChars(response, "\r\n\t ", &response);
|
||||||
|
EXPECT_EQ(kExpectedPostResponse, response);
|
||||||
|
}
|
||||||
|
|
||||||
SimpleHttpFetcher fetcher;
|
TEST(DISABLED_HttpKeyFetcherTest, InvalidUrl) {
|
||||||
|
const char kHttpNotFound[] = "404";
|
||||||
|
HttpKeyFetcher fetcher;
|
||||||
std::string response;
|
std::string response;
|
||||||
const std::string invalid_url(kTestUrl, sizeof(kTestUrl) - 2);
|
const std::string invalid_url(kTestUrl, sizeof(kTestUrl) - 2);
|
||||||
Status status = fetcher.Get(invalid_url, &response);
|
Status status = fetcher.FetchKeys(invalid_url, kPostData, &response);
|
||||||
EXPECT_EQ(error::HTTP_FAILURE, status.error_code());
|
EXPECT_EQ(error::HTTP_FAILURE, status.error_code());
|
||||||
EXPECT_NE(std::string::npos, status.error_message().find(kHttpNotFound));
|
EXPECT_NE(std::string::npos, status.error_message().find(kHttpNotFound));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(DISABLED_HttpFetcherTest, UrlWithPort) {
|
TEST(DISABLED_HttpKeyFetcherTest, UrlWithPort) {
|
||||||
CheckHttpGet(kTestUrlWithPort, kExpectedGetResponse);
|
HttpKeyFetcher fetcher;
|
||||||
|
std::string response;
|
||||||
|
ASSERT_OK(fetcher.FetchKeys(kTestUrlWithPort, kPostData, &response));
|
||||||
|
base::RemoveChars(response, "\r\n\t ", &response);
|
||||||
|
EXPECT_EQ(kExpectedPostResponse, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(DISABLED_HttpFetcherTest, SmallTimeout) {
|
TEST(DISABLED_HttpKeyFetcherTest, SmallTimeout) {
|
||||||
const uint32_t kTimeoutInSeconds = 1;
|
const uint32_t kTimeoutInSeconds = 1;
|
||||||
SimpleHttpFetcher fetcher(kTimeoutInSeconds);
|
HttpKeyFetcher fetcher(kTimeoutInSeconds);
|
||||||
std::string response;
|
std::string response;
|
||||||
Status status = fetcher.Post(kTestUrl, kDelayTwoSecs, &response);
|
Status status = fetcher.FetchKeys(kTestUrl, kDelayTwoSecs, &response);
|
||||||
EXPECT_EQ(error::TIME_OUT, status.error_code());
|
EXPECT_EQ(error::TIME_OUT, status.error_code());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(DISABLED_HttpFetcherTest, BigTimeout) {
|
TEST(DISABLED_HttpKeyFetcherTest, BigTimeout) {
|
||||||
const uint32_t kTimeoutInSeconds = 5;
|
const uint32_t kTimeoutInSeconds = 5;
|
||||||
SimpleHttpFetcher fetcher(kTimeoutInSeconds);
|
HttpKeyFetcher fetcher(kTimeoutInSeconds);
|
||||||
std::string response;
|
std::string response;
|
||||||
Status status = fetcher.Post(kTestUrl, kDelayTwoSecs, &response);
|
Status status = fetcher.FetchKeys(kTestUrl, kDelayTwoSecs, &response);
|
||||||
EXPECT_OK(status);
|
EXPECT_OK(status);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
// Copyright 2014 Google Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file or at
|
||||||
|
// https://developers.google.com/open-source/licenses/bsd
|
||||||
|
|
||||||
|
#include "packager/media/base/key_fetcher.h"
|
||||||
|
|
||||||
|
namespace edash_packager {
|
||||||
|
namespace media {
|
||||||
|
|
||||||
|
KeyFetcher::KeyFetcher() {}
|
||||||
|
KeyFetcher::~KeyFetcher() {}
|
||||||
|
|
||||||
|
} // namespace media
|
||||||
|
} // namespace edash_packager
|
|
@ -0,0 +1,40 @@
|
||||||
|
// Copyright 2014 Google Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file or at
|
||||||
|
// https://developers.google.com/open-source/licenses/bsd
|
||||||
|
|
||||||
|
#ifndef MEDIA_BASE_KEY_FETCHER_H_
|
||||||
|
#define MEDIA_BASE_KEY_FETCHER_H_
|
||||||
|
|
||||||
|
#include "base/macros.h"
|
||||||
|
#include "packager/media/base/status.h"
|
||||||
|
|
||||||
|
namespace edash_packager {
|
||||||
|
namespace media {
|
||||||
|
|
||||||
|
/// Base class for fetching keys from the license service.
|
||||||
|
class KeyFetcher {
|
||||||
|
public:
|
||||||
|
KeyFetcher();
|
||||||
|
virtual ~KeyFetcher();
|
||||||
|
|
||||||
|
/// Fetch Keys from license service.
|
||||||
|
/// |response| is owned by caller.
|
||||||
|
/// @param service_address license service address.
|
||||||
|
/// @param request JSON formatted request.
|
||||||
|
/// @param response JSON formatted response. Owned by caller.
|
||||||
|
/// @return OK on success.
|
||||||
|
virtual Status FetchKeys(const std::string& service_address,
|
||||||
|
const std::string& request,
|
||||||
|
std::string* response) = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(KeyFetcher);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace media
|
||||||
|
} // namespace edash_packager
|
||||||
|
|
||||||
|
#endif // MEDIA_BASE_KEY_FETCHER_H_
|
||||||
|
|
|
@ -55,7 +55,7 @@ class KeySource {
|
||||||
/// @param asset_id is the Widevine Classic asset ID for the content to be
|
/// @param asset_id is the Widevine Classic asset ID for the content to be
|
||||||
/// decrypted.
|
/// decrypted.
|
||||||
/// @return OK on success, an error status otherwise.
|
/// @return OK on success, an error status otherwise.
|
||||||
virtual Status FetchKeys(uint32_t asset_id) OVERRIDE;
|
virtual Status FetchKeys(uint32_t asset_id);
|
||||||
|
|
||||||
/// Get encryption key of the specified track type.
|
/// Get encryption key of the specified track type.
|
||||||
/// @param track_type is the type of track for which retrieving the key.
|
/// @param track_type is the type of track for which retrieving the key.
|
||||||
|
|
|
@ -36,8 +36,10 @@
|
||||||
'decrypt_config.cc',
|
'decrypt_config.cc',
|
||||||
'decrypt_config.h',
|
'decrypt_config.h',
|
||||||
'decryptor_source.h',
|
'decryptor_source.h',
|
||||||
'http_fetcher.cc',
|
'http_key_fetcher.cc',
|
||||||
'http_fetcher.h',
|
'http_key_fetcher.h',
|
||||||
|
'key_fetcher.cc',
|
||||||
|
'key_fetcher.h',
|
||||||
'key_source.cc',
|
'key_source.cc',
|
||||||
'key_source.h',
|
'key_source.h',
|
||||||
'limits.h',
|
'limits.h',
|
||||||
|
@ -90,7 +92,7 @@
|
||||||
'container_names_unittest.cc',
|
'container_names_unittest.cc',
|
||||||
'fake_prng.cc', # For rsa_key_unittest
|
'fake_prng.cc', # For rsa_key_unittest
|
||||||
'fake_prng.h', # For rsa_key_unittest
|
'fake_prng.h', # For rsa_key_unittest
|
||||||
'http_fetcher_unittest.cc',
|
'http_key_fetcher_unittest.cc',
|
||||||
'muxer_util_unittest.cc',
|
'muxer_util_unittest.cc',
|
||||||
'offset_byte_queue_unittest.cc',
|
'offset_byte_queue_unittest.cc',
|
||||||
'producer_consumer_queue_unittest.cc',
|
'producer_consumer_queue_unittest.cc',
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
#include "packager/base/json/json_writer.h"
|
#include "packager/base/json/json_writer.h"
|
||||||
#include "packager/base/memory/ref_counted.h"
|
#include "packager/base/memory/ref_counted.h"
|
||||||
#include "packager/base/stl_util.h"
|
#include "packager/base/stl_util.h"
|
||||||
#include "packager/media/base/http_fetcher.h"
|
#include "packager/media/base/http_key_fetcher.h"
|
||||||
#include "packager/media/base/producer_consumer_queue.h"
|
#include "packager/media/base/producer_consumer_queue.h"
|
||||||
#include "packager/media/base/request_signer.h"
|
#include "packager/media/base/request_signer.h"
|
||||||
|
|
||||||
|
@ -43,7 +43,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.
|
const int kKeyFetchTimeoutInSeconds = 60; // 1 minute.
|
||||||
|
|
||||||
bool Base64StringToBytes(const std::string& base64_string,
|
bool Base64StringToBytes(const std::string& base64_string,
|
||||||
std::vector<uint8_t>* bytes) {
|
std::vector<uint8_t>* bytes) {
|
||||||
|
@ -143,7 +143,7 @@ WidevineKeySource::WidevineKeySource(
|
||||||
"KeyProductionThread",
|
"KeyProductionThread",
|
||||||
base::Bind(&WidevineKeySource::FetchKeysTask,
|
base::Bind(&WidevineKeySource::FetchKeysTask,
|
||||||
base::Unretained(this))),
|
base::Unretained(this))),
|
||||||
http_fetcher_(new SimpleHttpFetcher(kHttpTimeoutInSeconds)),
|
key_fetcher_(new HttpKeyFetcher(kKeyFetchTimeoutInSeconds)),
|
||||||
server_url_(server_url),
|
server_url_(server_url),
|
||||||
signer_(signer.Pass()),
|
signer_(signer.Pass()),
|
||||||
crypto_period_count_(kDefaultCryptoPeriodCount),
|
crypto_period_count_(kDefaultCryptoPeriodCount),
|
||||||
|
@ -251,9 +251,9 @@ Status WidevineKeySource::GetCryptoPeriodKey(uint32_t crypto_period_index,
|
||||||
return GetKeyInternal(crypto_period_index, track_type, key);
|
return GetKeyInternal(crypto_period_index, track_type, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WidevineKeySource::set_http_fetcher(
|
void WidevineKeySource::set_key_fetcher(
|
||||||
scoped_ptr<HttpFetcher> http_fetcher) {
|
scoped_ptr<KeyFetcher> key_fetcher) {
|
||||||
http_fetcher_ = http_fetcher.Pass();
|
key_fetcher_ = key_fetcher.Pass();
|
||||||
}
|
}
|
||||||
|
|
||||||
Status WidevineKeySource::GetKeyInternal(uint32_t crypto_period_index,
|
Status WidevineKeySource::GetKeyInternal(uint32_t crypto_period_index,
|
||||||
|
@ -324,7 +324,7 @@ Status WidevineKeySource::FetchKeysInternal(bool enable_key_rotation,
|
||||||
// Perform client side retries if seeing server transient error to workaround
|
// Perform client side retries if seeing server transient error to workaround
|
||||||
// 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 = key_fetcher_->FetchKeys(server_url_, message, &raw_response);
|
||||||
if (status.ok()) {
|
if (status.ok()) {
|
||||||
VLOG(1) << "Retry [" << i << "] Response:" << raw_response;
|
VLOG(1) << "Retry [" << i << "] Response:" << raw_response;
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
namespace edash_packager {
|
namespace edash_packager {
|
||||||
namespace media {
|
namespace media {
|
||||||
class HttpFetcher;
|
class KeyFetcher;
|
||||||
class RequestSigner;
|
class RequestSigner;
|
||||||
template <class T> class ProducerConsumerQueue;
|
template <class T> class ProducerConsumerQueue;
|
||||||
|
|
||||||
|
@ -47,9 +47,9 @@ class WidevineKeySource : public KeySource {
|
||||||
EncryptionKey* key) OVERRIDE;
|
EncryptionKey* key) OVERRIDE;
|
||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
/// Inject an @b HttpFetcher object, mainly used for testing.
|
/// Inject an @b KeyFetcher object, mainly used for testing.
|
||||||
/// @param http_fetcher points to the @b HttpFetcher object to be injected.
|
/// @param key_fetcher points to the @b KeyFetcher object to be injected.
|
||||||
void set_http_fetcher(scoped_ptr<HttpFetcher> http_fetcher);
|
void set_key_fetcher(scoped_ptr<KeyFetcher> key_fetcher);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ClosureThread key_production_thread_;
|
ClosureThread key_production_thread_;
|
||||||
|
@ -98,10 +98,10 @@ class WidevineKeySource : public KeySource {
|
||||||
// Push the keys to the key pool.
|
// Push the keys to the key pool.
|
||||||
bool PushToKeyPool(EncryptionKeyMap* encryption_key_map);
|
bool PushToKeyPool(EncryptionKeyMap* encryption_key_map);
|
||||||
|
|
||||||
// The fetcher object used to fetch HTTP response from server.
|
// The fetcher object used to fetch keys from the license service.
|
||||||
// It is initialized to a default fetcher on class initialization.
|
// It is initialized to a default fetcher on class initialization.
|
||||||
// Can be overridden using set_http_fetcher for testing or other purposes.
|
// Can be overridden using set_key_fetcher for testing or other purposes.
|
||||||
scoped_ptr<HttpFetcher> http_fetcher_;
|
scoped_ptr<KeyFetcher> key_fetcher_;
|
||||||
std::string server_url_;
|
std::string server_url_;
|
||||||
scoped_ptr<RequestSigner> signer_;
|
scoped_ptr<RequestSigner> signer_;
|
||||||
base::DictionaryValue request_dict_;
|
base::DictionaryValue request_dict_;
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
#include "packager/base/base64.h"
|
#include "packager/base/base64.h"
|
||||||
#include "packager/base/strings/string_number_conversions.h"
|
#include "packager/base/strings/string_number_conversions.h"
|
||||||
#include "packager/base/strings/stringprintf.h"
|
#include "packager/base/strings/stringprintf.h"
|
||||||
#include "packager/media/base/http_fetcher.h"
|
#include "packager/media/base/key_fetcher.h"
|
||||||
#include "packager/media/base/request_signer.h"
|
#include "packager/media/base/request_signer.h"
|
||||||
#include "packager/media/base/status_test_util.h"
|
#include "packager/media/base/status_test_util.h"
|
||||||
#include "packager/media/base/widevine_key_source.h"
|
#include "packager/media/base/widevine_key_source.h"
|
||||||
|
@ -129,26 +129,25 @@ class MockRequestSigner : public RequestSigner {
|
||||||
DISALLOW_COPY_AND_ASSIGN(MockRequestSigner);
|
DISALLOW_COPY_AND_ASSIGN(MockRequestSigner);
|
||||||
};
|
};
|
||||||
|
|
||||||
class MockHttpFetcher : public HttpFetcher {
|
class MockKeyFetcher : public KeyFetcher {
|
||||||
public:
|
public:
|
||||||
MockHttpFetcher() : HttpFetcher() {}
|
MockKeyFetcher() : KeyFetcher() {}
|
||||||
virtual ~MockHttpFetcher() {}
|
virtual ~MockKeyFetcher() {}
|
||||||
|
|
||||||
MOCK_METHOD2(Get, Status(const std::string& url, std::string* response));
|
MOCK_METHOD3(FetchKeys,
|
||||||
MOCK_METHOD3(Post,
|
Status(const std::string& service_address,
|
||||||
Status(const std::string& url,
|
|
||||||
const std::string& data,
|
const std::string& data,
|
||||||
std::string* response));
|
std::string* response));
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DISALLOW_COPY_AND_ASSIGN(MockHttpFetcher);
|
DISALLOW_COPY_AND_ASSIGN(MockKeyFetcher);
|
||||||
};
|
};
|
||||||
|
|
||||||
class WidevineKeySourceTest : public ::testing::Test {
|
class WidevineKeySourceTest : public ::testing::Test {
|
||||||
public:
|
public:
|
||||||
WidevineKeySourceTest()
|
WidevineKeySourceTest()
|
||||||
: mock_request_signer_(new MockRequestSigner(kSignerName)),
|
: mock_request_signer_(new MockRequestSigner(kSignerName)),
|
||||||
mock_http_fetcher_(new MockHttpFetcher()) {}
|
mock_key_fetcher_(new MockKeyFetcher()) {}
|
||||||
|
|
||||||
virtual void SetUp() OVERRIDE {
|
virtual void SetUp() OVERRIDE {
|
||||||
content_id_.assign(
|
content_id_.assign(
|
||||||
|
@ -161,8 +160,8 @@ class WidevineKeySourceTest : public ::testing::Test {
|
||||||
widevine_key_source_.reset(new WidevineKeySource(
|
widevine_key_source_.reset(new WidevineKeySource(
|
||||||
kServerUrl,
|
kServerUrl,
|
||||||
mock_request_signer_.PassAs<RequestSigner>()));
|
mock_request_signer_.PassAs<RequestSigner>()));
|
||||||
widevine_key_source_->set_http_fetcher(
|
widevine_key_source_->set_key_fetcher(
|
||||||
mock_http_fetcher_.PassAs<HttpFetcher>());
|
mock_key_fetcher_.PassAs<KeyFetcher>());
|
||||||
}
|
}
|
||||||
|
|
||||||
void VerifyKeys(bool classic) {
|
void VerifyKeys(bool classic) {
|
||||||
|
@ -182,7 +181,7 @@ class WidevineKeySourceTest : public ::testing::Test {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
scoped_ptr<MockRequestSigner> mock_request_signer_;
|
scoped_ptr<MockRequestSigner> mock_request_signer_;
|
||||||
scoped_ptr<MockHttpFetcher> mock_http_fetcher_;
|
scoped_ptr<MockKeyFetcher> mock_key_fetcher_;
|
||||||
scoped_ptr<WidevineKeySource> widevine_key_source_;
|
scoped_ptr<WidevineKeySource> widevine_key_source_;
|
||||||
std::vector<uint8_t> content_id_;
|
std::vector<uint8_t> content_id_;
|
||||||
|
|
||||||
|
@ -212,7 +211,7 @@ TEST_F(WidevineKeySourceTest, GenerateSignatureFailure) {
|
||||||
|
|
||||||
// Check whether expected request message and post data was generated and
|
// Check whether expected request message and post data was generated and
|
||||||
// verify the correct behavior on http failure.
|
// verify the correct behavior on http failure.
|
||||||
TEST_F(WidevineKeySourceTest, HttpPostFailure) {
|
TEST_F(WidevineKeySourceTest, HttpFetchFailure) {
|
||||||
std::string expected_message = base::StringPrintf(
|
std::string expected_message = base::StringPrintf(
|
||||||
kExpectedRequestMessageFormat, Base64Encode(kContentId).c_str(), kPolicy);
|
kExpectedRequestMessageFormat, Base64Encode(kContentId).c_str(), kPolicy);
|
||||||
EXPECT_CALL(*mock_request_signer_, GenerateSignature(expected_message, _))
|
EXPECT_CALL(*mock_request_signer_, GenerateSignature(expected_message, _))
|
||||||
|
@ -224,8 +223,8 @@ TEST_F(WidevineKeySourceTest, HttpPostFailure) {
|
||||||
Base64Encode(kMockSignature).c_str(),
|
Base64Encode(kMockSignature).c_str(),
|
||||||
kSignerName);
|
kSignerName);
|
||||||
const Status kMockStatus = Status::UNKNOWN;
|
const Status kMockStatus = Status::UNKNOWN;
|
||||||
EXPECT_CALL(*mock_http_fetcher_,
|
EXPECT_CALL(*mock_key_fetcher_,
|
||||||
Post(StrEq(kServerUrl), expected_post_data, _))
|
FetchKeys(kServerUrl, expected_post_data, _))
|
||||||
.WillOnce(Return(kMockStatus));
|
.WillOnce(Return(kMockStatus));
|
||||||
|
|
||||||
CreateWidevineKeySource();
|
CreateWidevineKeySource();
|
||||||
|
@ -240,7 +239,7 @@ TEST_F(WidevineKeySourceTest, LicenseStatusCencOK) {
|
||||||
std::string mock_response = base::StringPrintf(
|
std::string mock_response = base::StringPrintf(
|
||||||
kHttpResponseFormat, Base64Encode(GenerateMockLicenseResponse()).c_str());
|
kHttpResponseFormat, Base64Encode(GenerateMockLicenseResponse()).c_str());
|
||||||
|
|
||||||
EXPECT_CALL(*mock_http_fetcher_, Post(_, _, _))
|
EXPECT_CALL(*mock_key_fetcher_, FetchKeys(_, _, _))
|
||||||
.WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK)));
|
.WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK)));
|
||||||
|
|
||||||
CreateWidevineKeySource();
|
CreateWidevineKeySource();
|
||||||
|
@ -256,7 +255,7 @@ TEST_F(WidevineKeySourceTest, LicenseStatusCencNotOK) {
|
||||||
kHttpResponseFormat, Base64Encode(
|
kHttpResponseFormat, Base64Encode(
|
||||||
GenerateMockClassicLicenseResponse()).c_str());
|
GenerateMockClassicLicenseResponse()).c_str());
|
||||||
|
|
||||||
EXPECT_CALL(*mock_http_fetcher_, Post(_, _, _))
|
EXPECT_CALL(*mock_key_fetcher_, FetchKeys(_, _, _))
|
||||||
.WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK)));
|
.WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK)));
|
||||||
|
|
||||||
CreateWidevineKeySource();
|
CreateWidevineKeySource();
|
||||||
|
@ -272,7 +271,7 @@ TEST_F(WidevineKeySourceTest, LicenseStatusCencWithPsshDataOK) {
|
||||||
std::string mock_response = base::StringPrintf(
|
std::string mock_response = base::StringPrintf(
|
||||||
kHttpResponseFormat, Base64Encode(GenerateMockLicenseResponse()).c_str());
|
kHttpResponseFormat, Base64Encode(GenerateMockLicenseResponse()).c_str());
|
||||||
|
|
||||||
EXPECT_CALL(*mock_http_fetcher_, Post(_, _, _))
|
EXPECT_CALL(*mock_key_fetcher_, FetchKeys(_, _, _))
|
||||||
.WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK)));
|
.WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK)));
|
||||||
|
|
||||||
CreateWidevineKeySource();
|
CreateWidevineKeySource();
|
||||||
|
@ -291,7 +290,7 @@ TEST_F(WidevineKeySourceTest, LicenseStatusClassicOK) {
|
||||||
kHttpResponseFormat, Base64Encode(
|
kHttpResponseFormat, Base64Encode(
|
||||||
GenerateMockClassicLicenseResponse()).c_str());
|
GenerateMockClassicLicenseResponse()).c_str());
|
||||||
|
|
||||||
EXPECT_CALL(*mock_http_fetcher_, Post(_, _, _))
|
EXPECT_CALL(*mock_key_fetcher_, FetchKeys(_, _, _))
|
||||||
.WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK)));
|
.WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK)));
|
||||||
|
|
||||||
CreateWidevineKeySource();
|
CreateWidevineKeySource();
|
||||||
|
@ -307,7 +306,7 @@ TEST_F(WidevineKeySourceTest, RetryOnHttpTimeout) {
|
||||||
kHttpResponseFormat, Base64Encode(GenerateMockLicenseResponse()).c_str());
|
kHttpResponseFormat, Base64Encode(GenerateMockLicenseResponse()).c_str());
|
||||||
|
|
||||||
// Retry is expected on HTTP timeout.
|
// Retry is expected on HTTP timeout.
|
||||||
EXPECT_CALL(*mock_http_fetcher_, Post(_, _, _))
|
EXPECT_CALL(*mock_key_fetcher_, FetchKeys(_, _, _))
|
||||||
.WillOnce(Return(Status(error::TIME_OUT, "")))
|
.WillOnce(Return(Status(error::TIME_OUT, "")))
|
||||||
.WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK)));
|
.WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK)));
|
||||||
|
|
||||||
|
@ -329,7 +328,7 @@ TEST_F(WidevineKeySourceTest, RetryOnTransientError) {
|
||||||
kHttpResponseFormat, Base64Encode(GenerateMockLicenseResponse()).c_str());
|
kHttpResponseFormat, Base64Encode(GenerateMockLicenseResponse()).c_str());
|
||||||
|
|
||||||
// Retry is expected on transient error.
|
// Retry is expected on transient error.
|
||||||
EXPECT_CALL(*mock_http_fetcher_, Post(_, _, _))
|
EXPECT_CALL(*mock_key_fetcher_, FetchKeys(_, _, _))
|
||||||
.WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK)))
|
.WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK)))
|
||||||
.WillOnce(DoAll(SetArgPointee<2>(expected_retried_response),
|
.WillOnce(DoAll(SetArgPointee<2>(expected_retried_response),
|
||||||
Return(Status::OK)));
|
Return(Status::OK)));
|
||||||
|
@ -348,7 +347,7 @@ TEST_F(WidevineKeySourceTest, NoRetryOnUnknownError) {
|
||||||
std::string mock_response = base::StringPrintf(
|
std::string mock_response = base::StringPrintf(
|
||||||
kHttpResponseFormat, Base64Encode(mock_license_status).c_str());
|
kHttpResponseFormat, Base64Encode(mock_license_status).c_str());
|
||||||
|
|
||||||
EXPECT_CALL(*mock_http_fetcher_, Post(_, _, _))
|
EXPECT_CALL(*mock_key_fetcher_, FetchKeys(_, _, _))
|
||||||
.WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK)));
|
.WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK)));
|
||||||
|
|
||||||
CreateWidevineKeySource();
|
CreateWidevineKeySource();
|
||||||
|
@ -412,7 +411,7 @@ TEST_F(WidevineKeySourceTest, KeyRotationTest) {
|
||||||
.WillOnce(Return(true));
|
.WillOnce(Return(true));
|
||||||
std::string mock_response = base::StringPrintf(
|
std::string mock_response = base::StringPrintf(
|
||||||
kHttpResponseFormat, Base64Encode(GenerateMockLicenseResponse()).c_str());
|
kHttpResponseFormat, Base64Encode(GenerateMockLicenseResponse()).c_str());
|
||||||
EXPECT_CALL(*mock_http_fetcher_, Post(_, _, _))
|
EXPECT_CALL(*mock_key_fetcher_, FetchKeys(_, _, _))
|
||||||
.WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK)));
|
.WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK)));
|
||||||
|
|
||||||
for (uint32_t i = 0; i < kCryptoIterations; ++i) {
|
for (uint32_t i = 0; i < kCryptoIterations; ++i) {
|
||||||
|
@ -432,7 +431,7 @@ TEST_F(WidevineKeySourceTest, KeyRotationTest) {
|
||||||
Base64Encode(GenerateMockKeyRotationLicenseResponse(
|
Base64Encode(GenerateMockKeyRotationLicenseResponse(
|
||||||
first_crypto_period_index, kCryptoPeriodCount))
|
first_crypto_period_index, kCryptoPeriodCount))
|
||||||
.c_str());
|
.c_str());
|
||||||
EXPECT_CALL(*mock_http_fetcher_, Post(_, _, _))
|
EXPECT_CALL(*mock_key_fetcher_, FetchKeys(_, _, _))
|
||||||
.WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK)));
|
.WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue