Source release 19.3.0

This commit is contained in:
John W. Bruce
2024-09-05 07:02:36 +00:00
parent cd8256726f
commit 11c108a8da
122 changed files with 2259 additions and 1082 deletions

View File

@@ -115,7 +115,7 @@ class MockCdmEngineImpl : public CdmEngine {
class WvCdmEngineMetricsImplTest : public ::testing::Test {
public:
void SetUp() override {
file_system_.reset(CreateTestFileSystem());
file_system_ = CreateTestFileSystem();
std::shared_ptr<EngineMetrics> engine_metrics(new EngineMetrics);
test_cdm_metrics_engine_.reset(
new CdmEngineMetricsImpl<StrictMock<MockCdmEngineImpl>>(

View File

@@ -1,13 +1,13 @@
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
#ifndef CDM_TEST_CONFIG_TEST_ENV_H_
#define CDM_TEST_CONFIG_TEST_ENV_H_
#include <string>
#include "disallow_copy_and_assign.h"
#include "wv_cdm_types.h"
#include "wv_class_utils.h"
// Declare class ConfigTestEnv - holds the configuration settings needed
// to talk to the various provisioning and license servers.
@@ -45,7 +45,6 @@ enum ContentId {
// Configures default test environment.
class ConfigTestEnv {
public:
typedef struct {
ServerConfigurationId id;
std::string license_server_url;
@@ -63,12 +62,9 @@ class ConfigTestEnv {
bool release);
// Allow copy, assign, and move. Performance is not an issue in test
// initialization.
ConfigTestEnv(const ConfigTestEnv&) = default;
ConfigTestEnv(ConfigTestEnv&&) = default;
ConfigTestEnv& operator=(const ConfigTestEnv&) = default;
ConfigTestEnv& operator=(ConfigTestEnv&&) = default;
WVCDM_DEFAULT_COPY_AND_MOVE(ConfigTestEnv);
~ConfigTestEnv() {};
~ConfigTestEnv() {}
ServerConfigurationId server_id() { return server_id_; }
const std::string& client_auth() const { return client_auth_; }
@@ -157,11 +153,8 @@ class ConfigTestEnv {
// It dump_golden_data_ is true, message data is dumped to a file for help
// in generating golden test data.
bool dump_golden_data_ = false;
};
}; // class ConfigTestEnv
// The default provisioning server URL for a default provisioning request.
extern const std::string kDefaultProvisioningServerUrl;
} // namespace wvcdm
#endif // CDM_TEST_CONFIG_TEST_ENV_H_

View File

@@ -5,6 +5,7 @@
#include "certificate_provisioning.h"
#include "license_holder.h"
#include "log.h"
#include "oec_device_features.h"
#include "provisioning_holder.h"
#include "test_base.h"
#include "wv_cdm_types.h"
@@ -135,6 +136,9 @@ class CoreIntegrationTest : public WvCdmTestBaseWithEngine {
* different apps. Test using two different apps and origins.
*/
TEST_F(CoreIntegrationTest, ProvisioningStableSpoidTest) {
if (wvoec::global_features.provisioning_method == OEMCrypto_DrmCertificate) {
GTEST_SKIP() << "Device does not provision.";
}
std::string level;
ASSERT_EQ(
NO_ERROR,

View File

@@ -5,11 +5,13 @@
#ifndef CDM_TEST_CREATE_TEST_FILE_SYSTEM_H_
#define CDM_TEST_CREATE_TEST_FILE_SYSTEM_H_
#include <memory>
#include "file_store.h"
// Create a new FileSystem object that is suitable for using to create a new
// CdmEngine object. How this is implemented is platform-specific. The caller
// owns the returned pointer and is responsible for deleting it.
wvutil::FileSystem* CreateTestFileSystem();
std::unique_ptr<wvutil::FileSystem> CreateTestFileSystem();
#endif // CDM_TEST_CREATE_TEST_FILE_SYSTEM_H_

View File

@@ -1,20 +1,9 @@
// Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
#include "fake_provisioning_server.h"
#include "core_message_deserialize.h"
#include "core_message_serialize.h"
#include "core_message_serialize_proto.h"
#include "crypto_session.h"
#include "license_protocol.pb.h"
#include "log.h"
#include "oec_key_deriver.h"
#include "oec_test_data.h"
#include "privacy_crypto.h"
#include "service_certificate.h"
#include "string_conversions.h"
#include <inttypes.h>
// TODO: refactor oec_session so that these are not needed.
#include <gtest/gtest.h>
@@ -27,7 +16,18 @@
#include <openssl/rand.h>
#include <openssl/x509.h>
#include <openssl/x509_vfy.h>
#include <stdint.h>
#include "core_message_deserialize.h"
#include "core_message_serialize.h"
#include "core_message_serialize_proto.h"
#include "crypto_session.h"
#include "license_protocol.pb.h"
#include "log.h"
#include "oec_key_deriver.h"
#include "oec_test_data.h"
#include "privacy_crypto.h"
#include "service_certificate.h"
#include "string_conversions.h"
namespace wvcdm {
namespace {
@@ -357,5 +357,4 @@ bool FakeProvisioningServer::MakeResponse(
json_response->append(kJsonEnd);
return true;
}
} // namespace wvcdm

View File

@@ -1,7 +1,6 @@
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
#ifndef CDM_TEST_HTTP_SOCKET_H_
#define CDM_TEST_HTTP_SOCKET_H_
@@ -13,13 +12,14 @@
#include <gtest/gtest_prod.h>
#include <openssl/ssl.h>
#include "disallow_copy_and_assign.h"
#include "wv_class_utils.h"
namespace wvcdm {
// Provides basic Linux based TCP socket interface.
class HttpSocket {
public:
HttpSocket() = delete;
WVCDM_DISALLOW_COPY_AND_MOVE(HttpSocket);
// A scheme (http:// or https://) is required for the URL.
explicit HttpSocket(const std::string& url);
~HttpSocket();
@@ -70,10 +70,6 @@ class HttpSocket {
// When the socket was created. Logged on error to help debug flaky
// tests. e.g. b/186031735
std::time_t create_time_;
CORE_DISALLOW_COPY_AND_ASSIGN(HttpSocket);
};
}; // class HttpSocket
} // namespace wvcdm
#endif // CDM_TEST_HTTP_SOCKET_H_

View File

@@ -102,7 +102,7 @@ void LicenseHolder::GenerateAndPostRenewalRequest(
void LicenseHolder::FetchRenewal() {
ASSERT_NE(request_in_flight_, nullptr) << "Failed for " << content_id();
ASSERT_NO_FATAL_FAILURE(
request_in_flight_->AssertOkResponse(&request_response_))
request_in_flight_->AssertOkResponseWithRetry(&request_response_))
<< "Renewal failed for " << content_id();
}
@@ -144,7 +144,7 @@ void LicenseHolder::GenerateAndPostReleaseRequest(
void LicenseHolder::FetchRelease() {
ASSERT_NE(request_in_flight_, nullptr) << "Failed for " << content_id();
ASSERT_NO_FATAL_FAILURE(
request_in_flight_->AssertOkResponse(&request_response_))
request_in_flight_->AssertOkResponseWithRetry(&request_response_))
<< "Renewal failed for " << content_id();
}
@@ -293,7 +293,7 @@ void LicenseHolder::GetKeyResponse(const CdmKeyRequest& key_request) {
std::string http_response;
url_request.PostRequest(key_request.message);
ASSERT_NO_FATAL_FAILURE(url_request.AssertOkResponse(&http_response))
ASSERT_NO_FATAL_FAILURE(url_request.AssertOkResponseWithRetry(&http_response))
<< "Failed for " << content_id();
LicenseRequest license_request;
license_request.GetDrmMessage(http_response, key_response_);

View File

@@ -1,31 +1,27 @@
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
#ifndef CDM_TEST_LICENSE_REQUEST_H_
#define CDM_TEST_LICENSE_REQUEST_H_
#include <string>
#include "disallow_copy_and_assign.h"
#include "wv_class_utils.h"
namespace wvcdm {
// Parses response from a license request.
// This class assumes a particular response format defined by
// Google license servers.
class LicenseRequest {
public:
LicenseRequest() {}
LicenseRequest() = default;
WVCDM_DISALLOW_COPY_AND_MOVE(LicenseRequest);
~LicenseRequest() {}
void GetDrmMessage(const std::string& response, std::string& drm_msg);
private:
size_t FindHeaderEndPosition(const std::string& response) const;
CORE_DISALLOW_COPY_AND_ASSIGN(LicenseRequest);
};
}; // class LicenseRequest
} // namespace wvcdm
#endif // CDM_TEST_LICENSE_REQUEST_H_

View File

@@ -22,10 +22,32 @@
#include "wv_cdm_constants.h"
namespace wvcdm {
// Protobuf generated classes
using ClientCapabilities =
video_widevine::ClientIdentification::ClientCapabilities;
using video_widevine::ClientIdentification;
using video_widevine::License;
using KeyContainer = video_widevine::License::KeyContainer;
using video_widevine::LicenseRequest;
using ContentIdentification = LicenseRequest::ContentIdentification;
using video_widevine::SignedMessage;
using PsshEntitledKey = video_widevine::WidevinePsshData::EntitledKey;
// gmock methods
using ::testing::_;
using ::testing::DoAll;
using ::testing::NotNull;
using ::testing::PrintToStringParamName;
using ::testing::Return;
using ::testing::ReturnRef;
using ::testing::SetArgPointee;
using ::testing::SetArgReferee;
using ::testing::UnorderedElementsAre;
using ::testing::Values;
namespace {
using wvutil::a2bs_hex;
namespace {
const std::string kEmptyString;
const std::string kAesKey = a2bs_hex("000102030405060708090a0b0c0d0e0f");
const std::string kAesIv = a2bs_hex("000102030405060708090a0b0c0d0e0f");
@@ -156,7 +178,7 @@ class MockCryptoSession : public TestCryptoSession {
OEMCrypto_SignatureHashAlgorithm&),
(override));
MOCK_METHOD(CdmResponseType, LoadEntitledContentKeys,
(const std::vector<CryptoKey>& key_array), (override));
(const std::vector<CryptoKey>&), (override));
MOCK_METHOD(bool, GetResourceRatingTier, (uint32_t*), (override));
MOCK_METHOD(bool, GetWatermarkingSupport, (CdmWatermarkingSupport*),
(override));
@@ -169,37 +191,11 @@ class MockPolicyEngine : public PolicyEngine {
public:
MockPolicyEngine(CryptoSession* crypto)
: PolicyEngine("mock_session_id", nullptr, crypto) {}
MOCK_METHOD(
void, SetEntitledLicenseKeys,
(const std::vector<video_widevine::WidevinePsshData_EntitledKey>&),
(override));
MOCK_METHOD(void, SetEntitledLicenseKeys,
(const std::vector<PsshEntitledKey>&), (override));
};
} // namespace
// Protobuf generated classes
using ClientCapabilities =
video_widevine::ClientIdentification::ClientCapabilities;
using video_widevine::ClientIdentification;
using video_widevine::License;
using video_widevine::License_KeyContainer;
using video_widevine::LicenseRequest;
using video_widevine::LicenseRequest_ContentIdentification;
using video_widevine::SignedMessage;
using video_widevine::WidevinePsshData_EntitledKey;
// gmock methods
using ::testing::_;
using ::testing::DoAll;
using ::testing::NotNull;
using ::testing::PrintToStringParamName;
using ::testing::Return;
using ::testing::ReturnRef;
using ::testing::SetArgPointee;
using ::testing::SetArgReferee;
using ::testing::UnorderedElementsAre;
using ::testing::Values;
class CdmLicenseTestPeer : public CdmLicense {
public:
CdmLicenseTestPeer(const CdmSessionId& session_id, wvutil::Clock* clock)
@@ -208,7 +204,10 @@ class CdmLicenseTestPeer : public CdmLicense {
using CdmLicense::HandleNewEntitledKeys;
void set_entitlement_keys(const License& license) {
entitlement_keys_.CopyFrom(license.key());
for (const auto& key_container : license.key()) {
if (key_container.type() != KeyContainer::ENTITLEMENT) continue;
entitlement_key_ids_.insert(key_container.id());
}
}
};
@@ -368,15 +367,13 @@ TEST_F(CdmLicenseTest, PrepareKeyRequestValidation) {
// Verify Client Identification
const ClientIdentification& client_id = license_request.client_id();
EXPECT_EQ(
video_widevine::ClientIdentification_TokenType_DRM_DEVICE_CERTIFICATE,
client_id.type());
EXPECT_EQ(ClientIdentification::DRM_DEVICE_CERTIFICATE, client_id.type());
EXPECT_TRUE(std::equal(client_id.token().begin(), client_id.token().end(),
kToken.begin()));
EXPECT_LT(0, client_id.client_info_size());
for (int i = 0; i < client_id.client_info_size(); ++i) {
const ::video_widevine::ClientIdentification_NameValue& name_value =
const ClientIdentification::NameValue& name_value =
client_id.client_info(i);
EXPECT_TRUE(!name_value.name().empty());
EXPECT_TRUE(!name_value.value().empty());
@@ -406,14 +403,13 @@ TEST_F(CdmLicenseTest, PrepareKeyRequestValidation) {
ClientCapabilities::WATERMARKING_CONFIGURABLE);
// Verify Content Identification
const LicenseRequest_ContentIdentification& content_id =
license_request.content_id();
const ContentIdentification& content_id = license_request.content_id();
ASSERT_TRUE(content_id.has_widevine_pssh_data());
EXPECT_FALSE(content_id.has_webm_key_id());
EXPECT_FALSE(content_id.has_existing_license());
const ::video_widevine::LicenseRequest_ContentIdentification_WidevinePsshData&
widevine_pssh_data = content_id.widevine_pssh_data();
const ContentIdentification::WidevinePsshData& widevine_pssh_data =
content_id.widevine_pssh_data();
EXPECT_TRUE(std::equal(widevine_pssh_data.pssh_data(0).begin(),
widevine_pssh_data.pssh_data(0).end(),
kCencPssh.begin()));
@@ -423,8 +419,7 @@ TEST_F(CdmLicenseTest, PrepareKeyRequestValidation) {
kCryptoRequestId.begin()));
// Verify other license request fields
EXPECT_EQ(::video_widevine::LicenseRequest_RequestType_NEW,
license_request.type());
EXPECT_EQ(LicenseRequest::NEW, license_request.type());
EXPECT_EQ(kLicenseStartTime, license_request.request_time());
EXPECT_EQ(video_widevine::VERSION_2_1, license_request.protocol_version());
EXPECT_EQ(kNonce, license_request.key_control_nonce());
@@ -502,15 +497,13 @@ TEST_F(CdmLicenseTest, PrepareKeyRequestValidationV15) {
// Verify Client Identification
const ClientIdentification& client_id = license_request.client_id();
EXPECT_EQ(
video_widevine::ClientIdentification_TokenType_DRM_DEVICE_CERTIFICATE,
client_id.type());
EXPECT_EQ(ClientIdentification::DRM_DEVICE_CERTIFICATE, client_id.type());
EXPECT_TRUE(std::equal(client_id.token().begin(), client_id.token().end(),
kToken.begin()));
EXPECT_LT(0, client_id.client_info_size());
for (int i = 0; i < client_id.client_info_size(); ++i) {
const ::video_widevine::ClientIdentification_NameValue& name_value =
const ClientIdentification::NameValue& name_value =
client_id.client_info(i);
EXPECT_TRUE(!name_value.name().empty());
EXPECT_TRUE(!name_value.value().empty());
@@ -540,14 +533,13 @@ TEST_F(CdmLicenseTest, PrepareKeyRequestValidationV15) {
ClientCapabilities::WATERMARKING_NOT_SUPPORTED);
// Verify Content Identification
const LicenseRequest_ContentIdentification& content_id =
license_request.content_id();
const ContentIdentification& content_id = license_request.content_id();
ASSERT_TRUE(content_id.has_widevine_pssh_data());
EXPECT_FALSE(content_id.has_webm_key_id());
EXPECT_FALSE(content_id.has_existing_license());
const ::video_widevine::LicenseRequest_ContentIdentification_WidevinePsshData&
widevine_pssh_data = content_id.widevine_pssh_data();
const ContentIdentification::WidevinePsshData& widevine_pssh_data =
content_id.widevine_pssh_data();
EXPECT_TRUE(std::equal(widevine_pssh_data.pssh_data(0).begin(),
widevine_pssh_data.pssh_data(0).end(),
kCencPssh.begin()));
@@ -557,8 +549,7 @@ TEST_F(CdmLicenseTest, PrepareKeyRequestValidationV15) {
kCryptoRequestId.begin()));
// Verify other license request fields
EXPECT_EQ(::video_widevine::LicenseRequest_RequestType_NEW,
license_request.type());
EXPECT_EQ(LicenseRequest::NEW, license_request.type());
EXPECT_EQ(kLicenseStartTime, license_request.request_time());
EXPECT_EQ(video_widevine::VERSION_2_1, license_request.protocol_version());
EXPECT_EQ(kNonce, license_request.key_control_nonce());
@@ -590,14 +581,13 @@ TEST_P(CdmLicenseEntitledKeyTest, LoadsEntitledKeys) {
// Set up a known, fake entitlement key
License entitlement_license;
License_KeyContainer* entitlement_key = entitlement_license.add_key();
entitlement_key->set_type(
video_widevine::License_KeyContainer_KeyType_ENTITLEMENT);
KeyContainer* entitlement_key = entitlement_license.add_key();
entitlement_key->set_type(KeyContainer::ENTITLEMENT);
entitlement_key->set_id(kFakeEntitlementKeyId);
// Set up a fake entitled key that matches the entitlement key
std::vector<WidevinePsshData_EntitledKey> entitled_keys(1);
WidevinePsshData_EntitledKey& padded_key = entitled_keys[0];
std::vector<PsshEntitledKey> entitled_keys(1);
PsshEntitledKey& padded_key = entitled_keys[0];
padded_key.set_entitlement_key_id(kFakeEntitlementKeyId);
padded_key.set_key_id(kFakeEntitledKeyId);
padded_key.set_key(variant.key);

View File

@@ -235,24 +235,30 @@ void MessageDumper::DumpProvisioningRequest(
const CdmProvisioningRequest& request) {
if (wvoec::global_features.derive_key_method ==
wvoec::DeviceFeatures::TEST_PROVISION_40) {
LOGD("Provisioning 4.0 does not have a v17 or v18 core message.");
// The ODKGoldenProvision40V19 test will have its own class for now since
// we are only testing the request.
DumpHeader(&provision_file, "Provision40");
} else {
DumpHeader(&provision_file, "Provision");
SignedProvisioningMessage signed_message;
EXPECT_TRUE(signed_message.ParseFromString(request))
<< "Request = " << wvutil::b2a_hex(request);
if (wvoec::global_features.api_version >= wvoec::kCoreMessagesAPI) {
EXPECT_TRUE(signed_message.has_oemcrypto_core_message());
DumpHex(&provision_file, "core_request",
signed_message.oemcrypto_core_message());
}
}
SignedProvisioningMessage signed_message;
EXPECT_TRUE(signed_message.ParseFromString(request))
<< "Request = " << wvutil::b2a_hex(request);
if (wvoec::global_features.api_version >= wvoec::kCoreMessagesAPI) {
EXPECT_TRUE(signed_message.has_oemcrypto_core_message());
DumpHex(&provision_file, "core_request",
signed_message.oemcrypto_core_message());
}
}
void MessageDumper::DumpProvisioning(const CdmProvisioningResponse& response) {
if (wvoec::global_features.derive_key_method ==
wvoec::DeviceFeatures::TEST_PROVISION_40) {
LOGD("Provisioning 4.0 does not have a core message.");
LOGD(
"Provisioning 4.0 does not have a v17, v18 or v19 core message in the "
"response.");
provision_file << " RunTest();\n";
provision_file << "}\n\n";
} else {
SignedProvisioningMessage signed_response;
if (!signed_response.ParseFromString(response)) {

View File

@@ -69,7 +69,7 @@ void ProvisioningHolder::Provision(CdmCertificateType cert_type,
url_request.PostCertRequestInQueryString(request);
// Receive and parse response.
ASSERT_NO_FATAL_FAILURE(url_request.AssertOkResponse(&response_))
ASSERT_NO_FATAL_FAILURE(url_request.AssertOkResponseWithRetry(&response_))
<< "Failed to fetch provisioning response. "
<< DumpProvAttempt(request, response_, cert_type);

View File

@@ -22,6 +22,7 @@ using wvutil::TestSleep;
namespace wvcdm {
FileSystem* RebootTest::file_system_;
std::unique_ptr<FileSystem> RebootTest::default_file_system_;
namespace {
// How much fudge or round off error do we allow in license durations for reboot
@@ -31,7 +32,10 @@ constexpr int64_t kFudge = 10;
void RebootTest::SetUp() {
WvCdmTestBase::SetUp();
if (!file_system_) file_system_ = CreateTestFileSystem();
if (!file_system_) {
if (!default_file_system_) default_file_system_ = CreateTestFileSystem();
file_system_ = default_file_system_.get();
}
const ::testing::TestInfo* const test_info =
::testing::UnitTest::GetInstance()->current_test_info();

View File

@@ -6,6 +6,7 @@
#define WVCDM_CORE_REBOOT_TEST_H_
#include <map>
#include <memory>
#include <string>
#include <vector>
@@ -37,6 +38,7 @@ class RebootTest : public WvCdmTestBaseWithEngine {
// This is used to store each test's persistent data.
static wvutil::FileSystem* file_system_;
static std::unique_ptr<wvutil::FileSystem> default_file_system_;
// The persistent data for the current test.
std::map<std::string, std::string> persistent_data_;

View File

@@ -373,9 +373,12 @@ void WvCdmTestBase::InstallTestRootOfTrust() {
sizeof(test_keybox)));
break;
case wvoec::DeviceFeatures::LOAD_TEST_RSA_KEY:
// Rare case: used by devices with baked in DRM cert.
// Rare case: used by devices with baked in production DRM cert.
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_LoadTestRSAKey());
break;
case wvoec::DeviceFeatures::PRELOADED_RSA_KEY:
// Rare case: used by devices with baked in test DRM cert.
break;
case wvoec::DeviceFeatures::TEST_PROVISION_30:
// Can use oem certificate to install test rsa key.
break;
@@ -404,6 +407,10 @@ void WvCdmTestBase::Provision() {
}
void WvCdmTestBase::EnsureProvisioned() {
if (wvoec::global_features.provisioning_method == OEMCrypto_DrmCertificate) {
LOGD("Device is preprovisioned.");
return;
}
CdmSessionId session_id;
std::unique_ptr<wvutil::FileSystem> file_system(CreateTestFileSystem());
// OpenSession will check if a DRM certificate exists, while

View File

@@ -5,7 +5,9 @@
#include "url_request.h"
#include <errno.h>
#include <unistd.h>
#include <iostream>
#include <sstream>
#include <gtest/gtest.h>
@@ -24,11 +26,15 @@ const int kConnectTimeoutMs = 15000;
const int kWriteTimeoutMs = 12000;
const int kReadTimeoutMs = 12000;
constexpr int kHttpOk = 200;
const std::vector<int> kRetryCodes = {502, 504};
const std::string kGoogleHeaderUpper("X-Google");
const std::string kGoogleHeaderLower("x-google");
const std::string kCrLf("\r\n");
constexpr unsigned kRetryCount = 3;
constexpr unsigned kRetryIntervalSeconds = 1;
// Concatenate all chunks into one blob and returns the response with
// header information.
void ConcatenateChunkedResponse(const std::string http_response,
@@ -127,13 +133,34 @@ bool UrlRequest::GetResponse(std::string* message) {
return true;
}
void UrlRequest::AssertOkResponse(std::string* message) {
void UrlRequest::AssertOkResponseWithRetry(std::string* message) {
ASSERT_TRUE(message);
ASSERT_TRUE(GetResponse(message));
const int status_code = GetStatusCode(*message);
ASSERT_EQ(kHttpOk, status_code) << "HTTP response from " << socket_.url()
<< ": (" << message->size() << ") :\n"
<< *message;
int status_code = 0;
for (unsigned i = 0; i < kRetryCount; i++) {
*message = "";
ASSERT_TRUE(GetResponse(message)) << "For attempt " << (i + 1);
status_code = GetStatusCode(*message);
// If we didn't get a retry status, then we're done.
if (std::find(kRetryCodes.begin(), kRetryCodes.end(), status_code) ==
kRetryCodes.end()) {
ASSERT_EQ(kHttpOk, status_code) << "HTTP response from " << socket_.url()
<< ": (" << message->size() << ") :\n"
<< *message;
return;
}
std::cerr << "Temporary failure HTTP response from " << socket_.url()
<< ": (" << message->size() << ") :\n"
<< *message << "\n"
<< "Attempt " << (i + 1) << "\n";
socket_.CloseSocket();
is_connected_ = false;
sleep(kRetryIntervalSeconds << i);
Reconnect();
SendRequestOnce();
}
GTEST_FAIL() << "HTTP response from " << socket_.url() << ": ("
<< message->size() << ") :\n"
<< *message;
}
// static
@@ -190,36 +217,35 @@ bool UrlRequest::GetDebugHeaderFields(
bool UrlRequest::PostRequestWithPath(const std::string& path,
const std::string& data) {
std::string request;
request_.clear();
request.append("POST ");
request.append(path);
request.append(" HTTP/1.1\r\n");
request_.append("POST ");
request_.append(path);
request_.append(" HTTP/1.1\r\n");
request.append("Host: ");
request.append(socket_.domain_name());
request.append("\r\n");
request_.append("Host: ");
request_.append(socket_.domain_name());
request_.append("\r\n");
request.append("Connection: close\r\n");
request.append("User-Agent: Widevine CDM v1.0\r\n");
request.append("X-Return-Encrypted-Headers: request_and_response\r\n");
request_.append("Connection: close\r\n");
request_.append("User-Agent: Widevine CDM v1.0\r\n");
request_.append("X-Return-Encrypted-Headers: request_and_response\r\n");
// buffer to store length of data as a string
char data_size_buffer[32] = {0};
snprintf(data_size_buffer, sizeof(data_size_buffer), "%zu", data.size());
request_.append("Content-Length: ");
request_.append(std::to_string(data.size()));
request_.append("\r\n");
request.append("Content-Length: ");
request.append(data_size_buffer); // appends size of data
request.append("\r\n");
request_.append("\r\n"); // empty line to terminate headers
request.append("\r\n"); // empty line to terminate headers
request.append(data);
request_.append(data);
return SendRequestOnce();
}
bool UrlRequest::SendRequestOnce() {
const int ret = socket_.WriteAndLogErrors(
request.c_str(), static_cast<int>(request.size()), kWriteTimeoutMs);
LOGV("HTTP request: (%zu): %s", request.size(), request.c_str());
LOGV("HTTP request hex: %s", wvutil::b2a_hex(request).c_str());
request_.c_str(), static_cast<int>(request_.size()), kWriteTimeoutMs);
LOGV("HTTP request: (%zu): %s", request_.size(), request_.c_str());
LOGV("HTTP request hex: %s", wvutil::b2a_hex(request_).c_str());
return ret != -1;
}

View File

@@ -1,22 +1,23 @@
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
#ifndef CDM_TEST_URL_REQUEST_H_
#define CDM_TEST_URL_REQUEST_H_
#include <map>
#include <string>
#include "disallow_copy_and_assign.h"
#include "http_socket.h"
#include "wv_class_utils.h"
namespace wvcdm {
// Provides simple HTTP request and response service.
// Only POST request method is implemented.
class UrlRequest {
public:
UrlRequest() = delete;
WVCDM_DISALLOW_COPY_AND_MOVE(UrlRequest);
explicit UrlRequest(const std::string& url);
~UrlRequest();
@@ -29,7 +30,8 @@ class UrlRequest {
bool GetResponse(std::string* message);
static int GetStatusCode(const std::string& response);
// Get the response, and expect the status is OK.
void AssertOkResponse(std::string* message);
// It will retry if the response code is in the 500 range.
void AssertOkResponseWithRetry(std::string* message);
static bool GetDebugHeaderFields(
const std::string& response,
@@ -37,13 +39,11 @@ class UrlRequest {
private:
bool PostRequestWithPath(const std::string& path, const std::string& data);
bool SendRequestOnce();
bool is_connected_;
HttpSocket socket_;
CORE_DISALLOW_COPY_AND_ASSIGN(UrlRequest);
};
std::string request_;
}; // class UrlRequest
} // namespace wvcdm
#endif // CDM_TEST_URL_REQUEST_H_