diff --git a/libwvdrmengine/cdm/test/request_license_test.cpp b/libwvdrmengine/cdm/test/request_license_test.cpp index c892345b..9288984e 100644 --- a/libwvdrmengine/cdm/test/request_license_test.cpp +++ b/libwvdrmengine/cdm/test/request_license_test.cpp @@ -1548,6 +1548,118 @@ FourSampleDecryptionInfo kCenc30SwitchCipherData[8] = { }}, }; +// Extracts the scheme, hostname and path from the provided URL. +// Example: +// Input: "https://www.widevine.com/service?id=1234&device=pixel&flag" +// Output: "https://www.widevine.com/service" +std::string GetUrlHostAndPath(const std::string& full_url) { + const auto start_of_params = full_url.find('?'); + if (start_of_params == std::string::npos) return full_url; + return full_url.substr(0, start_of_params); +} + +// Extracts and splits the query parameters from the provided URL. +// Returns an empty list if no parameters are found. +// +// Example: +// Input: "https://www.widevine.com/service?id=1234&device=pixel&flag" +// Output: {"id=1234", "device=pixel", "flag"} +std::vector GetUrlQueryParamPairs(const std::string& full_url) { + const auto start_of_params = full_url.find('?'); + if (start_of_params == std::string::npos) return {}; // No params. + // Remove host and path. + const std::string all_params = full_url.substr(start_of_params + 1); + if (all_params.empty()) return {}; + // Check if there are more than 1 parameters. + auto param_separator = all_params.find('&'); + if (param_separator == std::string::npos) { + return {all_params}; // Only 1 parameter. + } + // Split parameters by '&'. + std::vector params; + params.push_back(all_params.substr(0, param_separator)); + while (param_separator != std::string::npos) { + auto next_param_separator = all_params.find('&', param_separator + 1); + if (next_param_separator == std::string::npos) { + params.push_back(all_params.substr(param_separator + 1)); + } else { + params.push_back(all_params.substr( + param_separator + 1, next_param_separator - param_separator - 1)); + } + param_separator = next_param_separator; + } + return params; +} + +// Extracts and maps the query parameters from the provided URL. +// Creates a map between the parameter keys and values. Parameters +// that are only keys have an empty string value. +// +// Example: +// Input: "https://www.widevine.com/service?id=1234&device=pixel&flag" +// Output: {"id": "1234", "device": "pixel", "flag": ""} +std::map GetUrlQueryParams( + const std::string& full_url) { + const std::vector param_pairs = GetUrlQueryParamPairs(full_url); + std::map params; + if (param_pairs.empty()) return params; + for (const auto& pair : param_pairs) { + const auto value_separator = pair.find('='); + if (value_separator == std::string::npos) { + // Just the key. + params.emplace(pair, ""); + } else { + params.emplace(pair.substr(0, value_separator), + pair.substr(value_separator + 1)); + } + } + return params; +} + +// Checks that the |actual_url| is a super set of information compared +// to the |expected_url|. The scheme, hostname and path must be the +// same. The |actual_url| must contain at all the query parameters of +// the |expected_url|. Order of the query parameters do not matter. +// +// Example A: +// Expected: "https://www.widevine.com/service?key=1234" +// Actual: "https://www.widevine.com/service?retry=true&key=1234" +// Result: true +// +// Example B: +// Expected: "https://www.widevine.com/service?key=1234&retry=true" +// Actual: "https://www.widevine.com/service?key=1234" +// Result: false +// +// Example C: +// Expected: "https://www.widevine.com/service?key=1234" +// Actual: "https://www.widevine.org/service?key=1234" +// Result: false +bool IsUrlSimilar(const std::string& expected_url, + const std::string& actual_url) { + // First check the host and path. + const std::string expected_host_and_path = GetUrlHostAndPath(expected_url); + const std::string actual_host_and_path = GetUrlHostAndPath(actual_url); + if (expected_host_and_path != actual_host_and_path) { + return false; // Bad host and/or path. + } + // Compare query parameters. + const std::map expected_params = + GetUrlQueryParams(expected_url); + const std::map actual_params = + GetUrlQueryParams(actual_url); + if (actual_params.size() < expected_params.size()) { + return false; // Missing params. + } + for (const auto& expected_param : expected_params) { + const auto actual_param = actual_params.find(expected_param.first); + if (actual_param == actual_params.end()) + return false; // Missing particular param. + if (actual_param->second != expected_param.second) + return false; // Incorrect param value. + } + return true; +} } // namespace namespace wvcdm { @@ -1556,6 +1668,10 @@ using video_widevine::ClientIdentification; using video_widevine::ClientIdentification_NameValue; using video_widevine::SignedMessage; +MATCHER_P(IsSimilarUrlTo, expected_url, "") { + return IsUrlSimilar(expected_url, arg); +} + class TestWvCdmClientPropertySet : public CdmClientPropertySet { public: TestWvCdmClientPropertySet() @@ -2058,7 +2174,8 @@ class WvCdmRequestLicenseTest : public WvCdmTestBase { &provisioning_server); EXPECT_EQ(wvcdm::NO_ERROR, status); if (NO_ERROR != status) return; - EXPECT_EQ(provisioning_server, kDefaultProvisioningServerUrl); + EXPECT_THAT(provisioning_server, + IsSimilarUrlTo(kDefaultProvisioningServerUrl)); CdmProvisioningResponse response = GetCertRequestResponse(config_.provisioning_server()); @@ -2177,7 +2294,8 @@ TEST_F(WvCdmRequestLicenseTest, ProvisioningTest) { cert_type, cert_authority, kDefaultCdmIdentifier, kEmptyServiceCertificate, kLevelDefault, &key_msg_, &provisioning_server)); - EXPECT_EQ(provisioning_server, kDefaultProvisioningServerUrl); + EXPECT_THAT(provisioning_server, + IsSimilarUrlTo(kDefaultProvisioningServerUrl)); std::string response = GetCertRequestResponse(config_.provisioning_server()); EXPECT_NE(0, static_cast(response.size())); @@ -2202,7 +2320,8 @@ TEST_F(WvCdmRequestLicenseTest, ProvisioningTestWithServiceCertificate) { cert_type, cert_authority, kDefaultCdmIdentifier, config_.provisioning_service_certificate(), kLevelDefault, &key_msg_, &provisioning_server)); - EXPECT_EQ(provisioning_server, kDefaultProvisioningServerUrl); + EXPECT_THAT(provisioning_server, + IsSimilarUrlTo(kDefaultProvisioningServerUrl)); std::string response = GetCertRequestResponse(config_.provisioning_server()); EXPECT_NE(0, static_cast(response.size())); @@ -2227,7 +2346,8 @@ TEST_F(WvCdmRequestLicenseTest, L3ProvisioningTest) { decryptor_->GetProvisioningRequest( cert_type, cert_authority, kDefaultCdmIdentifier, kEmptyServiceCertificate, kLevel3, &key_msg_, &provisioning_server)); - EXPECT_EQ(provisioning_server, kDefaultProvisioningServerUrl); + EXPECT_THAT(provisioning_server, + IsSimilarUrlTo(kDefaultProvisioningServerUrl)); std::string response = GetCertRequestResponse(config_.provisioning_server()); EXPECT_NE(0, static_cast(response.size())); @@ -2330,14 +2450,16 @@ TEST_F(WvCdmRequestLicenseTest, ProvisioningInterposedRetryTest) { cert_type, cert_authority, kDefaultCdmIdentifier, kEmptyServiceCertificate, kLevelDefault, &key_msg1, &provisioning_server)); - EXPECT_EQ(provisioning_server, kDefaultProvisioningServerUrl); + EXPECT_THAT(provisioning_server, + IsSimilarUrlTo(kDefaultProvisioningServerUrl)); EXPECT_EQ(wvcdm::NO_ERROR, decryptor_->GetProvisioningRequest( cert_type, cert_authority, kDefaultCdmIdentifier, kEmptyServiceCertificate, kLevelDefault, &key_msg2, &provisioning_server)); - EXPECT_EQ(provisioning_server, kDefaultProvisioningServerUrl); + EXPECT_THAT(provisioning_server, + IsSimilarUrlTo(kDefaultProvisioningServerUrl)); // Second message should succeed. key_msg_ = key_msg2; @@ -2375,14 +2497,16 @@ TEST_F(WvCdmRequestLicenseTest, ProvisioningInterspersedRetryTest) { cert_type, cert_authority, kDefaultCdmIdentifier, kEmptyServiceCertificate, kLevelDefault, &key_msg1, &provisioning_server)); - EXPECT_EQ(provisioning_server, kDefaultProvisioningServerUrl); + EXPECT_THAT(provisioning_server, + IsSimilarUrlTo(kDefaultProvisioningServerUrl)); EXPECT_EQ(wvcdm::NO_ERROR, decryptor_->GetProvisioningRequest( cert_type, cert_authority, kDefaultCdmIdentifier, kEmptyServiceCertificate, kLevelDefault, &key_msg2, &provisioning_server)); - EXPECT_EQ(provisioning_server, kDefaultProvisioningServerUrl); + EXPECT_THAT(provisioning_server, + IsSimilarUrlTo(kDefaultProvisioningServerUrl)); // First request expected to fail, because only one message may be active. key_msg_ = key_msg1; @@ -2421,7 +2545,8 @@ TEST_F(WvCdmRequestLicenseTest, DISABLED_X509ProvisioningTest) { cert_type, cert_authority, kDefaultCdmIdentifier, kEmptyServiceCertificate, kLevelDefault, &key_msg_, &provisioning_server)); - EXPECT_EQ(provisioning_server, kDefaultProvisioningServerUrl); + EXPECT_THAT(provisioning_server, + IsSimilarUrlTo(kDefaultProvisioningServerUrl)); std::string response = GetCertRequestResponse(config_.provisioning_server()); EXPECT_NE(0, static_cast(response.size())); @@ -2512,7 +2637,8 @@ TEST_F(WvCdmRequestLicenseTest, ProvisioningRevocationTest) { EXPECT_EQ(wvcdm::NO_ERROR, result); if (NO_ERROR != result) return; - EXPECT_EQ(provisioning_server, kDefaultProvisioningServerUrl); + EXPECT_THAT(provisioning_server, + IsSimilarUrlTo(kDefaultProvisioningServerUrl)); if (!wvcdm::Properties::provisioning_messages_are_binary()) { std::vector request = @@ -2550,7 +2676,8 @@ TEST_F(WvCdmRequestLicenseTest, ProvisioningRevocationTest) { EXPECT_EQ(wvcdm::NO_ERROR, result); if (NO_ERROR != result) return; - EXPECT_EQ(provisioning_server, kDefaultProvisioningServerUrl); + EXPECT_THAT(provisioning_server, + IsSimilarUrlTo(kDefaultProvisioningServerUrl)); ProvisioningResponse provisioning_response; provisioning_response.set_status(status); @@ -2663,7 +2790,8 @@ TEST_F(WvCdmRequestLicenseTest, PropertySetTest) { cert_type, cert_authority, kDefaultCdmIdentifier, kEmptyServiceCertificate, kLevel3, &key_msg_, &provisioning_server)); - EXPECT_EQ(provisioning_server, kDefaultProvisioningServerUrl); + EXPECT_THAT(provisioning_server, + IsSimilarUrlTo(kDefaultProvisioningServerUrl)); std::string response = GetCertRequestResponse(config_.provisioning_server()); EXPECT_NE(0, static_cast(response.size())); @@ -2740,7 +2868,8 @@ TEST_F(WvCdmRequestLicenseTest, ForceL3Test) { cert_type, cert_authority, kDefaultCdmIdentifier, kEmptyServiceCertificate, kLevel3, &key_msg_, &provisioning_server)); - EXPECT_EQ(provisioning_server, kDefaultProvisioningServerUrl); + EXPECT_THAT(provisioning_server, + IsSimilarUrlTo(kDefaultProvisioningServerUrl)); std::string response = GetCertRequestResponse(config_.provisioning_server()); EXPECT_NE(0, static_cast(response.size())); EXPECT_EQ(NO_ERROR, @@ -3150,7 +3279,8 @@ TEST_F(WvCdmRequestLicenseTest, ReleaseRetryL3OfflineKeyTest) { cert_type, cert_authority, kDefaultCdmIdentifier, kEmptyServiceCertificate, kLevel3, &key_msg_, &provisioning_server)); - EXPECT_EQ(provisioning_server, kDefaultProvisioningServerUrl); + EXPECT_THAT(provisioning_server, + IsSimilarUrlTo(kDefaultProvisioningServerUrl)); std::string response = GetCertRequestResponse(config_.provisioning_server()); EXPECT_NE(0, static_cast(response.size())); @@ -3220,7 +3350,8 @@ TEST_F(WvCdmRequestLicenseTest, cert_type, cert_authority, kDefaultCdmIdentifier, kEmptyServiceCertificate, kLevel3, &key_msg_, &provisioning_server_url)); - EXPECT_EQ(provisioning_server_url, kDefaultProvisioningServerUrl); + EXPECT_THAT(provisioning_server_url, + IsSimilarUrlTo(kDefaultProvisioningServerUrl)); std::string response = GetCertRequestResponse(config_.provisioning_server()); EXPECT_NE(0, static_cast(response.size())); diff --git a/libwvdrmengine/run_all_unit_tests.sh b/libwvdrmengine/run_all_unit_tests.sh index bda1f1e3..1cd4fe85 100755 --- a/libwvdrmengine/run_all_unit_tests.sh +++ b/libwvdrmengine/run_all_unit_tests.sh @@ -108,7 +108,7 @@ adb_shell_run event_metric_unittest adb_shell_run file_store_unittest adb_shell_run file_utils_unittest adb_shell_run generic_crypto_unittest -adb_shell_run hidl_metrics_adapter_unittest +adb_shell_run hal_metrics_adapter_unittest adb_shell_run http_socket_test adb_shell_run initialization_data_unittest adb_shell_run libwvdrmdrmplugin_hal_test